diff --git a/.github/workflows.disabled/aggregate-docs.yml b/.github/workflows.disabled/aggregate-docs.yml deleted file mode 100644 index 2ecdc6c..0000000 --- a/.github/workflows.disabled/aggregate-docs.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Aggregate Documentation - -on: - # Run on schedule (daily at 2 AM UTC) - schedule: - - cron: "0 2 * * *" - - workflow_dispatch: - inputs: - repo: - description: "Specific repository to aggregate (optional)" - required: false - type: string - - # Trigger from other repos via webhook - repository_dispatch: - types: [docs-updated] - -permissions: - contents: write - -jobs: - aggregate: - runs-on: ubuntu-latest - - steps: - - name: Checkout docs-ng repository - uses: actions/checkout@v4 - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.13" - - - name: Configure Git - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Run documentation aggregation - run: | - chmod +x scripts/*.sh scripts/*.py - - if [ -n "${{ github.event.inputs.repo }}" ]; then - echo "Aggregating docs for specific repo: ${{ github.event.inputs.repo }}" - ./scripts/aggregate-docs.sh --repo "${{ github.event.inputs.repo }}" - else - echo "Aggregating docs for all repositories" - ./scripts/aggregate-docs.sh - fi - - - name: Check for changes - id: check_changes - run: | - if git diff --quiet docs/projects/; then - echo "has_changes=false" >> $GITHUB_OUTPUT - echo "No changes detected" - else - echo "has_changes=true" >> $GITHUB_OUTPUT - echo "Changes detected" - fi - - - name: Commit and push changes - if: steps.check_changes.outputs.has_changes == 'true' - run: | - git add docs/projects/ - git add docs/.vitepress/config.generated.json || true - - # Create commit message - if [ -n "${{ github.event.inputs.repo }}" ]; then - COMMIT_MSG="docs: update aggregated docs for ${{ github.event.inputs.repo }}" - else - COMMIT_MSG="docs: update aggregated documentation from source repos" - fi - - git commit -m "$COMMIT_MSG" -m "Automated documentation aggregation" - git push - - - name: Summary - if: always() - run: | - echo "## Documentation Aggregation Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - if [ "${{ steps.check_changes.outputs.has_changes }}" == "true" ]; then - echo "Documentation updated and committed" >> $GITHUB_STEP_SUMMARY - else - echo "No changes detected - documentation is up to date" >> $GITHUB_STEP_SUMMARY - fi - - echo "" >> $GITHUB_STEP_SUMMARY - echo "### Aggregated Repositories" >> $GITHUB_STEP_SUMMARY - echo "- gardenlinux/gardenlinux" >> $GITHUB_STEP_SUMMARY - echo "- gardenlinux/builder" >> $GITHUB_STEP_SUMMARY - echo "- gardenlinux/python-gardenlinux-lib" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/check-pr-main.yml b/.github/workflows/check-pr-main.yml new file mode 100644 index 0000000..6b59324 --- /dev/null +++ b/.github/workflows/check-pr-main.yml @@ -0,0 +1,40 @@ +name: Validate repos-config.json + +on: + pull_request: + branches: [main] + paths: + - 'repos-config.json' + +jobs: + validate: + name: Check for non-main refs + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Validate repos-config.json + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const fs = require('fs'); + const config = JSON.parse(fs.readFileSync('repos-config.json', 'utf8')); + const ALLOWED_REFS = new Set(['main', 'master']); + + const errors = []; + for (const repo of config.repos) { + const ref = repo.ref || ''; + if (!ALLOWED_REFS.has(ref) && !ref.startsWith('v') && !ref.startsWith('release-')) { + errors.push(` - ${repo.name}: ref='${ref}' (expected 'main' or a tag)`); + } + } + + if (errors.length > 0) { + core.setFailed( + `repos-config.json contains non-main branch references:\n${errors.join('\n')}\n\n` + + `PRs cannot be merged until all repos reference main branches or tags.` + ); + } else { + core.info('All repos reference main branches or tags'); + } diff --git a/.github/workflows/docs-checks.yml b/.github/workflows/docs-checks.yml new file mode 100644 index 0000000..79c38e4 --- /dev/null +++ b/.github/workflows/docs-checks.yml @@ -0,0 +1,150 @@ +name: Documentation Quality Checks + +on: + workflow_call: + inputs: + override-repo: + description: 'Repository name to override (e.g., gardenlinux)' + required: false + type: string + override-ref: + description: 'Git ref to use for the overridden repo' + required: false + type: string + override-commit: + description: 'Git commit SHA to use for the overridden repo' + required: false + type: string + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + aggregate: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: gardenlinux/docs-ng + # TODO: remove + ref: feat/reusable_ci_workflows + + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pin@v6.2.0 + with: + python-version: "3.13" + + - name: Install Python dependencies + run: | + pip install git+https://github.com/gardenlinux/glrd.git@v4.1.0 + pip install git+https://github.com/gardenlinux/python-gardenlinux-lib.git@0.10.20 + pip install -r requirements.txt + + - name: Run aggregate + run: | + OVERRIDE_ARGS="" + if [ -n "${{ inputs.override-repo }}" ]; then + OVERRIDE_ARGS="--repo ${{ inputs.override-repo }}" + if [ -n "${{ inputs.override-ref }}" ]; then + OVERRIDE_ARGS="$OVERRIDE_ARGS --override-ref ${{ inputs.override-ref }}" + fi + if [ -n "${{ inputs.override-commit }}" ]; then + OVERRIDE_ARGS="$OVERRIDE_ARGS --override-commit ${{ inputs.override-commit }}" + fi + fi + python3 src/aggregate.py $OVERRIDE_ARGS + + - name: Upload aggregated docs + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: aggregated-docs + path: docs/ + retention-days: 1 + + linkcheck: + needs: aggregate + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: gardenlinux/docs-ng + + - name: Download aggregated docs + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: aggregated-docs + path: docs/ + + # installing lychee to call it via make target is hard + - name: Run link check + uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # v2.8.0 + with: + args: docs/**/*.md --config lychee.toml --root-dir "$(pwd)/docs/" + + spelling: + needs: aggregate + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: gardenlinux/docs-ng + + - name: Download aggregated docs + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: aggregated-docs + path: docs/ + + - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 + + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: "22" + cache: "pnpm" + + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pin@v6.2.0 + with: + python-version: "3.13" + + - name: Install dependencies + run: | + pnpm install + pip install -r requirements.txt + + - name: Run spelling check + run: make spelling + + woke: + needs: aggregate + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: gardenlinux/docs-ng + + - name: Download aggregated docs + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: aggregated-docs + path: docs/ + + - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 + + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: "22" + cache: "pnpm" + + - name: Install dependencies + run: | + pnpm install + go install github.com/get-woke/woke@latest + + - name: Run inclusive language check + run: | + export PATH=$PATH:$HOME/go/bin + make woke diff --git a/.github/workflows/docs-pr.yml b/.github/workflows/docs-pr.yml new file mode 100644 index 0000000..9a06cd3 --- /dev/null +++ b/.github/workflows/docs-pr.yml @@ -0,0 +1,131 @@ +name: Create/Update Docs PR + +on: + repository_dispatch: + types: [docs-pr] + workflow_dispatch: + inputs: + repo: + description: 'Repository name (e.g., gardenlinux)' + required: true + type: string + pr_number: + description: 'PR number in source repo' + required: true + type: string + commit_sha: + description: 'Commit SHA from source repo' + required: true + type: string + ref: + description: 'Git ref/branch from source repo' + required: true + type: string + event: + description: 'Event type (pr_success or merged)' + required: true + type: choice + options: + - pr_success + - merged + +jobs: + create-pr: + runs-on: ubuntu-24.04 + steps: + - name: Checkout docs-ng + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Extract payload + id: payload + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + let payload; + if (context.eventName === 'workflow_dispatch') { + payload = context.payload.inputs; + } else { + payload = context.payload.client_payload; + } + core.setOutput('repo', payload.repo); + core.setOutput('pr_number', payload.pr_number); + core.setOutput('commit_sha', payload.commit_sha); + core.setOutput('ref', payload.ref); + core.setOutput('event', payload.event); + + - name: Create or update branch + run: | + BRANCH="auto/${{ steps.payload.outputs.repo }}/${{ steps.payload.outputs.pr_number }}" + git fetch origin main + git checkout -B "$BRANCH" origin/main + + - name: Update repos-config.json + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const fs = require('fs'); + const repoName = '${{ steps.payload.outputs.repo }}'; + const commitSha = '${{ steps.payload.outputs.commit_sha }}'; + const ref = '${{ steps.payload.outputs.ref }}'; + const event = '${{ steps.payload.outputs.event }}'; + + const config = JSON.parse(fs.readFileSync('repos-config.json', 'utf8')); + + for (const repo of config.repos) { + if (repo.name === repoName) { + repo.commit = commitSha; + // If merged, update ref to main; otherwise keep PR branch + repo.ref = event === 'merged' ? 'main' : ref; + break; + } + } + + fs.writeFileSync('repos-config.json', JSON.stringify(config, null, 2) + '\n'); + core.info(`Updated ${repoName}: ref=${ref}, commit=${commitSha}`); + + - name: Commit and push + run: | + git add repos-config.json + git commit -m "docs(${{ steps.payload.outputs.repo }}): update commit lock to ${{ steps.payload.outputs.commit_sha }}" + git push -f origin "auto/${{ steps.payload.outputs.repo }}/${{ steps.payload.outputs.pr_number }}" + + - name: Create or update PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + BRANCH="auto/${{ steps.payload.outputs.repo }}/${{ steps.payload.outputs.pr_number }}" + PR_NUMBER="${{ steps.payload.outputs.pr_number }}" + REPO="${{ steps.payload.outputs.repo }}" + EVENT="${{ steps.payload.outputs.event }}" + + # Check if PR already exists + EXISTING_PR=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number' || echo "") + + if [ -n "$EXISTING_PR" ]; then + echo "PR #$EXISTING_PR already exists, updating..." + if [ "$EVENT" = "merged" ]; then + gh pr ready "$EXISTING_PR" + fi + else + echo "Creating new draft PR..." + gh pr create \ + --draft \ + --title "docs($REPO): Update commit lock from PR #$PR_NUMBER" \ + --body "## Summary + + Automated PR to update the commit lock for \`$REPO\` repository. + + - **Source PR:** https://github.com/gardenlinux/$REPO/pull/$PR_NUMBER + - **Commit:** \`${{ steps.payload.outputs.commit_sha }}\` + - **Status:** $( [ "$EVENT" = "merged" ] && echo 'Ready for review' || echo 'Draft (waiting for source PR to merge)' ) + + This PR was automatically created by the docs-check workflow." + fi diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml deleted file mode 100644 index 491086e..0000000 --- a/.github/workflows/linkcheck.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Link Check - -on: - pull_request: - branches: [main] - push: - branches: [main] - -jobs: - linkcheck: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - - - name: Setup Node.js - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "22" - cache: "pnpm" - - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pin@v6.2.0 - with: - python-version: "3.13" - - - name: Install dependencies - run: | - pnpm install - pip install git+https://github.com/gardenlinux/glrd.git@v4.1.0 - pip install git+https://github.com/gardenlinux/python-gardenlinux-lib.git@0.10.20 - pip install -r requirements.txt - - - name: Run aggregate - run: | - make aggregate - - - name: Run link check - uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # v2.8.0 - with: - args: docs/**/*.md --config lychee.toml --root-dir "$(pwd)/docs/" diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml deleted file mode 100644 index 3ff69d0..0000000 --- a/.github/workflows/spelling.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Spelling Check - -on: - pull_request: - branches: [main] - push: - branches: [main] - -jobs: - spelling: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - - - name: Setup Node.js - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "22" - cache: "pnpm" - - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pin@v6.2.0 - with: - python-version: "3.13" - - - name: Install dependencies - run: | - pnpm install - pip install git+https://github.com/gardenlinux/glrd.git@v4.1.0 - pip install git+https://github.com/gardenlinux/python-gardenlinux-lib.git@0.10.20 - pip install -r requirements.txt - - - name: Run aggregate - run: | - make aggregate - - - name: Run spelling check - run: | - make spelling diff --git a/.github/workflows/woke.yml b/.github/workflows/woke.yml deleted file mode 100644 index 29f9206..0000000 --- a/.github/workflows/woke.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Inclusive Language Check - -on: - pull_request: - branches: [main] - push: - branches: [main] - -jobs: - woke: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0 - - - name: Setup Node.js - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "22" - cache: "pnpm" - - - name: Set up Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # pin@v6.2.0 - with: - python-version: "3.13" - - - name: Install dependencies - run: | - go install github.com/get-woke/woke@latest - pnpm install - pip install git+https://github.com/gardenlinux/glrd.git@v4.1.0 - pip install git+https://github.com/gardenlinux/python-gardenlinux-lib.git@0.10.20 - pip install -r requirements.txt - - - name: Run aggregate - run: | - make aggregate - - - name: Run inclusive language check - run: | - export PATH=$PATH:$HOME/go/bin - make woke diff --git a/src/aggregate.py b/src/aggregate.py index 6f9a6b6..c8ee02e 100755 --- a/src/aggregate.py +++ b/src/aggregate.py @@ -114,6 +114,9 @@ def main() -> int: # Aggregate specific repository %(prog)s --repo gardenlinux + # Aggregate with ref/commit override (for CI from external repos) + %(prog)s --repo gardenlinux --override-ref feature/my-docs --override-commit abc123def + # Update commit locks (fetch and update config with resolved commit hashes) %(prog)s --update-locks """, @@ -138,6 +141,14 @@ def main() -> int: action="store_true", help="Update commit locks: fetch and update config with resolved commit hashes", ) + parser.add_argument( + "--override-ref", + help="Override ref for the repo specified by --repo", + ) + parser.add_argument( + "--override-commit", + help="Override commit for the repo specified by --repo", + ) args = parser.parse_args() @@ -171,6 +182,20 @@ def main() -> int: repos = load_config(str(config_path)) + # Apply overrides if specified + if args.repo and (args.override_ref or args.override_commit): + for repo in repos: + if repo.name == args.repo: + if args.override_ref: + repo.ref = args.override_ref + print(f"Override ref for {repo.name}: {args.override_ref}") + if args.override_commit: + repo.commit = args.override_commit + print(f"Override commit for {repo.name}: {args.override_commit}") + break + else: + print(f"WARNING: Repository '{args.repo}' not found for override") + # Create temporary directory for fetched docs with tempfile.TemporaryDirectory() as temp_dir_str: temp_dir = Path(temp_dir_str)