From c3911d4b74c9c337a74ebf3ecf689d0ebfbe586c Mon Sep 17 00:00:00 2001 From: Alexander Lanin Date: Thu, 3 Sep 2026 08:37:20 +0200 Subject: [PATCH 1/3] ci: remove obsolete link check and try new caching --- .github/actions/link-check/action.yml | 74 ------------ .github/actions/link-check/link_check.sh | 15 --- .github/actions/link-check/link_parser.py | 114 ------------------ .../instructions/process_req.instructions.md | 24 ---- .github/workflows/_test.yml | 7 +- .../workflows/downstream_compatibility.yml | 5 + .github/workflows/link_check.yml | 40 ------ .github/workflows/test_links.yml | 6 + 8 files changed, 13 insertions(+), 272 deletions(-) delete mode 100644 .github/actions/link-check/action.yml delete mode 100755 .github/actions/link-check/link_check.sh delete mode 100644 .github/actions/link-check/link_parser.py delete mode 100644 .github/instructions/process_req.instructions.md delete mode 100644 .github/workflows/link_check.yml diff --git a/.github/actions/link-check/action.yml b/.github/actions/link-check/action.yml deleted file mode 100644 index ca15bda2f..000000000 --- a/.github/actions/link-check/action.yml +++ /dev/null @@ -1,74 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2026 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* -name: 'Link Check and Automated Issue' -description: 'Checks links, parses results, and creates or updates an issue with findings.' -inputs: - github-token: - description: 'GitHub token' - required: true -runs: - using: "composite" - steps: - - name: Checkout repository - uses: actions/checkout@v4.2.2 - - - name: Run LinkChecker (generates linkcheck_output.txt) - shell: bash - run: | - chmod +x ${{ github.action_path }}/link_check.sh - ${{ github.action_path }}/link_check.sh - - - name: Parse broken links (generates issue_body.md) - shell: bash - run: | - python3 ${{ github.action_path }}/link_parser.py linkcheck_output.txt - - - name: Create or update GitHub issue from findings - if: success() && hashFiles('issue_body.md') != '' - uses: actions/github-script@v7 - with: - github-token: ${{ inputs.github-token }} - script: | - const fs = require('fs'); - const path = require('path'); - const body = fs.readFileSync(path.join(process.cwd(), 'issue_body.md'), 'utf-8'); - const title = "Automated Issue: Broken Documentation Links"; - - // Find existing open issue with the same title created by GitHub Actions bot - const { data: issues } = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: "open", - creator: "github-actions[bot]", - labels: undefined, - }); - - const issue = issues.find(i => i.title === title); - - if (issue) { - // Update the existing issue - await github.rest.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body, - }); - } else { - // Create a new issue - await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title, - body, - }); - } diff --git a/.github/actions/link-check/link_check.sh b/.github/actions/link-check/link_check.sh deleted file mode 100755 index 02a6b8290..000000000 --- a/.github/actions/link-check/link_check.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash -# ******************************************************************************* -# Copyright (c) 2026 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* -set -e -bazel run //:docs_link_check > linkcheck_output.txt || true diff --git a/.github/actions/link-check/link_parser.py b/.github/actions/link-check/link_parser.py deleted file mode 100644 index 8ff2ca1de..000000000 --- a/.github/actions/link-check/link_parser.py +++ /dev/null @@ -1,114 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2026 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* -import argparse -import re -import sys -from dataclasses import dataclass -from datetime import datetime - -PARSING_STATUSES = ["broken"] - - -@dataclass -class BrokenLink: - location: str - line_nr: str - reasoning: str - - -def parse_broken_links(log: str) -> list[BrokenLink]: - broken_links: list[BrokenLink] = [] - lines = log.strip().split("\n") - - for line in lines: - parts = line.split(") ") - if len(parts) < 2: - continue - - location_part = parts[0].replace("(", "").strip() - location = location_part.split(":")[0].strip() - line_nr = location_part.split("line")[-1].strip() - status_and_url_part = parts[1] - - if not any(status in status_and_url_part for status in PARSING_STATUSES): - continue - status_and_url = status_and_url_part.split(" - ") - if len(status_and_url) < 2: - continue - reasoning = status_and_url[1].strip() - - broken_links.append( - BrokenLink( - location=location, - line_nr=line_nr, - reasoning=reasoning, - ) - ) - - return broken_links - - -def generate_markdown_table(broken_links: list[BrokenLink]) -> str: - table = "| Location | Line Number | Reasoning |\n" - table += "|----------|-------------|-----------|\n" - - for link in broken_links: - table += f"| {link.location} | {link.line_nr} | {link.reasoning} |\n" - - return table - - -def generate_issue_body(broken_links: list[BrokenLink]) -> str: - markdown_table = generate_markdown_table(broken_links) - return f""" -# Broken Links Report. -**Last updated: {datetime.now().strftime("%d-%m-%Y %H:%M")}** - -The following broken links were detected in the documentation: -{markdown_table} -Please investigate and fix these issues to ensure all links are functional. -Thank you! - -> To test locally if all link issues are resolved use `bazel run //:docs_link_check` - ---- -This issue will be auto updated regularly if link issues are found. -You may close it if you wish. -Though a new one will be created if link issues are still present. - -""" - - -def strip_ansi_codes(text: str) -> str: - """Remove ANSI escape sequences from text""" - ansi_escape = re.compile(r"\x1b\[[0-9;]*m") - return ansi_escape.sub("", text) - - -if __name__ == "__main__": - arg = argparse.ArgumentParser( - description="Parse broken links from Sphinx log and generate issue body." - ) - arg.add_argument("logfile", type=str, help="Path to the Sphinx log file.") - args = arg.parse_args() - with open(args.logfile) as f: - log_content_raw = f.read() - log_content = strip_ansi_codes(log_content_raw) - broken_links = parse_broken_links(log_content) - if not broken_links: - # Nothing broken found, can exit early - sys.exit(0) - issue_body = generate_issue_body(broken_links) - if broken_links: - with open("issue_body.md", "w") as out: - out.write(issue_body) diff --git a/.github/instructions/process_req.instructions.md b/.github/instructions/process_req.instructions.md deleted file mode 100644 index 437298ff1..000000000 --- a/.github/instructions/process_req.instructions.md +++ /dev/null @@ -1,24 +0,0 @@ - - ---- -applyTo: "docs/requirements/requirements.rst" ---- - -This file contains docs-as-code requirements which derived from upstream process requirements. -Those are specified in `bazel-out/k8-fastbuild/bin/external/score_process_description+/needs_json/_build/needs/needs.json` - -The docs-as-code requirements are implemented in this repository, most notably in `src/extensions/score_metamodel/metamodel.yaml` -The metamodel has references to docs-as-code requirement ids. - -Ensure all of that is consistent. diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index c60767295..0141e7185 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -37,12 +37,9 @@ jobs: repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - name: Setup Bazel with shared caching - uses: bazel-contrib/setup-bazel@0.19.0 + uses: eclipse-score/cicd-actions/setup-bazel-cache@cache with: - disk-cache: true - repository-cache: true - bazelisk-cache: true - cache-save: ${{ github.event_name == 'push' }} + disk-cache-key: ${{ github.job }} - name: Setup venv run: bazel run --lockfile_mode=error //:ide_support diff --git a/.github/workflows/downstream_compatibility.yml b/.github/workflows/downstream_compatibility.yml index ccba472da..16d0c4f49 100644 --- a/.github/workflows/downstream_compatibility.yml +++ b/.github/workflows/downstream_compatibility.yml @@ -57,6 +57,11 @@ jobs: packages: graphviz cache: false + - name: Setup Bazel with shared caching + uses: eclipse-score/cicd-actions/setup-bazel-cache@cache + with: + disk-cache-key: ${{ github.job }} + - name: Checkout PR uses: actions/checkout@v7 diff --git a/.github/workflows/link_check.yml b/.github/workflows/link_check.yml deleted file mode 100644 index 589e62fda..000000000 --- a/.github/workflows/link_check.yml +++ /dev/null @@ -1,40 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2026 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* -name: Link Check - -on: - workflow_dispatch: - schedule: - # Runs every week at 00:00 on Sunday - - cron: '0 0 * * 0' - -permissions: - contents: read - issues: write - -jobs: - link-check: - runs-on: ubuntu-latest - steps: - - name: 🛡️ Harden Runner - if: github.repository_owner == 'eclipse-score' - uses: step-security/harden-runner@v2.21.0 - with: - egress-policy: audit - - name: Checkout repo - uses: actions/checkout@v7 - - - name: Run link check action - uses: ./.github/actions/link-check - with: - github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test_links.yml b/.github/workflows/test_links.yml index 179abe609..e47c15fe8 100644 --- a/.github/workflows/test_links.yml +++ b/.github/workflows/test_links.yml @@ -26,6 +26,12 @@ jobs: uses: step-security/harden-runner@v2.21.0 with: egress-policy: audit + + - name: Setup Bazel with shared caching + uses: eclipse-score/cicd-actions/setup-bazel-cache@cache + with: + disk-cache-key: ${{ github.job }} + - name: Checkout repository uses: actions/checkout@v7 From 2e207b96935e92b95e17474b4a9bdba20a466e76 Mon Sep 17 00:00:00 2001 From: Alexander Lanin Date: Thu, 3 Sep 2026 08:53:47 +0200 Subject: [PATCH 2/3] rename job --- .github/workflows/_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 0141e7185..e403ac7f9 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -15,7 +15,7 @@ name: Run Bazel Tests on: workflow_call: jobs: - code: + _tests: runs-on: ubuntu-latest steps: - name: 🛡️ Harden Runner From b973d6b7ac918cffa3c93b3205980d910d2f30a8 Mon Sep 17 00:00:00 2001 From: Alexander Lanin Date: Thu, 3 Sep 2026 09:48:26 +0200 Subject: [PATCH 3/3] ci: restore link check configuration --- .github/actions/link-check/action.yml | 74 ++++++++++++ .github/actions/link-check/link_check.sh | 15 +++ .github/actions/link-check/link_parser.py | 114 ++++++++++++++++++ .../instructions/process_req.instructions.md | 24 ++++ .github/workflows/link_check.yml | 40 ++++++ 5 files changed, 267 insertions(+) create mode 100644 .github/actions/link-check/action.yml create mode 100755 .github/actions/link-check/link_check.sh create mode 100644 .github/actions/link-check/link_parser.py create mode 100644 .github/instructions/process_req.instructions.md create mode 100644 .github/workflows/link_check.yml diff --git a/.github/actions/link-check/action.yml b/.github/actions/link-check/action.yml new file mode 100644 index 000000000..ca15bda2f --- /dev/null +++ b/.github/actions/link-check/action.yml @@ -0,0 +1,74 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +name: 'Link Check and Automated Issue' +description: 'Checks links, parses results, and creates or updates an issue with findings.' +inputs: + github-token: + description: 'GitHub token' + required: true +runs: + using: "composite" + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.2 + + - name: Run LinkChecker (generates linkcheck_output.txt) + shell: bash + run: | + chmod +x ${{ github.action_path }}/link_check.sh + ${{ github.action_path }}/link_check.sh + + - name: Parse broken links (generates issue_body.md) + shell: bash + run: | + python3 ${{ github.action_path }}/link_parser.py linkcheck_output.txt + + - name: Create or update GitHub issue from findings + if: success() && hashFiles('issue_body.md') != '' + uses: actions/github-script@v7 + with: + github-token: ${{ inputs.github-token }} + script: | + const fs = require('fs'); + const path = require('path'); + const body = fs.readFileSync(path.join(process.cwd(), 'issue_body.md'), 'utf-8'); + const title = "Automated Issue: Broken Documentation Links"; + + // Find existing open issue with the same title created by GitHub Actions bot + const { data: issues } = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: "open", + creator: "github-actions[bot]", + labels: undefined, + }); + + const issue = issues.find(i => i.title === title); + + if (issue) { + // Update the existing issue + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body, + }); + } else { + // Create a new issue + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title, + body, + }); + } diff --git a/.github/actions/link-check/link_check.sh b/.github/actions/link-check/link_check.sh new file mode 100755 index 000000000..02a6b8290 --- /dev/null +++ b/.github/actions/link-check/link_check.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +set -e +bazel run //:docs_link_check > linkcheck_output.txt || true diff --git a/.github/actions/link-check/link_parser.py b/.github/actions/link-check/link_parser.py new file mode 100644 index 000000000..8ff2ca1de --- /dev/null +++ b/.github/actions/link-check/link_parser.py @@ -0,0 +1,114 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +import argparse +import re +import sys +from dataclasses import dataclass +from datetime import datetime + +PARSING_STATUSES = ["broken"] + + +@dataclass +class BrokenLink: + location: str + line_nr: str + reasoning: str + + +def parse_broken_links(log: str) -> list[BrokenLink]: + broken_links: list[BrokenLink] = [] + lines = log.strip().split("\n") + + for line in lines: + parts = line.split(") ") + if len(parts) < 2: + continue + + location_part = parts[0].replace("(", "").strip() + location = location_part.split(":")[0].strip() + line_nr = location_part.split("line")[-1].strip() + status_and_url_part = parts[1] + + if not any(status in status_and_url_part for status in PARSING_STATUSES): + continue + status_and_url = status_and_url_part.split(" - ") + if len(status_and_url) < 2: + continue + reasoning = status_and_url[1].strip() + + broken_links.append( + BrokenLink( + location=location, + line_nr=line_nr, + reasoning=reasoning, + ) + ) + + return broken_links + + +def generate_markdown_table(broken_links: list[BrokenLink]) -> str: + table = "| Location | Line Number | Reasoning |\n" + table += "|----------|-------------|-----------|\n" + + for link in broken_links: + table += f"| {link.location} | {link.line_nr} | {link.reasoning} |\n" + + return table + + +def generate_issue_body(broken_links: list[BrokenLink]) -> str: + markdown_table = generate_markdown_table(broken_links) + return f""" +# Broken Links Report. +**Last updated: {datetime.now().strftime("%d-%m-%Y %H:%M")}** + +The following broken links were detected in the documentation: +{markdown_table} +Please investigate and fix these issues to ensure all links are functional. +Thank you! + +> To test locally if all link issues are resolved use `bazel run //:docs_link_check` + +--- +This issue will be auto updated regularly if link issues are found. +You may close it if you wish. +Though a new one will be created if link issues are still present. + +""" + + +def strip_ansi_codes(text: str) -> str: + """Remove ANSI escape sequences from text""" + ansi_escape = re.compile(r"\x1b\[[0-9;]*m") + return ansi_escape.sub("", text) + + +if __name__ == "__main__": + arg = argparse.ArgumentParser( + description="Parse broken links from Sphinx log and generate issue body." + ) + arg.add_argument("logfile", type=str, help="Path to the Sphinx log file.") + args = arg.parse_args() + with open(args.logfile) as f: + log_content_raw = f.read() + log_content = strip_ansi_codes(log_content_raw) + broken_links = parse_broken_links(log_content) + if not broken_links: + # Nothing broken found, can exit early + sys.exit(0) + issue_body = generate_issue_body(broken_links) + if broken_links: + with open("issue_body.md", "w") as out: + out.write(issue_body) diff --git a/.github/instructions/process_req.instructions.md b/.github/instructions/process_req.instructions.md new file mode 100644 index 000000000..437298ff1 --- /dev/null +++ b/.github/instructions/process_req.instructions.md @@ -0,0 +1,24 @@ + + +--- +applyTo: "docs/requirements/requirements.rst" +--- + +This file contains docs-as-code requirements which derived from upstream process requirements. +Those are specified in `bazel-out/k8-fastbuild/bin/external/score_process_description+/needs_json/_build/needs/needs.json` + +The docs-as-code requirements are implemented in this repository, most notably in `src/extensions/score_metamodel/metamodel.yaml` +The metamodel has references to docs-as-code requirement ids. + +Ensure all of that is consistent. diff --git a/.github/workflows/link_check.yml b/.github/workflows/link_check.yml new file mode 100644 index 000000000..589e62fda --- /dev/null +++ b/.github/workflows/link_check.yml @@ -0,0 +1,40 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* +name: Link Check + +on: + workflow_dispatch: + schedule: + # Runs every week at 00:00 on Sunday + - cron: '0 0 * * 0' + +permissions: + contents: read + issues: write + +jobs: + link-check: + runs-on: ubuntu-latest + steps: + - name: 🛡️ Harden Runner + if: github.repository_owner == 'eclipse-score' + uses: step-security/harden-runner@v2.21.0 + with: + egress-policy: audit + - name: Checkout repo + uses: actions/checkout@v7 + + - name: Run link check action + uses: ./.github/actions/link-check + with: + github-token: ${{ secrets.GITHUB_TOKEN }}