From dd496427b8cd80b9cf84437bb20842c0ab08a239 Mon Sep 17 00:00:00 2001 From: 8Guy <200744326+iknowimnotgood@users.noreply.github.com> Date: Sat, 29 Aug 2026 19:24:04 +0700 Subject: [PATCH] Delete .github/workflows directory --- .github/workflows/all-documents.yml | 42 - .github/workflows/article-api-docs.yml | 45 -- .../auto-add-ready-for-doc-review.yml | 56 -- .github/workflows/auto-close-dependencies.yml | 68 -- .github/workflows/benchmark-pages.yml | 170 ---- .github/workflows/changelog-agent.yml | 749 ------------------ .github/workflows/changelog-prompt.yml | 68 -- .github/workflows/check-for-spammy-issues.yml | 82 -- .github/workflows/check-for-spammy-prs.yml | 59 -- .github/workflows/close-bad-repo-sync-prs.yml | 63 -- .github/workflows/close-on-invalid-label.yaml | 47 -- .github/workflows/codeql.yml | 50 -- .../workflows/comment-release-note-info.yml | 33 - .../confirm-internal-staff-work-in-docs.yml | 98 --- .github/workflows/content-lint-markdown.yml | 55 -- .../workflows/content-linter-rules-docs.yml | 48 -- .github/workflows/content-pipelines.yml | 201 ----- .github/workflows/copilot-code-review.yml | 20 - .github/workflows/copilot-setup-steps.yml | 58 -- .../workflows/copy-api-issue-to-internal.yml | 91 --- .../count-translation-corruptions.yml | 44 - .github/workflows/create-changelog-pr.yml | 172 ---- .../delete-orphan-translation-files.yml | 168 ---- .github/workflows/docs-review-collect.yml | 49 -- .github/workflows/dont-delete-assets.yml | 66 -- .github/workflows/dont-delete-features.yml | 65 -- .github/workflows/enterprise-dates.yml | 81 -- .../workflows/enterprise-release-issue.yml | 46 -- .../expertise-required-label-message.yml | 25 - .github/workflows/feedback-prompt.yml | 80 -- .../first-responder-v2-prs-collect.yml | 56 -- .../generate-code-scanning-query-lists.yml | 268 ------- .github/workflows/headless-tests.yml | 68 -- .../workflows/hubber-contribution-help.yml | 69 -- .../workflows/index-autocomplete-search.yml | 58 -- .github/workflows/index-general-search-pr.yml | 111 --- .github/workflows/index-general-search.yml | 369 --------- .github/workflows/keep-caches-warm.yml | 56 -- .github/workflows/line-endings.yml | 45 -- .github/workflows/link-check-external.yml | 227 ------ .../workflows/link-check-github-github.yml | 84 -- .github/workflows/link-check-internal.yml | 432 ---------- .github/workflows/link-check-on-pr.yml | 68 -- .github/workflows/lint-code.yml | 37 - .../lint-entire-content-data-markdown.yml | 56 -- .github/workflows/local-dev.yml | 50 -- .github/workflows/merged-notification.yml | 30 - .github/workflows/moda-allowed-ips.yml | 67 -- .github/workflows/moda-ci.yaml | 103 --- .github/workflows/move-content.yml | 68 -- ...ve-existing-issues-to-the-correct-repo.yml | 80 -- .github/workflows/move-ready-to-merge-pr.yaml | 51 -- .../move-reopened-issues-to-triage.yaml | 59 -- .github/workflows/needs-sme-stale-check.yaml | 53 -- .github/workflows/needs-sme-workflow.yml | 56 -- .github/workflows/no-response.yaml | 84 -- .github/workflows/notify-about-deployment.yml | 59 -- .github/workflows/notify-release-pms.yml | 88 -- .../notify-when-maintainers-cannot-edit.yaml | 66 -- .github/workflows/orphaned-features-check.yml | 114 --- .github/workflows/orphaned-files-check.yml | 127 --- .github/workflows/os-ready-for-review.yml | 69 -- .github/workflows/package-lock-lint.yml | 63 -- .github/workflows/purge-fastly.yml | 123 --- .github/workflows/readability.yml | 106 --- .github/workflows/ready-for-doc-review.yml | 58 -- .../remove-fr-label-remove-from-fr-v2.yml | 46 -- .github/workflows/repo-sync.yml | 200 ----- .github/workflows/restrict-merge-queue.yml | 216 ----- .github/workflows/review-comment.yml | 102 --- .../workflows/reviewers-content-systems.yml | 45 -- .github/workflows/reviewers-dependabot.yml | 46 -- .../workflows/reviewers-docs-engineering.yml | 100 --- .github/workflows/reviewers-legal.yml | 65 -- .github/workflows/site-policy-reminder.yml | 29 - .github/workflows/site-policy-sync.yml | 70 -- .../workflows/sme-review-tracking-issue.yml | 61 -- .github/workflows/stale.yml | 56 -- .github/workflows/sync-audit-logs.yml | 121 --- .github/workflows/sync-codeql-cli.yml | 129 --- .github/workflows/sync-graphql.yml | 107 --- .github/workflows/sync-llms-txt.yml | 282 ------- .github/workflows/sync-openapi.yml | 126 --- .github/workflows/sync-sdk-docs.yml | 245 ------ .github/workflows/sync-secret-scanning.yml | 88 -- .github/workflows/test-changed-content.yml | 64 -- .github/workflows/test.yml | 176 ---- .github/workflows/triage-issue-comments.yml | 80 -- .github/workflows/triage-issues.yml | 31 - .github/workflows/triage-pull-requests.yml | 33 - .github/workflows/triage-stale-check.yml | 94 --- .../triage-unallowed-contributions.yml | 57 -- .github/workflows/validate-asset-images.yml | 28 - .../validate-github-github-docs-urls.yml | 134 ---- .github/workflows/validate-openapi-check.yml | 48 -- .github/workflows/zizmor.yml | 33 - 96 files changed, 9389 deletions(-) delete mode 100644 .github/workflows/all-documents.yml delete mode 100644 .github/workflows/article-api-docs.yml delete mode 100644 .github/workflows/auto-add-ready-for-doc-review.yml delete mode 100644 .github/workflows/auto-close-dependencies.yml delete mode 100644 .github/workflows/benchmark-pages.yml delete mode 100644 .github/workflows/changelog-agent.yml delete mode 100644 .github/workflows/changelog-prompt.yml delete mode 100644 .github/workflows/check-for-spammy-issues.yml delete mode 100644 .github/workflows/check-for-spammy-prs.yml delete mode 100644 .github/workflows/close-bad-repo-sync-prs.yml delete mode 100644 .github/workflows/close-on-invalid-label.yaml delete mode 100644 .github/workflows/codeql.yml delete mode 100644 .github/workflows/comment-release-note-info.yml delete mode 100644 .github/workflows/confirm-internal-staff-work-in-docs.yml delete mode 100644 .github/workflows/content-lint-markdown.yml delete mode 100644 .github/workflows/content-linter-rules-docs.yml delete mode 100644 .github/workflows/content-pipelines.yml delete mode 100644 .github/workflows/copilot-code-review.yml delete mode 100644 .github/workflows/copilot-setup-steps.yml delete mode 100644 .github/workflows/copy-api-issue-to-internal.yml delete mode 100644 .github/workflows/count-translation-corruptions.yml delete mode 100644 .github/workflows/create-changelog-pr.yml delete mode 100644 .github/workflows/delete-orphan-translation-files.yml delete mode 100644 .github/workflows/docs-review-collect.yml delete mode 100644 .github/workflows/dont-delete-assets.yml delete mode 100644 .github/workflows/dont-delete-features.yml delete mode 100644 .github/workflows/enterprise-dates.yml delete mode 100644 .github/workflows/enterprise-release-issue.yml delete mode 100644 .github/workflows/expertise-required-label-message.yml delete mode 100644 .github/workflows/feedback-prompt.yml delete mode 100644 .github/workflows/first-responder-v2-prs-collect.yml delete mode 100644 .github/workflows/generate-code-scanning-query-lists.yml delete mode 100644 .github/workflows/headless-tests.yml delete mode 100644 .github/workflows/hubber-contribution-help.yml delete mode 100644 .github/workflows/index-autocomplete-search.yml delete mode 100644 .github/workflows/index-general-search-pr.yml delete mode 100644 .github/workflows/index-general-search.yml delete mode 100644 .github/workflows/keep-caches-warm.yml delete mode 100644 .github/workflows/line-endings.yml delete mode 100644 .github/workflows/link-check-external.yml delete mode 100644 .github/workflows/link-check-github-github.yml delete mode 100644 .github/workflows/link-check-internal.yml delete mode 100644 .github/workflows/link-check-on-pr.yml delete mode 100644 .github/workflows/lint-code.yml delete mode 100644 .github/workflows/lint-entire-content-data-markdown.yml delete mode 100644 .github/workflows/local-dev.yml delete mode 100644 .github/workflows/merged-notification.yml delete mode 100644 .github/workflows/moda-allowed-ips.yml delete mode 100644 .github/workflows/moda-ci.yaml delete mode 100644 .github/workflows/move-content.yml delete mode 100644 .github/workflows/move-existing-issues-to-the-correct-repo.yml delete mode 100644 .github/workflows/move-ready-to-merge-pr.yaml delete mode 100644 .github/workflows/move-reopened-issues-to-triage.yaml delete mode 100644 .github/workflows/needs-sme-stale-check.yaml delete mode 100644 .github/workflows/needs-sme-workflow.yml delete mode 100644 .github/workflows/no-response.yaml delete mode 100644 .github/workflows/notify-about-deployment.yml delete mode 100644 .github/workflows/notify-release-pms.yml delete mode 100644 .github/workflows/notify-when-maintainers-cannot-edit.yaml delete mode 100644 .github/workflows/orphaned-features-check.yml delete mode 100644 .github/workflows/orphaned-files-check.yml delete mode 100644 .github/workflows/os-ready-for-review.yml delete mode 100644 .github/workflows/package-lock-lint.yml delete mode 100644 .github/workflows/purge-fastly.yml delete mode 100644 .github/workflows/readability.yml delete mode 100644 .github/workflows/ready-for-doc-review.yml delete mode 100644 .github/workflows/remove-fr-label-remove-from-fr-v2.yml delete mode 100644 .github/workflows/repo-sync.yml delete mode 100644 .github/workflows/restrict-merge-queue.yml delete mode 100644 .github/workflows/review-comment.yml delete mode 100644 .github/workflows/reviewers-content-systems.yml delete mode 100644 .github/workflows/reviewers-dependabot.yml delete mode 100644 .github/workflows/reviewers-docs-engineering.yml delete mode 100644 .github/workflows/reviewers-legal.yml delete mode 100644 .github/workflows/site-policy-reminder.yml delete mode 100644 .github/workflows/site-policy-sync.yml delete mode 100644 .github/workflows/sme-review-tracking-issue.yml delete mode 100644 .github/workflows/stale.yml delete mode 100644 .github/workflows/sync-audit-logs.yml delete mode 100644 .github/workflows/sync-codeql-cli.yml delete mode 100644 .github/workflows/sync-graphql.yml delete mode 100644 .github/workflows/sync-llms-txt.yml delete mode 100644 .github/workflows/sync-openapi.yml delete mode 100644 .github/workflows/sync-sdk-docs.yml delete mode 100644 .github/workflows/sync-secret-scanning.yml delete mode 100644 .github/workflows/test-changed-content.yml delete mode 100644 .github/workflows/test.yml delete mode 100644 .github/workflows/triage-issue-comments.yml delete mode 100644 .github/workflows/triage-issues.yml delete mode 100644 .github/workflows/triage-pull-requests.yml delete mode 100644 .github/workflows/triage-stale-check.yml delete mode 100644 .github/workflows/triage-unallowed-contributions.yml delete mode 100644 .github/workflows/validate-asset-images.yml delete mode 100644 .github/workflows/validate-github-github-docs-urls.yml delete mode 100644 .github/workflows/validate-openapi-check.yml delete mode 100644 .github/workflows/zizmor.yml diff --git a/.github/workflows/all-documents.yml b/.github/workflows/all-documents.yml deleted file mode 100644 index 1f0101e770ed..000000000000 --- a/.github/workflows/all-documents.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: All documents script - -# **What it does**: Verifies that the all-documents script works. -# **Why we have it**: Code quality and sustainability. -# **Who does it impact**: docs-engineering - -on: - pull_request: - paths: - - 'src/content-render/scripts/all-documents/**' - - 'package*.json' - - .github/workflows/all-documents.yml - -permissions: - contents: read - -jobs: - all-documents-script: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Run all-documents script - env: - NODE_ENV: production - run: | - echo "Help..." - npm run all-documents -- --help - - echo "" - echo "Storing in a file (English only)" - npm run all-documents -- -o all-documents.json -l en - - echo "" - echo "Look at the first 50 lines of the file..." - cat all-documents.json | jq | head -n 50 - - # We're essentially expecting it to not crash and fail. diff --git a/.github/workflows/article-api-docs.yml b/.github/workflows/article-api-docs.yml deleted file mode 100644 index 8bb96924ab4d..000000000000 --- a/.github/workflows/article-api-docs.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: 'Check article-api docs' - -# **What it does**: Makes sure changes to the article api are documented. -# **Why we have it**: So what's documented doesn't fall behind -# **Who does it impact**: Docs engineering, CGS team - -on: - workflow_dispatch: - pull_request: - paths: - - 'src/article-api/middleware/article.ts' - - 'src/article-api/middleware/pagelist.ts' - # Self-test - - .github/workflows/article-api-docs.yml - -permissions: - contents: read - -jobs: - check-content-linter-rules-docs: - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Check that src/article-api/README.md is up-to-date - run: npm run generate-article-api-docs - - - name: Fail if it isn't up-to-date - run: | - if [ -n "$(git status --porcelain)" ]; then - git status - git diff - - # Some whitespace for the sake of the message below - echo "" - echo "" - - echo "src/article-api/README.md is out of date." - echo "Please run 'npm run generate-article-api-docs' and commit the changes." - exit 1; - fi diff --git a/.github/workflows/auto-add-ready-for-doc-review.yml b/.github/workflows/auto-add-ready-for-doc-review.yml deleted file mode 100644 index a96829d134cf..000000000000 --- a/.github/workflows/auto-add-ready-for-doc-review.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Auto-add ready-for-doc-review label - -# **What it does**: Automatically adds the "ready-for-doc-review" label to DIY docs PRs that contain content or data changes when they are opened in a non-draft state or converted from draft to ready for review. -# **Why we have it**: To ensure DIY docs PRs are automatically added to the docs-content review board without requiring manual labeling. -# **Who does it impact**: Contributors making content changes and docs-content reviewers. - -on: - pull_request: - types: - - opened - - ready_for_review - paths: - - 'content/**' - - 'data/**' - -permissions: - contents: read - pull-requests: write - -jobs: - add-review-label: - name: Add ready-for-doc-review label to DIY docs PRs - if: github.repository == 'github/docs-internal' && github.event.pull_request.draft == false && github.actor != 'github-openapi-bot' && github.actor != 'docs-bot' - runs-on: ubuntu-latest - - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Check team membership - id: membership_check - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - try { - // Team is addressed by numeric ID (org github = 9919, team docs = 325922) - // because IDs survive team renames and slugs do not. - await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', { - org_id: 9919, - team_id: 325922, - username: context.payload.sender.login, - }); - return true - } catch(err) { - console.log(err) - return false - } - - - name: Add ready-for-doc-review label - if: steps.membership_check.outputs.result == 'false' - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - PR_URL: ${{ github.event.pull_request.html_url }} - run: | - gh pr edit $PR_URL --add-label ready-for-doc-review diff --git a/.github/workflows/auto-close-dependencies.yml b/.github/workflows/auto-close-dependencies.yml deleted file mode 100644 index a073fa3328fa..000000000000 --- a/.github/workflows/auto-close-dependencies.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Auto Close Open Source Dependency Updates - -# **What it does**: -# - close-external: Automatically close dependabot's pull requests in the open-source repository. -# **Why we have it**: -# - close-external: To avoid duplicating updates against the internal repository. -# **Who does it impact**: It helps docs engineering focus on higher value work. - -on: - pull_request: - paths: - - 'package*.json' - - 'Gemfile*' - - 'Dockerfile' - - '.github/workflows/**' - pull_request_review: - types: - - edited - - submitted - -permissions: - contents: write - pull-requests: write - -jobs: - close-external: - if: >- - ${{ - github.repository == 'github/docs' && - github.event.pull_request.number && - github.event.pull_request.base.ref == 'main' && - github.event.pull_request.user.login == 'dependabot[bot]' && - github.event.pull_request.state == 'open' - }} - runs-on: ubuntu-latest - steps: - - name: Close pull request and delete branch - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_URL: ${{ github.event.pull_request.html_url }} - run: | - gh pr close "$PR_URL" --delete-branch - - - name: Comment on the pull request - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_URL: ${{ github.event.pull_request.html_url }} - run: | - gh pr comment "$PR_URL" --body "This dependency update will be handled internally by our engineering team." - - # Because we get far too much spam ;_; - - name: Lock conversations - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - env: - PR_NUMBER: ${{ github.event.pull_request.number }} - with: - script: | - try { - await github.rest.issues.lock({ - ...context.repo, - issue_number: parseInt(process.env.PR_NUMBER, 10), - lock_reason: 'resolved' - }) - console.log('Locked the pull request to prevent spam!') - } catch (error) { - console.error(`Failed to lock the pull request. Error: ${error}`) - throw error - } diff --git a/.github/workflows/benchmark-pages.yml b/.github/workflows/benchmark-pages.yml deleted file mode 100644 index a23b3c37784d..000000000000 --- a/.github/workflows/benchmark-pages.yml +++ /dev/null @@ -1,170 +0,0 @@ -name: 'Weekly page benchmark' - -# **What it does**: Benchmarks all pages via the article API, flags errors and slow pages -# **Why we have it**: Catch perf regressions and broken pages before users hit them -# **Who does it impact**: Docs engineering - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: read - -jobs: - benchmark: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - env: - BENCHMARK_LABEL: benchmark-regression - ISSUE_REPO: github/technical-content - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: 'false' - - uses: ./.github/actions/node-npm-setup - - - name: Build - run: npm run build - - - name: Start server - env: - NODE_ENV: production - PORT: 4000 - run: | - npm run start-for-ci & - sleep 5 - curl --retry-connrefused --retry 6 -I http://localhost:4000/ - - - name: Run benchmark - run: | - npx tsx src/workflows/benchmark-pages.ts \ - --versions "free-pro-team@latest,enterprise-cloud@latest,enterprise-server@latest" \ - --modes article-body \ - --slow 1000 \ - --json /tmp/benchmark-results.json | tee /tmp/benchmark-output.txt - - - name: Check results and create issue if needed - if: always() - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - run: | - echo "Reading benchmark results..." - ERRORS=$(jq '.errors | length' /tmp/benchmark-results.json 2>/dev/null || echo "0") - SLOW=$(jq '.slow | length' /tmp/benchmark-results.json 2>/dev/null || echo "0") - TOTAL=$(jq '.totalRequests' /tmp/benchmark-results.json 2>/dev/null || echo "0") - P50=$(jq '.p50' /tmp/benchmark-results.json 2>/dev/null || echo "0") - P99=$(jq '.p99' /tmp/benchmark-results.json 2>/dev/null || echo "0") - MAX=$(jq '.max' /tmp/benchmark-results.json 2>/dev/null || echo "0") - echo "Done reading results: $TOTAL pages, $ERRORS errors, $SLOW slow" - - VERSIONS="free-pro-team@latest, enterprise-cloud@latest, enterprise-server@latest" - LANGS="en" - - if [ "$ERRORS" = "0" ] && [ "$SLOW" = "0" ]; then - echo "✅ All clear — $TOTAL pages, p50=${P50}ms, p99=${P99}ms, max=${MAX}ms" - - echo "Checking for existing open issue..." - existing=$(gh issue list \ - --repo "$ISSUE_REPO" \ - --label "$BENCHMARK_LABEL" \ - --state open \ - --json number \ - --jq '.[0].number // empty' 2>/dev/null || true) - if [ -n "$existing" ]; then - echo "Closing issue #$existing..." - gh issue close "$existing" \ - --repo "$ISSUE_REPO" \ - --comment "All clear as of $RUN_URL — closing." - echo "Done closing issue #$existing" - else - echo "No existing issue to close" - fi - exit 0 - fi - - PROBLEM_COUNT=$((ERRORS + SLOW)) - echo "Found $ERRORS errors and $SLOW slow pages ($PROBLEM_COUNT total problems)" - - echo "Ensuring label exists..." - gh label create "$BENCHMARK_LABEL" \ - --repo "$ISSUE_REPO" \ - --description "Weekly page benchmark found slow or errored pages" \ - --color "e16f24" 2>/dev/null || true - echo "Done ensuring label" - - echo "Building issue body..." - BODY_FILE=/tmp/benchmark-issue-body.md - { - echo "## Weekly page benchmark found issues" - echo "" - echo "**Run:** $RUN_URL" - echo "**Languages:** $LANGS" - echo "**Versions:** $VERSIONS" - echo "**Total pages:** $TOTAL" - echo "**Stats:** p50=${P50}ms · p99=${P99}ms · max=${MAX}ms" - echo "**Errors:** $ERRORS" - echo "**Slow (≥1000ms):** $SLOW" - } > "$BODY_FILE" - - if [ "$ERRORS" -gt 0 ]; then - { - echo "" - echo "### Errors" - echo "" - echo "| Status | Mode | Path | Error |" - echo "|--------|------|------|-------|" - jq -r '.errors[] | "| \(.status) | \(.mode) | \(.path) | \(.errorBody // "" | gsub("\\|"; "\\|") | gsub("\r"; " ") | gsub("\n"; " ")) |"' /tmp/benchmark-results.json - } >> "$BODY_FILE" - fi - - if [ "$SLOW" -gt 0 ]; then - { - echo "" - echo "### Slow pages" - echo "" - echo "| Time | Mode | Path |" - echo "|------|------|------|" - jq -r '.slow[] | "| \(.timeMs)ms | \(.mode) | \(.path) |"' /tmp/benchmark-results.json - } >> "$BODY_FILE" - fi - echo "Done building issue body" - - echo "Checking for existing open issue..." - existing=$(gh issue list \ - --repo "$ISSUE_REPO" \ - --label "$BENCHMARK_LABEL" \ - --state open \ - --json number \ - --jq '.[0].number // empty' 2>/dev/null || true) - - if [ -n "$existing" ]; then - echo "Commenting on existing issue #$existing..." - gh issue comment "$existing" \ - --repo "$ISSUE_REPO" \ - --body-file "$BODY_FILE" - echo "Done commenting on issue #$existing" - else - echo "Creating new issue..." - gh issue create \ - --repo "$ISSUE_REPO" \ - --label "$BENCHMARK_LABEL" \ - --title "[Benchmark] ${PROBLEM_COUNT} slow or errored pages detected" \ - --body-file "$BODY_FILE" - echo "Done creating issue" - fi - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/changelog-agent.yml b/.github/workflows/changelog-agent.yml deleted file mode 100644 index e3894303e0f3..000000000000 --- a/.github/workflows/changelog-agent.yml +++ /dev/null @@ -1,749 +0,0 @@ -name: Changelog agent — draft entry when a qualified PR merges - -# **What it does**: When a PR merges that closes a docs-content issue with a -# parent issue, uses an LLM to draft a changelog entry, opens a PR in -# github/docs-content, and DMs the author in Slack for review. -# **Why we have it**: Automates the changelog drafting process so authors -# don't have to remember to write a changelog entry manually. -# **Who does it impact**: docs-content team members. - -on: - pull_request: - types: [closed] - workflow_dispatch: - inputs: - pr_number: - description: 'PR number to test with (must be a merged PR)' - required: true - type: number - dry_run: - description: 'Dry run — log actions but do not create PR or send Slack DM' - required: false - type: boolean - default: true - -concurrency: - group: changelog-agent-${{ github.event.pull_request.number || github.event.inputs.pr_number }} - cancel-in-progress: true - -permissions: - contents: read - pull-requests: write - issues: write - -env: - CHANGELOG_FILE: docs-content-docs/docs-content-workflows/changelog-internal.md - TARGET_REPO: github/docs-content - -jobs: - generate-changelog: - if: >- - github.repository == 'github/docs-internal' && - ( - (github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main') || - github.event_name == 'workflow_dispatch' - ) - runs-on: ubuntu-latest - steps: - - name: Resolve PR data - id: resolve_pr - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - let pr; - if (context.eventName === 'workflow_dispatch') { - const prNumber = parseInt('${{ inputs.pr_number }}', 10); - const { data } = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - }); - pr = data; - if (!pr.merged) { - core.setFailed(`PR #${prNumber} has not been merged. Cannot test.`); - return; - } - } else { - pr = context.payload.pull_request; - } - core.setOutput('pr_number', pr.number.toString()); - core.setOutput('pr_author', pr.user.login); - core.setOutput('pr_title', pr.title); - core.setOutput('pr_body', pr.body || ''); - core.setOutput('pr_url', pr.html_url); - - - name: Check if PR author is in the team - id: check_team - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const author = '${{ steps.resolve_pr.outputs.pr_author }}'; - - // Fetch github-to-slack.json from docs-content via API - let mapping = {}; - try { - const { data } = await github.rest.repos.getContent({ - owner: 'github', - repo: 'docs-content', - path: '.github/github-to-slack.json', - }); - const content = Buffer.from(data.content, 'base64').toString('utf-8'); - mapping = JSON.parse(content); - } catch (err) { - core.setFailed(`Could not fetch github-to-slack.json from docs-content: ${err.message}`); - return; - } - - // Remove non-user keys (like _comment) - const teamMembers = Object.keys(mapping).filter(k => !k.startsWith('_')); - - if (!teamMembers.includes(author)) { - core.info(`PR author @${author} is not in the team mapping. Skipping.`); - core.setOutput('is_team_member', 'false'); - return; - } - - core.info(`PR author @${author} is a team member. Proceeding.`); - core.setOutput('is_team_member', 'true'); - - - name: Extract linked docs-content issue - if: steps.check_team.outputs.is_team_member == 'true' - id: extract_issue - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - PR_BODY: ${{ steps.resolve_pr.outputs.pr_body }} - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const body = process.env.PR_BODY || ''; - - // Match closing keywords followed by docs-content issue references. - // Supports: closes github/docs-content#123, fixes https://github.com/github/docs-content/issues/123 - const patterns = [ - /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?):?\s+github\/docs-content#(\d+)/gi, - /(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?):?\s+https:\/\/github\.com\/github\/docs-content\/issues\/(\d+)/gi, - ]; - - let issueNumber = null; - for (const pattern of patterns) { - const match = pattern.exec(body); - if (match) { - issueNumber = parseInt(match[1], 10); - break; - } - } - - if (!issueNumber) { - core.info('No linked docs-content issue found in PR body. Exiting.'); - core.setOutput('found', 'false'); - return; - } - - core.info(`Found linked docs-content issue: #${issueNumber}`); - core.setOutput('found', 'true'); - core.setOutput('issue_number', issueNumber.toString()); - - - name: Check for parent issue - if: steps.extract_issue.outputs.found == 'true' - id: check_parent - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const issueNumber = parseInt('${{ steps.extract_issue.outputs.issue_number }}', 10); - - let issue; - try { - const { data } = await github.rest.issues.get({ - owner: 'github', - repo: 'docs-content', - issue_number: issueNumber, - }); - issue = data; - } catch (err) { - core.info(`Could not fetch docs-content issue #${issueNumber}: ${err.message}. Skipping.`); - core.setOutput('has_parent', 'false'); - return; - } - - // Query for parent issue via GraphQL - const query = ` - query($nodeId: ID!) { - node(id: $nodeId) { - ... on Issue { - parent { - number - title - body - url - author { login } - assignees(first: 10) { - nodes { login } - } - repository { - nameWithOwner - } - } - } - } - } - `; - - let result; - try { - result = await github.graphql(query, { nodeId: issue.node_id }); - } catch (err) { - core.info(`GraphQL parent query failed: ${err.message}. Skipping.`); - core.setOutput('has_parent', 'false'); - return; - } - - const parent = result.node?.parent; - - if (!parent) { - core.info('docs-content issue has no parent issue. Exiting.'); - core.setOutput('has_parent', 'false'); - return; - } - - core.info(`Found parent issue: ${parent.repository.nameWithOwner}#${parent.number}`); - core.setOutput('has_parent', 'true'); - core.setOutput('parent_number', parent.number.toString()); - core.setOutput('parent_title', parent.title); - core.setOutput('parent_body', parent.body || ''); - core.setOutput('parent_url', parent.url); - core.setOutput('parent_author', parent.author?.login || ''); - core.setOutput('parent_assignees', (parent.assignees?.nodes || []).map(a => a.login).join(',')); - core.setOutput('parent_repo', parent.repository.nameWithOwner); - - // Also store the docs-content issue details - core.setOutput('dc_issue_title', issue.title); - core.setOutput('dc_issue_body', issue.body || ''); - - - name: Gather PR context - if: steps.check_parent.outputs.has_parent == 'true' - id: gather_context - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - PR_TITLE: ${{ steps.resolve_pr.outputs.pr_title }} - PR_BODY: ${{ steps.resolve_pr.outputs.pr_body }} - PR_URL: ${{ steps.resolve_pr.outputs.pr_url }} - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const prNumber = parseInt('${{ steps.resolve_pr.outputs.pr_number }}', 10); - const prAuthor = '${{ steps.resolve_pr.outputs.pr_author }}'; - - // Get approved reviewers (exclude bots and PR author) - const { data: reviews } = await github.rest.pulls.listReviews({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - }); - - const approvedReviewers = [...new Set( - reviews - .filter(r => r.state === 'APPROVED' && r.user.type !== 'Bot' && r.user.login !== prAuthor) - .map(r => r.user.login) - )]; - - // Get changed files (paths only, limit to 50) - const { data: files } = await github.rest.pulls.listFiles({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNumber, - per_page: 50, - }); - - const changedFiles = files.map(f => f.filename); - - core.setOutput('pr_author', prAuthor); - core.setOutput('pr_title', process.env.PR_TITLE || ''); - core.setOutput('pr_body', process.env.PR_BODY || ''); - core.setOutput('pr_url', process.env.PR_URL || ''); - core.setOutput('pr_number', prNumber.toString()); - core.setOutput('approved_reviewers', approvedReviewers.join(',')); - core.setOutput('changed_files', changedFiles.join('\n')); - - - name: Check for existing changelog PR - if: steps.check_parent.outputs.has_parent == 'true' - id: check_existing - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const branchName = `changelog-agent-${{ steps.resolve_pr.outputs.pr_number }}`; - const { data: pulls } = await github.rest.pulls.list({ - owner: 'github', - repo: 'docs-content', - head: `github:${branchName}`, - state: 'open', - }); - - if (pulls.length > 0) { - core.info(`Changelog PR already exists: ${pulls[0].html_url}`); - core.setOutput('exists', 'true'); - core.setOutput('existing_pr_url', pulls[0].html_url); - } else { - core.setOutput('exists', 'false'); - } - - - name: Read existing changelog examples - if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false' - id: read_examples - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - // Fetch changelog-internal.md from docs-content - const { data } = await github.rest.repos.getContent({ - owner: 'github', - repo: 'docs-content', - path: 'docs-content-docs/docs-content-workflows/changelog-internal.md', - }); - const changelog = Buffer.from(data.content, 'base64').toString('utf-8'); - - // Extract the first 3 entries (each starts with **date**) - const lines = changelog.split('\n'); - let count = 0; - let examples = []; - let capturing = false; - for (const line of lines) { - if (/^\*\*\d/.test(line)) { - count++; - if (count > 3) break; - capturing = true; - } - if (capturing) examples.push(line); - } - - core.setOutput('examples', examples.join('\n')); - - - name: Prepare prompts for LLM - if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false' - id: prepare_prompts - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - PR_TITLE: ${{ steps.gather_context.outputs.pr_title }} - PR_BODY: ${{ steps.gather_context.outputs.pr_body }} - PR_AUTHOR: ${{ steps.gather_context.outputs.pr_author }} - CHANGED_FILES: ${{ steps.gather_context.outputs.changed_files }} - APPROVED_REVIEWERS: ${{ steps.gather_context.outputs.approved_reviewers }} - DC_ISSUE_TITLE: ${{ steps.check_parent.outputs.dc_issue_title }} - DC_ISSUE_BODY: ${{ steps.check_parent.outputs.dc_issue_body }} - PARENT_TITLE: ${{ steps.check_parent.outputs.parent_title }} - PARENT_BODY: ${{ steps.check_parent.outputs.parent_body }} - PARENT_AUTHOR: ${{ steps.check_parent.outputs.parent_author }} - PARENT_ASSIGNEES: ${{ steps.check_parent.outputs.parent_assignees }} - CHANGELOG_EXAMPLES: ${{ steps.read_examples.outputs.examples }} - with: - script: | - const fs = require('fs'); - - const today = new Date(); - const dateStr = today.toLocaleDateString('en-GB', { - day: 'numeric', month: 'long', year: 'numeric' - }); - - const systemPrompt = `You are a technical writer for GitHub Docs. You write changelog entries for the internal docs changelog. - - Rules: - - Write in plain, clear language suitable for an internal audience of docs team members - - Focus on what shipped and its impact on users of docs.github.com - - Use present tense or past tense consistently - - Include links to relevant docs pages when possible (use full https://docs.github.com/... URLs) - - The entry MUST include these sections in order: - 1. A brief description paragraph of what shipped - 2. **Anticipated impact**: One or two sentences about who is affected and how - 3. **Authored by**: @username of the PR author - 4. **Thanks to**: @usernames of reviewers and stakeholders who helped - - Do NOT include any internal issue numbers, PR numbers, or repo references in the description - - Do NOT disclose sensitive information - - Match the tone and structure of the example entries provided - - Output ONLY the changelog entry text (no date header, no
tag — those are added automatically)`; - - const reviewers = process.env.APPROVED_REVIEWERS - ? process.env.APPROVED_REVIEWERS.split(',').filter(r => r !== process.env.PR_AUTHOR).map(r => `@${r}`).join(', ') - : ''; - const stakeholders = [ - process.env.PARENT_AUTHOR, - ...(process.env.PARENT_ASSIGNEES ? process.env.PARENT_ASSIGNEES.split(',') : []), - ].filter(Boolean).filter(u => u !== process.env.PR_AUTHOR).filter((v, i, a) => a.indexOf(v) === i).map(u => `@${u}`).join(', '); - - const thanksTo = [reviewers, stakeholders].filter(Boolean).join(', '); - - const userPrompt = `Draft a changelog entry for a docs change that just shipped. - - ## PR details - Title: ${process.env.PR_TITLE} - Description: ${process.env.PR_BODY} - Author: @${process.env.PR_AUTHOR} - Changed files: - ${process.env.CHANGED_FILES} - - ## docs-content issue - Title: ${process.env.DC_ISSUE_TITLE} - Description: ${process.env.DC_ISSUE_BODY} - - ## Parent issue (broader feature/initiative) - Title: ${process.env.PARENT_TITLE} - Description: ${process.env.PARENT_BODY} - - ## Credits - Author: @${process.env.PR_AUTHOR} - Thanks to: ${thanksTo || 'N/A'} - - ## Example entries from the existing changelog (match this style): - ${process.env.CHANGELOG_EXAMPLES} - - Write the changelog entry now. Include the **Anticipated impact**, **Authored by**, and **Thanks to** sections.`; - - fs.writeFileSync('system-prompt.txt', systemPrompt); - fs.writeFileSync('prompt.txt', userPrompt); - core.setOutput('date_str', dateStr); - - - name: Set up Node.js for Copilot CLI - if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false' - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 24 - - - name: Install GitHub Copilot CLI - if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false' - run: npm install -g @github/copilot@1.0.71 - - - name: Generate changelog draft via Copilot - if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false' - id: generate_draft - uses: actions/ai-inference@2c43c91ae16266ca159d311430343c67a5ffa222 # v3 - with: - provider: copilot - # No model is pinned: actions/ai-inference forwards --model to the - # Copilot CLI only when it differs from its GitHub Models default, so - # omitting it lets the CLI pick its own current default (latest Sonnet) - # and avoids breaking when a pinned slug (e.g. gpt-4.1) is retired. - prompt-file: prompt.txt - system-prompt-file: system-prompt.txt - max-completion-tokens: 1000 - temperature: 0.3 - env: - COPILOT_GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_COPILOT }} - - - name: Dry run summary - if: steps.generate_draft.outputs.response != '' && inputs.dry_run == true - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - PR_AUTHOR: ${{ steps.gather_context.outputs.pr_author }} - PR_URL: ${{ steps.gather_context.outputs.pr_url }} - PARENT_TITLE: ${{ steps.check_parent.outputs.parent_title }} - DRAFT: ${{ steps.generate_draft.outputs.response }} - with: - script: | - core.info('=== DRY RUN — no PR will be created, no Slack DM sent ==='); - core.info(`PR author: ${process.env.PR_AUTHOR || ''}`); - core.info(`Source PR: ${process.env.PR_URL || ''}`); - core.info(`Parent issue: ${process.env.PARENT_TITLE || ''}`); - core.info('--- Generated changelog draft ---'); - core.info((process.env.DRAFT || '').replace(/^::/gm, ': :')); - core.info('--- End of draft ---'); - - - name: Create changelog PR in docs-content - if: steps.generate_draft.outputs.response != '' && steps.check_existing.outputs.exists == 'false' && inputs.dry_run != true - id: create_pr - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - DRAFT: ${{ steps.generate_draft.outputs.response }} - DATE_STR: ${{ steps.prepare_prompts.outputs.date_str }} - PR_AUTHOR: ${{ steps.gather_context.outputs.pr_author }} - PR_URL: ${{ steps.gather_context.outputs.pr_url }} - PR_NUMBER: ${{ steps.gather_context.outputs.pr_number }} - APPROVED_REVIEWERS: ${{ steps.gather_context.outputs.approved_reviewers }} - PARENT_TITLE: ${{ steps.check_parent.outputs.parent_title }} - PARENT_URL: ${{ steps.check_parent.outputs.parent_url }} - PARENT_AUTHOR: ${{ steps.check_parent.outputs.parent_author }} - PARENT_ASSIGNEES: ${{ steps.check_parent.outputs.parent_assignees }} - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const branchName = `changelog-agent-${{ steps.resolve_pr.outputs.pr_number }}`; - const filePath = 'docs-content-docs/docs-content-workflows/changelog-internal.md'; - - // Get the current changelog file from docs-content - const { data: fileData } = await github.rest.repos.getContent({ - owner: 'github', - repo: 'docs-content', - path: filePath, - }); - - let changelog = Buffer.from(fileData.content, 'base64').toString('utf-8'); - - // Build the new entry - const entry = `**${process.env.DATE_STR}**\n\n${process.env.DRAFT}\n\n
`; - - // Insert after the first H1 heading so leading frontmatter, comments, - // or blank lines do not affect placement. - const lines = changelog.split('\n'); - const headingIndex = lines.findIndex((line) => line.startsWith('# ')); - - if (headingIndex === -1) { - changelog = `${entry}\n${changelog}`; - } else { - const beforeAndHeading = lines.slice(0, headingIndex + 1).join('\n'); - const rest = lines.slice(headingIndex + 1).join('\n'); - changelog = rest - ? `${beforeAndHeading}\n\n${entry}\n${rest}` - : `${beforeAndHeading}\n\n${entry}`; - } - - // Get the default branch SHA for creating a new branch - const { data: ref } = await github.rest.git.getRef({ - owner: 'github', - repo: 'docs-content', - ref: 'heads/main', - }); - - // Create the branch in docs-content - try { - await github.rest.git.createRef({ - owner: 'github', - repo: 'docs-content', - ref: `refs/heads/${branchName}`, - sha: ref.object.sha, - }); - } catch (err) { - if (err.status === 422) { - core.info('Branch already exists, will update file on existing branch.'); - } else { - throw err; - } - } - - // Fetch the file from the branch (handles both new and existing branches) - const { data: branchFileData } = await github.rest.repos.getContent({ - owner: 'github', - repo: 'docs-content', - path: filePath, - ref: branchName, - }); - - // Update the changelog file on the new branch - await github.rest.repos.createOrUpdateFileContents({ - owner: 'github', - repo: 'docs-content', - path: filePath, - message: `Changelog draft for docs-internal PR #${process.env.PR_NUMBER}`, - content: Buffer.from(changelog).toString('base64'), - sha: branchFileData.sha, - branch: branchName, - committer: { - name: 'github-actions[bot]', - email: 'github-actions[bot]@users.noreply.github.com', - }, - }); - - // Build credits for the PR body - const reviewers = process.env.APPROVED_REVIEWERS - ? process.env.APPROVED_REVIEWERS.split(',').map(r => `@${r}`).join(', ') - : 'None'; - const parentAuthor = process.env.PARENT_AUTHOR ? `@${process.env.PARENT_AUTHOR}` : 'Unknown'; - const parentAssignees = process.env.PARENT_ASSIGNEES - ? process.env.PARENT_ASSIGNEES.split(',').map(a => `@${a}`).join(', ') - : 'None'; - - const prBody = [ - '### Automated docs changelog draft', - '', - `_Generated by the changelog-agent workflow from [docs-internal PR #${process.env.PR_NUMBER}](${process.env.PR_URL})._`, - '', - '**⚠️ This is an AI-generated draft. Please review carefully before merging.**', - '', - `**Source PR:** [docs-internal#${process.env.PR_NUMBER}](${process.env.PR_URL})`, - `**Parent initiative:** [${process.env.PARENT_TITLE}](${process.env.PARENT_URL})`, - '', - '#### Credits', - `- **Author:** @${process.env.PR_AUTHOR}`, - `- **Reviewers:** ${reviewers}`, - `- **Parent issue author:** ${parentAuthor}`, - `- **Parent issue assignees:** ${parentAssignees}`, - '', - '#### Review checklist', - '- [ ] Entry is accurate and covers what shipped', - '- [ ] Content is appropriate for the internal audience', - '- [ ] Format is consistent with other changelog entries', - '- [ ] No sensitive information disclosed', - ].join('\n'); - - const { data: pullRequest } = await github.rest.pulls.create({ - owner: 'github', - repo: 'docs-content', - title: `Changelog draft for docs-internal PR #${process.env.PR_NUMBER}`, - body: prBody, - head: branchName, - base: 'main', - draft: false, - }); - - // Add labels - try { - await github.rest.issues.addLabels({ - owner: 'github', - repo: 'docs-content', - issue_number: pullRequest.number, - labels: ['skip FR board', 'llm-generated'], - }); - } catch (err) { - core.warning(`Failed to add labels: ${err.message}`); - } - - // Request review from PR author - try { - await github.rest.pulls.requestReviewers({ - owner: 'github', - repo: 'docs-content', - pull_number: pullRequest.number, - reviewers: [process.env.PR_AUTHOR], - }); - } catch (err) { - core.warning(`Failed to request review from @${process.env.PR_AUTHOR}: ${err.message}`); - } - - core.setOutput('changelog_pr_url', pullRequest.html_url); - core.setOutput('changelog_pr_number', pullRequest.number.toString()); - - - name: Notify author via Slack DM - if: steps.create_pr.outputs.changelog_pr_url != '' && inputs.dry_run != true - id: slack_notify - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - SLACK_TOKEN: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - PR_AUTHOR: ${{ steps.gather_context.outputs.pr_author }} - CHANGELOG_PR_URL: ${{ steps.create_pr.outputs.changelog_pr_url }} - PR_URL: ${{ steps.gather_context.outputs.pr_url }} - APPROVED_REVIEWERS: ${{ steps.gather_context.outputs.approved_reviewers }} - PARENT_TITLE: ${{ steps.check_parent.outputs.parent_title }} - PARENT_AUTHOR: ${{ steps.check_parent.outputs.parent_author }} - PARENT_ASSIGNEES: ${{ steps.check_parent.outputs.parent_assignees }} - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const author = process.env.PR_AUTHOR; - const changelogPrUrl = process.env.CHANGELOG_PR_URL; - - // Fetch GitHub-to-Slack mapping from docs-content - let slackMapping = {}; - try { - const { data } = await github.rest.repos.getContent({ - owner: 'github', - repo: 'docs-content', - path: '.github/github-to-slack.json', - }); - const content = Buffer.from(data.content, 'base64').toString('utf-8'); - slackMapping = JSON.parse(content); - } catch (err) { - core.warning(`Could not fetch github-to-slack.json: ${err.message}`); - } - - const slackUserId = slackMapping[author]; - - // Build credits summary for the DM - const reviewers = process.env.APPROVED_REVIEWERS - ? process.env.APPROVED_REVIEWERS.split(',').join(', ') - : 'none'; - const stakeholders = [ - process.env.PARENT_AUTHOR, - ...(process.env.PARENT_ASSIGNEES ? process.env.PARENT_ASSIGNEES.split(',') : []), - ].filter(Boolean).filter((v, i, a) => a.indexOf(v) === i).join(', '); - - const slackMessage = [ - `👋 Hi! A changelog draft has been created for your merged PR:`, - ``, - `📝 *Changelog PR:* ${changelogPrUrl}`, - `🔗 *Source PR:* ${process.env.PR_URL}`, - `🎯 *Parent initiative:* ${process.env.PARENT_TITLE}`, - ``, - `*Reviewers to thank:* ${reviewers || 'none'}`, - `*Stakeholders to thank:* ${stakeholders || 'none'}`, - ``, - `Please review the draft changelog entry and merge or close the PR. The entry is AI-generated, so double-check accuracy and tone.`, - ].join('\n'); - - if (slackUserId) { - try { - const response = await fetch('https://slack.com/api/chat.postMessage', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.SLACK_TOKEN}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - channel: slackUserId, - text: slackMessage, - }), - }); - - const result = await response.json(); - if (result.ok) { - core.info(`Slack DM sent to ${author} (${slackUserId})`); - core.setOutput('notified_via', 'slack'); - return; - } else { - core.warning(`Slack API error: ${result.error}`); - } - } catch (err) { - core.warning(`Slack DM failed: ${err.message}`); - } - } else { - core.warning(`No Slack mapping found for GitHub user: ${author}`); - } - - // Fallback: post a GitHub comment on the source PR - core.info('Falling back to GitHub comment notification.'); - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: parseInt('${{ steps.resolve_pr.outputs.pr_number }}', 10), - body: [ - `👋 @${author} — A changelog draft has been created for this PR!`, - ``, - `📝 **Changelog PR:** ${changelogPrUrl}`, - ``, - `Please review the draft entry and merge or close it. The entry is AI-generated, so double-check accuracy and tone.`, - ``, - `**Reviewers to thank:** ${reviewers || 'none'}`, - `**Stakeholders to thank:** ${stakeholders || 'none'}`, - ].join('\n'), - }); - core.setOutput('notified_via', 'github_comment'); - - - name: Post agent marker comment - if: steps.create_pr.outputs.changelog_pr_url != '' && inputs.dry_run != true - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const changelogPrUrl = '${{ steps.create_pr.outputs.changelog_pr_url }}'; - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: parseInt('${{ steps.resolve_pr.outputs.pr_number }}', 10), - body: `\n🤖 A changelog draft PR has been automatically created in docs-content: ${changelogPrUrl}`, - }); - - # Local composite actions below require the repository to be checked out. - - name: Check out repo - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/changelog-prompt.yml b/.github/workflows/changelog-prompt.yml deleted file mode 100644 index 092d796b6f74..000000000000 --- a/.github/workflows/changelog-prompt.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Changelog prompt when a PR is closed - -on: - pull_request: - types: [closed] - -permissions: - contents: read - pull-requests: write - -jobs: - comment-on-pr: - # This workflow should only run on the 'github/docs-internal' repository because it posts changelog instructions - # and links that are specific to the internal documentation process and resources. - # It also only runs if PR is merged into the main branch. - if: github.repository == 'github/docs-internal' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' - - runs-on: ubuntu-latest - - steps: - - name: Check if PR author is in docs-content team - id: check_team - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - try { - const pr = context.payload.pull_request; - // Team is addressed by numeric ID (org github = 9919, team docs-content = 2796154) - // because IDs survive team renames and slugs do not. - await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', { - org_id: 9919, - team_id: 2796154, - username: pr.user.login, - }); - core.exportVariable('CONTINUE_WORKFLOW', 'true'); - } catch(err) { - core.info("Workflow triggered by a merged PR, but the PR author is not a member of the docs-content team."); - core.exportVariable('CONTINUE_WORKFLOW', 'false'); - } - - - name: Post changelog instructions comment - - if: env.CONTINUE_WORKFLOW == 'true' - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - // Get PR author username - const pr = context.payload.pull_request; - const prAuthor = pr.user.login; - - // Compose the comment body with readable YAML and correct formatting - const commentBody = - "👋 @" + prAuthor + - " - Did this PR add noteworthy changes to the GitHub docs? If so, you might want to publicize this by adding an entry to " + - "the [Docs changelog](https://github.com/github/docs-internal/blob/main/CHANGELOG.md).\n\n" + - "To do this, type `/changelog` in a new comment on this PR and complete the fields.\n\n" + - "A message will be posted to the **#docs-changelog** channel and a PR will be raised to update the [CHANGELOG.md](https://github.com/github/docs-internal/blob/main/CHANGELOG.md) file."; - - // Post the comment - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - body: commentBody - }); diff --git a/.github/workflows/check-for-spammy-issues.yml b/.github/workflows/check-for-spammy-issues.yml deleted file mode 100644 index 578706526565..000000000000 --- a/.github/workflows/check-for-spammy-issues.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: Check for Spammy Issues - -# **What it does**: This action closes low value issues in the open-source repository. -# **Why we have it**: We get lots of spam in the open-source repository. -# **Who does it impact**: Open-source contributors. - -on: - issues: - types: [opened] - -permissions: - contents: read - -jobs: - spammy-title-check: - name: Remove issues with spammy titles - if: github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - - const issue = context.payload.issue - const owner = 'github' - const repo = 'docs' - - const titleWordCount = issue.title.trim().split(' ').length - const titleWordCountMin = 3 - - try { - await github.rest.teams.getMembershipForUserInOrg({ - org: 'github', - team_slug: 'employees', - username: context.payload.sender.login, - }); - - // Do not perform this workflow with GitHub employees. This return - // statement only gets hit if the user is a GitHub employee - return - } catch (err) { - // An error will be thrown if the user is not a GitHub employee - // If a user is not a GitHub employee, we should check to see if title has at least the minimum required number of words in it and if it does, we can exit the workflow - - if (titleWordCount >= titleWordCountMin) { - return - } - } - - // - // Assuming the user is not a GitHub employee and the issue title - // does not contain the minimum number of words required, proceed. - // - - // Close the issue and add the invalid label - await github.rest.issues.update({ - owner: owner, - repo: repo, - issue_number: issue.number, - labels: ['invalid'], - state: 'closed' - }); - - // Comment on the issue - await github.rest.issues.createComment({ - owner: owner, - repo: repo, - issue_number: issue.number, - body: `This issue may have been opened accidentally. I'm going to close it now, but feel free to open a new issue with a more descriptive title!` - }); - - // Add the issue to the Done column on the triage board - try { - await github.rest.projects.createCard({ - column_id: 11167427, - content_id: context.payload.issue.id, - content_type: "Issue" - }); - } catch (error) { - console.log(error); - } diff --git a/.github/workflows/check-for-spammy-prs.yml b/.github/workflows/check-for-spammy-prs.yml deleted file mode 100644 index f10202bf7204..000000000000 --- a/.github/workflows/check-for-spammy-prs.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Check for Spammy PRs - -# **What it does**: This action closes low value pull requests in the open-source repository. -# **Why we have it**: We get lots of spam in the open-source repository. -# **Who does it impact**: Open-source contributors. - -on: - pull_request_target: - types: [opened] - -permissions: - contents: read - pull-requests: write - -jobs: - spammy-pr-check: - name: Label PRs that only delete files or touch a large number of files - if: > - github.repository == 'github/docs' && github.event_name == 'pull_request_target' && - github.event.pull_request.user.login != 'docs-bot' - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const owner = 'github' - const repo = 'docs' - const pull_number = context.payload.pull_request.number - - const { data: files } = await github.rest.pulls.listFiles({ - owner: owner, - repo: repo, - pull_number: pull_number, - }); - - const onlyDeletes = files.length > 0 && files.every(f => f.status === 'removed') - const isEmptyCommit = !files.length - const touchesTooMany = files.length > 10 - const totalChanges = files.reduce((sum, f) => sum + f.additions + f.deletions, 0) - const isOneLineAddition = files.every(f => f.status === 'added') && totalChanges <= 1 - - // Close the PR and add the invalid label - if (onlyDeletes || isEmptyCommit || touchesTooMany || isOneLineAddition) { - await github.rest.issues.update({ - owner: owner, - repo: repo, - issue_number: pull_number, - labels: ['invalid'], - }); - - // Comment on the PR - await github.rest.issues.createComment({ - owner: owner, - repo: repo, - issue_number: pull_number, - body: `This pull request may have been opened accidentally. I'm going to close it now, but feel free to check out our [contribution guidelines](https://docs.github.com/en/contributing), or raise an issue.`, - }); - } diff --git a/.github/workflows/close-bad-repo-sync-prs.yml b/.github/workflows/close-bad-repo-sync-prs.yml deleted file mode 100644 index 507b8596f2da..000000000000 --- a/.github/workflows/close-bad-repo-sync-prs.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Close bad repo-sync PRs - -# **What it does**: -# Closes and PR from `repo-sync` to `main` that wasn't created by a Hubber. -# **Why we have it**: -# Unfortunately, a lot of PRs in github/docs are created by people who -# shouldn't be creating such PRs. We bot our bots to own it. -# **Who does it impact**: Open-source. - -on: - # Necessary in lieu of `pull_request` so that PRs opened from forks can be closed if they try to push to a repo sync branch. - pull_request_target: - -permissions: - contents: write - pull-requests: write - -jobs: - close-invalid-repo-sync-pr: - if: ${{ github.repository == 'github/docs' && github.event.pull_request.base.ref == 'main' && github.event.pull_request.head.ref == 'repo-sync' }} - name: Close if invalid repo-sync PR author - runs-on: ubuntu-latest - steps: - - name: Close pull request if unwanted - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const { owner, repo } = context.repo - const prCreator = context.actor - const prNumber = context.issue.number - - try { - await github.rest.teams.getMembershipForUserInOrg({ - org: 'github', - team_slug: 'employees', - username: prCreator - }) - - // If the PR creator is a GitHub employee, stop now - console.log("PR creator is a GitHub employee") - return - } catch (err) { - // An error will be thrown if the user is not a GitHub employee. - // That said, we still want to proceed anyway! - } - - // Close the PR and add the invalid label - await github.rest.issues.update({ - owner, - repo, - issue_number: prNumber, - labels: ['invalid'], - state: 'closed' - }) - - // Comment on the PR - await github.rest.issues.createComment({ - owner, - repo, - issue_number: prNumber, - body: "Please leave this `repo-sync` branch to the robots!\n\nI'm going to close this pull request now, but feel free to open a new issue in the repository!" - }) diff --git a/.github/workflows/close-on-invalid-label.yaml b/.github/workflows/close-on-invalid-label.yaml deleted file mode 100644 index 654d97402bdc..000000000000 --- a/.github/workflows/close-on-invalid-label.yaml +++ /dev/null @@ -1,47 +0,0 @@ -name: Close issue/PR on adding invalid label - -# **What it does**: This action closes invalid pull requests in the open-source repository. -# **Why we have it**: We get lots of spam in the open-source repository. -# **Who does it impact**: Open-source contributors. - -on: - issues: - types: [labeled] - # Needed in lieu of `pull_request` so that PRs from a fork can be - # closed when marked as invalid. - pull_request_target: - types: [labeled] - -permissions: - contents: read - issues: write - pull-requests: write - -jobs: - close-on-adding-invalid-label: - if: github.repository == 'github/docs' && github.event.label.name == 'invalid' - runs-on: ubuntu-latest - - steps: - - name: Close issue - if: ${{ github.event_name == 'issues' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ISSUE_URL: ${{ github.event.issue.html_url }} - run: gh issue close "$ISSUE_URL" - - - name: Close PR - if: ${{ github.event_name == 'pull_request_target' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_URL: ${{ github.event.pull_request.html_url }} - run: gh pr close "$PR_URL" - - - name: Check out repo - if: ${{ failure() && github.event_name != 'pull_request_target' }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'pull_request_target' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 28a2c2fb23ff..000000000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: CodeQL analysis - -# **What it does**: This runs CodeQL on our repository. -# **Why we have it**: Security scanning. -# **Who does it impact**: Docs engineering. - -on: - pull_request: - branches: - - main - # This is so that when CodeQL runs on a pull request, it can compare - # against the state of the base branch. - push: - branches: - - main - -permissions: - actions: read - contents: read - security-events: write - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - build: - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 - with: - languages: javascript # comma separated list of values from {go, python, javascript, java, cpp, csharp, ruby} - - uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7 - continue-on-error: true - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'pull_request' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'pull_request' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/comment-release-note-info.yml b/.github/workflows/comment-release-note-info.yml deleted file mode 100644 index 8aabdb277200..000000000000 --- a/.github/workflows/comment-release-note-info.yml +++ /dev/null @@ -1,33 +0,0 @@ -# This workflow provides information when a contributor edits a release note file - -name: Comment on release note changes - -on: - pull_request: - types: - - opened - paths: - - data/release-notes/enterprise-server/** - - .github/workflows/comment-release-note-info.yml - -permissions: - contents: read - pull-requests: write - -jobs: - comment: - # Do not add this comment on PRs created by the bot during the standard patch release process - # or in the github/docs repository - if: github.event.pull_request.user.login != 'release-controller[bot]' && github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 - with: - issue-number: ${{ github.event.pull_request.number }} - body: | - Thank you for updating our GitHub Enterprise Server release notes. Please request a technical review for your changes. Once the technical review is complete, a member of the `docs-content-enterprise` team will review your changes. - - - If the change is urgent, post in `#docs-content-enterprise` on Slack. - - Review the [style guide for release notes](https://docs.github.com/en/contributing/style-guide-and-content-model/style-guide#release-notes). - - If you're updating or adding a note, add a datestamp in the format `[Updated: YYYY-MM-DD]`. - - If you're removing a note, add an [Errata](https://docs.github.com/en/contributing/style-guide-and-content-model/style-guide#errata) section with details of the change. diff --git a/.github/workflows/confirm-internal-staff-work-in-docs.yml b/.github/workflows/confirm-internal-staff-work-in-docs.yml deleted file mode 100644 index f655b4655ba9..000000000000 --- a/.github/workflows/confirm-internal-staff-work-in-docs.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: Confirm internal staff meant to post in public - -# **What it does**: If a GitHub staff makes an issue/pull request in the open-source repo, creates an issue in the internal one to verify intent. -# **Why we have it**: We don't want GitHub staff accidentally making issues/pull requests in the wrong repository. -# **Who does it impact**: GitHub staff. - -on: - issues: - types: - - opened - - transferred - # Required in lieu of `pull_request` so that this workflow can query users in org to determine membership. - pull_request_target: - types: - - opened - -permissions: - contents: read - -jobs: - check-team-membership: - runs-on: ubuntu-latest - continue-on-error: true - if: github.repository == 'github/docs' && github.actor != 'docs-bot' - steps: - - id: membership_check - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - env: - TEAM_CONTENT_REPO: ${{ secrets.TEAM_CONTENT_REPO }} - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - // Only perform this action with GitHub employees - try { - await github.rest.teams.getMembershipForUserInOrg({ - org: 'github', - team_slug: 'employees', - username: context.payload.sender.login, - }); - } catch(err) { - // An error will be thrown if the user is not a GitHub employee - // If a user is not a GitHub employee, we should stop here and - // Not send a notification - return - } - - // Don't perform this action with Docs team members - try { - // Team is addressed by numeric ID (org github = 9919, team docs = 325922) - // because IDs survive team renames and slugs do not. - await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', { - org_id: 9919, - team_id: 325922, - username: context.payload.sender.login, - }); - // If the user is a Docs team member, we should stop here and not send - // a notification - return - } catch(err) { - // An error will be thrown if the user is not a Docs team member - // If a user is not a Docs team member we should continue and send - // the notification - } - - const issueNo = context.number || context.issue.number - - // Create an issue in our private repo - await github.rest.issues.create({ - owner: 'github', - repo: process.env.TEAM_CONTENT_REPO, - title: `@${context.payload.sender.login} confirm that \#${issueNo} should be in the public github/docs repo`, - body: `@${context.payload.sender.login} opened https://github.com/github/docs/issues/${issueNo} publicly in the github/docs repo, instead of the private github/${process.env.TEAM_CONTENT_REPO} repo.\n\n@${context.payload.sender.login}, please confirm that this belongs in the public repo and that no sensitive information was disclosed by commenting below and closing the issue.\n\nIf this was not intentional and sensitive information was shared, please delete https://github.com/github/docs/issues/${issueNo} and notify us in the \#docs-open-source channel.\n\nThanks!`, - labels: ['OS confirmation', 'skip FR board'], - }); - - core.setOutput('did_warn', 'true') - - - name: Send Slack notification if a GitHub employee who isn't on the Technical Content team opens an issue in public - if: ${{ steps.membership_check.outputs.did_warn && github.repository == 'github/docs' }} - uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0 - env: - SLACK_MESSAGE: <@${{ github.actor }}> opened https://github.com/github/docs/issues/${{ github.event.number || github.event.issue.number }} publicly on the github/docs repo instead of a private repo. They have been notified via a new issue in the private repo to confirm this was intentional. - SLACK_CHANNEL_ID: ${{ secrets.DOCS_OPEN_SOURCE_SLACK_CHANNEL_ID }} - with: - method: chat.postMessage - token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - errors: true - payload: | - channel: ${{ toJSON(env.SLACK_CHANNEL_ID) }} - text: ${{ toJSON(env.SLACK_MESSAGE) }} - - - name: Check out repo - if: ${{ failure() && github.event_name != 'pull_request_target' }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'pull_request_target' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} diff --git a/.github/workflows/content-lint-markdown.yml b/.github/workflows/content-lint-markdown.yml deleted file mode 100644 index adb16aa08720..000000000000 --- a/.github/workflows/content-lint-markdown.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: 'Content Lint Markdown' - -# **What it does**: Lints our content markdown to ensure the content matches the specified styleguide. -# **Why we have it**: We want some level of consistency to our content markdown files. -# **Who does it impact**: Docs content writers. - -on: - pull_request: - merge_group: - workflow_dispatch: - inputs: - branch: - description: The branch containing the changes we want to lint. - required: true - type: string - default: main -permissions: - contents: read - -jobs: - lint-content: - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Fetch 2 commits so tj-actions/changed-files can diff without extra API calls - fetch-depth: 2 - - - name: Set up Node and dependencies - uses: ./.github/actions/node-npm-setup - - - name: Get changed content/data files - id: changed_files - uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - with: - files: | - content/** - data/** - - - name: Print content linter annotations if changed content/data files - if: steps.changed_files.outputs.any_modified == 'true' - env: - CHANGED_FILES: ${{ steps.changed_files.outputs.all_modified_files }} - # If there are errors, using `--print-annotations` will make it - # so it does *not* exit non-zero. - # This is so that all warnings and errors are printed. - run: npm run lint-content -- --print-annotations --paths $CHANGED_FILES - - - name: Run content linter if changed content/data files - if: steps.changed_files.outputs.any_modified == 'true' - env: - CHANGED_FILES: ${{ steps.changed_files.outputs.all_modified_files }} - run: npm run lint-content -- --errors-only --paths $CHANGED_FILES diff --git a/.github/workflows/content-linter-rules-docs.yml b/.github/workflows/content-linter-rules-docs.yml deleted file mode 100644 index da5de0d478d7..000000000000 --- a/.github/workflows/content-linter-rules-docs.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: 'Check content-linter rules docs' - -# **What it does**: Makes sure the content-linter-rules.md is up-to-date. -# **Why we have it**: So what's automated doesn't fall behind -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - pull_request: - paths: - - 'src/content-linter/**' - # In case imported markdownlint rules are updated - - package-lock.json - # In case manual changes are made to the content-linter-rules.md file - - data/reusables/contributing/content-linter-rules.md - # Self-test - - .github/workflows/content-linter-rules-docs.yml - -permissions: - contents: read - -jobs: - check-content-linter-rules-docs: - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Check that content-linter-rules.md is up-to-date - run: npm run generate-content-linter-docs - - - name: Fail if it isn't up-to-date - run: | - if [ -n "$(git status --porcelain)" ]; then - git status - git diff - - # Some whitespace for the sake of the message below - echo "" - echo "" - - echo "content-linter-rules.md is out of date." - echo "Please run 'npm run generate-content-linter-docs' and commit the changes." - exit 1; - fi diff --git a/.github/workflows/content-pipelines.yml b/.github/workflows/content-pipelines.yml deleted file mode 100644 index 9ddfc5f3045f..000000000000 --- a/.github/workflows/content-pipelines.yml +++ /dev/null @@ -1,201 +0,0 @@ -name: 'Content pipelines: Update content' - -# **What it does**: On a schedule, runs the content pipeline update script for each -# configured entry. The script clones each source repo, detects changes, and -# runs a Copilot agent to update content articles. The workflow handles -# branching, committing, and opening PRs. -# **Why we have it**: Keeps reference documentation in sync with upstream source -# docs without storing copies of those source docs in this repository. -# **Who does it impact**: Docs content writers, docs engineering. -# -# To add a new entry, add it to src/content-pipelines/config.yml and to the matrix -# `include` list below (only `id` is needed). The update logic lives in -# src/content-pipelines/scripts/update.ts, which reads config.yml for all other -# values. Run locally: npx tsx src/content-pipelines/scripts/update.ts --help - -on: - schedule: - - cron: '20 16 * * 1-5' # Mon-Fri at 16:20 UTC - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -env: - HUSKY: 0 - -jobs: - update: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - # Each entry only needs `id`. Everything else (source-repo, - # source-path, target-articles, etc.) is read from - # src/content-pipelines/config.yml by the update script. - - id: copilot-cli - - id: gh-stack - # - id: mcp-server - - steps: - - name: Checkout docs-internal - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Install Copilot CLI - run: npm install -g @github/copilot@prerelease - - - name: Derive branch name - id: branch - run: echo "update_branch=docs/content-pipeline-${{ matrix.id }}-update" >> "$GITHUB_OUTPUT" - - - name: Check for existing PR - id: check-pr - env: - GH_TOKEN: ${{ github.token }} - UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }} - run: | - PR_NUMBER=$(gh pr list --head "$UPDATE_BRANCH" --state open --json number --jq '.[0].number // empty' 2>/dev/null || echo "") - echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT" - - - name: Setup branch - id: setup-branch - env: - UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }} - PR_NUMBER: ${{ steps.check-pr.outputs.pr_number }} - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - if git ls-remote --exit-code --heads origin "$UPDATE_BRANCH" > /dev/null 2>&1; then - git fetch --unshallow origin "$UPDATE_BRANCH" main 2>/dev/null || git fetch origin "$UPDATE_BRANCH" main - git checkout "$UPDATE_BRANCH" - git merge origin/main --no-edit || { - echo "Merge conflict with main — resetting branch to main" - git merge --abort 2>/dev/null || true - git checkout -f main - git branch -D "$UPDATE_BRANCH" - if [ -z "$PR_NUMBER" ]; then - git push origin --delete "$UPDATE_BRANCH" || true - else - echo "Skipping remote branch delete — PR #$PR_NUMBER is open" - echo "force_push=true" >> "$GITHUB_OUTPUT" - fi - git checkout -b "$UPDATE_BRANCH" - } - else - git checkout -b "$UPDATE_BRANCH" - fi - - - name: Run content pipeline update script - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COPILOT_GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_COPILOT }} - run: npx tsx src/content-pipelines/scripts/update.ts --id "${{ matrix.id }}" - - - name: Commit changes - id: commit - env: - ID: ${{ matrix.id }} - run: | - git add content/ data/ - if git diff --cached --quiet; then - echo "has_changes=false" >> "$GITHUB_OUTPUT" - echo "No documentation changes to commit" - else - git add "src/content-pipelines/state/${ID}.sha" - git commit -m "docs: update ${ID} content from source docs" \ - -m "Updated by the content-pipeline-update agent (${ID}) via GitHub Actions." \ - -m "Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - echo "has_changes=true" >> "$GITHUB_OUTPUT" - fi - - - name: Push changes - if: steps.commit.outputs.has_changes == 'true' - env: - UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }} - FORCE_PUSH: ${{ steps.setup-branch.outputs.force_push }} - run: | - if [ "$FORCE_PUSH" = "true" ]; then - echo "Force-pushing to align branch after merge conflict reset" - git push --force-with-lease origin "$UPDATE_BRANCH" - else - git push origin "$UPDATE_BRANCH" - fi - - - name: Read source repo info from config - id: source-info - env: - PIPELINE_ID: ${{ matrix.id }} - run: | - SOURCE_REPO=$(yq -r ".[\"${PIPELINE_ID}\"].\"source-repo\"" src/content-pipelines/config.yml) - SOURCE_PATH=$(yq -r ".[\"${PIPELINE_ID}\"].\"source-path\"" src/content-pipelines/config.yml) - echo "source_repo=$SOURCE_REPO" >> "$GITHUB_OUTPUT" - echo "source_path=$SOURCE_PATH" >> "$GITHUB_OUTPUT" - - - name: Create or update PR - if: steps.commit.outputs.has_changes == 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }} - PIPELINE_ID: ${{ matrix.id }} - SOURCE_REPO: ${{ steps.source-info.outputs.source_repo }} - SOURCE_PATH: ${{ steps.source-info.outputs.source_path }} - run: | - PR_NUMBER="${{ steps.check-pr.outputs.pr_number }}" - PR_TITLE="docs: update ${PIPELINE_ID} content from source docs" - SOURCE_LINK="See the [upstream repo](https://github.com/${SOURCE_REPO}/tree/main/${SOURCE_PATH}) for changes that triggered this update." - - if [ -n "$PR_NUMBER" ]; then - echo "PR #$PR_NUMBER already exists" - - echo "Ensuring PR #$PR_NUMBER is marked ready for review" - gh pr ready "$PR_NUMBER" || echo "Unable to mark PR #$PR_NUMBER as ready (it may already be ready)" - else - echo "Creating new PR" - - PR_BODY="_GitHub Copilot generated this pull request._"$'\n\n' - PR_BODY+="> [!NOTE]"$'\n' - PR_BODY+="> This PR is **automatically generated** by the [content pipeline update workflow](${{ github.server_url }}/${{ github.repository }}/actions/workflows/content-pipelines.yml). Each run adds a new commit with any documentation changes detected."$'\n\n' - PR_BODY+="> [!WARNING]"$'\n' - PR_BODY+="> **Review with care before merging.** The agent generally does a good job, but these PRs can contain:"$'\n' - PR_BODY+="> * Information customers don't need to know"$'\n' - PR_BODY+="> * Internal or feature-flagged details that shouldn't be public"$'\n' - PR_BODY+="> * Excessive or low-value detail"$'\n' - PR_BODY+=">"$'\n' - PR_BODY+="> Cross-check changes against the source docs linked below. If in doubt, leave the review to a subject-matter expert on the Technical Content team."$'\n\n' - PR_BODY+="## What this does"$'\n\n' - PR_BODY+="Runs the \`content-pipeline-update\` agent (${PIPELINE_ID}) against the latest source docs and updates official articles under \`content/\` that have fallen out of sync."$'\n\n' - PR_BODY+="## Source changes"$'\n\n' - PR_BODY+="${SOURCE_LINK}"$'\n\n' - PR_BODY+="## Review"$'\n\n' - PR_BODY+="* Review each commit for accuracy — the agent uses AI, so spot-check important changes against the source docs"$'\n' - PR_BODY+="* Watch especially for invented examples, internal-only content, and excessive detail (see warning above)"$'\n' - PR_BODY+="* To adjust agent behavior, see [Modifying results](${{ github.server_url }}/${{ github.repository }}/blob/main/src/content-pipelines/README.md#modifying-results)"$'\n' - PR_BODY+="* Once satisfied, merge to keep docs up to date"$'\n' - PR_BODY+="* A new PR will be created on the next run if there are further changes" - - gh pr create \ - --title "$PR_TITLE" \ - --body "$PR_BODY" \ - --base main \ - --head "$UPDATE_BRANCH" \ - --label "workflow-generated,content-pipeline-update,ready-for-doc-review,skip FR board" - fi - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/copilot-code-review.yml b/.github/workflows/copilot-code-review.yml deleted file mode 100644 index b61a8bebbf92..000000000000 --- a/.github/workflows/copilot-code-review.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Copilot Code Review setup steps -# -# Code Review cannot access the private early-access repository, so it uses -# this secret-free setup instead of the cloud agent setup workflow. - -name: 'Copilot Code Review Setup Steps' - -on: - workflow_dispatch: - -jobs: - copilot-setup-steps: - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - permissions: - contents: read - steps: - - name: Checkout code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml deleted file mode 100644 index 417a195a078e..000000000000 --- a/.github/workflows/copilot-setup-steps.yml +++ /dev/null @@ -1,58 +0,0 @@ -# Copilot cloud agent setup steps -# -# This is a special-name workflow recognized by Copilot cloud agent. -# When a cloud agent session starts (via GitHub issue assignment or the -# Copilot UI), these steps run first to bootstrap the development -# environment before the agent begins working. -# -# The workflow_dispatch trigger allows manual testing of the setup steps. -# This is NOT a regular CI workflow — it does not run on push or PR events. -# -# See also: -# .github/copilot-instructions.md — always-on agent instructions -# .github/instructions/ — contextual instruction files -# .github/prompts/ — on-demand prompt files (e.g. /code-review) - -name: 'Copilot Setup Steps' - -on: - workflow_dispatch: - -jobs: - copilot-setup-steps: - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - permissions: - contents: read - id-token: write - env: - ELASTICSEARCH_URL: http://localhost:9200/ - steps: - - name: Checkout code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - # Search and language test suites require a running Elasticsearch instance. - - uses: ./.github/actions/setup-elasticsearch - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - # docs-internal has early-access content that must be fetched separately. - - uses: ./.github/actions/get-docs-early-access - if: ${{ github.repository == 'github/docs-internal' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - # Many test suites depend on Next.js build artifacts. - - name: Build - run: npm run build - - # Populate Elasticsearch with fixture data so search/language tests work. - # ELASTICSEARCH_URL is set inline in the run command because the - # Copilot/GHAS agent runtime executes these setup steps with its own - # injected environment and does not apply the workflow's `env:` blocks - # (job-level or step-level). The inline assignment is part of the run - # command, which the agent runs verbatim, so it is honored in both the - # agent context and normal workflow_dispatch runs. - - name: Index fixtures into the local Elasticsearch - run: ELASTICSEARCH_URL=http://localhost:9200/ npm run index-test-fixtures diff --git a/.github/workflows/copy-api-issue-to-internal.yml b/.github/workflows/copy-api-issue-to-internal.yml deleted file mode 100644 index 1c24f6dbc800..000000000000 --- a/.github/workflows/copy-api-issue-to-internal.yml +++ /dev/null @@ -1,91 +0,0 @@ -name: Copy to API/events issue to docs-content - -# **What it does**: Copies an issue in the open source repo to the docs-content repo, comments on and closes the original issue -# **Why we have it**: OpenAPI/GraphQL schema updates cannot be made in the open source repo. Instead, we copy the issue to an internal issue (we do not transfer so that the issue does not disappear for the contributor) and close the original issue. -# **Who does it impact**: Open source and docs-content maintainers - -on: - issues: - types: - - labeled - -permissions: - contents: read - -jobs: - transfer-issue: - name: Transfer issue - runs-on: ubuntu-latest - if: github.event.label.name == 'fix-internally' && github.repository == 'github/docs' - steps: - - name: Check if this run was triggered by a member of the docs team - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - id: triggered-by-member - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - result-encoding: string - script: | - const triggerer_login = context.payload.sender.login - // Team is addressed by numeric ID (org github = 9919, team docs = 325922) - // because IDs survive team renames and slugs do not. - const teamMembers = await github.request( - `/organizations/9919/team/325922/members?per_page=100` - ) - const logins = teamMembers.data.map(member => member.login) - if (logins.includes(triggerer_login)) { - console.log(`This workflow was triggered by ${triggerer_login} (on the docs team).`) - return 'true' - } - console.log(`This workflow was triggered by ${triggerer_login} (not on the docs team), so no action will be taken.`) - return 'false' - - - name: Exit if not triggered by a docs team member - if: steps.triggered-by-member.outputs.result == 'false' - run: | - echo Aborting. This workflow must be triggered by a member of the docs team. - exit 1 - - - name: Create an issue in the docs-content repo - run: | - new_issue_url="$(gh issue create --title "$ISSUE_TITLE" --body "$ISSUE_BODY - - Copied to this repo by the [$GITHUB_WORKFLOW workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)." --repo github/docs-content --label "workflow-generated")" - echo 'NEW_ISSUE='$new_issue_url >> $GITHUB_ENV - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - ISSUE_TITLE: ${{ github.event.issue.title }} - ISSUE_BODY: ${{ github.event.issue.body }} - - - name: Comment on the old issue - run: gh issue comment $OLD_ISSUE --body "Thank you for opening this issue! Updates to this documentation must be made internally. I have copied your issue to an internal issue, so I will close this issue." - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - OLD_ISSUE: ${{ github.event.issue.html_url }} - - - name: Close the old issue - run: gh issue close $OLD_ISSUE - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - OLD_ISSUE: ${{ github.event.issue.html_url }} - - - name: Comment on the new issue - run: gh issue comment $NEW_ISSUE --body "This issue was originally opened in the open source repo as $OLD_ISSUE" - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - NEW_ISSUE: ${{ env.NEW_ISSUE }} - OLD_ISSUE: ${{ github.event.issue.html_url }} - - - name: Check out repo - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/count-translation-corruptions.yml b/.github/workflows/count-translation-corruptions.yml deleted file mode 100644 index beb046358e4c..000000000000 --- a/.github/workflows/count-translation-corruptions.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Count translation corruptions - -# **What it does**: Generates a summary of Liquid corruptions per language. -# **Why we have it**: For insights into the state of translations and things we can do to fix them -# **Who does it impact**: Engineering - -on: - workflow_dispatch: - pull_request: - paths: - - src/languages/scripts/count-translation-corruptions.ts - - src/languages/lib/correct-translation-content.ts - - .github/workflows/count-translation-corruptions.yml - - .github/actions/node-npm-setup/action.yml - - .github/actions/clone-translations/action.yml - - 'package**.json' - -permissions: - contents: read - -jobs: - count-translation-corruptions: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout English repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Using a PAT is necessary so that the new commit will trigger the - # CI in the PR. (Events from GITHUB_TOKEN don't trigger new workflows.) - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - # It's important because translations are often a bit behind. - # So if a translation is a bit behind, it might still be referencing - # an asset even though none of the English content does. - - name: Clone all translations - uses: ./.github/actions/clone-translations - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/node-npm-setup - - - name: Run count - run: npm run count-translation-corruptions diff --git a/.github/workflows/create-changelog-pr.yml b/.github/workflows/create-changelog-pr.yml deleted file mode 100644 index bbffdd387582..000000000000 --- a/.github/workflows/create-changelog-pr.yml +++ /dev/null @@ -1,172 +0,0 @@ -name: Create a PR to add an entry to the CHANGELOG.md file in this repo - -# **What it does**: If a member of the github org posts a changelog comment, it creates a PR to update the CHANGELOG.md file. -# **Why we have it**: This surfaces docs changelog details publicly. -# **Who does it impact**: GitHub users and staff. - -on: - issue_comment: - types: [created] - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -env: - CHANGELOG_FILE: CHANGELOG.md - CHANGELOG_FILE_URL: https://github.com/github/docs-internal/blob/main/CHANGELOG.md - -jobs: - docs-changelog-pr: - if: ${{ github.repository == 'github/docs-internal' && github.event.issue.pull_request }} - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: 'Ensure ${{ env.CHANGELOG_FILE }} exists' - run: | - if [ ! -f ${{ env.CHANGELOG_FILE }} ]; then - echo "${{ env.CHANGELOG_FILE }} is missing at the root of the repository." - exit 1 - fi - - - name: Check that the user belongs to the github org - id: hubber_check - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - try { - await github.rest.teams.getMembershipForUserInOrg({ - org: 'github', - team_slug: 'employees', - username: context.payload.sender.login, - }); - core.exportVariable('CONTINUE_WORKFLOW', 'true'); - } catch(err) { - core.info("Workflow triggered by a comment, but the commenter is not a Hubber. Exiting."); - core.exportVariable('CONTINUE_WORKFLOW', 'false'); - } - - - name: Check if comment starts with '## Changelog summary' - if: env.CONTINUE_WORKFLOW == 'true' - id: check_summary - env: - COMMENT_BODY: ${{ github.event.comment.body }} - run: | - # Get the first line of the comment and trim the leading/trailing whitespace: - FIRST_LINE=$(printf "%s\n" "$COMMENT_BODY" | head -n1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') - if [[ "$FIRST_LINE" != '## Changelog summary' ]]; then - echo "FIRST_LINE=|$FIRST_LINE|" - echo "The pull request comment is not a changelog summary. Exiting." - echo "CONTINUE_WORKFLOW=false" >> $GITHUB_ENV - fi - - - name: Create changelog text - if: env.CONTINUE_WORKFLOW == 'true' - id: create_text - env: - COMMENT_BODY: ${{ github.event.comment.body }} - run: | - set -euo pipefail - DATE=$(date +"**%-d %B %Y**") - BODY="$(printf "%s\n" "$COMMENT_BODY" | tail -n +2)" - CHANGELOG_TEXT="$(printf "%s\n" "$BODY" | awk '/^:writing_hand:/{exit} {print}')" - { - echo "$DATE" - echo -e "$CHANGELOG_TEXT\n
" - } > changelog_entry.txt - - - name: Set up git - if: env.CONTINUE_WORKFLOW == 'true' - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Prepare branch - if: env.CONTINUE_WORKFLOW == 'true' - run: | - BRANCH="changelog-update-$(date +%s)" - echo "BRANCH=$BRANCH" >> $GITHUB_ENV - git checkout -b "$BRANCH" - - # Insert new changelog entry after the first heading, as follows: - # Print the first line of the existing CHANGELOG.md file into a `tmp` file, followed by an empty line. - # Then, print the contents of `changelog_entry.txt` into the `tmp` file. - # Then, print the rest of the existing CHANGELOG.md file into the `tmp` file. - # Finally, replace the existing CHANGELOG.md file with the `tmp` file. - awk 'NR==1{print; print ""; while ((getline line < "changelog_entry.txt") > 0) print line; next}1' CHANGELOG.md > tmp && mv tmp CHANGELOG.md - - git add CHANGELOG.md - git commit -m "Update changelog for $(head -n1 changelog_entry.txt)" - git push origin "$BRANCH" - - - name: Create a pull request - if: env.CONTINUE_WORKFLOW == 'true' - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - id: create_pull_request - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const { data: pullRequest } = await github.rest.pulls.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: `Update docs changelog (for PR #${context.payload.issue.number})`, - body: `### Automated docs changelog update\n\n**Purpose:** Update the [${{ env.CHANGELOG_FILE }}](${{ env.CHANGELOG_FILE_URL }}) file with details of a recent docs change.\n\nThis PR is an automated update, generated by the create-changelog-pr.yml Actions workflow as a result of a "Changelog summary" comment being added to [PR #${context.payload.issue.number}](${context.payload.issue.html_url}).\n\n**Notes for reviewer**:\n- This change to the [${{ env.CHANGELOG_FILE }}](${{ env.CHANGELOG_FILE_URL }}) file will be synced to the public docs site, so make sure that the content of the entry is appropriate for public consumption. If the content is wholly inappropriate for public consumption, then this PR can be closed.\n- Make sure the format of this changelog entry is consistent with the other entries in the file.\n\n
Original PR comment posted by @${context.payload.comment.user.login}, using the /changelog slash command:\n\n${context.payload.comment.body}
`, - head: process.env.BRANCH, - base: 'main' - }); - - core.setOutput('pull-request-number', pullRequest.number); - core.setOutput('pull-request-url', pullRequest.html_url); - - - name: Add 'ready-for-doc-review' and 'skip FR board' labels to PR - if: env.CONTINUE_WORKFLOW == 'true' - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - env: - # Get the number of the PR that was just created: - PULL_REQUEST_NUMBER: ${{ steps.create_pull_request.outputs.pull-request-number }} - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: Number(process.env.PULL_REQUEST_NUMBER), - labels: ['ready-for-doc-review','skip FR board'] - }); - - - name: Assign PR to commenter - if: env.CONTINUE_WORKFLOW == 'true' - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - env: - # Reuse the PR number captured earlier - PULL_REQUEST_NUMBER: ${{ steps.create_pull_request.outputs.pull-request-number }} - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - try { - const username = context.payload.comment.user.login; - await github.rest.issues.addAssignees({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: Number(process.env.PULL_REQUEST_NUMBER), - assignees: [username] - }); - } catch (err) { - core.info(`Failed to assign PR to @${context.payload.comment.user.login}: ${err.message}`); - } - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/delete-orphan-translation-files.yml b/.github/workflows/delete-orphan-translation-files.yml deleted file mode 100644 index c827f9848abc..000000000000 --- a/.github/workflows/delete-orphan-translation-files.yml +++ /dev/null @@ -1,168 +0,0 @@ -name: Delete orphan translation files - -# **What it does**: -# Compares content & data files left in each translation that aren't -# in docs-internal. Then creates a PR to delete these files. -# **Why we have it**: -# When Juno dumps to each translation repo it can not account for the -# fact that files in docs-internal get moved or deleted. So the -# sum total of files constantly grows. -# This leads to excess files in each translation repo that are not -# ever used but has to be put into every production build. -# **Who does it impact**: Docs engineering - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: write - -jobs: - delete-orphan-translation-files: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - language: zh - language_dir: translations/zh-cn - language_repo: github/docs-internal.zh-cn - - - language: es - language_dir: translations/es-es - language_repo: github/docs-internal.es-es - - - language: pt - language_dir: translations/pt-br - language_repo: github/docs-internal.pt-br - - - language: ru - language_dir: translations/ru-ru - language_repo: github/docs-internal.ru-ru - - - language: ja - language_dir: translations/ja-jp - language_repo: github/docs-internal.ja-jp - - - language: fr - language_dir: translations/fr-fr - language_repo: github/docs-internal.fr-fr - - - language: de - language_dir: translations/de-de - language_repo: github/docs-internal.de-de - - - language: ko - language_dir: translations/ko-kr - language_repo: github/docs-internal.ko-kr - - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - name: Checkout the language-specific repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: ${{ matrix.language_repo }} - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - path: ${{ matrix.language_dir }} - - - uses: ./.github/actions/node-npm-setup - - - name: Delete orphan files - run: | - npm run delete-orphan-translation-files -- ${{ matrix.language_dir }} - - - name: Debug deleted files - working-directory: ${{ matrix.language_dir }} - run: git status - - - name: Git config - working-directory: ${{ matrix.language_dir }} - run: | - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - - - name: Git commit and push, create and merge PR - working-directory: ${{ matrix.language_dir }} - env: - # Needed for gh - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - # If nothing to commit, exit now. It's fine. No orphans. - changes=$(git diff --name-only | wc -l) - untracked=$(git status --untracked-files --short | wc -l) - if [[ $changes -eq 0 ]] && [[ $untracked -eq 0 ]]; then - echo "There are no changes to commit or untracked files. Exiting." - exit 0 - fi - - # Create a general retry function that retries and sleeps - retry_command() { - local max_attempts=3 - local attempt=1 - - while [ $attempt -le $max_attempts ]; do - echo "Attempt $attempt: $@" - "$@" && return 0 - ((attempt++)) - sleep 3 # You can adjust the sleep duration as needed - done - - echo "Max attempts reached. Command failed after $max_attempts attempts." - return 1 - } - - git status - current_timestamp=$(date '+%Y-%m-%d-%H%M%S') - branch_name="delete-orphan-files-$current_timestamp" - git checkout -b "$branch_name" - current_daystamp=$(date '+%Y-%m-%d') - git commit -a -m "Delete orphan files ($current_daystamp)" - git push origin "$branch_name" - - # Create PR - echo "Creating pull request..." - gh pr create \ - --title "Delete orphan files ($current_daystamp)" \ - --body '👋 humans. This PR was generated by the [Delete orphan translation files](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run. - ' \ - --repo "${{ matrix.language_repo }}" \ - --label "workflow-generated" \ - --head=$branch_name - echo "Merge created PR..." - # Prefer enabling auto-merge so the PR waits for any required - # checks before merging. If auto-merge can't be enabled — usually - # because all required checks completed before this step ran and - # the PR is already immediately mergeable — fall back to a direct - # merge. GitHub returns one of these misleading errors in that - # case: "Branch does not have required protected branch rules", - # "Pull request is in unstable status", or "Pull request is not - # in a mergeable state". - auto_merge_err=$(mktemp) - trap 'rm -f "$auto_merge_err"' EXIT - if retry_command gh pr merge --merge --auto --delete-branch "$branch_name" 2>"$auto_merge_err"; then - : - else - cat "$auto_merge_err" - if grep -qE "does not have required protected branch rules|unstable status|Pull request is not in a mergeable state" "$auto_merge_err"; then - echo "Auto-merge unavailable; PR appears immediately mergeable. Falling back to direct merge." - retry_command gh pr merge --merge --delete-branch "$branch_name" - else - echo "Auto-merge failed with an unexpected error." - exit 1 - fi - fi - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/docs-review-collect.yml b/.github/workflows/docs-review-collect.yml deleted file mode 100644 index d34402f0295a..000000000000 --- a/.github/workflows/docs-review-collect.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Add docs-reviewers request to the docs-content review board - -# **What it does**: Adds PRs in github/github and github/audit-log-allowlists that requested a review from docs-reviewers to the docs-content review board -# **Why we have it**: To catch docs-reviewers requests in github/audit-log-allowlists -# **Who does it impact**: docs-content maintainers - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1-5' # Run Mon-Fri at 16:20 UTC / 8:20 PST - -permissions: - contents: read - -jobs: - add-requests-to-board: - name: Add requests to board - if: ${{ github.repository == 'github/docs-internal' }} - runs-on: ubuntu-latest - - steps: - - name: Check out repo content - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Set up Node and dependencies - uses: ./.github/actions/node-npm-setup - - - name: Run script for audit-log-allowlists - run: | - npm run fr-add-docs-reviewers-requests - env: - TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - PROJECT_NUMBER: 2936 - ORGANIZATION: 'github' - REPO: 'audit-log-allowlists' - REVIEWER: 'docs-reviewers' - FEATURE: 'Audit log event descriptions' - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/dont-delete-assets.yml b/.github/workflows/dont-delete-assets.yml deleted file mode 100644 index 3c3e73d4cacf..000000000000 --- a/.github/workflows/dont-delete-assets.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Don't delete assets - -# **What it does**: -# If the PR (against main) involves deletion of assets, if any of -# them are deletions or renames, post a comment, and ultimately -# fail the check. -# **Why we have it**: -# If you delete the reference to an image, the English content is fine -# because it no longer tries to serve an image that doesn't exist. -# But this is not the case for translations. -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - pull_request: - branches: - - main - paths: - - 'assets/**' - - '.github/workflows/dont-delete-assets.yml' - -permissions: - contents: read - pull-requests: write - -jobs: - dont-delete-assets: - # It's 'docs-bot' that creates those PR from "Delete orphaned assets" - if: github.event.pull_request.user.login != 'docs-bot' && (github.repository == 'github/docs-internal' || github.repository == 'github/docs') - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Get comment markdown - id: comment - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: npm run deleted-assets-pr-comment - - - name: Find possible previous comment - if: ${{ steps.comment.outputs.markdown != '' }} - uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad - id: findComment - with: - issue-number: ${{ github.event.number }} - comment-author: 'github-actions[bot]' - body-includes: '' - - - name: Update comment - if: ${{ steps.comment.outputs.markdown != '' }} - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 - with: - comment-id: ${{ steps.findComment.outputs.comment-id }} - issue-number: ${{ github.event.number }} - body: ${{ steps.comment.outputs.markdown }} - edit-mode: replace - - - name: Ultimately fail the workflow for attention - if: ${{ steps.comment.outputs.markdown != '' }} - run: | - echo "More than 1 asset image was deleted as part of this PR." - echo "See posted PR commented about how to get them back." - exit 1 diff --git a/.github/workflows/dont-delete-features.yml b/.github/workflows/dont-delete-features.yml deleted file mode 100644 index 66c5995c0f3f..000000000000 --- a/.github/workflows/dont-delete-features.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Don't delete features - -# **What it does**: -# If the PR (against main) involves deletion of features, if any of -# them are deletions or renames, post a comment, and ultimately -# fail the check. -# **Why we have it**: -# If you delete the reference to an image, the English content is fine -# because it no longer tries to use the feature that doesn't exist. -# But this is not the case for translations. -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - pull_request: - branches: - - main - paths: - - 'data/features/**' - - .github/workflows/dont-delete-features.yml - -permissions: - contents: read - pull-requests: write - -jobs: - dont-delete-features: - if: github.event.pull_request.user.login != 'docs-bot' && github.event.pull_request.user.login != 'docs-engineering-bot[bot]' && (github.repository == 'github/docs-internal' || github.repository == 'github/docs') - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Get comment markdown - id: comment - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: npm run deleted-features-pr-comment - - - name: Find possible previous comment - if: ${{ steps.comment.outputs.markdown != '' }} - uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad - id: findComment - with: - issue-number: ${{ github.event.number }} - comment-author: 'github-actions[bot]' - body-includes: '' - - - name: Update comment - if: ${{ steps.comment.outputs.markdown != '' }} - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 - with: - comment-id: ${{ steps.findComment.outputs.comment-id }} - issue-number: ${{ github.event.number }} - body: ${{ steps.comment.outputs.markdown }} - edit-mode: replace - - - name: Ultimately fail the workflow for attention - if: ${{ steps.comment.outputs.markdown != '' }} - run: | - echo "More than 1 feature was deleted as part of this PR." - echo "See posted PR commented about how to get them back." - exit 1 diff --git a/.github/workflows/enterprise-dates.yml b/.github/workflows/enterprise-dates.yml deleted file mode 100644 index 2bc66b8a6cf6..000000000000 --- a/.github/workflows/enterprise-dates.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Enterprise date updater - -# **What it does**: Runs on a schedule to update -# src/ghes-releases/lib/enterprise-dates.json. -# **Why we have it**: The src/ghes-releases/lib/enterprise-dates.json -# file needs to be up-to-date for the -# Used to display deprecation banner dates and as a reference -# for all past server release numbers. -# **Who does it impact**: Docs engineering, docs content. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: write - pull-requests: write - -jobs: - open_enterprise_issue: - name: Enterprise date updater - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout repository code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - - name: Run src/ghes-releases/scripts/update-enterprise-dates.ts - run: npm run update-enterprise-dates - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Create pull request - id: create-pull-request - uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # pin @v8.0.0 - env: - # Disable pre-commit hooks; they don't play nicely here - HUSKY: '0' - with: - # need to use a token with repo and workflow scopes for this step - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - commit-message: '🤖 ran src/ghes-releases/scripts/update-enterprise-dates.ts' - title: 🤖 src/ghes-releases/lib/enterprise-dates.json update - body: - "Hello! The GitHub Enterprise Server release dates have changed.\n\n - If CI passes, this PR will be auto-merged. :green_heart:\n\n - If CI does not pass or other problems arise, contact #technical-content on slack.\n\nThis PR was 🤖-crafted by `.github/workflows/enterprise-dates.yml`. 🧶" - branch: enterprise-server-dates-update - delete-branch: true - - - name: Enable GitHub auto-merge - if: ${{ steps.create-pull-request.outputs.pull-request-number }} - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - AUTOMERGE_PR_NUMBER: ${{ steps.create-pull-request.outputs.pull-request-number }} - run: npm run enable-automerge - - - if: ${{ failure() }} - name: Delete remote branch (if previous steps failed) - run: git push origin --delete enterprise-server-dates-update - - - if: ${{ steps.create-pull-request.outputs.pull-request-number }} - name: Approve - uses: juliangruber/approve-pull-request-action@68fcc9a5a73b5641cadf757cf99d73720dcb05d0 # v2.1.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - number: ${{ steps.create-pull-request.outputs.pull-request-number }} - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/enterprise-release-issue.yml b/.github/workflows/enterprise-release-issue.yml deleted file mode 100644 index ac929c5f06a6..000000000000 --- a/.github/workflows/enterprise-release-issue.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Open Enterprise release or deprecation issue - -# **What it does**: Checks if there is an Enterprise release or deprecation upcoming, and if so, opens an issue with the tasks to be completed. -# **Why we have it**: GHES releases and deprecations run on a predictable schedule, so we can automate some of the project management aspects. -# **Who does it impact**: Docs engineering, docs content. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: read - -jobs: - open_enterprise_issue: - name: Open Enterprise issue - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout repository code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Create an enterprise release issue - run: npm run create-enterprise-issue -- release - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Create an enterprise deprecation issue - run: npm run create-enterprise-issue -- deprecation - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/expertise-required-label-message.yml b/.github/workflows/expertise-required-label-message.yml deleted file mode 100644 index a3e3613cec43..000000000000 --- a/.github/workflows/expertise-required-label-message.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Expertise Required label message - -# **What it does**: Adds a bot comment stating a certain level of expertise is required to a docs-content issue when the `contributor-expertise-required` label is applied -# **Why we have it**: We need a method to surface a message denoting if an issue requires a certain level of expertise in order to be resolved -# **Who does it impact**: Open Source and Hubbers - -on: - issues: - types: - - labeled - -jobs: - job: - name: Comment on issue with expertise required message - runs-on: ubuntu-latest - permissions: - issues: write - if: github.event.label.name == 'contributor-expertise-required' && github.repository == 'github/docs' - steps: - - name: Comment on issue - env: - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} - issue: ${{ github.event.issue.html_url }} - run: | - gh issue comment $issue --body 'Addressing this issue will require additional expertise from the contributor. Please make sure to review the issue carefully before opening a PR and ask any questions you might have in the issue.' diff --git a/.github/workflows/feedback-prompt.yml b/.github/workflows/feedback-prompt.yml deleted file mode 100644 index dace8f90a87f..000000000000 --- a/.github/workflows/feedback-prompt.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Feedback prompt for non-Technical Content team contributors when a PR is closed - -on: - pull_request: - types: [closed] - -permissions: - contents: read - pull-requests: write - -jobs: - comment-on-pr: - # This workflow should only run on the 'github/docs-internal' repository because it posts a feedback request - # to non-Docs team contributors when their PR is merged into the main branch. - # The feedback request asks contributors to leave feedback on their contributing experience in Slack. - if: github.repository == 'github/docs-internal' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main' - - runs-on: ubuntu-latest - - steps: - - name: Check if PR author is in docs-content team - id: check_team - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - try { - const pr = context.payload.pull_request; - // Team is addressed by numeric ID (org github = 9919, team docs-content = 2796154) - // because IDs survive team renames and slugs do not. - await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', { - org_id: 9919, - team_id: 2796154, - username: pr.user.login, - }); - // Author is in the team. Do nothing! - } catch(err) { - // Author not in team - core.exportVariable('NON_DOCS_HUBBER', 'true'); - } - - - name: Post changelog instructions comment - - if: env.NON_DOCS_HUBBER == 'true' - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const pr = context.payload.pull_request; - const prAuthor = pr.user.login; - const assignees = (pr.assignees ?? []) - .filter(a => a.login.toLowerCase() !== "copilot") - .map(a => "@" + a.login) - .join(" "); - - let commentBody; - if (assignees) { - commentBody = - "👋 " + assignees + - " - Thanks for your contribution! " + - "If you think something could be improved about the contributor experience, please post in `#docs-contributor-feedback` on Slack."; - } else if (prAuthor.toLowerCase() !== "copilot") { - commentBody = - "👋 @" + prAuthor + - " - Thanks for your contribution! " + - "If you think something could be improved about the contributor experience, please post in `#docs-contributor-feedback` on Slack."; - } else { - // nobody to mention! - commentBody = - "👋 Thanks for your contribution! " + - "If you think something could be improved about the contributor experience, please post in `#docs-contributor-feedback` on Slack."; - } - - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr.number, - body: commentBody - }); diff --git a/.github/workflows/first-responder-v2-prs-collect.yml b/.github/workflows/first-responder-v2-prs-collect.yml deleted file mode 100644 index ff0d2aba47c7..000000000000 --- a/.github/workflows/first-responder-v2-prs-collect.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Add maintenance PRs to the docs-content FR project v2 - -# **What it does**: Adds docs-internal pull requests authored by docs-bot to the docs-content FR project v2 -# **Why we have it**: So we don't lose track of maintenance pull requests for docs-content to review -# **Who does it impact**: Docs content - -on: - pull_request: - types: - - reopened - - opened - - ready_for_review - -permissions: - contents: read - pull-requests: write - repository-projects: write - -jobs: - first-responder-triage-pr: - name: Add maintenance PR to FR project v2 - if: github.repository == 'github/docs-internal' && github.event.pull_request.draft == false && github.event.pull_request.user.id == 77750099 && github.event.pull_request.head.ref != 'repo-sync' && !contains(github.event.pull_request.labels.*.name, 'skip FR board') - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - # Add to the FR project - # and set type to "Maintenance" - # and set date to now - - name: Triage to docs-content FR project - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - PR_URL: ${{ github.event.pull_request.html_url }} - PROJECT_NUMBER: 11672 - PROJECT_ID: PVT_kwDNJr_OAGNkBg - TYPE_FIELD_ID: PVTSSF_lADNJr_OAGNkBs4D-Nyn - DATE_FIELD_ID: PVTF_lADNJr_OAGNkBs4D-N1h - TYPE_FIELD_VALUE: 3f142cf2 - run: | - echo "Adding item to project..." - - ITEM_ID=$(gh project item-add $PROJECT_NUMBER --owner github --url $PR_URL --format json | jq .id) - - echo "Editing type..." - - gh project item-edit --project-id $PROJECT_ID --id $ITEM_ID --field-id $TYPE_FIELD_ID --single-select-option-id $TYPE_FIELD_VALUE - - echo "Editing date..." - - DATE=$(date '+%Y-%m-%d') - - gh project item-edit --project-id $PROJECT_ID --id $ITEM_ID --field-id $DATE_FIELD_ID --date $DATE - - echo "done editing" diff --git a/.github/workflows/generate-code-scanning-query-lists.yml b/.github/workflows/generate-code-scanning-query-lists.yml deleted file mode 100644 index 0558abd14e33..000000000000 --- a/.github/workflows/generate-code-scanning-query-lists.yml +++ /dev/null @@ -1,268 +0,0 @@ -name: Generate code scanning query lists - -# **What it does**: This workflow is currently run manually approximately every two weeks as part -# of the release process for the CodeQL CLI. We hope to automate this in the future -# When run, this workflow generates updated query lists with data from the codeql -# repository, and creates a pull request if there are updates. -# **Why we have it**: So we can automate CodeQL query tables and show code scanning users the built in queries. -# **Who does it impact**: Anyone making CodeQL query suite changes in `github/codeql`, and wanting to get them published on the docs site. - -on: - workflow_dispatch: - inputs: - SOURCE_BRANCH: - description: 'Branch to pull the source files from in the codeql repo (for example codeql-cli-2.x.x).' - type: string - required: true - default: 'main' - - pull_request: - paths: - - .github/workflows/generate-code-scanning-query-lists.yml - - src/codeql-queries/scripts/generate-code-scanning-query-list.ts - - src/codeql-queries/scripts/generate-code-quality-query-list.ts - - .github/actions/install-cocofix/action.yml - -permissions: - contents: read - -jobs: - generate-security-query-lists: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout repository code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Checkout codeql repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: github/codeql - path: codeql - ref: ${{ inputs.SOURCE_BRANCH || 'main' }} - - - name: Get the codeql SHA being synced - id: codeql - shell: bash - run: | - cd codeql - OPENAPI_COMMIT_SHA=$(git rev-parse HEAD) - echo "OPENAPI_COMMIT_SHA=$OPENAPI_COMMIT_SHA" >> $GITHUB_OUTPUT - echo "Copied files from github/codeql repo. Commit SHA: $OPENAPI_COMMIT_SHA" - - - name: Download CodeQL CLI - # Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo - uses: ./codeql/.github/actions/fetch-codeql - - - name: Test CodeQL CLI Download - shell: bash - run: codeql --version - - # "Server for running multiple commands while avoiding repeated JVM initialization." - # Having started this should speed up the execution of the various - # CLI calls of the executable. - - name: Start CodeQL CLI server in the background - shell: bash - run: | - codeql execute cli-server & - sleep 3 - codeql --version - - - uses: ./.github/actions/install-cocofix - with: - # The Docs Engineering Bot app cannot read the org-scoped - # @github/cocofix package (its Packages permission is repo-level - # only), so this step keeps using the PAT until the app is granted - # organization package read access. - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Build code scanning security query lists - shell: bash - run: | - for lang in "actions" "cpp" "csharp" "go" "java" "javascript" "python" "ruby" "rust" "swift"; do - echo "Generating code scanning query list for $lang" - npm run generate-code-scanning-query-list -- \ - --verbose \ - --codeql-path codeql \ - --codeql-dir codeql \ - -o data/reusables/code-scanning/codeql-query-tables/$lang.md \ - $lang - done - - - name: Upload security query lists - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: security-query-lists - path: data/reusables/code-scanning/codeql-query-tables/ - - generate-quality-query-lists: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout repository code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Checkout codeql repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: github/codeql - path: codeql - ref: ${{ inputs.SOURCE_BRANCH || 'main' }} - - - name: Get the codeql SHA being synced - id: codeql - shell: bash - run: | - cd codeql - OPENAPI_COMMIT_SHA=$(git rev-parse HEAD) - echo "OPENAPI_COMMIT_SHA=$OPENAPI_COMMIT_SHA" >> $GITHUB_OUTPUT - echo "Copied files from github/codeql repo. Commit SHA: $OPENAPI_COMMIT_SHA" - - - name: Download CodeQL CLI - # Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo - uses: ./codeql/.github/actions/fetch-codeql - - - name: Test CodeQL CLI Download - shell: bash - run: codeql --version - - # "Server for running multiple commands while avoiding repeated JVM initialization." - # Having started this should speed up the execution of the various - # CLI calls of the executable. - - name: Start CodeQL CLI server in the background - shell: bash - run: | - codeql execute cli-server & - sleep 3 - codeql --version - - - name: Build code quality query lists - shell: bash - run: | - for lang in "csharp" "go" "java" "javascript" "python" "ruby"; do - echo "Generating code quality query list for $lang" - npm run generate-code-quality-query-list -- \ - --verbose \ - --codeql-path codeql \ - --codeql-dir codeql \ - -o data/reusables/code-quality/codeql-query-tables/$lang.md \ - $lang - done - - - name: Upload quality query lists - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: quality-query-lists - path: data/reusables/code-quality/codeql-query-tables/ - - create-pull-request: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - needs: [generate-security-query-lists, generate-quality-query-lists] - steps: - - name: Checkout repository code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Checkout codeql repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: github/codeql - path: codeql - ref: ${{ inputs.SOURCE_BRANCH || 'main' }} - - - name: Get the codeql SHA being synced - id: codeql - shell: bash - run: | - cd codeql - OPENAPI_COMMIT_SHA=$(git rev-parse HEAD) - echo "OPENAPI_COMMIT_SHA=$OPENAPI_COMMIT_SHA" >> $GITHUB_OUTPUT - echo "Copied files from github/codeql repo. Commit SHA: $OPENAPI_COMMIT_SHA" - - - name: Download security query lists - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 - with: - name: security-query-lists - path: data/reusables/code-scanning/codeql-query-tables/ - - - name: Download quality query lists - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 - with: - name: quality-query-lists - path: data/reusables/code-quality/codeql-query-tables/ - - - name: Insight into diff - shell: bash - run: | - git diff - - - name: Create pull request - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - DRY_RUN: ${{ github.event_name == 'pull_request'}} - shell: bash - run: | - - # When we started, we downloaded the CodeQL CLI here in this workflow. - # We have no intention of checking that in but we also don't want - # `git status ...` to show it as an untracked file. - rm -fr ./codeql - - # If nothing to commit, exit now. It's fine. No orphans. - changes=$(git diff --name-only | wc -l) - untracked=$(git status --untracked-files --short | wc -l) - if [[ $changes -eq 0 ]] && [[ $untracked -eq 0 ]]; then - echo "There are no changes to commit after running the generation and conversion scripts. Exiting..." - exit 0 - fi - - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - - branchname=codeql-query-tables-${{ steps.codeql.outputs.OPENAPI_COMMIT_SHA }} - - # Exit if the branch already exists. Since the actions/checkout fetch-depth is 1, - # it doesn't "know" about branches locally, so we need to manually list them. - branchExists=$(git ls-remote --heads origin refs/heads/$branchname | wc -l) - - # When run on a pull_request, we're just testing the tooling. - # Exit before it actually pushes the possible changes. - if [ "$DRY_RUN" = "true" ]; then - echo "Dry-run mode when run in a pull request" - echo "See the 'Insight into diff' step for the changes it would create PR about." - exit 0 - fi - - if [ $branchExists -ne 0 ]; then - echo "Branch $branchname already exists in the remote repository." - exit 0 - else - git checkout -b $branchname - fi - - git add data/reusables/code-scanning/codeql-query-tables - git add data/reusables/code-quality/codeql-query-tables - git commit -m "Update CodeQL query tables" - git push -u origin $branchname - - echo "Creating pull request..." - gh pr create \ - --title "Update CodeQL query tables" \ - --repo github/docs-internal \ - --label "codeql-query-tables,skip FR board,ready-for-doc-review,workflow-generated" \ - --body '👋 humans. This PR updates the **CodeQL query table reusables** with the latest changes in preparation for the next **CodeQL CLI** release. (Synced from codeql@${{ steps.codeql.outputs.OPENAPI_COMMIT_SHA }}) - - - No action is required from the first responder for the Docs content team. This PR is automatically added to the Docs content review board. Any writer can review this by checking that the PR looks sensible. If CI does not pass or other problems arise, contact #technical-content on slack. - - - When the DRI for the CodeQL CLI release is ready to publish, they will ask us to merge this PR in #docs-content. - - _Generated by the [Generate code scanning query lists](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run._' diff --git a/.github/workflows/headless-tests.yml b/.github/workflows/headless-tests.yml deleted file mode 100644 index 54e844c36906..000000000000 --- a/.github/workflows/headless-tests.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Headless Tests - -# **What it does**: This runs our browser tests to test things that depend -# on client-side JavaScript. -# **Why we have it**: Because most automated vitest tests only test static -# input and outputs. -# **Who does it impact**: Docs engineering, open-source engineering contributors. - -on: - workflow_dispatch: - merge_group: - pull_request: - -permissions: - contents: read - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -env: - ELASTICSEARCH_URL: http://localhost:9200/ - -jobs: - playwright-tests: - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ubuntu-latest - strategy: - # When we're comfortable a11y tests aren't generating false positives and helping, - # let's remove the matrix and just run playwright in a single job. - matrix: - node: - - playwright-rendering - - playwright-a11y - - playwright-secret-scanning - fail-fast: false - timeout-minutes: 60 - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/setup-elasticsearch - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/cache-nextjs - - - name: Run build script - run: npm run build - - - name: Index fixtures into the local Elasticsearch - run: npm run index-test-fixtures - - - name: Install headless browser - run: npx playwright install --no-shell - - - name: Run Playwright tests - env: - PLAYWRIGHT_WORKERS: ${{ fromJSON('[1, 4]')[github.repository == 'github/docs-internal'] }} - # workaround for https://github.com/nodejs/node/issues/59364 as of 22.18.0 - NODE_OPTIONS: '--no-experimental-strip-types' - PLAYWRIGHT_TIMEOUT: ${{ matrix.node == 'playwright-a11y' && '60000' || '' }} - - # Run playwright rendering tests and a11y tests (axe scans) as distinct checks - # so that we can run them without blocking merges until we can be confident - # results for a11y tests are meaningul and scenarios we're testing are correct. - run: npm run playwright-test -- ${{ matrix.node }} --reporter list diff --git a/.github/workflows/hubber-contribution-help.yml b/.github/workflows/hubber-contribution-help.yml deleted file mode 100644 index 45eec0641fde..000000000000 --- a/.github/workflows/hubber-contribution-help.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Hubber contribution help - -# **What it does**: When a PR is opened by a non-Docs team Hubber, adds a bot comment with helpful links -# **Why we have it**: To help non–Docs Hubbers navigate how to get a PR reviewed by the Docs team -# **Who does it impact**: docs-internal contributors - -on: - pull_request: - types: - - opened - paths: - - .github/workflows/hubber-contribution-help.yml - - 'content/**' - - 'data/**' - -permissions: - contents: read - pull-requests: write - -jobs: - check-team-membership: - if: github.repository == 'github/docs-internal' && github.actor != 'github-openapi-bot' && github.actor != 'docs-bot' - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - id: membership_check - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - try { - // Team is addressed by numeric ID (org github = 9919, team docs = 325922) - // because IDs survive team renames and slugs do not. - await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', { - org_id: 9919, - team_id: 325922, - username: context.payload.sender.login, - }); - return true - } catch(err) { - return false - } - - - name: Comment on the PR - if: steps.membership_check.outputs.result == 'false' - run: | - gh pr comment $PR --body "## Requesting a review from the Technical Content team - - ### 🚧 Draft PRs - - To add the PR to the Docs Content review board, click **Ready for review** in the merge box. - - ### 🚀 Non-draft PRs - - The PR is **ready** and has automatically been added to the Docs Content review board. The Technical Content team will review it as soon as possible. - - ### Lead time for review - - Please allow at least 3 business days for a Docs Content review. - - ### Need help? - - Reach out in [#docs-content](https://github-grid.enterprise.slack.com/archives/C0E9DK082) on Slack." - - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/index-autocomplete-search.yml b/.github/workflows/index-autocomplete-search.yml deleted file mode 100644 index d9c4d96418ad..000000000000 --- a/.github/workflows/index-autocomplete-search.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Index autocomplete search in Elasticsearch - -# **What it does**: Indexes AI search autocomplete data into Elasticsearch. -# **Why we have it**: So we can power the APIs for AI search autocomplete. -# **Who does it impact**: docs-engineering - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1-5' # Run Mon-Fri at 16:20 UTC / 8:20 PST - pull_request: - paths: - - .github/workflows/index-autocomplete-search.yml - - 'src/search/scripts/index/**' - - 'package*.json' - -permissions: - contents: read - -jobs: - index-autocomplete-elasticsearch: - if: ${{ github.repository == 'github/docs-internal' }} - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/setup-elasticsearch - if: ${{ github.event_name == 'pull_request' }} - - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - repository: github/docs-internal-data - path: docs-internal-data - - - name: Check that Elasticsearch is accessible - if: ${{ github.event_name == 'pull_request' }} - run: curl --fail --retry-connrefused --retry 5 -I http://localhost:9200 - - - name: Run AI search auto-complete indexing - env: - ELASTICSEARCH_URL: ${{ github.event_name == 'pull_request' && 'http://localhost:9200' || secrets.ELASTICSEARCH_URL }} - run: npm run index-ai-search-autocomplete -- docs-internal-data - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name == 'schedule' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name == 'schedule' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/index-general-search-pr.yml b/.github/workflows/index-general-search-pr.yml deleted file mode 100644 index ca386f5af510..000000000000 --- a/.github/workflows/index-general-search-pr.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: Index general search in Elasticsearch on PR - -# **What it does**: This does what `index-general-search-elasticsearch.yml` does but -# with a localhost Elasticsearch and only for English. -# **Why we have it**: To test that the script works and the popular pages json is valid. -# **Who does it impact**: Docs engineering - -on: - workflow_dispatch: - pull_request: - paths: - - 'src/search/**' - - 'package*.json' - # For debugging this workflow - - .github/workflows/index-general-search-pr.yml - # Make sure we run this if the composite action changes - - .github/actions/setup-elasticsearch/action.yml - -permissions: - contents: read - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -env: - ELASTICSEARCH_URL: http://localhost:9200 - # Since we'll run in NDOE_ENV=production, we need to be explicit that - # we don't want Hydro configured. - HYDRO_ENDPOINT: '' - HYDRO_SECRET: '' - -jobs: - dryRunElasticsearchIndexes: - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Clone docs-internal-data - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: github/docs-internal-data - # This works because user `docs-bot` has read access to that private repo. - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - path: docs-internal-data - - - uses: ./.github/actions/setup-elasticsearch - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/cache-nextjs - - - name: Build - run: npm run build - - - name: Start the server in the background - env: - ENABLE_DEV_LOGGING: false - run: | - npm run general-search-scrape-server > /tmp/stdout.log 2> /tmp/stderr.log & - - # first sleep to give it a chance to start - sleep 6 - curl --retry-connrefused --retry 6 -I http://localhost:4002/ - - - if: ${{ failure() }} - name: Debug server outputs on errors - run: | - echo "____STDOUT____" - cat /tmp/stdout.log - echo "____STDERR____" - cat /tmp/stderr.log - - - name: Scrape records into a temp directory - env: - # If a reusable, or anything in the `data/*` directory is deleted - # you might get a - # - # RenderError: Can't find the key 'site.data.reusables...' in the scope - # - # But that'll get fixed in the next translation pipeline. For now, - # let's just accept an empty string instead. - THROW_ON_EMPTY: false - - DOCS_INTERNAL_DATA: docs-internal-data - - run: | - mkdir /tmp/records - npm run general-search-scrape -- /tmp/records \ - --language en \ - --version fpt - - ls -lh /tmp/records - - - name: Check that Elasticsearch is accessible - run: | - curl --fail --retry-connrefused --retry 5 -I ${{ env.ELASTICSEARCH_URL }} - - - name: Index into Elasticsearch - run: | - npm run index-general-search -- /tmp/records \ - --language en \ - --version fpt - - - name: Check created indexes and aliases - run: | - curl --fail --retry-connrefused --retry 5 ${{ env.ELASTICSEARCH_URL }}/_cat/indices?v - curl --fail --retry-connrefused --retry 5 ${{ env.ELASTICSEARCH_URL }}/_cat/indices?v diff --git a/.github/workflows/index-general-search.yml b/.github/workflows/index-general-search.yml deleted file mode 100644 index 3e7809b10f5e..000000000000 --- a/.github/workflows/index-general-search.yml +++ /dev/null @@ -1,369 +0,0 @@ -name: Index general search in Elasticsearch - -# **What it does**: It scrapes the whole site and dumps the records in a -# temp directory. Then it indexes that into Elasticsearch. -# **Why we have it**: We want our search indexes kept up to date. -# **Who does it impact**: Anyone using search on docs. - -on: - workflow_dispatch: - inputs: - version: - description: "Version to exclusively generate the search index for. E.g. 'dotcom', 'ghes-3.12'" - required: false - default: '' - languages: - description: "Comma separated languages. E.g. 'en,es,ja,pt,zh,ru,fr,ko,de' (defaults to all)" - required: false - default: '' - schedule: - - cron: '20 16 * * 1-5' # Run Mon-Fri at 16:20 UTC / 8:20 PST - workflow_run: - workflows: ['Purge Fastly'] - types: - - completed - -permissions: - contents: read - -# This allows a subsequently queued workflow run to cancel previous runs. -# Include the triggering workflow's conclusion in the group so that runs triggered -# by skipped Purge Fastly workflows don't cancel runs triggered by successful ones. -concurrency: - group: '${{ github.workflow }} @ ${{ github.head_ref }} ${{ github.event_name }} ${{ github.event.workflow_run.conclusion }}' - cancel-in-progress: true - -env: - ELASTICSEARCH_URL: ${{ secrets.ELASTICSEARCH_URL }} - # Since we'll run in NODE_ENV=production, we need to be explicit that - # we don't want Hydro configured. - HYDRO_ENDPOINT: '' - HYDRO_SECRET: '' - -jobs: - figureOutMatrix: - # Skip immediately if triggered by a non-successful Purge Fastly run. - # This prevents skipped runs from canceling valid indexing runs via concurrency. - if: ${{ github.repository == 'github/docs-internal' && (github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success') }} - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set-matrix.outputs.result }} - steps: - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - id: set-matrix - with: - script: | - // Edit this list for the definitive list of languages - // (other than English) we want to index in Elasticsearch. - const allNonEnglish = 'es,ja,pt,zh,ru,fr,ko,de'.split(',') - const allPossible = ["en", ...allNonEnglish] - - if (context.eventName === "workflow_run") { - // Job-level `if` already ensures we only get here for successful runs, - // but keep this as a safety check. - if (context.payload.workflow_run.conclusion === "success") { - return ["en"] - } - // This shouldn't happen due to job-level filter, but handle gracefully. - console.warn(`Unexpected: workflow_run with conclusion '${context.payload.workflow_run.conclusion}'`) - return [] - } - - if (context.eventName === "workflow_dispatch") { - if (context.payload.inputs.languages) { - const clean = context.payload.inputs.languages.split(',').map(x => x.trim()).filter(Boolean) - const notRecognized = clean.find(x => !allPossible.includes(x)) - if (notRecognized) { - throw new Error(`'${notRecognized}' is not a recognized language code`) - } - return clean - } - return allPossible - } - - if (context.eventName === "schedule") { - return allNonEnglish - } - - console.log(context) - throw new Error(`Unable figure out what languages to run (${context.eventName})`) - - - name: Debug output - run: echo "${{ steps.set-matrix.outputs.result }}" - - - name: Check out repo - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} - - updateElasticsearchIndexes: - needs: figureOutMatrix - name: Update indexes - if: ${{ github.repository == 'github/docs-internal' && needs.figureOutMatrix.outputs.matrix != '[]' }} - runs-on: ubuntu-latest - strategy: - fail-fast: false - # When it's only English (i.e. a simple array of ['en']), this value - # does not matter. If it's ALL the languages, then we know we can - # be patient because it's a daily scheduled run and it's run by bots - # while humans are asleep. So there's no rush and no need to finish - # the whole job fast. - # As of June 2023, it takes about 10+ minutes to index one whole - # language and we have 8 non-English languages. - # As of May 2025, we index so many pages that we are being rate-limited by - # Elasticsearch. So we are shrinking this value to 2, down from 3 - max-parallel: 2 - matrix: - language: ${{ fromJSON(needs.figureOutMatrix.outputs.matrix) }} - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - name: Clone docs-internal-data - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: github/docs-internal-data - # This works because user `docs-bot` has read access to that private repo. - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - path: docs-internal-data - - - name: Clone all translations - if: ${{ matrix.language != 'en' }} - uses: ./.github/actions/clone-translations - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/cache-nextjs - - - name: Run build scripts - run: npm run build - - - name: Start the server in the background - env: - ENABLE_DEV_LOGGING: false - run: | - npm run general-search-scrape-server > /tmp/stdout.log 2> /tmp/stderr.log & - - # first sleep to give it a chance to start - sleep 6 - curl --retry-connrefused --retry 6 -I http://localhost:4002/ - - - if: ${{ failure() }} - name: Debug server outputs on errors - run: | - echo "____STDOUT____" - cat /tmp/stdout.log - echo "____STDERR____" - cat /tmp/stderr.log - - - name: Scrape records into a temp directory - env: - # If a reusable, or anything in the `data/*` directory is deleted - # you might get a - # - # RenderError: Can't find the key 'site.data.reusables...' in the scope - # - # But that'll get fixed in the next translation pipeline. For now, - # let's just accept an empty string instead. - THROW_ON_EMPTY: false - - # Note that by default, this is '' (empty string) and that means - # the same as not set within the script. - VERSION: ${{ inputs.version }} - - DOCS_INTERNAL_DATA: docs-internal-data - - run: | - mkdir /tmp/records - npm run general-search-scrape -- /tmp/records \ - --language ${{ matrix.language }} - - ls -lh /tmp/records - - - name: Check for scraping failures - id: check-failures - run: | - if [ -f /tmp/records/failures-summary.json ]; then - FAILED_PAGES=$(jq -r '.totalFailedPages' /tmp/records/failures-summary.json) - echo "failed_pages=$FAILED_PAGES" >> $GITHUB_OUTPUT - echo "has_failures=true" >> $GITHUB_OUTPUT - echo "⚠️ Warning: $FAILED_PAGES page(s) failed to scrape" - else - echo "has_failures=false" >> $GITHUB_OUTPUT - echo "✅ All pages scraped successfully" - fi - - - name: Check that Elasticsearch is accessible - run: | - curl --fail --retry-connrefused --retry 5 -I ${{ env.ELASTICSEARCH_URL }} - - - name: Index into Elasticsearch - env: - # Must match what we used when scraping (npm run general-search-scrape) - # otherwise the script will seek other versions from disk that might - # not exist. - VERSION: ${{ inputs.version }} - run: | - npm run index-general-search -- /tmp/records \ - --language ${{ matrix.language }} \ - --stagger-seconds 5 \ - --retries 5 - - - name: Check created indexes and aliases - run: | - # Not using `--fail` here because I've observed that it can fail - # with a rather cryptic 404 error when it should, if anything, be - # a 200 OK with a list of no indices. - curl --retry-connrefused --retry 5 ${{ env.ELASTICSEARCH_URL }}/_cat/indices?v - curl --retry-connrefused --retry 5 ${{ env.ELASTICSEARCH_URL }}/_cat/indices?v - - - name: Purge Fastly edge cache - env: - FASTLY_TOKEN: ${{ secrets.FASTLY_TOKEN }} - FASTLY_SERVICE_ID: ${{ secrets.FASTLY_SERVICE_ID }} - run: npm run purge-fastly -- --surrogate-key api-search:${{ matrix.language }} - - - name: Upload failures artifact - if: ${{ steps.check-failures.outputs.has_failures == 'true' }} - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: search-failures-${{ matrix.language }} - path: /tmp/records/failures-summary.json - retention-days: 1 - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} - - notifyScrapingFailures: - name: Notify scraping failures - needs: updateElasticsearchIndexes - if: ${{ always() && github.repository == 'github/docs-internal' && github.event_name != 'workflow_dispatch' && needs.updateElasticsearchIndexes.result != 'cancelled' }} - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - name: Download all failure artifacts - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 - with: - pattern: search-failures-* - path: /tmp/failures - continue-on-error: true - - - name: Check if any failures were downloaded - id: check-artifacts - run: | - if [ -d /tmp/failures ] && [ "$(ls -A /tmp/failures 2>/dev/null)" ]; then - echo "has_artifacts=true" >> $GITHUB_OUTPUT - else - echo "has_artifacts=false" >> $GITHUB_OUTPUT - fi - - - uses: ./.github/actions/node-npm-setup - if: ${{ steps.check-artifacts.outputs.has_artifacts == 'true' }} - - - name: Aggregate failures and format message - if: ${{ steps.check-artifacts.outputs.has_artifacts == 'true' }} - id: aggregate - run: | - RESULT=$(npx tsx src/search/scripts/aggregate-search-index-failures.ts /tmp/failures \ - --workflow-url "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}") - { - echo 'result<> "$GITHUB_OUTPUT" - - - name: Comment on or create scraping failure issue - if: ${{ steps.check-artifacts.outputs.has_artifacts == 'true' && fromJSON(steps.aggregate.outputs.result || '{"hasFailures":false}').hasFailures }} - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - FAILURE_MESSAGE: ${{ fromJSON(steps.aggregate.outputs.result || '{"message":""}').message }} - RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - FILE_URL: ${{ github.server_url }}/${{ github.repository }}/blob/main/.github/workflows/index-general-search.yml - WORKFLOW_NAME: ${{ github.workflow }} - run: | - # Reuse the oldest open scraping-failures issue if one exists, - # to keep the noise down. Otherwise open a new one. - existing_issue=$(gh issue list \ - --repo github/technical-content \ - --label "search-scraping-failures" \ - --state open \ - --limit 200 \ - --json number,createdAt \ - --jq 'sort_by(.createdAt) | .[0].number // empty') - - today=$(date -u +%Y-%m-%d) - - if [ -n "$existing_issue" ]; then - comment_body=$(cat <> $GITHUB_OUTPUT - else - echo "has_report=false" >> $GITHUB_OUTPUT - echo "No broken link report generated - all links valid!" - fi - - - name: Create or update the rolling report issue - if: | - always() - && steps.check.outcome == 'success' - && steps.check_report.outputs.has_report == 'true' - && !inputs.max_urls - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const fs = require('fs') - const title = '🌐 Broken External Links Report' - const owner = 'github' - const repo = 'docs-content' - const label = 'broken link report' - - // GitHub rejects issue bodies over 65536 characters with a 422. - // Truncate and point at the run artifact for the full contents. - const MAX_BODY_SIZE = 60000 - const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` - let body = fs.readFileSync('artifacts/external-link-report.md', 'utf8') - if (body.length > MAX_BODY_SIZE) { - const notice = `\n\n---\n\n*Report truncated. Download the full report from the [workflow run artifacts](${runUrl}).*` - body = body.slice(0, MAX_BODY_SIZE - notice.length) + notice - core.warning(`Report exceeded ${MAX_BODY_SIZE} characters, so it was truncated.`) - } - - // Reuse a single rolling issue instead of opening a new one every - // week, which floods the first responders' board. Find the open - // report issues (newest first). - const open = await github.paginate(github.rest.issues.listForRepo, { - owner, - repo, - state: 'open', - labels: label, - per_page: 100, - }) - const reportIssues = open - .filter((issue) => !issue.pull_request && issue.title === title) - .sort((a, b) => b.number - a.number) - - if (reportIssues.length === 0) { - const created = await github.rest.issues.create({ - owner, - repo, - title, - body, - labels: [label], - }) - core.info(`Created rolling report issue: ${created.data.html_url}`) - return - } - - // Refresh the newest open report in place and close any older - // duplicates so exactly one canonical issue remains. - const [canonical, ...superseded] = reportIssues - await github.rest.issues.update({ - owner, - repo, - issue_number: canonical.number, - title, - body, - }) - core.info(`Updated rolling report issue: ${canonical.html_url}`) - - // Attempt every duplicate even if one fails, so a single transient - // API error doesn't leave the rest open. - const results = await Promise.allSettled( - superseded.map(async (issue) => { - await github.rest.issues.createComment({ - owner, - repo, - issue_number: issue.number, - body: `Superseded by the current rolling report: #${canonical.number}.`, - }) - await github.rest.issues.update({ - owner, - repo, - issue_number: issue.number, - state: 'closed', - state_reason: 'not_planned', - }) - core.info(`Closed superseded report issue #${issue.number}`) - }), - ) - const failures = results.filter((result) => result.status === 'rejected') - if (failures.length > 0) { - throw new AggregateError( - failures.map((failure) => failure.reason), - `Failed to close ${failures.length} superseded report issue(s).`, - ) - } - - - name: Close the rolling report issue when all links are valid - if: | - always() - && steps.check.outcome == 'success' - && steps.check_report.outputs.has_report == 'false' - && !inputs.max_urls - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const title = '🌐 Broken External Links Report' - const owner = 'github' - const repo = 'docs-content' - const label = 'broken link report' - - // A clean run means the open report is stale. Leaving it open would - // keep fixed failures on the first responders' board. - const open = await github.paginate(github.rest.issues.listForRepo, { - owner, - repo, - state: 'open', - labels: label, - per_page: 100, - }) - const reportIssues = open.filter( - (issue) => !issue.pull_request && issue.title === title, - ) - - if (reportIssues.length === 0) { - core.info('No open report issue to close.') - return - } - - const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` - const results = await Promise.allSettled( - reportIssues.map(async (issue) => { - await github.rest.issues.createComment({ - owner, - repo, - issue_number: issue.number, - body: `All external links are valid as of the [latest run](${runUrl}). Closing this report. A new one opens if links break again.`, - }) - await github.rest.issues.update({ - owner, - repo, - issue_number: issue.number, - state: 'closed', - state_reason: 'completed', - }) - core.info(`Closed resolved report issue #${issue.number}`) - }), - ) - const failures = results.filter((result) => result.status === 'rejected') - if (failures.length > 0) { - throw new AggregateError( - failures.map((failure) => failure.reason), - `Failed to close ${failures.length} resolved report issue(s).`, - ) - } - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/link-check-github-github.yml b/.github/workflows/link-check-github-github.yml deleted file mode 100644 index 7f6e14c92c9d..000000000000 --- a/.github/workflows/link-check-github-github.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: 'Link Check: github/github' - -# **What it does**: This checks for any broken docs.github.com links in github/github -# **Why we have it**: Make sure all docs in github/github are up to date -# **Who does it impact**: Docs engineering, people on GitHub - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: read - -jobs: - check_github_github_links: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - env: - REPORT_AUTHOR: docs-bot - REPORT_LABEL: github github broken link report,workflow-generated - REPORT_REPOSITORY: github/docs-content - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # To prevent issues with cloning early access content later - persist-credentials: 'false' - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/get-docs-early-access - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Build server - run: npm run build - - - name: Start server in the background - env: - NODE_ENV: production - PORT: 4000 - ENABLED_LANGUAGES: en - run: | - npm run start-for-ci & - sleep 5 - curl --retry-connrefused --retry 5 -I http://localhost:4000/ - - - name: Run broken github/github link check - env: - # Needs a token with access to github/github; the app token is scoped to it above - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - npm run check-github-github-links -- broken_github_github_links.md - - - name: Get title for issue - # If the file 'broken_github_github_links.md' got created, - # the hash of it will not be an empty string. That means if found - # broken links, we want to create an issue. - if: ${{ hashFiles('broken_github_github_links.md') != '' }} - id: check - run: echo "title=$(head -1 broken_github_github_links.md)" >> $GITHUB_OUTPUT - - - name: Create issue from file - if: ${{ hashFiles('broken_github_github_links.md') != '' }} - id: github-github-broken-link-report - uses: peter-evans/create-issue-from-file@fca9117c27cdc29c6c4db3b86c48e4115a786710 - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - title: ${{ steps.check.outputs.title }} - content-filepath: ./broken_github_github_links.md - repository: ${{ env.REPORT_REPOSITORY }} - labels: ${{ env.REPORT_LABEL }} - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/link-check-internal.yml b/.github/workflows/link-check-internal.yml deleted file mode 100644 index 482948c6ab28..000000000000 --- a/.github/workflows/link-check-internal.yml +++ /dev/null @@ -1,432 +0,0 @@ -name: 'Link Check: Internal' - -on: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - workflow_dispatch: - inputs: - version: - description: 'Version to check (e.g., free-pro-team@latest, enterprise-server@3.19)' - type: string - required: true - language: - description: 'Language to check (e.g., en, es, ja)' - type: string - required: true - default: 'en' - create_copilot_issue: - description: 'Create a Copilot-assigned issue with the top 10 redirects to fix' - type: boolean - required: false - default: false - create_report: - description: "Publish the combined report to the rolling docs-content issue. A manual run only covers one version/language, so it will overwrite the scheduled run's fuller report." - type: boolean - required: false - default: false - -permissions: - contents: read - -jobs: - # Determine which version/language combos to run - setup-matrix: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - - name: Set matrix - id: set-matrix - run: | - if [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then - # Manual run: use the provided version and language - echo "matrix={\"include\":[{\"version\":\"${INPUT_VERSION}\",\"language\":\"${INPUT_LANGUAGE}\"}]}" >> $GITHUB_OUTPUT - else - # Scheduled run: every published version, in English. A link can be broken in - # one version and fine in another, so checking two of eight left most of the - # site unchecked. The report job merges the results, so this does not multiply - # the size of the issue. - MATRIX=$(npx tsx -e "import { allVersions } from './src/versions/lib/all-versions'; console.log(JSON.stringify({ include: Object.keys(allVersions).map((version) => ({ version, language: 'en' })) }))") - echo "matrix=${MATRIX}" >> $GITHUB_OUTPUT - fi - env: - EVENT_NAME: ${{ github.event_name }} - INPUT_VERSION: ${{ inputs.version }} - INPUT_LANGUAGE: ${{ inputs.language }} - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} - - check-internal-links: - if: github.repository == 'github/docs-internal' - needs: setup-matrix - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }} - env: - # Disable Elasticsearch for faster warmServer - ELASTICSEARCH_URL: '' - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - # Clone translations if not English - - name: Clone translations - if: matrix.language != 'en' - uses: ./.github/actions/clone-translations - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Check internal links - env: - VERSION: ${{ matrix.version }} - LANGUAGE: ${{ matrix.language }} - CHECK_ANCHORS: true - ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - run: npm run check-links-internal - - - name: Upload report artifact - if: always() - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: link-report-${{ matrix.version }}-${{ matrix.language }} - # Include the JSON alongside the Markdown so the structured report is - # consumable outside this job, not just readable in the issue body. - path: artifacts/link-report-* - retention-days: 5 - if-no-files-found: ignore - - - name: Create Copilot redirect issue - if: inputs.create_copilot_issue - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const fs = require('fs') - const reportFile = 'artifacts/link-report-${{ matrix.version }}-${{ matrix.language }}.json' - - if (!fs.existsSync(reportFile)) { - core.info('No JSON report found — all links valid, skipping Copilot issue.') - return - } - - const report = JSON.parse(fs.readFileSync(reportFile, 'utf8')) - const allRedirectGroups = report.groups.filter(g => g.isWarning) - const redirectGroups = allRedirectGroups.slice(0, 10) - - if (redirectGroups.length === 0) { - core.info('No redirect groups found, skipping Copilot issue.') - return - } - - const directives = redirectGroups.map(g => { - const occ = g.occurrences[0] - const redirectTarget = occ?.redirectTarget ?? 'unknown' - const file = occ?.file ?? 'unknown' - const lines = (occ?.lines ?? []).join(', ') || 'unknown' - return `- Update \`${g.target}\` to \`${redirectTarget}\` in \`${file}\` (line(s): ${lines})` - }).join('\n') - - const artifactsUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}/artifacts` - - const bodyLines = [ - 'Copilot, fix the redirected internal links listed below. All changes should be made within the `github/docs-internal` repository.', - '', - 'For each directive below, open the specified file and find the old link path. Replace it with the new link path exactly as shown. Do not invent or guess link paths — only use the exact paths provided in each directive.', - '', - 'When all changes are made, open a pull request in `github/docs-internal` with the fixes. The pull request description should reference this issue to create a link between them. When the pull request is open, leave a comment on this issue with a link to it.', - '', - `These are the first ${redirectGroups.length} of ${allRedirectGroups.length} redirects found.`, - '', - '## Redirects to update', - '', - directives, - ] - - const MAX_ISSUE_BODY_LENGTH = 65536 - const artifactNote = `\n\n> [!NOTE]\n> The report was truncated because it exceeded the issue body length limit. [View the complete redirect report in the workflow artifacts](${artifactsUrl}).` - - let body = bodyLines.join('\n') - if (body.length > MAX_ISSUE_BODY_LENGTH) { - const truncatedLength = MAX_ISSUE_BODY_LENGTH - artifactNote.length - const lastNewline = body.lastIndexOf('\n', truncatedLength) - body = body.slice(0, lastNewline > 0 ? lastNewline : truncatedLength) + artifactNote - } - - // Use the REST API with agent_assignment to properly trigger Copilot cloud agent. - // See: https://docs.github.com/en/copilot/how-tos/use-copilot-agents/cloud-agent/start-copilot-sessions#using-the-rest-api - const issue = await github.request('POST /repos/{owner}/{repo}/issues', { - owner: 'github', - repo: 'docs-content', - title: '[Copilot Task] Fix top redirect links: ${{ matrix.version }}/${{ matrix.language }}', - body, - labels: ['broken link report'], - assignees: ['copilot-swe-agent[bot]'], - agent_assignment: { - target_repo: 'github/docs-internal', - base_branch: 'main', - custom_instructions: 'Follow each directive in the issue exactly. Each directive specifies a file, the old link to find, and the new link to replace it with. Use only the exact paths provided — do not invent or guess any link paths. When all changes are made, open a pull request in github/docs-internal with the fixes. When the pull request is open, leave a comment on this issue with a link to it.', - }, - }) - - core.info(`Created Copilot redirect issue: ${issue.data.html_url}`) - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} - - # Create combined report after all matrix jobs complete - create-report: - if: always() && github.repository == 'github/docs-internal' - needs: [setup-matrix, check-internal-links] - runs-on: ubuntu-latest - # Serialize publishing so two overlapping runs can't both create a - # "rolling" issue, or write their results out of order. - concurrency: - group: broken-internal-links-report - cancel-in-progress: false - permissions: - contents: read - issues: write - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - - name: Download all artifacts - uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 - with: - path: reports - pattern: link-report-* - merge-multiple: true - - - name: Combine reports - id: combine - env: - ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - # A version with no broken links uploads no report, so the files on disk undercount - # what was checked. Pass the matrix so the report can say "broken in all versions" - # and mean it. - MATRIX: ${{ needs.setup-matrix.outputs.matrix }} - run: | - # Merge the per-version JSON rather than concatenating the rendered Markdown. - # A link broken in every version is one problem, not one per version. - if ls reports/*.json 1> /dev/null 2>&1; then - echo "has_reports=true" >> $GITHUB_OUTPUT - VERSIONS=$(echo "$MATRIX" | jq -r '[.include[] | "\(.version) \(.language)"] | join(",")') - npm run combine-link-reports -- \ - --input reports \ - --output combined-report.md \ - --versions "$VERSIONS" \ - --action-url "$ACTION_RUN_URL" - else - echo "has_reports=false" >> $GITHUB_OUTPUT - echo "No broken link reports generated - all links valid!" - fi - - - name: Upload the combined report - if: steps.combine.outputs.has_reports == 'true' - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - # The issue body caps every long section, and the notes there point at - # "the report attached to the workflow run". Upload it so that is true. - name: combined-link-report - path: combined-report.md - retention-days: 5 - if-no-files-found: error - - - name: Create or update the rolling report issue - if: | - steps.combine.outputs.has_reports == 'true' - && needs.check-internal-links.result == 'success' - && (github.event_name != 'workflow_dispatch' || inputs.create_report) - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const fs = require('fs') - const title = '🔗 Broken Internal Links Report' - const owner = 'github' - const repo = 'docs-content' - const label = 'broken link report' - - // GitHub rejects issue bodies over 65536 characters with a 422. The - // internal report routinely exceeds that, so truncate and point at - // the run artifact for the full contents. - const MAX_BODY_SIZE = 60000 - const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` - let body = fs.readFileSync('combined-report.md', 'utf8') - if (body.length > MAX_BODY_SIZE) { - const notice = `\n\n---\n\n*Report truncated. Download the full report from the [workflow run artifacts](${runUrl}).*` - let cut = body.slice(0, MAX_BODY_SIZE - notice.length) - // Cut at a line boundary so the last thing a reader sees is not half - // a table row, and close any `
` the cut left open, since an - // unclosed one swallows everything after it. - cut = cut.slice(0, cut.lastIndexOf('\n')) - const opened = (cut.match(/
/g) || []).length - const closed = (cut.match(/<\/details>/g) || []).length - cut += '\n
'.repeat(Math.max(0, opened - closed)) - body = cut + notice - core.warning(`Report exceeded ${MAX_BODY_SIZE} characters, so it was truncated.`) - } - - // Reuse a single rolling issue instead of opening a new one every - // week, which floods the first responders' board. Find the open - // report issues (newest first). - const open = await github.paginate(github.rest.issues.listForRepo, { - owner, - repo, - state: 'open', - labels: label, - per_page: 100, - }) - const reportIssues = open - .filter((issue) => !issue.pull_request && issue.title === title) - .sort((a, b) => b.number - a.number) - - if (reportIssues.length === 0) { - const created = await github.rest.issues.create({ - owner, - repo, - title, - body, - labels: [label], - }) - core.info(`Created rolling report issue: ${created.data.html_url}`) - return - } - - // Refresh the newest open report in place and close any older - // duplicates so exactly one canonical issue remains. - const [canonical, ...superseded] = reportIssues - await github.rest.issues.update({ - owner, - repo, - issue_number: canonical.number, - title, - body, - }) - core.info(`Updated rolling report issue: ${canonical.html_url}`) - - // Attempt every duplicate even if one fails, so a single transient - // API error doesn't leave the rest open. - const results = await Promise.allSettled( - superseded.map(async (issue) => { - await github.rest.issues.createComment({ - owner, - repo, - issue_number: issue.number, - body: `Superseded by the current rolling report: #${canonical.number}.`, - }) - await github.rest.issues.update({ - owner, - repo, - issue_number: issue.number, - state: 'closed', - state_reason: 'not_planned', - }) - core.info(`Closed superseded report issue #${issue.number}`) - }), - ) - const failures = results.filter((result) => result.status === 'rejected') - if (failures.length > 0) { - throw new AggregateError( - failures.map((failure) => failure.reason), - `Failed to close ${failures.length} superseded report issue(s).`, - ) - } - - - name: Close the rolling report issue when all links are valid - if: | - steps.combine.outputs.has_reports == 'false' - && needs.check-internal-links.result == 'success' - && github.event_name != 'workflow_dispatch' - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const title = '🔗 Broken Internal Links Report' - const owner = 'github' - const repo = 'docs-content' - const label = 'broken link report' - - // A clean run means the open report is stale. Leaving it open would - // keep fixed failures on the first responders' board. - const open = await github.paginate(github.rest.issues.listForRepo, { - owner, - repo, - state: 'open', - labels: label, - per_page: 100, - }) - const reportIssues = open.filter( - (issue) => !issue.pull_request && issue.title === title, - ) - - if (reportIssues.length === 0) { - core.info('No open report issue to close.') - return - } - - const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` - const results = await Promise.allSettled( - reportIssues.map(async (issue) => { - await github.rest.issues.createComment({ - owner, - repo, - issue_number: issue.number, - body: `All internal links are valid as of the [latest run](${runUrl}). Closing this report. A new one opens if links break again.`, - }) - await github.rest.issues.update({ - owner, - repo, - issue_number: issue.number, - state: 'closed', - state_reason: 'completed', - }) - core.info(`Closed resolved report issue #${issue.number}`) - }), - ) - const failures = results.filter((result) => result.status === 'rejected') - if (failures.length > 0) { - throw new AggregateError( - failures.map((failure) => failure.reason), - `Failed to close ${failures.length} resolved report issue(s).`, - ) - } - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/link-check-on-pr.yml b/.github/workflows/link-check-on-pr.yml deleted file mode 100644 index 39fa97ade145..000000000000 --- a/.github/workflows/link-check-on-pr.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: 'Link Check: On PR' - -# **What it does**: Checks internal links in changed content files. -# **Why we have it**: To catch broken links before they're merged. -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - # merge_group: - pull_request: - types: [opened, synchronize, reopened] - -permissions: - contents: read - pull-requests: write - issues: write - -# Cancel in-progress runs for the same PR -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - check-links: - name: Check links - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Fetch 2 commits so tj-actions/changed-files can diff without extra API calls - fetch-depth: 2 - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/get-docs-early-access - if: ${{ github.repository == 'github/docs-internal' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Get changed files - id: changed-files - uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - with: - files: | - content/**/*.md - data/**/*.md - - - name: Check links in changed files - if: steps.changed-files.outputs.any_changed == 'true' - env: - FILES_CHANGED: ${{ steps.changed-files.outputs.all_changed_files }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - SHOULD_COMMENT: ${{ secrets.DOCS_BOT_PAT_BASE != '' }} - FAIL_ON_FLAW: true - # Cross-page anchor checking is on, but non-blocking during rollout: broken - # anchors are reported in the PR comment without failing the build. Flip - # FAIL_ON_ANCHOR_FLAW to true once false-positive/perf rates look clean. - CHECK_ANCHORS: true - FAIL_ON_ANCHOR_FLAW: false - ENABLED_LANGUAGES: en - run: npm run check-links-pr - - - name: No content changes - if: steps.changed-files.outputs.any_changed != 'true' - run: echo "No content files changed. Skipping link check." diff --git a/.github/workflows/lint-code.yml b/.github/workflows/lint-code.yml deleted file mode 100644 index 3600a02cbeb3..000000000000 --- a/.github/workflows/lint-code.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Lint code - -# **What it does**: Lints our code to ensure the code matches the specified code style. -# **Why we have it**: We want some level of consistency to our code. -# **Who does it impact**: Docs engineering, open-source engineering contributors. - -on: - workflow_dispatch: - merge_group: - pull_request: - -permissions: - contents: read - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - lint-code: - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Run linter - run: npm run lint - - - name: Run Prettier - run: npm run prettier-check - - - name: Run TypeScript - run: npm run tsc diff --git a/.github/workflows/lint-entire-content-data-markdown.yml b/.github/workflows/lint-entire-content-data-markdown.yml deleted file mode 100644 index 9817a99675fa..000000000000 --- a/.github/workflows/lint-entire-content-data-markdown.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: 'Lint entire content and data markdown files' - -# **What it does**: Lints our content markdown weekly to ensure the content matches the specified styleguide. If errors or warnings exist, it opens an issue for the Docs content team to review. -# **Why we have it**: Extra precaution to run linter on the entire content/data directories. -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: read - issues: write - -jobs: - lint-entire-content-data: - name: Lint entire content and data directories - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Check that gh CLI is installed - run: gh --version - - - name: Check out repo's default branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Set up Node and dependencies - uses: ./.github/actions/node-npm-setup - - - name: Run content linter - id: linting-content-data - timeout-minutes: 10 - continue-on-error: true - run: npm run lint-content -- --paths content data --output-file /tmp/lint-results.json - - - name: Open issue in docs-content - if: ${{ always() && steps.linting-content-data.outcome == 'failure' }} - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - REPORT_AUTHOR: docs-bot - REPORT_LABEL: broken content markdown report - REPORT_REPOSITORY: github/docs-content - run: npm run lint-report -- --path /tmp/lint-results.json - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/local-dev.yml b/.github/workflows/local-dev.yml deleted file mode 100644 index 048f6f2629cc..000000000000 --- a/.github/workflows/local-dev.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Local development - -# **What it does**: Basic smoke test to ensure local dev server starts and serves content -# **Why we have it**: Catch catastrophic "npm start is completely broken" scenarios -# **Who does it impact**: Engineers, Contributors. - -on: - merge_group: - pull_request: - -permissions: - contents: read - -jobs: - local-dev: - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/get-docs-early-access - if: ${{ github.repository == 'github/docs-internal' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Disable Next.js telemetry - run: npx next telemetry disable - - - name: Start server and basic smoke test - run: | - # Start server in background - npm start > /tmp/stdout.log 2> /tmp/stderr.log & - SERVER_PID=$! - - # Wait for server to be ready and test homepage - if curl --fail --retry-connrefused --retry 10 --retry-delay 2 http://localhost:4000/; then - echo "✅ Local dev server started successfully and serves homepage" - kill $SERVER_PID 2>/dev/null || true - else - echo "❌ Local dev server failed to start or serve content" - echo "____STDOUT____" - cat /tmp/stdout.log - echo "____STDERR____" - cat /tmp/stderr.log - kill $SERVER_PID 2>/dev/null || true - exit 1 - fi diff --git a/.github/workflows/merged-notification.yml b/.github/workflows/merged-notification.yml deleted file mode 100644 index c650e765ee94..000000000000 --- a/.github/workflows/merged-notification.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Merged notification - -# **What it does**: When we merge an open-source pull request, we want to set expectations that deployment may take awhile. -# **Why we have it**: We deploy to production from docs-internal, not docs. -# **Who does it impact**: Open-source contributors. - -on: - # Needed in lieu of `pull_request` so that the notification comment is posted to a PR from a fork. - pull_request_target: - types: - - 'closed' - -permissions: - issues: write - pull-requests: write - contents: read - -jobs: - comment: - if: github.repository == 'github/docs' && github.event.pull_request.merged && github.event.pull_request.base.ref == github.event.repository.default_branch && github.event.pull_request.user.login != 'docs-bot' - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - script: | - github.rest.issues.createComment({ - ...context.repo, - issue_number: context.payload.pull_request.number, - body: "Thanks very much for contributing! Your pull request has been merged 🎉 You should see your changes appear on the site in approximately 24 hours. If you're looking for your next contribution, check out our [help wanted issues](https://github.com/github/docs/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) :zap:" - }) diff --git a/.github/workflows/moda-allowed-ips.yml b/.github/workflows/moda-allowed-ips.yml deleted file mode 100644 index 9709bb7c191f..000000000000 --- a/.github/workflows/moda-allowed-ips.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Update Moda allowed IPs - -# **What it does**: Make sure that the allowed IPs in Moda are up to date. -# **Why we have it**: The IP ranges from Fastly can change. -# **Who does it impact**: Docs engineering. - -on: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - update-moda-allowed-ips: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Check out the repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - name: Update list of allowed IPs - run: | - echo "Getting a list of Fastly IP addresses...." - ips=$( \ - curl -s https://api.fastly.com/public-ip-list \ - | jq -r '.addresses | join(",")' \ - ) - echo "Got a list of Fastly IP addresses: $ips" - - echo "Updating the list of allowed IPs in Moda config..." - yq -i ".metadata.annotations[\"moda.github.net/allowed-ips\"] = \"$ips\"" \ - config/kubernetes/production/services/webapp.yaml - echo "Updated the list of allowed IPs in Moda config" - - echo "Checking if there is a change to make..." - if git diff --quiet; then - echo "No changes to the allowed IPs" - exit 0 - fi - - echo "Change found; making a pull request..." - branchname=update-allowed-ips-$(date +%s) - git checkout -b $branchname - git commit -am "Update list of allowed IPs" - git push - gh pr create \ - --title "Update list of allowed IPs" \ - --body "This PR updates the list of allowed IPs in Moda. It is automatically generated. - - _Generated by the [Update Moda allowed IPs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run._" \ - --label "workflow-generated" \ - --head=$branchname - echo "Pull request created" - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/moda-ci.yaml b/.github/workflows/moda-ci.yaml deleted file mode 100644 index 43240c6dcdb3..000000000000 --- a/.github/workflows/moda-ci.yaml +++ /dev/null @@ -1,103 +0,0 @@ -name: docs-internal Moda CI - -# More info on CI actions setup can be found here: -# https://github.com/github/ops/blob/master/docs/playbooks/build-systems/moving-moda-apps-from-bp-to-actions.md - -on: - workflow_dispatch: - push: - branches-ignore: - - 'gh-readonly-queue/**' - merge_group: - types: [checks_requested] - -jobs: - ########################## - # Generate Vault keys - ########################## - set-vault-keys: - runs-on: ubuntu-latest - outputs: - modified_vault_keys: ${{ steps.modify_vault_keys.outputs.modified }} - steps: - - name: Set vault-keys output - id: modify_vault_keys - run: | - if [ -z "${{ vars.VAULT_KEYS }}" ]; then - # We want to add the DOCS_BOT_PAT_BASE to the list of keys - # so that builds fetch the secret from the docs-internal vault - # where --environment is "ci" - echo "modified=DOCS_BOT_PAT_BASE" >> $GITHUB_OUTPUT - else - echo "modified=${{ vars.VAULT_KEYS }},DOCS_BOT_PAT_BASE" >> $GITHUB_OUTPUT - fi - - ############# - # Moda jobs - ############# - moda-config-bundle: - if: ${{ github.repository == 'github/docs-internal' }} - name: ${{ matrix.ci_job.job }} - needs: set-vault-keys - strategy: - fail-fast: false - matrix: - ci_job: [{ 'job': 'docs-internal-moda-config-bundle' }] - uses: github/internal-actions/.github/workflows/moda.yml@main - with: - ci-formatted-job-name: ${{ matrix.ci_job.job }} - vault-keys: ${{ needs.set-vault-keys.outputs.modified_vault_keys }} - secrets: - dx-bot-token: ${{ secrets.INTERNAL_ACTIONS_DX_BOT_ACCOUNT_TOKEN }} - datadog-api-key: ${{ secrets.DATADOG_API_KEY }} - - ############# - # Docker Image jobs - ############# - docker-image: - if: ${{ github.repository == 'github/docs-internal' }} - name: ${{ matrix.ci_job.job }} - needs: set-vault-keys - strategy: - fail-fast: false - matrix: - ci_job: [{ 'job': 'docs-internal-docker-image' }] - uses: github/internal-actions/.github/workflows/kube.yml@main - with: - ci-formatted-job-name: ${{ matrix.ci_job.job }} - vault-keys: ${{ needs.set-vault-keys.outputs.modified_vault_keys }} - # Passes 'DOCS_BOT_PAT_BASE' secret from Vault to docker as --secret id=DOCS_BOT_PAT_BASE,src= - attest: true - docker-build-env-secrets: 'DOCS_BOT_PAT_BASE' - secrets: - dx-bot-token: ${{ secrets.INTERNAL_ACTIONS_DX_BOT_ACCOUNT_TOKEN }} - datadog-api-key: ${{ secrets.DATADOG_API_KEY }} - - ############# - # Docker Security jobs - ############# - docker-security: - if: ${{ github.repository == 'github/docs-internal' }} - name: ${{ matrix.ci_job.job }} - needs: set-vault-keys - strategy: - fail-fast: false - matrix: - ci_job: [{ 'job': 'docs-internal-docker-security' }] - uses: github/internal-actions/.github/workflows/docker_security.yml@main - with: - ci-formatted-job-name: ${{ matrix.ci_job.job }} - vault-keys: ${{ needs.set-vault-keys.outputs.modified_vault_keys }} - # Passes 'DOCS_BOT_PAT_BASE' secret from Vault to docker as --secret id=DOCS_BOT_PAT_BASE,src= - docker-build-env-secrets: 'DOCS_BOT_PAT_BASE' - secrets: - dx-bot-token: ${{ secrets.INTERNAL_ACTIONS_DX_BOT_ACCOUNT_TOKEN }} - datadog-api-key: ${{ secrets.DATADOG_API_KEY }} - -permissions: - actions: read - checks: read - contents: read - statuses: read - id-token: write - attestations: write diff --git a/.github/workflows/move-content.yml b/.github/workflows/move-content.yml deleted file mode 100644 index bfd9147230ab..000000000000 --- a/.github/workflows/move-content.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Move content script test - -# **What it does**: Tests the `npm run move-content` script -# **Why we have it**: To be sure it continues to work as expected -# **Who does it impact**: Docs team. - -on: - pull_request: - paths: - - src/content-render/scripts/move-content.ts - - src/content-render/scripts/test-move-content.ts - - 'src/frame/lib/**/*.js' - - .github/workflows/move-content.yml - # In case any of the dependencies affect the script - - 'package*.json' - - src/fixtures/fixtures/content/get-started/ - - src/fixtures/fixtures/content/code-security/ - -permissions: - contents: read - -jobs: - move-content-test: - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Set up a dummy git user - run: | - # These must be set to something before running the move-content - # script because it depends on executing `git mv ...` - # and `git commit ...` - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - - - name: Move hello-world.md to hello-wurld.md - env: - ROOT: src/fixtures/fixtures - run: | - npm run move-content -- \ - src/fixtures/fixtures/content/get-started/start-your-journey/hello-world.md \ - src/fixtures/fixtures/content/get-started/start-your-journey/hello-wurld.md - - npm run test-moved-content -- \ - src/fixtures/fixtures/content/get-started/start-your-journey/hello-world.md \ - src/fixtures/fixtures/content/get-started/start-your-journey/hello-wurld.md - - # TODO: Add tests that inspects the git log - git log | head -n 100 - - - name: Move code-security/getting-started to code-security/got-started - env: - ROOT: src/fixtures/fixtures - run: | - npm run move-content -- \ - src/fixtures/fixtures/content/code-security/getting-started \ - src/fixtures/fixtures/content/code-security/got-started - - npm run test-moved-content -- \ - src/fixtures/fixtures/content/code-security/getting-started \ - src/fixtures/fixtures/content/code-security/got-started - - # TODO: Add tests that inspects the git log - git log | head -n 100 diff --git a/.github/workflows/move-existing-issues-to-the-correct-repo.yml b/.github/workflows/move-existing-issues-to-the-correct-repo.yml deleted file mode 100644 index 12de61fa20c1..000000000000 --- a/.github/workflows/move-existing-issues-to-the-correct-repo.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Move existing issues to correct docs repo - -# **What it does**: Move all existing issues to the correct repo -# **Why we have it**: We don't want engineering or content issues in the docs-internal repo -# **Who does it impact**: GitHub staff. - -on: - workflow_dispatch: - -permissions: - contents: read - -jobs: - transfer_issues: - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' - steps: - - id: move_to_correct_repo - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - env: - TEAM_ENGINEERING_REPO: ${{ secrets.TEAM_ENGINEERING_REPO }} - TEAM_CONTENT_REPO: ${{ secrets.TEAM_CONTENT_REPO }} - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - const owner = 'github' - const originalRepo = 'docs-internal' - let correctRepo = process.env.TEAM_ENGINEERING_REPO - - const correctRepoObject = await github.rest.repos.get({ - owner: owner, - repo: correctRepo - }) - - const allIssues = await github.paginate(github.rest.issues.listForRepo, { - owner: owner, - repo: originalRepo, - per_page: 100, - labels: ['engineering'] - }) - - for (const issue of allIssues) { - // Extra redundancy with this additional check to be safe - if (issue.labels.find(label => label.name === 'engineering')) { - // Transfer the issue to the correct repo - const issueNodeId = issue.node_id - const correctRepositoryNodeId = correctRepoObject.data.node_id - console.log(`Issue GraphQL Node ID: ${issueNodeId}`) - console.log(`Repository GraphQL Node ID: ${correctRepositoryNodeId}`) - - const mutation = `mutation ($id: ID!, $repositoryId: ID!) { - transferIssue(input: { - issueId: $id, - repositoryId: $repositoryId - }) { - issue { - url, - number - } - } - }` - - const variables = { - id: issueNodeId, - repositoryId: correctRepositoryNodeId - } - - const graph = await github.graphql(mutation, variables) - console.log('GraphQL mutation result:\n' + JSON.stringify(graph)) - - // Add the same labels to the new issue - const newIssueNumber = graph.transferIssue.issue.number - await github.rest.issues.addLabels({ - owner: owner, - repo: correctRepo, - issue_number: newIssueNumber, - labels: issue.labels.map(label => label.name), - }) - } - } diff --git a/.github/workflows/move-ready-to-merge-pr.yaml b/.github/workflows/move-ready-to-merge-pr.yaml deleted file mode 100644 index 97d03d17b14b..000000000000 --- a/.github/workflows/move-ready-to-merge-pr.yaml +++ /dev/null @@ -1,51 +0,0 @@ -name: Move and unlabel ready to merge PRs - -# **What it does**: When a PR in the open source repo is labeled "ready to merge," the "waiting for review" label is removed and the PR is moved to the "Triage" column. -# **Why we have it**: To help with managing our project boards. -# **Who does it impact**: Open source contributors, open-source maintainers. - -on: - # Needed in lieu of `pull_request` so that the a PR from a fork can trigger the project board and label automation. - pull_request_target: - types: - - labeled - -permissions: - contents: read - pull-requests: write - -jobs: - unmark_for_review: - if: >- - ${{ - github.repository == 'github/docs' && - github.event.label.name == 'ready to merge' - }} - runs-on: ubuntu-latest - steps: - - name: Add PR to the open source board - uses: actions/add-to-project@5afcf98fcd03f1c2f92c3c83f58ae24323cc57fd # v2.0.0 - with: - project-url: https://github.com/orgs/github/projects/2936 - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Move PR to Triage on the open source board - uses: github/update-project-action@af4f6083118f5080c89828b421ef598d1906fb60 # v4 - with: - github_token: ${{ secrets.DOCS_BOT_PAT_BASE }} - organization: github - project_number: 2936 - content_id: ${{ github.event.pull_request.node_id }} - field: Status - value: Triage - - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: remove label - uses: ./.github/actions/labeler - with: - ignoreifAssigned: 'false' - removeLabels: 'waiting for review' diff --git a/.github/workflows/move-reopened-issues-to-triage.yaml b/.github/workflows/move-reopened-issues-to-triage.yaml deleted file mode 100644 index bc2bd0ae34fa..000000000000 --- a/.github/workflows/move-reopened-issues-to-triage.yaml +++ /dev/null @@ -1,59 +0,0 @@ -name: Move Reopened Issues to Triage - -# **What it does**: Moves issues that are reopened from the Done column to the Triage column. -# **Why we have it**: To prevent having to do this manually. -# **Who does it impact**: Open-source. - -on: - issues: - types: - - reopened - -permissions: - contents: read - repository-projects: write - -jobs: - move-reopened-issue-to-triage: - if: github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - script: | - const issueNumber = context.issue.number; - const doneColumnId = 11167427; - const triageColumnId = 11007039; - - try { - const cards = await github.rest.projects.listCards({ - column_id: doneColumnId - }); - - for (const card of cards) { - if (card.content_url.endsWith(`/${issueNumber}`)) { - await github.rest.projects.moveCard({ - card_id: card.id, - position: 'position', - column_id: triageColumnId - }); - } - } - } catch(e) { - console.log(e); - } - - - name: Check out repo - if: ${{ failure() }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/needs-sme-stale-check.yaml b/.github/workflows/needs-sme-stale-check.yaml deleted file mode 100644 index 5de7e7046ac8..000000000000 --- a/.github/workflows/needs-sme-stale-check.yaml +++ /dev/null @@ -1,53 +0,0 @@ -name: Stale check for issues or PRs with "needs SME" label - -# **What it does**: Runs only in the OS repository to provide stale checks on issues/PRs that need SME(subject matter expert) review. -# **Why we have it**: In the open repo, we want we want to check on issues/PRs that are waiting on SME review. -# **Who does it impact**: Anyone working in the open repo. - -on: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: read - issues: write - pull-requests: write - -jobs: - stale_needs-sme: - if: ${{ github.repository == 'github/docs' }} - runs-on: ubuntu-latest - - steps: - - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0 - id: stale - with: - only-labels: needs SME - days-before-stale: 28 # adds stale label if no activity for 7 days - temporarily changed to 28 days as we work through the backlog - stale-issue-message: 'This is a gentle reminder for the Technical Content team that this issue is waiting for technical review by a subject matter expert (SME).' - stale-issue-label: 'Waiting on SME review' - days-before-issue-close: -1 # never close - stale-pr-message: 'This is a gentle reminder for the Technical Content team that this PR is waiting for technical review by a subject matter expert.' - stale-pr-label: 'Waiting on SME review' - days-before-pr-close: -1 # never close - - - name: Print outputs - env: - STALED: ${{ steps.stale.outputs.staled-issues-prs || '0' }} - CLOSED: ${{ steps.stale.outputs.closed-issues-prs || '0' }} - run: echo "Staled issues/PRs:${STALED}, Closed issues/PRs:${CLOSED}" - - - name: Check out repo - if: ${{ failure() }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/needs-sme-workflow.yml b/.github/workflows/needs-sme-workflow.yml deleted file mode 100644 index f8e6fb7d9ba3..000000000000 --- a/.github/workflows/needs-sme-workflow.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Comment on adding "needs SME" label - -# **What it does**: Comment on issues and pull requests when a "needs SME" label is added. SME = subject matter expert. -# **Why we have it**: We want to manage our queue of issues and pull requests that need sme review. -# **Who does it impact**: Everyone that works on docs or docs-internal. - -on: - issues: - types: [labeled] - # Needed in lieu of `pull_request` so that PRs from a fork can be labeled. - pull_request_target: - types: [labeled] - -permissions: - contents: read - -jobs: - add-issue-comment: - if: ${{ github.repository == 'github/docs' && (github.event.label.name == 'needs SME' && github.event_name == 'issues') }} - runs-on: ubuntu-latest - permissions: - issues: write - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 - with: - issue-number: ${{ github.event.issue.number }} - body: | - Thanks for opening an issue! We've triaged this issue for technical review by a subject matter expert :eyes: - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'pull_request_target' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - - add-pr-comment: - if: ${{ github.repository == 'github/docs' && (github.event.label.name == 'needs SME' && github.event_name == 'pull_request_target') }} - runs-on: ubuntu-latest - permissions: - pull-requests: write - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 - with: - issue-number: ${{ github.event.pull_request.number }} - body: | - Thanks for opening a pull request! We've triaged this issue for technical review by a subject matter expert :eyes: - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'pull_request_target' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} diff --git a/.github/workflows/no-response.yaml b/.github/workflows/no-response.yaml deleted file mode 100644 index 2c43c14787e4..000000000000 --- a/.github/workflows/no-response.yaml +++ /dev/null @@ -1,84 +0,0 @@ -name: Stale check for no response from author - -# **What it does**: Runs only in the OS repository to close issues that don't have enough information to be -# actionable. -# **Why we have it**: To remove the need for maintainers to remember to check -# back on issues periodically to see if contributors have -# responded. -# **Who does it impact**: Everyone that works in the docs repository. - -on: - issue_comment: - types: [created] - - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: read - issues: write - pull-requests: write - -jobs: - noResponse: - runs-on: ubuntu-latest - # Only run in the OS repository, and skip bot-authored events. On failure the - # create-workflow-failure-issue step below posts a comment (as a bot); that - # comment is itself an issue_comment event that would re-trigger this workflow. - # During a transient failure that loops, so guard against bot actors to keep - # one failure from producing a flood of runs and Slack alerts. - if: >- - github.repository == 'github/docs' && - github.actor != 'docs-bot' && - github.actor != 'github-actions' && - !endsWith(github.actor, '[bot]') - steps: - - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0 - id: stale - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - only-labels: 'more-information-needed' - - # Define behavior for issues - days-before-issue-stale: 21 - days-before-issue-close: 1 # close after 1 day if the issue is not updated - stale-issue-label: 'Waiting on contributor' - close-issue-message: > - This issue has been automatically closed because there has been no response - to our request for more information from the original author. With only the - information that is currently in the issue, we don't have enough information - to take action. Please reach out if you have or find the answers we need so - that we can investigate further. See [this blog post on bug reports and the - importance of repro steps](https://www.lee-dohm.com/2015/01/04/writing-good-bug-reports/) - for more information about the kind of information that may be helpful. - - # Define behavior for pull requests - days-before-pr-stale: 21 - days-before-pr-close: 1 # close after a day if no activity is detected - stale-pr-label: 'Waiting on contributor' - close-pr-message: > - This PR has been automatically closed because there has been no response to - to our request for more information from the original author. Please reach out - if you have the information we requested, or open an [issue](https://github.com/github/docs/issues/new/choose) - to describe your changes. Then we can reopen this PR and begin the review process. - - - name: Print outputs - env: - STALED: ${{ steps.stale.outputs.staled-issues-prs || '0' }} - CLOSED: ${{ steps.stale.outputs.closed-issues-prs || '0' }} - run: echo "Staled issues/PRs:${STALED}, Closed issues/PRs:${CLOSED}" - - - name: Check out repo - if: ${{ failure() }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/notify-about-deployment.yml b/.github/workflows/notify-about-deployment.yml deleted file mode 100644 index 51edd5ae4f55..000000000000 --- a/.github/workflows/notify-about-deployment.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Notify about production deployment - -# **What it does**: Posts a comment on every PR in the deploy that got into -# production. The merge queue can batch several PRs into one -# deploy, so it walks back from the deployed commit to find -# all of them. -# **Why we have it**: So that the PR author can be informed when their merged PR is in production. -# **Who does it impact**: Writers - -on: - workflow_dispatch: - workflow_run: - workflows: ['Purge Fastly'] - types: - - completed - -permissions: - contents: read - pull-requests: write - -jobs: - find-pr-and-post-comment: - if: >- - ${{ - github.repository == 'github/docs-internal' && - (github.event_name != 'workflow_run' || - github.event.workflow_run.conclusion == 'success') - }} - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - # The "Purge Fastly" action takes about 6 minutes to purge all - # languages. First does the language agnostic URLs, then English, - # then all the other languages. - # So it takes about ~30 seconds until it has sent the purge for - # all English docs. - - name: Sleep a little to give Fastly Purge a chance - run: sleep 30 - - - name: Find PRs and post production comments - timeout-minutes: 5 - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: npm run find-past-built-pr - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/notify-release-pms.yml b/.github/workflows/notify-release-pms.yml deleted file mode 100644 index 4dc122f42e47..000000000000 --- a/.github/workflows/notify-release-pms.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Notify release PMs - -# **What it does**: Posts review notification comments on release issues -# in github/releases for generated GHES release notes. -# **Why we have it**: So comments are always posted by docs-bot, without -# needing to distribute a PAT to individual team members. -# **Who does it impact**: Docs content (GHES release DRIs). - -on: - workflow_dispatch: - inputs: - release: - description: 'GHES release version (e.g., 3.21)' - type: string - required: true - pr: - description: 'docs-internal PR number containing the release notes' - type: string - required: true - release_type: - description: 'Release type (auto-detects from files if not specified)' - type: choice - options: - - auto - - rc - - ga - default: 'auto' - review_date: - description: 'Override review deadline (YYYY-MM-DD, optional)' - type: string - required: false - dry_run: - description: 'Preview comments in the workflow log without posting them' - type: boolean - default: false - -permissions: - contents: read - pull-requests: read - -jobs: - notify: - name: Notify release PMs - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Get PR head branch - id: pr-ref - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ inputs.pr }} - run: | - ref=$(gh pr view "$PR_NUMBER" --repo github/docs-internal --json headRefName --jq '.headRefName') - echo "ref=$ref" >> "$GITHUB_OUTPUT" - - - name: Checkout repository code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - ref: ${{ steps.pr-ref.outputs.ref }} - - - uses: ./.github/actions/node-npm-setup - - - name: Post notification comments - env: - DOCS_BOT_PAT_BASE: ${{ secrets.DOCS_BOT_PAT_BASE }} - INPUT_RELEASE: ${{ inputs.release }} - INPUT_PR: ${{ inputs.pr }} - INPUT_RELEASE_TYPE: ${{ inputs.release_type }} - INPUT_REVIEW_DATE: ${{ inputs.review_date }} - INPUT_DRY_RUN: ${{ inputs.dry_run }} - run: | - args=(--release "$INPUT_RELEASE" --pr "$INPUT_PR") - - if [[ "$INPUT_RELEASE_TYPE" == "rc" ]]; then - args+=(--rc) - elif [[ "$INPUT_RELEASE_TYPE" == "ga" ]]; then - args+=(--ga) - fi - - if [[ -n "$INPUT_REVIEW_DATE" ]]; then - args+=(--review-date "$INPUT_REVIEW_DATE") - fi - - if [[ "$INPUT_DRY_RUN" == "true" ]]; then - args+=(--dry-run) - fi - - npm run notify-release-pms -- "${args[@]}" diff --git a/.github/workflows/notify-when-maintainers-cannot-edit.yaml b/.github/workflows/notify-when-maintainers-cannot-edit.yaml deleted file mode 100644 index 69a2298edb6b..000000000000 --- a/.github/workflows/notify-when-maintainers-cannot-edit.yaml +++ /dev/null @@ -1,66 +0,0 @@ -name: Notify When Maintainers Cannot Edit - -# **What it does**: Notifies the author of a PR when their PR does not allow maintainers to edit it. -# **Why we have it**: To prevent having to do this manually. -# **Who does it impact**: Open-source. - -on: - # Needed in lieu of `pull_request` so that PRs from a fork can be notified. - pull_request_target: - types: - - opened - -permissions: - contents: read - pull-requests: write - -jobs: - notify-when-maintainers-cannot-edit: - if: github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - script: | - const query = ` - query($number: Int!) { - repository(owner: "github", name: "docs") { - pullRequest(number: $number) { - headRepositoryOwner { - login - } - maintainerCanModify - } - } - } - `; - - const pullNumber = context.issue.number; - const variables = { number: pullNumber }; - - try { - console.log(`Check github/docs#${pullNumber} for maintainer edit access ...`); - const result = await github.graphql(query, variables); - - console.log(JSON.stringify(result, null, 2)); - - const pullRequest = result.repository.pullRequest; - - if (pullRequest.headRepositoryOwner.login === 'github') { - console.log('PR owned by github'); - return; - } - - if (!pullRequest.maintainerCanModify) { - console.log('PR not owned by github and does not have maintainer edits enabled'); - - await github.rest.issues.createComment({ - issue_number: pullNumber, - owner: 'github', - repo: 'docs', - body: "Thanks for submitting a PR to the GitHub Docs project!\n\nIn order to review and merge PRs most efficiently, we require that all PRs grant maintainer edit access before we review them. For information on how to do this, [see the documentation](https://docs.github.com/en/github/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)." - }); - } - } catch(e) { - console.log(e); - } diff --git a/.github/workflows/orphaned-features-check.yml b/.github/workflows/orphaned-features-check.yml deleted file mode 100644 index e9a00ae73602..000000000000 --- a/.github/workflows/orphaned-features-check.yml +++ /dev/null @@ -1,114 +0,0 @@ -name: 'Orphaned features check' - -# **What it does**: Finds any data/features that are no longer used in the repo. -# **Why we have it**: To avoid orphans into the repo. -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - pull_request: - paths: - - .github/workflows/orphaned-features-check.yml - # In case any of the dependencies affect the script - - 'package*.json' - - 'src/data-directory/scripts/find-orphaned-features/**' - - .github/actions/clone-translations/action.yml - - .github/actions/node-npm-setup/action.yml - -permissions: - contents: read - -jobs: - orphaned-features-check: - if: ${{ github.repository == 'github/docs-internal' }} - runs-on: ubuntu-latest - steps: - - name: Checkout English repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Using a PAT is necessary so that the new commit will trigger the - # CI in the PR. (Events from GITHUB_TOKEN don't trigger new workflows.) - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - # It's important because translations are often a bit behind. - # So if a translation is a bit behind, it might still be referencing - # a feature even though none of the English content does. - - name: Clone all translations - uses: ./.github/actions/clone-translations - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/node-npm-setup - - - name: Check for orphaned features - env: - # Needed for gh - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - DRY_RUN: ${{ github.event_name == 'pull_request'}} - run: | - set -e - - npm run find-orphaned-features -- find --verbose --output /tmp/orphaned-features.json - - if [ -f /tmp/orphaned-features.json ]; then - echo "Orphaned features found:" - cat /tmp/orphaned-features.json - else - echo "No orphaned features found" - exit 0 - fi - - npm run find-orphaned-features -- delete --verbose /tmp/orphaned-features.json - - git status - - # When run on a pull_request, we're just testing the tooling. - # Exit before it actually pushes the possible changes. - if [ "$DRY_RUN" = "true" ]; then - echo "Dry-run mode when run in a pull request" - exit 0 - fi - - # Replicated from the translation pipeline PR-maker Action - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - - date=$(date '+%Y-%m-%d-%H-%M') - branchname=orphaned-features-$date-$GITHUB_RUN_ID - - git checkout -b $branchname - git commit -a -m "Delete orphaned features $date" - git push origin $branchname - - body=$(cat <<-EOM - Found with the 'npm run find-orphaned-features' script. - The orphaned features workflow file .github/workflows/orphaned-features-check.yml - runs every Monday at 16:20 UTC / 8:20 PST. - The first responder should just spot-check some of the orphans - to make sure they aren't referenced anywhere - and then approve and merge the pull request. - For more information, see [Doc: Orphaned Features](https://github.com/github/technical-content/blob/main/engineering/orphaned-features.md). - - Generated by the [orphaned features workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID). - EOM - ) - - gh pr create \ - --title "Delete orphaned features ($date)" \ - --body "$body" \ - --repo github/docs-internal \ - --label docs-content-fr,workflow-generated - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name == 'schedule' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name == 'schedule' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/orphaned-files-check.yml b/.github/workflows/orphaned-files-check.yml deleted file mode 100644 index 9ba23f362176..000000000000 --- a/.github/workflows/orphaned-files-check.yml +++ /dev/null @@ -1,127 +0,0 @@ -name: 'Orphaned files check' - -# **What it does**: Checks that there are no files in ./assets/, ./data/reusables, or ./data/tables that aren't mentioned in any source file. -# **Why we have it**: To avoid orphans into the repo. -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - pull_request: - paths: - - .github/workflows/orphaned-assets-check.yml - - .github/workflows/orphaned-files-check.yml - # In case any of the dependencies affect the script - - 'package*.json' - - src/assets/scripts/find-orphaned-assets.ts - - src/content-render/scripts/reusables-cli/find/unused.ts - - src/data-directory/scripts/find-orphaned-tables.ts - - src/workflows/walk-files.ts - - src/languages/lib/languages.ts - - .github/actions/clone-translations/action.yml - - .github/actions/node-npm-setup/action.yml - -permissions: - contents: read - -jobs: - orphaned-files-check: - if: ${{ github.repository == 'github/docs-internal' }} - runs-on: ubuntu-latest - steps: - - name: Checkout English repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Using a PAT is necessary so that the new commit will trigger the - # CI in the PR. (Events from GITHUB_TOKEN don't trigger new workflows.) - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - # It's important because translations are often a bit behind. - # So if a translation is a bit behind, it might still be referencing - # an asset even though none of the English content does. - - name: Clone all translations - uses: ./.github/actions/clone-translations - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/node-npm-setup - - - name: Check for orphaned assets and reusables - env: - # Needed for gh - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - DRY_RUN: ${{ github.event_name == 'pull_request'}} - run: | - set -e - - # The `-s` is to make npm run silent and not print verbose - # information about the npm script alias. - assetFilesToRemove=$(npm run -s find-orphaned-assets) - reusableFilesToRemove=$(npm run -s reusables -- find unused | grep '^data/reusables' || true) - tableFilesToRemove=$(npm run -s find-orphaned-tables) - [ -z "$assetFilesToRemove" ] && [ -z "$reusableFilesToRemove" ] && [ -z "$tableFilesToRemove" ] && exit 0 - - if [ -n "$assetFilesToRemove" ]; then - echo $assetFilesToRemove | xargs git rm - fi - if [ -n "$reusableFilesToRemove" ]; then - echo $reusableFilesToRemove | xargs git rm - fi - if [ -n "$tableFilesToRemove" ]; then - echo $tableFilesToRemove | xargs git rm - fi - - git status - - # If nothing to commit, exit now. It's fine. No orphans. - git status -- ':!translations*' | grep 'nothing to commit' && exit 0 - - # When run on a pull_request, we're just testing the tooling. - # Exit before it actually pushes the possible changes. - if [ "$DRY_RUN" = "true" ]; then - echo "Dry-run mode when run in a pull request" - exit 0 - fi - - # Replicated from the translation pipeline PR-maker Action - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - - date=$(date '+%Y-%m-%d-%H-%M') - branchname=orphaned-files-$date-$GITHUB_RUN_ID - - git checkout -b $branchname - git commit -m "Delete orphaned files $date" - git push origin $branchname - - body=$(cat <<-EOM - Found with the `npm run find-orphaned-assets`, `npm run -s reusables -- find unused`, and `npm run find-orphaned-tables` scripts. - - The orphaned files workflow file .github/workflows/orphaned-files-check.yml runs every Monday at 16:20 UTC / 8:20 PST. - - If you are the first responder, please spot check some of the unused assets, reusables, and tables to make sure they aren't referenced anywhere. Then, approve and merge the pull request. - - For more information, see [Doc: Orphaned Assets](https://github.com/github/technical-content/blob/main/engineering/orphaned-assets.md) and [Doc: Reusables CLI](https://github.com/github/docs-internal/tree/main/src/content-render/scripts/reusables-cli). - - Generated by the [orphaned files workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID). - EOM - ) - - gh pr create \ - --title "Delete orphaned files ($date)" \ - --body "$body" \ - --repo github/docs-internal \ - --label docs-content-fr,workflow-generated - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name == 'schedule' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name == 'schedule' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/os-ready-for-review.yml b/.github/workflows/os-ready-for-review.yml deleted file mode 100644 index 3c3cd37aff82..000000000000 --- a/.github/workflows/os-ready-for-review.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: OS Ready for review - -# **What it does**: Adds pull requests and issues in the docs repository to the docs-content review board when the "waiting for review" label is added -# **Why we have it**: So that contributors in the OS repo can easily get reviews from the docs-content team, and so that writers can see when a PR is ready for review -# **Who does it impact**: Writers working in the docs repository -on: - # Needed in lieu of `pull_request` so that PRs from a fork can be triaged to the proper project board. - pull_request_target: - types: [labeled] - issues: - types: [labeled] - -permissions: - contents: read - -jobs: - request_doc_review: - name: Request a review from the docs-content team - if: github.event.label.name == 'waiting for review' && github.repository == 'github/docs' - runs-on: ubuntu-latest - steps: - - name: Check out repo content - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Check if this run was triggered by a member of the docs team - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - id: triggered-by-member - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - result-encoding: string - script: | - const triggerer_login = context.payload.sender.login - // Team is addressed by numeric ID (org github = 9919, team docs = 325922) - // because IDs survive team renames and slugs do not. - const teamMembers = await github.request( - `/organizations/9919/team/325922/members?per_page=100` - ) - const logins = teamMembers.data.map(member => member.login) - if (logins.includes(triggerer_login)) { - console.log(`This workflow was triggered by ${triggerer_login} (on the docs team).`) - return 'true' - } - console.log(`This workflow was triggered by ${triggerer_login} (not on the docs team), so no action will be taken.`) - return 'false' - - - name: Exit if not triggered by a docs team member - if: steps.triggered-by-member.outputs.result == 'false' - run: | - echo Aborting. This workflow must be triggered by a member of the docs team. - exit 1 - - - name: Set up Node and dependencies - uses: ./.github/actions/node-npm-setup - - - name: Run script - run: | - npm run ready-for-docs-review - env: - TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - PROJECT_NUMBER: 2936 - ORGANIZATION: 'github' - ITEM_NODE_ID: ${{ github.event.pull_request.node_id || github.event.issue.node_id }} - AUTHOR_LOGIN: ${{ github.event.pull_request.user.login || github.event.issue.user.login }} - REPO: ${{ github.repository }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'pull_request_target' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} diff --git a/.github/workflows/package-lock-lint.yml b/.github/workflows/package-lock-lint.yml deleted file mode 100644 index 502e5d6ac05f..000000000000 --- a/.github/workflows/package-lock-lint.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Package lock lint - -# **What it does**: Makes sure package.json and package-lock.json is in sync -# **Why we have it**: Accidental manual edits of the dependencies directly in package.json -# **Who does it impact**: Docs engineering/writers/contributors. - -on: - pull_request: - paths: - - package.json - - package-lock.json - - .github/workflows/package-lock-lint.yml - -permissions: - contents: read - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - lint: - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Setup Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version-file: 'package.json' - cache: npm - - - name: Run check - run: | - npm --version - - # Save the current top-level dependencies from package-lock.json - node -e "console.log(JSON.stringify(require('./package-lock.json').packages['']))" > /tmp/before.json - - # From https://docs.npmjs.com/cli/v7/commands/npm-install - # - # The --package-lock-only argument will only update the - # package-lock.json, instead of checking node_modules and - # downloading dependencies. - # - npm install --package-lock-only --ignore-scripts --include=optional - - # Extract the top-level dependencies after regeneration - node -e "console.log(JSON.stringify(require('./package-lock.json').packages['']))" > /tmp/after.json - - # Compare only the top-level package dependencies - # This ignores platform-specific differences in nested dependency resolution - # (like "peer" flags) that don't affect actual installed versions - if ! diff /tmp/before.json /tmp/after.json; then - echo "ERROR: Top-level dependencies in package-lock.json are out of sync with package.json" - echo "Please run 'npm install' locally and commit the updated package-lock.json" - exit 1 - fi - - echo "✓ Top-level dependencies are in sync" diff --git a/.github/workflows/purge-fastly.yml b/.github/workflows/purge-fastly.yml deleted file mode 100644 index 4949dd1775a0..000000000000 --- a/.github/workflows/purge-fastly.yml +++ /dev/null @@ -1,123 +0,0 @@ -name: Purge Fastly - -# **What it does**: -# On production deploy, hard-purge the changed English content pages by key. -# On demand, soft or hard purge language keys, a single key, or entire cache. -# **Why we have it**: So a just-deployed change is visible right away, and so -# docs engineering can clear a bad cache state without the Fastly UI. -# **Who does it impact**: Writers and engineers. A full purge impacts all readers -# and spikes origin traffic while the cache refills, so it's gated below. - -on: - deployment_status: - workflow_dispatch: - inputs: - languages: - description: "Languages: Comma separated languages, e.g. 'en,es,ja,pt,zh,ru,fr,ko,de'. Blank = all languages." - required: false - default: 'en' - hard: - description: 'Hard purge: Evict immediately instead of the default soft purge. Use when a soft purge fails to clear stale content.' - type: boolean - required: false - default: false - everything: - description: 'Everything: Hard-purge the entire Fastly cache... every key, all readers. Ignores the languages/hard inputs. To confirm, type exactly: "purge everything". Otherwise leave blank.' - required: false - default: '' - -permissions: - contents: read - deployments: read - -# Serialize full-cache purges so two can't overlap and leave the cache in an -# unknown state. Every other run (per-deploy, per-language) gets a unique group -# so those never block each other. -concurrency: - group: ${{ (inputs.everything == 'purge everything' && 'purge-fastly-all') || format('purge-fastly-{0}', github.run_id) }} - cancel-in-progress: false - -env: - FASTLY_TOKEN: ${{ secrets.FASTLY_TOKEN }} - FASTLY_SERVICE_ID: ${{ secrets.FASTLY_SERVICE_ID }} - -jobs: - send-purges: - # Run when workflow_dispatch is the event - # or when deployment_status is the event and it's a successful production deploy. - # NOTE: This workflow triggers on all deployment_status events, - # including staging, but only runs for production. - # Non-production deploys will show as "skipped" - this is expected behavior. - if: >- - ${{ - github.repository == 'github/docs-internal' && - (github.event_name != 'deployment_status' || - github.event.deployment_status.state == 'success' && github.event.deployment_status.environment == 'production') - }} - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Validate confirmation input - # A full-cache purge only triggers on the exact string "purge everything". - # Any other non-empty value (e.g. a typo) would otherwise be silently - # ignored and fall through to a normal soft purge that finishes green, so - # an operator could think they evicted the whole cache when they didn't. - # Fail loudly instead. - env: - EVERYTHING_INPUT: ${{ inputs.everything }} - run: | - if [ -n "$EVERYTHING_INPUT" ] && [ "$EVERYTHING_INPUT" != "purge everything" ]; then - echo "::error::To purge the entire cache, the 'everything' input must be exactly 'purge everything'. Got: '$EVERYTHING_INPUT'. Leave it blank for a normal purge." - exit 1 - fi - - - name: Wait for production to serve this build - if: ${{ github.event_name == 'deployment_status' }} - run: npm run wait-for-build - - - name: Purge Fastly (manual) - # Raw inputs are passed through the environment and quoted, never spliced - # into the command string, so a value like `en' --everything` can't break - # out of its argument and inject another flag. - if: ${{ github.event_name == 'workflow_dispatch' }} - env: - LANGUAGES_INPUT: ${{ inputs.languages }} - HARD_INPUT: ${{ inputs.hard }} - EVERYTHING_INPUT: ${{ inputs.everything }} - run: | - args=() - if [ -n "$LANGUAGES_INPUT" ]; then - args+=(--languages "$LANGUAGES_INPUT") - fi - if [ "$HARD_INPUT" = "true" ]; then - args+=(--hard) - fi - if [ "$EVERYTHING_INPUT" = "purge everything" ]; then - args+=(--everything) - fi - npm run purge-fastly -- "${args[@]}" - - - name: Hard-purge changed English content pages - # On prod deploys, evict the surrogate keys of the English content pages - # whose content/ files changed in this deploy. - if: ${{ github.event_name == 'deployment_status' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - HEAD_SHA: ${{ github.event.deployment.sha }} - run: npm run purge-fastly-changed-content - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/readability.yml b/.github/workflows/readability.yml deleted file mode 100644 index 13625f99667d..000000000000 --- a/.github/workflows/readability.yml +++ /dev/null @@ -1,106 +0,0 @@ -name: Readability report - -# **What it does**: Analyzes readability of rendered content for changed Markdown files in pull requests -# **Why we have it**: We want to track and improve the readability of our documentation over time -# **Who does it impact**: Contributors and content writers - -on: - # pull_request: - # paths: - # - 'content/**/*.md' - # - 'data/reusables/**/*.md' - # The pull_request trigger is currently disabled for testing purposes. - # Re-enable this trigger when ready to run readability analysis automatically on PRs. - workflow_dispatch: - inputs: - pull_request_number: - description: 'Pull request number to analyze (for testing)' - required: true - type: number - -permissions: - contents: read - pull-requests: write - -jobs: - readability-analysis: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Fetch 2 commits so tj-actions/changed-files can diff without extra API calls - fetch-depth: 2 - - name: Checkout PR for manual dispatch - if: ${{ github.event_name == 'workflow_dispatch' }} - run: | - gh pr checkout ${{ inputs.pull_request_number }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/get-docs-early-access - if: ${{ github.repository == 'github/docs-internal' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Get changed content files - id: changed_files - uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - with: - files: 'content/**/*.md' - - - name: Disable Next.js telemetry - run: npx next telemetry disable - - - name: Start server in the background - if: steps.changed_files.outputs.any_modified == 'true' - run: npm start > /tmp/stdout.log 2> /tmp/stderr.log & - - - name: Run readability analysis - if: steps.changed_files.outputs.any_modified == 'true' - env: - CHANGED_FILES: ${{ steps.changed_files.outputs.all_modified_files }} - run: npm run readability-report - - - name: Find existing readability comment - if: steps.changed_files.outputs.any_modified == 'true' - uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad - id: findComment - with: - issue-number: ${{ github.event_name == 'workflow_dispatch' && inputs.pull_request_number || github.event.number }} - comment-author: 'github-actions[bot]' - body-includes: '' - - - name: Read readability report - if: steps.changed_files.outputs.any_modified == 'true' - id: read_report - run: | - if [ -f "readability-report.md" ]; then - { - echo 'report<> "$GITHUB_OUTPUT" - fi - - - name: Create or update readability comment - if: steps.changed_files.outputs.any_modified == 'true' && steps.read_report.outputs.report - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 - with: - comment-id: ${{ steps.findComment.outputs.comment-id }} - issue-number: ${{ github.event_name == 'workflow_dispatch' && inputs.pull_request_number || github.event.number }} - body: | - - ${{ steps.read_report.outputs.report }} - edit-mode: replace - - - if: ${{ failure() }} - name: Debug server outputs on errors - run: | - echo "____STDOUT____" - cat /tmp/stdout.log || echo "No stdout log found" - echo "____STDERR____" - cat /tmp/stderr.log || echo "No stderr log found" diff --git a/.github/workflows/ready-for-doc-review.yml b/.github/workflows/ready-for-doc-review.yml deleted file mode 100644 index ad3cdf537114..000000000000 --- a/.github/workflows/ready-for-doc-review.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Ready for docs-content review - -# **What it does**: Adds pull requests in the docs-internal repository to the docs-content review board when the "ready-for-doc-review" label is added or when a review by docs-content or docs-reviewers is requested. This workflow is also called as a reusable workflow from other repos including docs-content, docs-strategy, docs-early-access, and github. -# **Why we have it**: So that other GitHub teams can easily request reviews from the docs-content team, and so that writers can see when a PR is ready for review -# **Who does it impact**: Writers who need to review docs-related PRs - -on: - pull_request: - types: [labeled, review_requested] - workflow_call: - -permissions: - contents: read - -jobs: - request_doc_review: - name: Request a review from the docs-content team - if: >- - github.repository_owner == 'github' && github.repository != 'github/docs' && - (github.event.label.name == 'ready-for-doc-review' || github.event.requested_team.name == 'docs-content' || github.event.requested_team.name == 'docs-reviewers') - runs-on: ubuntu-latest - steps: - - name: Check out repo content - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: github/docs-internal - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Setup Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version-file: 'package.json' - cache: npm - - - name: Install dependencies - run: npm ci - - - name: Set AUTHOR_LOGIN - run: | - if [[ "${IS_DOCS_BOT_ASSIGNEE}" == "true" ]]; then - echo "AUTHOR_LOGIN=${ASSIGNEE_LOGIN}" >> $GITHUB_ENV - else - echo "AUTHOR_LOGIN=${USER_LOGIN}" >> $GITHUB_ENV - fi - env: - IS_DOCS_BOT_ASSIGNEE: ${{ github.event.pull_request.assignee.login && github.event.pull_request.user.login == 'docs-bot' }} - ASSIGNEE_LOGIN: ${{ github.event.pull_request.assignee.login }} - USER_LOGIN: ${{ github.event.pull_request.user.login }} - - - name: Run script - run: | - npm run ready-for-docs-review - env: - TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - PROJECT_NUMBER: 2936 - ORGANIZATION: 'github' - ITEM_NODE_ID: ${{ github.event.pull_request.node_id }} - REPO: ${{ github.event.pull_request.base.repo.full_name }} diff --git a/.github/workflows/remove-fr-label-remove-from-fr-v2.yml b/.github/workflows/remove-fr-label-remove-from-fr-v2.yml deleted file mode 100644 index 76a0b9bed897..000000000000 --- a/.github/workflows/remove-fr-label-remove-from-fr-v2.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Remove PRs from FR project v2 when FR label is removed - -# **What it does**: When the `docs-content-fr` label is removed from a pull request, this workflow removes the PR from the FR project v2 project. -# **Why we have it**: Reduce busy work for the first responder. -# **Who does it impact**: docs-content first responder. - -on: - pull_request: - types: [unlabeled] - workflow_dispatch: - inputs: - PR_NUMBER: - description: 'PR Number' - type: string - required: true - -permissions: - pull-requests: write - contents: read - -jobs: - label-removed: - name: Remove from FR v2 project - runs-on: ubuntu-latest - if: | - (github.event.label.name == 'docs-content-fr') - && (github.repository == 'github/docs-internal') - steps: - - name: Remove issue from FR v2 project - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - PR_NUMBER: ${{ github.event.pull_request.number || inputs.PR_NUMBER }} - PROJECT_NUMBER: 11672 - run: | - echo "Finding item in project..." - - ITEM_ID=$(gh project item-list $PROJECT_NUMBER --owner github --limit 100 --format json | jq ".items[] | select(.content.number == $PR_NUMBER).id") - - if [ -n "$ITEM_ID" ]; then - echo "Archiving item $ITEM_ID ..." - gh project item-archive $PROJECT_NUMBER --owner github --id $ITEM_ID - else - echo "Pull request number $PR_NUMBER not found on FR v2 Project" - fi - - echo "done" diff --git a/.github/workflows/repo-sync.yml b/.github/workflows/repo-sync.yml deleted file mode 100644 index 4b4e76de0dd3..000000000000 --- a/.github/workflows/repo-sync.yml +++ /dev/null @@ -1,200 +0,0 @@ -name: Repo Sync - -# **What it does**: GitHub Docs has two repositories: github/docs (public) and github/docs-internal (private). -# This GitHub Actions workflow keeps the `main` branch of those two repos in sync. -# **Why we have it**: To keep the open-source repository up-to-date -# while still having an internal repository for sensitive work. -# **Who does it impact**: Open-source. -# For more details, see https://github.com/repo-sync/repo-sync#how-it-works - -on: - workflow_dispatch: - schedule: - - cron: '20 14-23/3 * * 1-5' # Mon-Fri 6:20a, 9:20a, 12:20p, 3:20p PST - -permissions: - contents: write - pull-requests: write - -jobs: - repo-sync: - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - name: Repo Sync - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - name: Sync repo to branch - env: - SOURCE_REPO: https://${{ secrets.DOCS_BOT_PAT_REPO_SYNC }}@github.com/github/${{ github.repository == 'github/docs-internal' && 'docs' || 'docs-internal' }}.git - SOURCE_BRANCH: main - DESTINATION_BRANCH: repo-sync - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_REPO_SYNC }} - run: | - set -euo pipefail - - : "${GH_TOKEN:?DOCS_BOT_PAT_REPO_SYNC is empty}" - : "${SOURCE_REPO:?SOURCE_REPO is empty}" - : "${SOURCE_BRANCH:?SOURCE_BRANCH is empty}" - : "${DESTINATION_BRANCH:?DESTINATION_BRANCH is empty}" - - git config --unset-all http."https://github.com/".extraheader || true - - git remote remove tmp_upstream 2>/dev/null || true - trap 'git remote remove tmp_upstream 2>/dev/null || true' EXIT - - git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git remote add tmp_upstream "${SOURCE_REPO}" - - git fetch tmp_upstream --quiet - git push origin "refs/remotes/tmp_upstream/${SOURCE_BRANCH}:refs/heads/${DESTINATION_BRANCH}" --force - - - name: Ship pull request - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_REPO_SYNC }} - result-encoding: string - script: | - const { owner, repo } = context.repo - const head = 'github:repo-sync' - const base = 'main' - - async function closePullRequest(prNumber) { - console.log('Closing pull request', prNumber) - await github.rest.pulls.update({ - owner, - repo, - pull_number: prNumber, - state: 'closed' - }) - // Error loud here, so no try/catch - console.log('Closed pull request', prNumber) - } - - console.log('Closing any existing pull requests') - const { data: existingPulls } = await github.rest.pulls.list({ owner, repo, head, base }) - if (existingPulls.length) { - console.log('Found existing pull requests', existingPulls.map(pull => pull.number)) - for (const pull of existingPulls) { - await closePullRequest(pull.number) - } - console.log('Closed existing pull requests') - } - - try { - const { data } = await github.rest.repos.compareCommits({ - owner, - repo, - head, - base, - }) - const { files } = data - console.log(`File changes between ${head} and ${base}:`, files) - if (!files.length) { - console.log('No files changed, bailing') - return - } - } catch (err) { - console.error(`Unable to compute the files difference between ${head} and ${base}`, err.message) - } - - console.log('Creating a new pull request') - const body = ` - This is an automated pull request to sync changes between the public and private repos. - Our bot will merge this pull request automatically. - To preserve continuity across repos, _do not squash_ this pull request. - ` - let pull, pull_number - try { - const response = await github.rest.pulls.create({ - owner, - repo, - head, - base, - title: 'Repo sync', - body, - }) - pull = response.data - pull_number = pull.number - console.log('Created pull request successfully', pull.html_url) - } catch (err) { - // Don't error/alert if there's no commits to sync - // Don't throw if > 100 pulls with same head_sha issue - if (err.message?.includes('No commits') || err.message?.includes('same head_sha')) { - console.log(err.message) - return - } - throw err - } - - console.log('Locking conversations to prevent spam') - try { - await github.rest.issues.lock({ - ...context.repo, - issue_number: pull_number, - lock_reason: 'spam' - }) - console.log('Locked the pull request to prevent spam') - } catch (error) { - console.error('Failed to lock the pull request.', error) - // Don't fail the workflow - } - - console.log('Counting files changed') - const { data: prFiles } = await github.rest.pulls.listFiles({ owner, repo, pull_number }) - if (prFiles.length) { - console.log(prFiles.length, 'files have changed') - } else { - console.log('No files changed, closing') - await closePullRequest(pull_number) - return - } - - console.log('Checking for merge conflicts') - if (pull.mergeable_state === 'dirty') { - console.log('Pull request has a conflict', pull.html_url) - await closePullRequest(pull_number) - throw new Error('Pull request has a conflict, please resolve manually') - } - console.log('No detected merge conflicts') - - console.log('Merging the pull request') - // Admin merge pull request to avoid squash - // Retry once per minute for up to 15 minutes to wait for required checks (e.g. CodeQL) - const maxAttempts = 15 - const delay = 60_000 // 1 minute - for (let attempt = 1; attempt <= maxAttempts; attempt++) { - try { - await github.rest.pulls.merge({ - owner, - repo, - pull_number, - merge_method: 'merge', - }) - console.log('Merged the pull request successfully') - break - } catch (mergeError) { - const msg = mergeError.message || mergeError.response?.data?.message || '' - const isRuleViolation = mergeError.status === 405 && - msg.includes('Repository rule violations') - if (!isRuleViolation || attempt === maxAttempts) { - throw mergeError - } - console.log(`Merge blocked by required checks (attempt ${attempt}/${maxAttempts}), retrying in 60s...`) - await new Promise(resolve => setTimeout(resolve, delay)) - } - } - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/restrict-merge-queue.yml b/.github/workflows/restrict-merge-queue.yml deleted file mode 100644 index bbaec5ac9f21..000000000000 --- a/.github/workflows/restrict-merge-queue.yml +++ /dev/null @@ -1,216 +0,0 @@ -name: Restrict who can queue merges - -# **What it does**: -# On a `merge_group` event, checks whether the person who put the pull -# request into the merge queue is on github/technical-content. If they -# are not, comments on the pull request saying so and fails, which -# ejects the entry from the queue. -# **Why we have it**: -# Classic branch protection used to restrict who could push to `main`, -# but that rule was swept org-wide on 2026-06-22, so today anyone with -# write access can merge. Rebuilding it means also enabling a merge -# queue on the same rule, which could collide with the merge queue on -# our ruleset and lock the branch for everyone. This does the same job -# with machinery we own outright. -# **Who does it impact**: Anyone merging to `main`. - -# Two things to know before changing this: -# -# 1. `merge-queue-restriction` has to be a required status check on the ruleset targeting `refs/heads/main`, or this -# enforces nothing. Add it there only after this workflow is on `main` and reporting. The other order makes the -# check required before it has ever reported, which blocks every pull request. To turn enforcement off again, -# remove it from the ruleset. This workflow keeps running and keeps passing. -# -# 2. The `pull_request` runs do no work. They exist so the required check reports a passing context on the pull -# request itself. Drop them and the check sits pending forever and nothing can ever be enqueued. - -on: - pull_request: - types: [opened, reopened, synchronize, ready_for_review] - merge_group: - -permissions: - contents: read - pull-requests: write - -# Keyed on head SHA rather than pull request number. Webhook delivery order is not guaranteed, and keying on the pull -# request would let a late event for an old SHA cancel the run for a newer one. -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha }} - cancel-in-progress: true - -jobs: - # The job id doubles as the check run name because this job deliberately has no `name:` key. Renaming this job renames - # the required status check, which silently stops enforcing anything. - merge-queue-restriction: - # This repository syncs a subset of files to the public github/docs, including workflows. Nothing here applies there. - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Check that the enqueuer is on the Technical Content team - if: github.event_name == 'merge_group' - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - # Reading org team membership needs `read:org`, which GITHUB_TOKEN does not have. `merge_group` always runs in - # the base repository, so this secret is always available here, including for pull requests from forks. - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: | - // Addressed by numeric ID (org github = 9919, team technical-content = 325922) because IDs survive renames - // and slugs do not. This team was called `docs` until recently and the rename broke a pile of automation. - const ORG_ID = 9919 - const TEAM_ID = 325922 - const TEAM = 'github/technical-content' - const MARKER = '' - const EXEMPT_USERS = ['docs-bot'] - const CONTENT_SLACK_CHANNEL = 'C0E9DK082' - const MAX_ATTEMPTS = 3 - - // `github.actor` is the person who enqueued. On a re-run it stays the original actor, unlike - // `github.triggering_actor`, so re-running cannot launder a failing check into a passing one. - const actor = context.actor - core.info(`This merge group was queued by @${actor}.`) - - // A GitHub App actor always ends in `[bot]`, and `[` is not a valid character in a username, so nobody can - // impersonate one. `docs-bot` is a plain User account and has to be named explicitly. - core.info(`Checking whether @${actor} is an automation account...`) - if (actor.endsWith('[bot]') || EXEMPT_USERS.includes(actor)) { - core.info(`Checked: @${actor} is an automation account. Allowing the merge.`) - return - } - core.info(`Checked: @${actor} is a person, so they need to be on the team.`) - - // Every request retries transient failures before giving up, then fails closed. Failing closed is safe - // here: github/technical-content is an `always` bypass actor on the ruleset, so a broken check stops - // non-Docs merges but never stops Docs. A 404 comes back as null data rather than as an error, because on - // both of the endpoints below it is an answer rather than a failure. - async function ask(description, route, params) { - for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { - core.info(`${description} (attempt ${attempt} of ${MAX_ATTEMPTS})...`) - try { - const { data } = await github.request(route, params) - return { data } - } catch (error) { - if (error.status === 404) return { data: null } - if (attempt === MAX_ATTEMPTS) return { error } - - const seconds = attempt * 2 - core.warning(`Asked and failed with HTTP ${error.status}. Retrying in ${seconds}s.`) - await new Promise((resolve) => setTimeout(resolve, seconds * 1000)) - } - } - } - - // Deliberately says nothing on the pull request. We only comment when we know the answer, and here we - // do not. - function giveUp(detail) { - core.setFailed(`${detail} Failing closed, so this stays out of the queue. Ask in #docs-content.`) - } - - // Checking the parent team is enough. Every member of every child team (docs-content, docs-engineering, - // docs-localization, docs-content-systems, docs-product-managers, docs-open-source, docs-design, - // docs-content-design, copilot-docs) also resolves as a member of the parent. - const membershipResult = await ask( - `Asking the API whether @${actor} is on ${TEAM}`, - 'GET /organizations/{org_id}/team/{team_id}/memberships/{username}', - { org_id: ORG_ID, team_id: TEAM_ID, username: actor }, - ) - - if (membershipResult.error) { - giveUp( - `Could not check ${TEAM} membership for @${actor}. ` + - `The last attempt returned HTTP ${membershipResult.error.status}.`, - ) - return - } - - const membership = membershipResult.data - - if (membership) { - core.info(`Asked: @${actor} has membership state "${membership.state}" on ${TEAM}.`) - } else { - core.info(`Asked: the API reports no membership for @${actor} on ${TEAM} (HTTP 404).`) - - // That 404 is ambiguous. It is byte for byte the same response for "not a member", "team no longer - // exists", and "the token lost visibility into the org". Read the team back before believing it, - // otherwise a deleted team or a downgraded token would blame every single person who tries to merge. - const teamResult = await ask( - `A 404 is ambiguous, so reading ${TEAM} back to confirm it is still visible`, - 'GET /organizations/{org_id}/team/{team_id}', - { org_id: ORG_ID, team_id: TEAM_ID }, - ) - - if (teamResult.error || !teamResult.data) { - giveUp( - `Could not read ${TEAM} itself, so the 404 for @${actor} says nothing about their membership. ` + - `The last attempt returned HTTP ${teamResult.error?.status ?? 404}. ` + - 'Either the team is gone or this token lost access to it.', - ) - return - } - - core.info(`Read it back: ${TEAM} is visible as "${teamResult.data.slug}", so the 404 is a real answer.`) - } - - if (membership?.state === 'active') { - core.info(`@${actor} is an active member of ${TEAM}. Allowing the merge.`) - return - } - - const reason = membership - ? `@${actor} has a "${membership.state}" membership on ${TEAM} rather than an active one.` - : `@${actor} is not a member of ${TEAM}.` - core.info(`Blocking the merge. ${reason}`) - - // A failed check on a `gh-readonly-queue` ref is not something anyone goes looking for, so say why on the - // pull request itself. The merge group ref is `refs/heads/gh-readonly-queue//pr--`, and - // the pull request it names is the one this actor just enqueued, so the number and the actor correspond. - const ref = context.payload.merge_group?.head_ref ?? context.ref - core.info(`Working out which pull request this merge group is for, from "${ref}"...`) - const number = Number(ref.match(/\/pr-(\d+)-[0-9a-f]+$/)?.[1]) - - if (!number) { - core.warning(`Worked it out: could not find a pull request number in "${ref}". Skipping the comment.`) - } else { - core.info(`Worked it out: this merge group is for #${number}.`) - - // Only comment once. Someone who tries to enqueue again already has the explanation, and repeating it - // turns a useful comment into noise. - core.info(`Reading the existing comments on #${number}...`) - const comments = await github.paginate(github.rest.issues.listComments, { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: number, - per_page: 100, - }) - core.info(`Read ${comments.length} comment(s) on #${number}.`) - - if (comments.some((comment) => comment.body?.includes(MARKER))) { - core.info(`#${number} already has this explanation, so not commenting again.`) - } else { - core.info(`Commenting on #${number} to explain...`) - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: number, - body: [ - // The marker has to be on its own line. GitHub parses ``, so anything sharing that - // line renders as literal text: no code spans, no links. - MARKER, - [ - `👋 Hi @${actor}, this pull request was removed from the merge queue.`, - 'Only the GitHub Technical Content team merges to `main` in this repository.', - 'Once this is reviewed and ready, ask in', - `[#docs-content](https://github.slack.com/archives/${CONTENT_SLACK_CHANNEL})`, - 'and someone on the team can merge it for you.', - ].join(' '), - ].join('\n'), - }) - core.info(`Commented on #${number}.`) - } - } - - core.setFailed( - `Only ${TEAM} merges to main in this repository. ${reason} ` + - 'Ask in #docs-content and someone on the team can merge this for you.', - ) diff --git a/.github/workflows/review-comment.yml b/.github/workflows/review-comment.yml deleted file mode 100644 index 5c6542dea0b9..000000000000 --- a/.github/workflows/review-comment.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: Review comment - -# **What it does**: When a PR is opened in docs-internal or docs containing code, it comments with instructions on how to deploy and review the changes. it adds the staging review and live article links in a Content Directory Changes table in a comment. -# **Why we have it**: To help Docs contributors understand how to review their changes. -# **Who does it impact**: docs-internal and docs maintainers and contributors - -on: - # Required in lieu of `pull_request` so that the comment can be posted to PRs opened from a fork. - pull_request_target: - types: - - opened - - synchronize - paths-ignore: - - '.github/workflows/review-comment.yml' - # For reviewing changes to this workflow - pull_request: - types: - - opened - - synchronize - paths: - - '.github/workflows/review-comment.yml' - -permissions: - contents: read - pull-requests: write - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }} x ${{ github.event_name }}' - cancel-in-progress: true - -jobs: - review-comment: - if: ${{ github.event.pull_request.user.login != 'docs-bot' && (github.repository == 'github/docs-internal' || github.repository == 'github/docs') }} - runs-on: ubuntu-latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ github.event.pull_request.number }} - steps: - - name: check out repo content - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - - name: Set APP_URL - run: | - if [[ "${{ github.repository }}" == "github/docs-internal" ]]; then - echo "APP_URL=https://docs-internal-staging-TREE.githubapp.com/en" >> $GITHUB_ENV - elif [[ "${{ github.repository }}" == 'github/docs' ]]; then - echo "APP_URL=https://adjective-noun-hash-4000.app.github.dev" >> $GITHUB_ENV - fi - - name: Find code changes comment - uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad - id: findComment - with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: 'github-actions[bot]' - body-includes: '' - - name: Get changes table - id: changes - timeout-minutes: 30 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - APP_URL: ${{ env.APP_URL }} - BASE_SHA: ${{ github.event.pull_request.base.sha }} - HEAD_SHA: ${{ github.event.pull_request.head.sha }} - run: npm run content-changes-table-comment - - name: Update comment - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 - with: - comment-id: ${{ steps.findComment.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - edit-mode: replace - body: | - - ### How to review these changes 👓 - - Thank you for your contribution. To review these changes, choose one of the following options: - - * [Spin up a codespace][codespace] - * [Set up a local development environment][local] - ${{ github.repository == 'github/docs-internal' && '* [Deploy a staging server][staging]' || '' }} - - ${{ fromJSON('["A Hubber will need to deploy your changes internally to review.",""]')[github.repository == 'github/docs-internal'] }} - -
Table of review links - - **Note**: Please update the URL for your staging server or codespace. - - ${{ steps.changes.outputs.changesTable && 'The table shows the files in the `content` directory that were changed in this pull request. This helps you review your changes on a staging server. Changes to the `data` directory are not included in this table.' || '' }} - - ${{ steps.changes.outputs.changesTable || '_This pull request contains code changes, so we will not generate a table of review links._' }} - - ${{ steps.changes.outputs.changesTable && 'Key: **fpt**: Free, Pro, Team; **ghec**: GitHub Enterprise Cloud; **ghes**: GitHub Enterprise Server' || '' }} - -
- - 🤖 This comment is [automatically generated][workflow]. - - [workflow]: ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.workflow_sha }}/.github/workflows/review-comment.yml - [codespace]: ${{ github.repository == 'github/docs-internal' && 'https://github.com/github/technical-content/blob/main/contributing-to-docs/tips-and-tricks/use-a-codespace-to-review.md' || 'https://docs.github.com/en/contributing/setting-up-your-environment-to-work-on-github-docs/working-on-github-docs-in-a-codespace' }} - [local]: https://docs.github.com/en/contributing/setting-up-your-environment-to-work-on-github-docs/creating-a-local-environment#setting-up-your-local-environment - [staging]: https://github.com/github/technical-content/blob/main/contributing-to-docs/tips-and-tricks/deploying-pr-to-staging-servers.md diff --git a/.github/workflows/reviewers-content-systems.yml b/.github/workflows/reviewers-content-systems.yml deleted file mode 100644 index 47d773b43482..000000000000 --- a/.github/workflows/reviewers-content-systems.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Reviewers - Content Systems - -# **What it does**: Automatically add reviewers based on paths, but only for the docs-internal repo. -# **Why we have it**: So we can have reviewers automatically without getting open source notifications. -# **Who does it impact**: Docs team. - -on: - pull_request: - types: - - edited - - opened - - ready_for_review - - reopened - - synchronize - paths: - - 'contributing/content-*.md' - - 'content/contributing/**.md' - - .github/workflows/reviewers-content-systems.yml - -permissions: - contents: read - pull-requests: write - repository-projects: read - -jobs: - reviewers-content-systems: - if: >- - ${{ github.repository == 'github/docs-internal' && - !github.event.pull_request.draft && - !contains(github.event.pull_request.labels.*.name, 'reviewers-content-systems') && - github.event.pull_request.head.ref != 'repo-sync' }} - runs-on: ubuntu-latest - env: - PR: ${{ github.event.pull_request.html_url }} - - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Add content systems as a reviewer - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - uses: ./.github/actions/retry-command - with: - command: gh pr edit $PR --add-reviewer github/docs-content-systems --add-label reviewers-content-systems diff --git a/.github/workflows/reviewers-dependabot.yml b/.github/workflows/reviewers-dependabot.yml deleted file mode 100644 index 56ec3af50009..000000000000 --- a/.github/workflows/reviewers-dependabot.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Reviewers - Dependabot - -# **What it does**: Automatically add reviewers based on paths, for docs-internal and docs repos. -# **Why we have it**: So dependabot maintainers can be notified about relevant pull requests. -# **Who does it impact**: dependabot-updates-reviewers. - -on: - pull_request: - types: - - edited - - opened - - ready_for_review - - reopened - - synchronize - paths: - - 'data/reusable/dependabot/**' - - 'content/code-security/dependabot/**' - - 'content/rest/dependabot/**' - - '.github/workflows/reviewers-dependabot.yml' - -permissions: - contents: read - pull-requests: write - repository-projects: read - -jobs: - reviewers-dependabot: - if: >- - ${{ github.repository == 'github/docs-internal' && - !github.event.pull_request.draft && - !contains(github.event.pull_request.labels.*.name, 'reviewers-dependabot') && - github.event.pull_request.head.ref != 'repo-sync' }} - runs-on: ubuntu-latest - env: - PR: ${{ github.event.pull_request.html_url }} - - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Add dependabot as a reviewer - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - uses: ./.github/actions/retry-command - with: - command: gh pr edit $PR --add-reviewer github/dependabot-updates-reviewers --add-label reviewers-dependabot diff --git a/.github/workflows/reviewers-docs-engineering.yml b/.github/workflows/reviewers-docs-engineering.yml deleted file mode 100644 index 422139ef62d4..000000000000 --- a/.github/workflows/reviewers-docs-engineering.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: Reviewers - Docs Engineering - -# **What it does**: Automatically add reviewers based on paths, but only for the docs-internal repo. -# And sets the 'engineering' label on the PR. It also edits the PR body to add a template -# for asking questions for the sake of being confident about the PRs rollout. -# **Why we have it**: So we can have reviewers automatically without getting open source notifications. -# **Who does it impact**: Docs team. - -on: - pull_request: - types: - - edited - - opened - - ready_for_review - - reopened - - synchronize - paths: - - '**.ts' - - '**.tsx' - - '**.scss' - - 'src/**' - - '!src/**.json' # So that Docs Engineering isn't reviewing automated pipeline data PRs - - '!src/**.yml' # So that Docs Engineering isn't reviewing automated pipeline data PRs - - '!src/**.sha' # So that Docs Engineering isn't reviewing automated pipeline data PRs - - '.github/**' - - 'config/**' - - '.devcontainer/**' - - '**Dockerfile' - - 'package*.json' - - .github/workflows/reviewers-docs-engineering.yml - -permissions: - contents: read - pull-requests: write - repository-projects: read - -jobs: - reviewers-docs-engineering: - if: >- - ${{ github.repository == 'github/docs-internal' && - !github.event.pull_request.draft && - !contains(github.event.pull_request.labels.*.name, 'reviewers-docs-engineering') && - !contains(github.event.pull_request.labels.*.name, 'lockfile-churn-only') && - github.event.pull_request.head.ref != 'repo-sync' }} - runs-on: ubuntu-latest - env: - PR: ${{ github.event.pull_request.html_url }} - - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - # Detect PRs that only changed package-lock.json (no engineering source files). - # These are usually cross-platform `npm install` churn from contributors - # editing content. We comment with reset instructions instead of pulling in - # docs-engineering for review. - - name: Detect lockfile-only churn - id: detect - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - changed=$(gh pr diff "$PR" --name-only) - echo "Changed files:" - echo "$changed" - lockfile=$(echo "$changed" | grep -c '^package-lock\.json$' || true) - other_eng=$(echo "$changed" | grep -cE '(\.tsx?$|\.scss$|^src/|^package\.json$|^\.github/|^config/|^\.devcontainer/|Dockerfile)' || true) - if [ "$lockfile" -gt 0 ] && [ "$other_eng" -eq 0 ]; then - echo "lockfile_only=true" >> "$GITHUB_OUTPUT" - else - echo "lockfile_only=false" >> "$GITHUB_OUTPUT" - fi - - - name: Comment and label lockfile-only PRs - if: steps.detect.outputs.lockfile_only == 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - cat > /tmp/lockfile-churn-body.md <<'EOF' - _Posted by Copilot on behalf of docs-engineering._ - - This PR includes `package-lock.json` changes but no engineering files. Please reset the lockfile: - - ``` - git checkout origin/main -- package-lock.json - git commit -m "Reset package-lock.json" - git push - ``` - - If the lockfile change is intentional, remove the `lockfile-churn-only` label and request docs-engineering review. - EOF - gh pr comment "$PR" --body-file /tmp/lockfile-churn-body.md - gh pr edit "$PR" --add-label lockfile-churn-only - - - name: Add docs engineering as a reviewer - if: steps.detect.outputs.lockfile_only != 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - uses: ./.github/actions/retry-command - with: - command: gh pr edit $PR --add-reviewer github/docs-engineering --add-label reviewers-docs-engineering diff --git a/.github/workflows/reviewers-legal.yml b/.github/workflows/reviewers-legal.yml deleted file mode 100644 index bef7f702d45c..000000000000 --- a/.github/workflows/reviewers-legal.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Reviewers - Legal - -# **What it does**: Enforces reviews of Responsible AI (RAI) content by the GitHub legal team. Because RAI content can live anywhere in the content directory, it becomes a maintenance problem to use CODEOWNERS to enforce review on each article. -# **Why we have it**: RAI content must be reviewed by the GitHub legal team. -# **Who does it impact**: Content writers and the GitHub legal team. - -on: - workflow_dispatch: - pull_request: - types: - - edited - - opened - - ready_for_review - - reopened - - synchronize - paths: - - 'content/**' - - .github/workflows/reviewers-legal.yml - -permissions: - contents: read - pull-requests: write - repository-projects: read - -jobs: - reviewers-legal: - if: >- - ${{ github.repository == 'github/docs-internal' && - !github.event.pull_request.draft && - !contains(github.event.pull_request.labels.*.name, 'reviewers-legal') && - github.event.pull_request.head.ref != 'repo-sync' }} - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Fetch 2 commits so tj-actions/changed-files can diff without extra API calls - fetch-depth: 2 - - - name: Get changed files - id: changed_files - uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - with: - files: 'content/**' - - - name: Set up Node and dependencies - if: steps.changed_files.outputs.any_modified == 'true' - uses: ./.github/actions/node-npm-setup - - - name: Check content type - if: steps.changed_files.outputs.any_modified == 'true' - id: checkContentType - run: npm run check-content-type - env: - CHANGED_FILE_PATHS: ${{ steps.changed_files.outputs.all_modified_files }} - CONTENT_TYPE: 'rai' - - - name: Add legal as a reviewer - if: steps.checkContentType.outputs.containsContentType == 'true' - uses: ./.github/actions/retry-command - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - PR: ${{ github.event.pull_request.html_url }} - with: - command: gh pr edit $PR --add-reviewer github/legal-product --add-label reviewers-legal diff --git a/.github/workflows/site-policy-reminder.yml b/.github/workflows/site-policy-reminder.yml deleted file mode 100644 index 7c335093c669..000000000000 --- a/.github/workflows/site-policy-reminder.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Site Policy Reminder - -# **What it does**: Automated comment reminder on a PR to change the title for public consumption before merging and to run the Site Policy repo sync action -# **Why we have it**: Titles of merged PRs to Site Policies are sent to the public site-policy repo when the repos are synced -# **Who does it impact**: Everyone merging changes to Site Policies - -on: - pull_request: - types: [labeled] - -permissions: - pull-requests: write - contents: read - -jobs: - run: - if: >- - github.event.label.name == 'Site Policy' && - github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - issue-number: ${{ github.event.pull_request.number }} - body: | - Before merging, please remember to change the title of this PR to a description of its changes that is suitable for public viewing on github/site-policy. - - <@github/site-policy-admins>, when these changes are ready to be synced to the site policy repo for the 24-hour or 30-day [review window](https://github.com/github/site-policy#whats-the-process), run the [site policy sync action](https://github.com/github/docs-internal/actions/workflows/site-policy-sync.yml) from this PR's branch. When these changes are ready to be merged in `docs-internal`, let the Technical Content team know on Slack in #docs-content and a writer will merge this PR. diff --git a/.github/workflows/site-policy-sync.yml b/.github/workflows/site-policy-sync.yml deleted file mode 100644 index 318a2de1d387..000000000000 --- a/.github/workflows/site-policy-sync.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: Site policy sync - -# **What it does**: Creates a branch in our site-policy repo with changes to site policy docs. -# **Why we have it**: We want to keep the site-policy repo up to date. -# **Who does it impact**: site-policy-admins and Developer Policy teams. - -# Controls when the action will run. -on: - # Triggers the workflow pull requests merged to the main branch - pull_request: - branches: - - main - types: - - closed - paths: - - 'content/site-policy/**' - - '.github/workflows/site-policy-sync.yml' - workflow_dispatch: - -permissions: - contents: read - -jobs: - sync: - name: Get the latest docs - if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.merged == true && github.repository == 'github/docs-internal') - runs-on: ubuntu-latest - steps: - - name: checkout docs-internal - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: checkout public site-policy - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - repository: github/site-policy - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - fetch-depth: '' - path: public-repo - - - name: Commits internal policies to copy of public repo with descriptive message from triggering PR title - env: - PR_TITLE: ${{ github.event.pull_request.title }} - run: | - cd public-repo - git config --local user.name 'site-policy-bot' - git config --local user.email 'site-policy-bot@github.com' - rm -rf Policies - cp -r ../content/site-policy Policies - git status - git checkout -b automated-sync-$GITHUB_RUN_ID - git add . - echo PR_TITLE: $PR_TITLE - [[ ! -z $PR_TITLE ]] && DESCRIPTION="${PR_TITLE}" || DESCRIPTION="Update manually triggered by workflow" - echo "DESCRIPTION=$DESCRIPTION" >> $GITHUB_ENV - git commit -m "$(echo $DESCRIPTION)" - - - name: If there are changes to push, create a branch in the public repo and push changes - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - cd public-repo - git config --local user.name 'site-policy-bot' - git config --local user.email 'site-policy-bot@github.com' - NUM_FILES_CHANGED=$(git diff --name-only HEAD^..HEAD | wc -l) - if [[ $NUM_FILES_CHANGED -ge 1 ]] - then - git push --set-upstream origin automated-sync-$GITHUB_RUN_ID - else - echo "No updates to push to the public repo" - fi diff --git a/.github/workflows/sme-review-tracking-issue.yml b/.github/workflows/sme-review-tracking-issue.yml deleted file mode 100644 index a1e33167c8e4..000000000000 --- a/.github/workflows/sme-review-tracking-issue.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Create SME review tracking issue - -# **What it does**: Creates an SME review tracking issue when the `needs SME` label is applied to a PR or issue -# **Why we have it**: We do not want to manually create an SME review tracking issue when an SME review is needed -# **Who does it impact**: Hubbers - -on: - issues: - types: - - labeled - # Required in lieu of `pull_request` so that this workflow can query users in org to determine membership. - pull_request_target: - types: - - labeled - -permissions: - contents: read - -jobs: - create-sme-review-tracking-issue: - runs-on: ubuntu-latest - if: github.repository == 'github/docs' && github.event.label.name == 'needs SME' - steps: - - id: create-issue - env: - URL: ${{ github.event.pull_request.html_url || github.event.issue.html_url }} - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - with: - github-token: ${{ secrets.DOCS_BOT_PAT_BASE }} - script: |- - - const issueNo = context.number || context.issue.number - - // Create an issue in technical-content repo - await github.rest.issues.create({ - owner: 'github', - repo: 'technical-content', - title: `SME tracking issue for \#${issueNo}`, - body: `### Issue / PR that requires an SME review - - ${process.env.URL} - - ### Reason for SME review - - @${context.payload.sender.login} (Optional) _Insert short answer regarding why SME assistance is required to review this contribution_ - - ### Location SME review was requested - - _Insert link to the location SME review was initially requested_ - - #### In the comments below, include notes regarding SME review progress (examples) - - - - Routed to another channel / team - - Reviewer stating they'll need to get back to us at a later time - - Review provided was unclear or missing key information, and a follow-up is necessary - - --- - _Generated by the [${context.workflow}](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) workflow run._ - `, - labels: ['on track','open source', 'sme-review', 'workflow-generated'], - }); diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml deleted file mode 100644 index d008aa8e812a..000000000000 --- a/.github/workflows/stale.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Stale check for stalled pull requests in the docs-internal repository - -# **What it does**: Identifies pull requests that have been inactive for 30 days. -# **Why we have it**: We want to avoid pull requests that are stalled and not being reviewed. -# **Who does it impact**: Everyone that works in the internal repository. - -on: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - push: - paths: - - .github/workflows/stale.yml - -permissions: - contents: read - pull-requests: write - issues: write - -jobs: - stale: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0 - id: stale - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - stale-pr-message: "It looks as if this pull request has been inactive for 30 days. We want to check in with you to see if you plan to continue working on it. If you do, please add a comment to let us know. If we don't hear from you, we will close this pull request after 14 days. If the PR has been reviewed by a writer and you think it's ready to merge, drop into [#docs-content](https://github-grid.enterprise.slack.com/archives/C0E9DK082) and ask us to merge it." - days-before-stale: 30 - days-before-close: 14 - stale-pr-label: 'stale' - exempt-pr-labels: 'never-stale' - close-pr-label: 'Closed as inactive' - - operations-per-run: 150 - - - name: Print outputs - env: - STALED: ${{ steps.stale.outputs.staled-issues-prs || '0' }} - CLOSED: ${{ steps.stale.outputs.closed-issues-prs || '0' }} - run: echo "Staled PRs:${STALED}, Closed PRs:${CLOSED}" - - - name: Check out repo - if: ${{ failure() }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/sync-audit-logs.yml b/.github/workflows/sync-audit-logs.yml deleted file mode 100644 index c80d44bef7d3..000000000000 --- a/.github/workflows/sync-audit-logs.yml +++ /dev/null @@ -1,121 +0,0 @@ -name: Sync Audit Log data - -# **What it does**: This updates our Audit Logs schema. -# **Why we have it**: We want our Audit Logs up to date. -# **Who does it impact**: Docs engineering, people reading Audit Logs. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1-5' # Run Mon-Fri at 16:20 UTC / 8:20 PST - -permissions: - contents: write - pull-requests: write - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - update-audit-log-files: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - - name: Run updater script - env: - # need to use a token from a user with access to github/audit-log-allowlists for this step - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - npm run sync-audit-log - - - name: Get the audit-log-allowlists SHA being synced - id: audit-log-allowlists - run: | - COMMIT_SHA=$(cat src/audit-logs/lib/config.json | jq -r '.sha') - echo "COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_OUTPUT - echo "Commit SHA from audit-log-allowlists: $COMMIT_SHA" - if [ -z $COMMIT_SHA ]; then - echo "audit-log-allowlists commit SHA is empty!" - exit 1 - fi - - - name: Create and merge pull request - env: - # Needed for gh - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - echo "Creating a new branch if needed..." - branchname=audit-logs-schema-update-${{ steps.audit-log-allowlists.outputs.COMMIT_SHA }} - remotesha=$(git ls-remote --heads origin $branchname) - if [ -n "$remotesha" ]; then - # output is not empty, it means the remote branch exists - echo "Branch $branchname already exists in 'github/docs-internal'. Exiting..." - exit 0 - fi - git checkout -b $branchname - echo "Created a new branch $branchname" - - echo "Preparing commit..." - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - git add -A . - echo "Prepared commit" - - echo "Check if there are changes..." - if git diff-index --cached --quiet HEAD -- . ':(exclude)src/audit-logs/lib/config.json' - then - echo "No real changes (only the SHA in config.json moved). Exiting…" - exit 0 - fi - echo "Changes detected, proceeding" - - echo "Creating commit..." - git commit -m "Add updated audit log event data" - echo "Created commit" - - echo "Pushing commit..." - git push origin $branchname - echo "Pushed commit" - - echo "Creating pull request..." - gh pr create \ - --title "Update audit log event data" \ - --body '👋 Docs First Responder. This PR updates the audit log event data with the latest changes, synced from github/audit-log-allowlists. - Make sure the PR builds successfully and there are no gross errors (for example, a file is deleted). You do not need to validate the contents (that is the responsibility of product teams). - If CI does not pass or other problems arise, contact #technical-content on slack.' \ - --repo github/docs-internal \ - --label audit-log-pipeline,workflow-generated \ - --head=$branchname - echo "Created pull request" - - # can't approve your own PR, approve with Actions - echo "Approving pull request..." - unset GITHUB_TOKEN - gh auth login --with-token <<< "${{ secrets.GITHUB_TOKEN }}" - gh pr review --approve - echo "Approved pull request" - - # Actions can't merge the PR so back to docs-bot to merge the PR - echo "Setting pull request to auto merge..." - unset GITHUB_TOKEN - gh auth login --with-token <<< "${{ secrets.DOCS_BOT_PAT_BASE }}" - gh pr merge --auto - echo "Set pull request to auto merge" - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/sync-codeql-cli.yml b/.github/workflows/sync-codeql-cli.yml deleted file mode 100644 index ed091a9450ff..000000000000 --- a/.github/workflows/sync-codeql-cli.yml +++ /dev/null @@ -1,129 +0,0 @@ -name: Sync CodeQL CLI - -# **What it does**: This workflow is run manually approximately every two weeks. -# When run, this workflow syncs the CodeQL CLI automated pipeline with the semmle-code -# repository, and creates a pull request if there are updates. -# **Why we have it**: So we can automate CodeQL CLI documentation. -# **Who does it impact**: Anyone making CodeQL CLI changes in `github/semmle-code`, and wanting to get them published on the docs site. - -on: - workflow_dispatch: - inputs: - SOURCE_BRANCH: - description: 'Branch to pull the source files from in the semmle-code repo.' - type: string - required: true - default: 'main' - -permissions: - contents: write - pull-requests: write - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - generate-codeql-files: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout repository code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - name: Checkout semmle-code repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # By default, only the most recent commit of the `main` branch - # will be checked out - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - repository: github/semmle-code - path: semmle-code - ref: ${{ inputs.SOURCE_BRANCH }} - - - uses: ./.github/actions/node-npm-setup - - - name: Get the semmle-code SHA being synced - id: semmle-code - run: | - cd semmle-code - OPENAPI_COMMIT_SHA=$(git rev-parse HEAD) - echo "OPENAPI_COMMIT_SHA=$OPENAPI_COMMIT_SHA" >> $GITHUB_OUTPUT - echo "Copied files from github/semmle-code repo. Commit SHA: $OPENAPI_COMMIT_SHA" - - - name: Install pandoc - run: | - # Remove all previous pandoc versions - sudo apt-get purge --auto-remove pandoc - # Download pandoc - wget https://github.com/jgm/pandoc/releases/download/3.0.1/pandoc-3.0.1-1-amd64.deb - # Install pandoc - sudo dpkg -i pandoc-3.0.1-1-amd64.deb - # Output the pandoc version installed - pandoc -v - rm pandoc-3.0.1-1-amd64.deb - - - name: Sync the CodeQL CLI data - run: | - npm run sync-codeql-cli - git status - echo "Deleting the cloned github/semmle-code repo..." - rm -rf semmle-code - - - name: Create pull request - env: - # Needed for gh - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - # If nothing to commit, exit now. It's fine. No orphans. - changes=$(git diff --name-only | wc -l) - untracked=$(git status --untracked-files --short | wc -l) - if [[ $changes -eq 0 ]] && [[ $untracked -eq 0 ]]; then - echo "There are no changes to commit after running 'npm run sync-codeql-cli'. Exiting..." - exit 0 - fi - - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - - branchname=codeql-cli-update-${{ steps.semmle-code.outputs.OPENAPI_COMMIT_SHA }} - - git checkout -b $branchname - git add . - git commit -m "Update CodeQL CLI data" - - # Force-push to handle reruns where the branch already exists on the - # remote from a prior failed attempt. Plain --force is safe here - # because these branches are exclusively managed by this workflow. - git push --force -u origin $branchname - - # If a PR already exists for this branch (e.g. a previous run - # succeeded but the workflow still reported failure), skip creation. - existing_pr=$(gh pr list --repo github/docs-internal --head "$branchname" --json number --jq '.[0].number') - if [[ -n "$existing_pr" ]]; then - echo "Pull request #$existing_pr already exists for branch $branchname. Skipping PR creation." - exit 0 - fi - - echo "Creating pull request..." - gh pr create \ - --title "Update CodeQL CLI manual" \ - --body '👋 humans. This PR updates the CodeQL CLI manual Markdown pages with the latest changes in preparation for the next **CodeQL CLI** release. - - This will be reviewed and merged by the Code scanning and GHAS focus team as part of the release of CodeQL CLI. (Synced from semmle-code@${{ steps.semmle-code.outputs.OPENAPI_COMMIT_SHA }}) - - If CI does not pass or other problems arise, contact #technical-content on slack.' \ - --repo github/docs-internal \ - --label "codeql-cli-pipeline,skip FR board,ready-for-doc-review,workflow-generated" - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/sync-graphql.yml b/.github/workflows/sync-graphql.yml deleted file mode 100644 index 57c77018ade1..000000000000 --- a/.github/workflows/sync-graphql.yml +++ /dev/null @@ -1,107 +0,0 @@ -name: Sync GraphQL schema - -# **What it does**: This updates our GraphQL schemas. -# **Why we have it**: We want our GraphQL docs up to date. -# **Who does it impact**: Docs engineering, people reading GraphQL docs. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1-5' # Run Mon-Fri at 16:20 UTC / 8:20 PST - -permissions: - contents: read - -jobs: - update_graphql_files: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - outputs: - ignored-changes: ${{ steps.sync.outputs.ignored-changes }} - ignored-count: ${{ steps.sync.outputs.ignored-count }} - ignored-types: ${{ steps.sync.outputs.ignored-types }} - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - name: Run updater scripts - id: sync - env: - # need to use a token from a user with access to github/github for this step - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: npm run sync-graphql - - name: Create pull request - id: create-pull-request - uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # pin @v8.0.0 - env: - # Disable pre-commit hooks; they don't play nicely here - HUSKY: '0' - with: - # Need to use a token with repo and workflow scopes for this step. - # Token should be a PAT because actions performed with GITHUB_TOKEN - # don't trigger other workflows and this action force pushes updates - # from the default branch. - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - commit-message: 'Update GraphQL data files' - title: GraphQL schema update - body: - "Hello! Some GraphQL data in github/github was updated recently. This PR - syncs up the GraphQL data in this repo.\n\n - If CI passes, this PR will be auto-merged. :green_heart:\n\n - If CI does not pass or other problems arise, contact #technical-content on slack." - branch: graphql-schema-update - - - name: Enable GitHub auto-merge - if: ${{ steps.create-pull-request.outputs.pull-request-number }} - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - AUTOMERGE_PR_NUMBER: ${{ steps.create-pull-request.outputs.pull-request-number }} - run: npm run enable-automerge - - - if: ${{ failure() }} - name: Delete remote branch (if previous steps failed) - run: git push origin --delete graphql-schema-update - - - if: ${{ steps.create-pull-request.outputs.pull-request-number }} - name: Approve - uses: juliangruber/approve-pull-request-action@68fcc9a5a73b5641cadf757cf99d73720dcb05d0 # v2.1.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - number: ${{ steps.create-pull-request.outputs.pull-request-number }} - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} - - notify_ignored_changes: - if: github.repository == 'github/docs-internal' && needs.update_graphql_files.outputs.ignored-count > 0 && github.event_name != 'workflow_dispatch' - needs: update_graphql_files - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/slack-alert - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - message: | - ⚠️ GraphQL Sync found ${{ needs.update_graphql_files.outputs.ignored-count }} ignored change types: ${{ needs.update_graphql_files.outputs.ignored-types }} - - These change types are not in CHANGES_TO_REPORT and were silently ignored. Consider reviewing if they should be added to the changelog. - - See workflow run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - - - uses: ./.github/actions/create-workflow-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} diff --git a/.github/workflows/sync-llms-txt.yml b/.github/workflows/sync-llms-txt.yml deleted file mode 100644 index f2592e684c30..000000000000 --- a/.github/workflows/sync-llms-txt.yml +++ /dev/null @@ -1,282 +0,0 @@ -name: Sync llms.txt - -# **What it does**: Generates docs.github.com/llms.txt, github.com/llms.txt, and -# github.com/llms-full.txt from the page catalog and popularity data, then -# opens PRs to update them. -# **Why we have it**: Agents discover docs through llms.txt; the page list keeps -# pace with what's actually popular without writers updating it by hand. -# **Who does it impact**: Docs consumers via agents, and anyone landing on -# github.com/llms.txt, github.com/llms-full.txt, or docs.github.com/llms.txt. - -on: - workflow_dispatch: - push: - branches: - - main - paths: - - '.github/workflows/sync-llms-txt.yml' - - 'data/llms-txt/**' - - 'src/workflows/generate-llms-txt.ts' - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 9:20 PDT / 8:20 PST - -permissions: - contents: read - -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - sync: - name: Sync llms.txt - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - env: - BRANCH: sync-llms-txt - steps: - - name: Checkout docs-internal - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - uses: ./.github/actions/node-npm-setup - - - name: Generate llms.txt for docs.github.com - env: - DOCS_BOT_PAT_BASE: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - npm run generate-llms-txt --silent -- \ - --config data/llms-txt/config-docs.yml \ - --output /tmp/docs-llms.txt - echo "Generated docs llms.txt ($(wc -l < /tmp/docs-llms.txt) lines, $(wc -c < /tmp/docs-llms.txt) bytes)" - - - name: Generate llms.txt for github.com - env: - DOCS_BOT_PAT_BASE: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - npm run generate-llms-txt --silent -- \ - --config data/llms-txt/config-monolith.yml \ - --output /tmp/monolith-llms.txt - echo "Generated monolith llms.txt ($(wc -l < /tmp/monolith-llms.txt) lines, $(wc -c < /tmp/monolith-llms.txt) bytes)" - - # ---------- PR to docs-internal: update data/llms-txt/docs.md ---------- - - - name: Diff docs llms.txt against committed copy - id: diff_docs - run: | - if diff -q /tmp/docs-llms.txt data/llms-txt/docs.md > /dev/null 2>&1; then - echo "No docs changes, skipping" - echo "changed=false" >> "$GITHUB_OUTPUT" - else - echo "Docs changes detected" - echo "changed=true" >> "$GITHUB_OUTPUT" - fi - - - name: Ensure sync branch exists in docs-internal - if: steps.diff_docs.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - REPO="github/docs-internal" - if gh api "repos/$REPO/git/ref/heads/$BRANCH" --jq '.object.sha' > /dev/null 2>&1; then - echo "Branch $BRANCH exists, fetching" - git -c url."https://x-access-token:${GH_TOKEN}@github.com/".insteadOf="https://github.com/" \ - fetch origin "$BRANCH" - git checkout "$BRANCH" - else - echo "Branch $BRANCH does not exist, creating from main" - git checkout -b "$BRANCH" - fi - - - name: Commit and push docs.md - if: steps.diff_docs.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - cp /tmp/docs-llms.txt data/llms-txt/docs.md - git config user.name "docs-bot" - git config user.email "77750099+docs-bot@users.noreply.github.com" - git add data/llms-txt/docs.md - # diff_docs compares against main, but the sync branch may already - # exist with this exact content (open PR from a prior run). In that - # case there is nothing new to stage, and `git commit` would exit 1 - # and fail the whole workflow. Skip the commit and push when the - # branch is already up to date. - if git diff --cached --quiet; then - echo "Sync branch already has the latest generated docs.md; nothing to commit." - else - git commit -m "Update data/llms-txt/docs.md from popularity data" - git push "https://x-access-token:${GH_TOKEN}@github.com/github/docs-internal.git" "$BRANCH" - fi - - - name: Create or update docs-internal PR - if: steps.diff_docs.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - REPO="github/docs-internal" - if EXISTING_PR=$(gh pr list --repo "$REPO" --head "$BRANCH" \ - --json number --jq '.[0].number' 2>/dev/null) && [ -n "$EXISTING_PR" ]; then - echo "Docs PR #$EXISTING_PR already exists, updated with new commit" - exit 0 - fi - - RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" - PR_BODY="The [sync-llms-txt workflow]($RUN_URL) generated this PR. - - Updates \`data/llms-txt/docs.md\`, served at https://docs.github.com/llms.txt. Built from the page catalog and popularity data using \`data/llms-txt/config-default.yml\` + \`config-docs.yml\`." - - gh pr create \ - --repo "$REPO" \ - --title "Update data/llms-txt/docs.md" \ - --body "$PR_BODY" \ - --head "$BRANCH" \ - --base main \ - --draft \ - --label "llm-generated" - - # ---------- PR to github/github: update public/llms*.txt ---------- - - - name: Fetch current public llms files from github/github - id: fetch_monolith - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - fetch_current() { - local target_file="$1" - local output_file="$2" - if gh api -H "Accept: application/vnd.github.raw" \ - "repos/github/github/contents/$target_file" \ - > "$output_file" 2>/dev/null; then - echo "Fetched current $target_file" - else - rm -f "$output_file" - fi - } - fetch_current public/llms.txt /tmp/monolith-current-llms.txt - fetch_current public/llms-full.txt /tmp/monolith-current-llms-full.txt - - - name: Diff monolith llms files - id: diff_monolith - run: | - if [ -f /tmp/monolith-current-llms.txt ] && \ - diff -q /tmp/monolith-llms.txt /tmp/monolith-current-llms.txt > /dev/null 2>&1 && \ - [ -f /tmp/monolith-current-llms-full.txt ] && \ - diff -q /tmp/monolith-llms.txt /tmp/monolith-current-llms-full.txt > /dev/null 2>&1; then - echo "No monolith changes, skipping" - echo "changed=false" >> "$GITHUB_OUTPUT" - else - echo "Monolith changes detected" - echo "changed=true" >> "$GITHUB_OUTPUT" - fi - - - name: Ensure sync branch exists in github/github - if: steps.diff_monolith.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - REPO="github/github" - if gh api "repos/$REPO/git/ref/heads/$BRANCH" --jq '.object.sha' > /dev/null 2>&1; then - echo "Branch $BRANCH exists" - else - DEFAULT_BRANCH=$(gh api "repos/$REPO" --jq '.default_branch') - BASE_SHA=$(gh api "repos/$REPO/git/ref/heads/$DEFAULT_BRANCH" --jq '.object.sha') - gh api "repos/$REPO/git/refs" \ - --method POST \ - -f ref="refs/heads/$BRANCH" \ - -f sha="$BASE_SHA" - echo "Created branch $BRANCH from $DEFAULT_BRANCH at $BASE_SHA" - fi - - - name: Commit monolith llms files to github/github - if: steps.diff_monolith.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - REPO="github/github" - CONTENT=$(base64 -w 0 /tmp/monolith-llms.txt) - - sync_file() { - local target_file="$1" - local branch_copy="/tmp/monolith-branch-$(basename "$target_file")" - if gh api -H "Accept: application/vnd.github.raw" \ - "repos/$REPO/contents/$target_file?ref=$BRANCH" \ - > "$branch_copy" 2>/dev/null && \ - diff -q /tmp/monolith-llms.txt "$branch_copy" > /dev/null 2>&1; then - echo "$target_file is already current on $BRANCH" - return - fi - - local existing_sha - existing_sha=$(gh api "repos/$REPO/contents/$target_file?ref=$BRANCH" \ - --jq '.sha' 2>/dev/null || true) - local commit_args=(-f "message=Sync $(basename "$target_file") from docs.github.com" - -f "content=$CONTENT" - -f "branch=$BRANCH") - if [ -n "$existing_sha" ]; then - commit_args+=(-f "sha=$existing_sha") - fi - gh api "repos/$REPO/contents/$target_file" \ - --method PUT \ - "${commit_args[@]}" --jq '.commit.sha' - } - - sync_file public/llms.txt - sync_file public/llms-full.txt - - - name: Create or update github/github PR - if: steps.diff_monolith.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - REPO="github/github" - RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}" - DEFAULT_BRANCH=$(gh api "repos/$REPO" --jq '.default_branch') - - PR_BODY="The [sync-llms-txt workflow]($RUN_URL) generated this PR. - - Updates the static generated files \`public/llms.txt\` and \`public/llms-full.txt\`, served at https://github.com/llms.txt and https://github.com/llms-full.txt. Both are built in docs-internal from the page catalog and popularity data using \`data/llms-txt/config-default.yml\` + \`config-monolith.yml\`. - - Initially, \`llms-full.txt\` is intentionally an exact duplicate of \`llms.txt\`. - - No feature flags. Static file in \`public/\`, no code changes. - - " - - if EXISTING_PR=$(gh pr list --repo "$REPO" --head "$BRANCH" \ - --json number --jq '.[0].number' 2>/dev/null) && [ -n "$EXISTING_PR" ]; then - gh api "repos/$REPO/pulls/$EXISTING_PR" \ - --method PATCH \ - -f title="Sync llms.txt and llms-full.txt from docs.github.com" \ - -f body="$PR_BODY" > /dev/null - echo "Monolith PR #$EXISTING_PR already exists, updated with new commit" - exit 0 - fi - - gh pr create \ - --repo "$REPO" \ - --title "Sync llms.txt and llms-full.txt from docs.github.com" \ - --body "$PR_BODY" \ - --head "$BRANCH" \ - --base "$DEFAULT_BRANCH" \ - --label "docs" - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/sync-openapi.yml b/.github/workflows/sync-openapi.yml deleted file mode 100644 index eb15a2db3d91..000000000000 --- a/.github/workflows/sync-openapi.yml +++ /dev/null @@ -1,126 +0,0 @@ -name: Sync OpenAPI schema - -# **What it does**: Syncs the REST, Webhooks, and GitHub Apps automated pipelines with the github/rest-api-description repository, and creates a pull request if there are updates to any of the data files we generate from the OpenAPI. Runs on a weekday schedule or a `sync-openapi` repository dispatch. -# **Why we have it**: So we can automate updates to REST, Webhooks, and GitHub Apps documentation -# **Who does it impact**: Anyone making OpenAPI changes in `github/github`, and wanting to get them published on the docs site. - -on: - workflow_dispatch: - inputs: - SOURCE_BRANCH: - description: 'Branch to pull the dereferenced OpenAPI source files from in the github/rest-api-descriptions repo.' - type: string - required: true - default: 'main' - repository_dispatch: - types: [sync-openapi] - schedule: - - cron: '20 16 * * 1-5' # Run Mon-Fri at 16:20 UTC / 8:20 PST - -permissions: - contents: write - pull-requests: write - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - generate-decorated-files: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout repository code - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - # Check out a nested repository inside of previous checkout - - name: Checkout rest-api-description repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # By default, only the most recent commit of the `main` branch - # will be checked out - repository: github/rest-api-description - path: rest-api-description - ref: ${{ inputs.SOURCE_BRANCH || github.event.client_payload.ref || 'main' }} - - - uses: ./.github/actions/node-npm-setup - - - name: Sync the REST, Webhooks, and GitHub Apps schemas - env: - # Needed for gh - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - NODE_OPTIONS: '--max-old-space-size=8192' - run: | - npm run sync-rest -- \ - --source-repos rest-api-description \ - --output rest github-apps webhooks rest-redirects - git status - echo "Deleting the cloned github/rest-api-description repo..." - rm -rf rest-api-description - - - name: Get the rest-api-description SHA being synced - id: rest-api-description - run: | - OPENAPI_COMMIT_SHA=$(cat src/rest/lib/config.json | jq -r '.sha') - echo "OPENAPI_COMMIT_SHA=$OPENAPI_COMMIT_SHA" >> $GITHUB_OUTPUT - echo "Copied files from github/rest-api-description repo. Commit SHA: $OPENAPI_COMMIT_SHA" - if [ -z $OPENAPI_COMMIT_SHA ]; then - echo "OpenAPI commit SHA is empty!" - exit 1 - fi - - - name: Create pull request - env: - # Needed for gh - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - # If nothing to commit, exit now. It's fine. No orphans. - changes=$(git diff --name-only | wc -l) - if [[ $changes -eq 0 ]]; then - echo "There are no changes to commit after running 'npm run sync-rest'. Exiting..." - exit 0 - fi - - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - - branchname=openapi-update-${{ steps.rest-api-description.outputs.OPENAPI_COMMIT_SHA }} - - remotesha=$(git ls-remote --heads origin $branchname) - if [ -n "$remotesha" ]; then - # output is not empty, it means the remote branch exists - echo "Branch $branchname already exists in 'github/docs-internal'. Exiting..." - exit 0 - fi - - git checkout -b $branchname - git add . - git commit -m "Add decorated OpenAPI schema files" - git push origin $branchname - - echo "Creating pull request..." - gh pr create \ - --title "Update OpenAPI Description" \ - --body '👋 humans. This PR updates the OpenAPI description with the latest changes. (Synced from github/rest-api-description@${{ steps.rest-api-description.outputs.OPENAPI_COMMIT_SHA }}) - - Docs First Responders should follow [the acting-as-the-first-responder instructions](https://github.com/github/technical-content/blob/main/contributing-to-docs/first-responder/acting-as-the-first-responder.md?plain=1#L156). - - If CI does not pass or other problems arise, contact #technical-content on slack. - - _Generated by the [Sync OpenAPI schema](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run._' \ - --repo github/docs-internal \ - --label github-openapi-bot,workflow-generated \ - --head=$branchname \ - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/sync-sdk-docs.yml b/.github/workflows/sync-sdk-docs.yml deleted file mode 100644 index b8d56344aaca..000000000000 --- a/.github/workflows/sync-sdk-docs.yml +++ /dev/null @@ -1,245 +0,0 @@ -name: 'Sync Copilot SDK docs' - -on: - # Event-driven sync — triggered by copilot-sdk when docs/ changes are pushed - repository_dispatch: - types: [sync-sdk-docs] - - # Manual trigger for on-demand syncs and testing - workflow_dispatch: - inputs: - dry_run: - description: 'Dry run — run normalization but skip push and PR creation' - required: false - default: 'false' - type: boolean - source_ref: - description: 'copilot-sdk ref to sync from (branch, tag, or SHA). Defaults to main.' - required: false - default: 'main' - type: string - - # PR validation — dry-run only, verifies scripts work on CI - pull_request: - types: [opened, synchronize, reopened] - paths: - - '.github/workflows/sync-sdk-docs.yml' - - 'src/workflows/sync-sdk-docs/**' - -concurrency: - group: sync-sdk-docs-${{ github.event_name }} - cancel-in-progress: true - -permissions: - contents: write - pull-requests: write - -jobs: - sync-docs: - name: 'Sync SDK docs' - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - env: - SDK_DOCS_TARGET: content/copilot/how-tos/copilot-sdk - SYNC_BRANCH: sdk-docs/auto-sync - ASSETS_TARGET: assets/images/help/copilot/copilot-sdk - SOURCE_REF: ${{ inputs.source_ref || 'main' }} - - steps: - - name: Checkout docs-internal - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Fetch SDK docs from copilot-sdk - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - set -e - tmp=$(mktemp -d) - echo "Cloning copilot-sdk@$SOURCE_REF (sparse: docs/ only)..." - git clone --depth 1 --branch "$SOURCE_REF" --filter=blob:none --sparse \ - "https://x-access-token:${GH_TOKEN}@github.com/github/copilot-sdk.git" "$tmp" 2>&1 | tail -1 - cd "$tmp" && git sparse-checkout set docs 2>/dev/null - SDK_SHA=$(git -C "$tmp" rev-parse HEAD) - echo "SDK_SHA=$SDK_SHA" >> "$GITHUB_ENV" - echo "SDK_TMP=$tmp" >> "$GITHUB_ENV" - echo "Fetched copilot-sdk@${SDK_SHA::7}" - - - name: Set up Node and dependencies - uses: ./.github/actions/node-npm-setup - - - name: Install mermaid-cli - run: npm install -g @mermaid-js/mermaid-cli@11 - - - name: Clean existing SDK docs - run: | - rm -rf "$SDK_DOCS_TARGET" - - - name: Copy SDK docs - run: | - mkdir -p "$SDK_DOCS_TARGET" - rsync -av --exclude='.validation/' --exclude='developer-docs/' "$SDK_TMP/docs/" "$SDK_DOCS_TARGET/" - echo "Copied $(find "$SDK_DOCS_TARGET" -name '*.md' | wc -l | tr -d ' ') markdown files" - - - name: Normalize content - run: | - npx tsx src/workflows/sync-sdk-docs/normalize-sdk-docs.ts \ - --content-dir content \ - --sdk-docs-dir "$SDK_DOCS_TARGET" - - - name: Convert Mermaid diagrams to PNG - env: - PUPPETEER_CHROMIUM_REVISION: '' - run: | - # Puppeteer needs --no-sandbox on GitHub Actions runners - echo '{ "args": ["--no-sandbox", "--disable-setuid-sandbox"] }' > /tmp/puppeteer-config.json - npx tsx src/workflows/sync-sdk-docs/convert-mermaid.ts \ - --sdk-docs-dir "$SDK_DOCS_TARGET" \ - --assets-dir "$ASSETS_TARGET" \ - --repo-root . \ - --puppeteer-config /tmp/puppeteer-config.json - - - name: Remove stale SDK assets - run: | - if [ ! -d "$ASSETS_TARGET" ]; then - echo "No assets directory — nothing to clean." - exit 0 - fi - # Collect image filenames referenced in the current SDK docs - REFERENCED=$(grep -roh '/assets/images/help/copilot/copilot-sdk/[^)]*' "$SDK_DOCS_TARGET" \ - | sed 's|.*/||' | sort -u) - STALE=0 - for file in "$ASSETS_TARGET"/*.png; do - [ -f "$file" ] || continue - BASENAME=$(basename "$file") - if ! echo "$REFERENCED" | grep -qxF "$BASENAME"; then - echo " STALE: $BASENAME" - rm "$file" - STALE=$((STALE + 1)) - fi - done - echo "Removed $STALE stale asset(s)." - - - name: Lint SDK content (non-blocking) - continue-on-error: true - run: | - SDK_FILES=$(find "$SDK_DOCS_TARGET" -name '*.md' | tr '\n' ' ') - if [ -z "$SDK_FILES" ]; then - echo "No SDK markdown files to lint." - exit 0 - fi - echo "Linting $(echo "$SDK_FILES" | wc -w | tr -d ' ') SDK files..." - if npm run lint-content -- --paths $SDK_FILES; then - echo "✅ Content linter passed — no issues found." - else - echo "" - echo "⚠️ Content linter found issues (see above)." - echo "These will appear as CI failures on the generated PR." - echo "Fix them in the copilot-sdk source docs or update the normalize script." - fi - - - name: Show diff summary - run: | - git add -A - if git diff --cached --quiet; then - echo "No changes detected." - echo "has_changes=false" >> "$GITHUB_ENV" - else - echo "has_changes=true" >> "$GITHUB_ENV" - echo "Changes detected:" - git diff --cached --stat - fi - - # --- PR-only: upload artifacts for review --- - - name: Upload normalized docs (PR validation) - if: github.event_name == 'pull_request' - uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 - with: - name: normalized-sdk-docs - path: | - ${{ env.SDK_DOCS_TARGET }} - ${{ env.ASSETS_TARGET }} - retention-days: 7 - - # --- Push and PR (only on schedule/dispatch, not dry-run, and changes exist) --- - - name: Commit and push - if: >- - env.has_changes == 'true' - && github.event_name != 'pull_request' - && inputs.dry_run != 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - - # Fetch the sync branch if it exists so force-with-lease knows the remote state - git fetch origin "$SYNC_BRANCH" 2>/dev/null || true - - git checkout -B "$SYNC_BRANCH" - git commit -m "Sync Copilot SDK docs from copilot-sdk@${SDK_SHA::7} - - Source commit: https://github.com/github/copilot-sdk/commit/$SDK_SHA - - This commit was automatically generated by the sync-sdk-docs workflow." - - git push --force-with-lease origin "$SYNC_BRANCH" - - - name: Create or update pull request - if: >- - env.has_changes == 'true' - && github.event_name != 'pull_request' - && inputs.dry_run != 'true' - env: - GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - PR_TITLE="Sync Copilot SDK docs (auto-generated)" - PR_BODY="## Summary - - This PR syncs documentation from [\`github/copilot-sdk/docs\`](https://github.com/github/copilot-sdk/tree/main/docs) to \`content/copilot/how-tos/copilot-sdk/\`. - - **Source commit:** https://github.com/github/copilot-sdk/commit/$SDK_SHA - - ### What this PR does - - Copies SDK documentation from \`copilot-sdk\` - - Adds YAML frontmatter for docs.github.com publishing - - Converts internal links to AUTOTITLE format - - Converts Mermaid diagrams to PNG images - - Normalizes code fence languages and list formatting - - > [!NOTE] - > This PR is auto-generated. Do not edit it directly — make changes in the [copilot-sdk docs](https://github.com/github/copilot-sdk/tree/main/docs) instead. - - --- - _Generated by the [sync-sdk-docs workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID)._" - - EXISTING_PR=$(gh pr list --head "$SYNC_BRANCH" --json number --jq '.[0].number' 2>/dev/null || true) - - if [ -n "$EXISTING_PR" ]; then - echo "Updating existing PR #$EXISTING_PR" - gh pr edit "$EXISTING_PR" --title "$PR_TITLE" --body "$PR_BODY" - gh pr comment "$EXISTING_PR" --body "🔄 Updated with changes from [\`${SDK_SHA::7}\`](https://github.com/github/copilot-sdk/commit/$SDK_SHA)." - else - echo "Creating new PR" - gh pr create \ - --title "$PR_TITLE" \ - --body "$PR_BODY" \ - --base main \ - --head "$SYNC_BRANCH" \ - --label "copilot-sdk-docs,workflow-generated" - fi - - - name: Cleanup - if: always() - run: rm -rf "$SDK_TMP" - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/sync-secret-scanning.yml b/.github/workflows/sync-secret-scanning.yml deleted file mode 100644 index 730464d206ce..000000000000 --- a/.github/workflows/sync-secret-scanning.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Sync Secret Scanning data - -# **What it does**: This updates the data used by the secret scanning patterns page. -# **Why we have it**: To automate updates to the secret scanning pattern data in our public-facing documentation. -# **Who does it impact**: Docs engineering, content writers. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1-5' # Run Mon-Fri at 16:20 UTC / 8:20 PST - -permissions: - contents: write - pull-requests: write - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -jobs: - update-secret-scanning-file: - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - - name: Sync secret scanning data - id: secret-scanning-sync - env: - # need to use a token from a user with access to - # github/token-scanning-service for this step - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - npm run sync-secret-scanning - - - name: Create pull request - id: create-pull-request - uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # pin @v8.0.0 - env: - # Disable pre-commit hooks; they don't play nicely here - HUSKY: '0' - with: - # need to use a token with repo and workflow scopes for this step - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - commit-message: 'Add updated secret scanning data' - title: Sync secret scanning data - body: | - 👋 humans. This PR updates the secret scanning data with the latest changes from github/token-scanning-service. - - If CI passes, this PR will be auto-merged. :green_heart: - - If CI does not pass or other problems arise, contact #technical-content on Slack. - - This automated PR was created by [this workflow](https://github.com/github/docs-internal/blob/main/.github/workflows/sync-secret-scanning.yml). - branch: sync-secret-scanning-data - labels: | - secret-scanning-pipeline - skip FR board - workflow-generated - - - name: Enable GitHub auto-merge - if: ${{ steps.create-pull-request.outputs.pull-request-number }} - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - AUTOMERGE_PR_NUMBER: ${{ steps.create-pull-request.outputs.pull-request-number }} - run: npm run enable-automerge - - - if: ${{ steps.create-pull-request.outputs.pull-request-number }} - name: Approve - uses: juliangruber/approve-pull-request-action@68fcc9a5a73b5641cadf757cf99d73720dcb05d0 # v2.1.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - number: ${{ steps.create-pull-request.outputs.pull-request-number }} - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name != 'workflow_dispatch' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/test-changed-content.yml b/.github/workflows/test-changed-content.yml deleted file mode 100644 index 29c9cd9704b6..000000000000 --- a/.github/workflows/test-changed-content.yml +++ /dev/null @@ -1,64 +0,0 @@ -name: Test changed content - -# **What it does**: Runs the vitest tests for changed and deleted content files. -# **Why we have it**: Use GitHub Actions to run tests on changed content files. -# **Who does it impact**: Docs engineering, open-source engineering contributors. - -on: - pull_request: - branches: - # This is important! If you make a PR against a megabranch, you - # might actually want to delete a file without setting up a - # redirect in its place. But if it's going into `main` we'll - # want to make sure that doesn't happen. - - main - paths: - - 'content/**' - - .github/workflows/test-changed-content.yml - -permissions: - contents: read - -jobs: - test-changed-content: - runs-on: ubuntu-latest - if: ${{ github.repository == 'github/docs-internal' || github.repository == 'github/docs' }} - steps: - # Each of these ifs needs to be repeated at each step to make sure the required check still runs - # Even if if doesn't do anything - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Fetch 2 commits so tj-actions/changed-files can diff without extra API calls - fetch-depth: 2 - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/get-docs-early-access - if: ${{ github.repository == 'github/docs-internal' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/cache-nextjs - - - name: Run build script - run: npm run build - - - name: Get changed files - id: changed_files - uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - with: - files: 'content/**' - # Needed to expose `all_old_new_renamed_files` (old,new pairs for renames). - # Without this, files git classifies as renames (status R) are invisible to - # the deleted-file redirect check below and old URLs can silently 404. - include_all_old_new_renamed_files: true - - - name: Run tests - env: - CHANGED_FILES: ${{ steps.changed_files.outputs.all_modified_files }} - DELETED_FILES: ${{ steps.changed_files.outputs.deleted_files }} - # Space-separated `oldPath,newPath` pairs. The test treats the old paths - # like deleted files so missing redirects on renames are caught. - RENAMED_FILES: ${{ steps.changed_files.outputs.all_old_new_renamed_files }} - run: npm test -- src/content-render/tests/render-changed-and-deleted-files.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 05f6da9695f9..000000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,176 +0,0 @@ -name: Test - -# **What it does**: Runs our tests. -# **Why we have it**: We want our tests to pass before merging code. -# **Who does it impact**: Docs engineering, open-source engineering contributors. -# -# For a catalog of what each suite covers and how risky it is to admin-merge -# past it when red, see src/tests/SUITES.md. - -on: - workflow_dispatch: - merge_group: - pull_request: - -permissions: - contents: read - pull-requests: read - -# This allows a subsequently queued workflow run to interrupt previous runs -concurrency: - group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' - cancel-in-progress: true - -env: - # Setting this will activate the vitest tests that depend on actually - # sending real search queries to Elasticsearch - ELASTICSEARCH_URL: http://localhost:9200/ - -jobs: - test: - name: ${{ matrix.name }} - if: github.repository == 'github/docs-internal' || github.repository == 'github/docs' - runs-on: ubuntu-latest - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - # Note that *if you add* to this, remember to also add that - # to the **required checks** in the branch protection rules. - name: - # src/ directory - - archives - - article-api - - assets - - audit-logs - - automated-pipelines - # - bookmarklets - # - code-scanning - # - codeql-cli - - color-schemes - - content-linter - - content-render - - data-directory - # - dev-toc - - early-access - - events - - fixtures - - frame - - github-apps - - graphql - - landings - - languages - # - links - - observability - # - open-source - # - pages - - products - - redirects - - release-notes - - rest - - search - - secret-scanning - - shielding - # - tests - # - tools - - versions - - webhooks - - workflows - - # The languages suite only runs on docs-internal - isPrivateRepo: - - ${{ github.repository == 'github/docs-internal' }} - exclude: - - name: languages - isPrivateRepo: false - - steps: - # Each of these ifs needs to be repeated at each step to make sure the required check still runs - # Even if if doesn't do anything - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - # Fetch 2 commits so tj-actions/changed-files can diff without extra API calls - fetch-depth: 2 - - - uses: ./.github/actions/setup-elasticsearch - if: ${{ matrix.name == 'search' || matrix.name == 'languages' }} - - - uses: ./.github/actions/node-npm-setup - - - uses: ./.github/actions/get-docs-early-access - if: ${{ github.repository == 'github/docs-internal' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Check the test fixture data (if applicable) - if: ${{ matrix.name == 'fixtures' }} - run: npm run copy-fixture-data -- --check - - # This keeps our fixture content/data in check - - name: Check the test fixture content (if applicable) - if: ${{ matrix.name == 'fixtures' }} - env: - ROOT: src/fixtures/fixtures - run: | - # If either of these fail, it means our fixture content's internal - # links can and should be updated. - npm run update-internal-links -- --dry-run --check --strict \ - src/fixtures/fixtures/content \ - --exclude src/fixtures/fixtures/content/get-started/foo/typo-autotitling.md \ - --exclude src/fixtures/fixtures/content/get-started/foo/anchor-autotitling.md - npm run update-internal-links -- --dry-run --check --strict \ - src/fixtures/fixtures/data - - - name: Clone all translations - if: ${{ matrix.name == 'languages' }} - uses: ./.github/actions/clone-translations - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - name: Gather files changed - if: ${{ matrix.name == 'content-linter' }} - id: changed_files - uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - - - name: Write changed files to diff file - if: ${{ matrix.name == 'content-linter' }} - run: echo "${{ steps.changed_files.outputs.all_modified_files }}" > get_diff_files.txt - - - uses: ./.github/actions/cache-nextjs - - - name: Run build script - run: npm run build - - - uses: ./.github/actions/warmup-remotejson-cache - # Only the 'routing' tests include end-to-end tests about - # archived enterprise server URLs. - if: ${{ matrix.name == 'redirects' }} - - - uses: ./.github/actions/precompute-pageinfo - # Only the 'pageinfo' tests include end-to-end tests about this. - if: ${{ matrix.name == 'article-api' }} - env: - ROOT: src/fixtures/fixtures - - - name: Index fixtures into the local Elasticsearch - # For the sake of saving time, only run this step if the group - # is one that will run tests against an Elasticsearch on localhost. - if: ${{ matrix.name == 'search' || matrix.name == 'languages' }} - run: npm run index-test-fixtures - - - name: Run tests - env: - DIFF_FILE: get_diff_files.txt - CHANGELOG_CACHE_FILE_PATH: src/fixtures/fixtures/changelog-feed.json - # By default, when `process.env.NODE_ENV === 'test'` it forces the - # tests run only in English. The exception is the - # `languages` suite which needs all languages to be set up. - ENABLED_LANGUAGES: ${{ matrix.name == 'languages' && 'all' || '' }} - ROOT: ${{ (matrix.name == 'fixtures' || matrix.name == 'article-api' || matrix.name == 'landings' ) && 'src/fixtures/fixtures' || '' }} - TRANSLATIONS_FIXTURE_ROOT: ${{ (matrix.name == 'fixtures' || matrix.name == 'article-api') && 'src/fixtures/fixtures/translations' || '' }} - # Enable debug logging when "Re-run jobs with debug logging" is used in GitHub Actions UI - # This will output additional timing and path information to help diagnose timeout issues - RUNNER_DEBUG: ${{ runner.debug }} - VITEST_FLAGS: ${{ matrix.name == 'article-api' && '--no-file-parallelism --maxWorkers=1' || '' }} - run: npm test -- $VITEST_FLAGS src/${{ matrix.name }}/tests/ diff --git a/.github/workflows/triage-issue-comments.yml b/.github/workflows/triage-issue-comments.yml deleted file mode 100644 index d56749eb48c3..000000000000 --- a/.github/workflows/triage-issue-comments.yml +++ /dev/null @@ -1,80 +0,0 @@ -name: Triage new issue comments - -# **What it does**: Adds label triage to new issue comments in the open source repository. -# **Why we have it**: Update open source project board for review. -# **Who does it impact**: Docs open source. - -on: - issue_comment: - types: - - created - -permissions: - contents: read - issues: write - -jobs: - triage-issue-comments: - if: ${{ github.repository == 'github/docs' && !github.event.issue.pull_request }} - runs-on: ubuntu-latest - - steps: - - name: Check if the event originated from a team member - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 - id: is-internal-contributor - with: - result-encoding: string - script: | - const repo = context.payload.repository.name - const org = context.payload.repository.owner.login - const actor = context.actor - let collaboratorStatus = '' - try { - collaboratorStatus = await github.request('GET /repos/{owner}/{repo}/collaborators/{username}', { - owner: org, - repo: repo, - username: actor - }) - console.log(`This issue was commented on by a Hubber.`) - return 'true' - } catch (error) { - console.log(`This issue was commented on by an external contributor.`) - return 'false' - } - - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Check issue exists - id: exists - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ISSUE_URL: ${{ github.event.issue.html_url }} - run: | - if gh issue view $ISSUE_URL > /dev/null 2>&1 - then - echo "exists=y" >> $GITHUB_OUTPUT - else - echo "exists=n" >> $GITHUB_OUTPUT - fi - - - name: Label issues with new comments with 'triage' - uses: ./.github/actions/labeler - if: ${{ steps.is-internal-contributor.outputs.result == 'false' && steps.exists.outputs.exists == 'y' }} - with: - addLabels: 'triage' - ignoreIfLabeled: true - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/triage-issues.yml b/.github/workflows/triage-issues.yml deleted file mode 100644 index 55b333e5413c..000000000000 --- a/.github/workflows/triage-issues.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Triage new issues - -# **What it does**: Add the 'triage' label to new issues in the open source repository. -# **Why we have it**: We want to make sure that new issues are triaged and assigned to the right team. -# **Who does it impact**: Docs open source. - -on: - issues: - types: - - reopened - - opened - -permissions: - contents: read - issues: write - -jobs: - triage_issues: - if: ${{ github.repository == 'github/docs' }} - runs-on: ubuntu-latest - - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Label new issues with 'triage' - uses: ./.github/actions/labeler - with: - addLabels: 'triage' diff --git a/.github/workflows/triage-pull-requests.yml b/.github/workflows/triage-pull-requests.yml deleted file mode 100644 index 39419711d2c5..000000000000 --- a/.github/workflows/triage-pull-requests.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Triage new pull requests - -# **What it does**: Adds triage label to new pull requests in the open source repository. -# **Why we have it**: Update project board for new pull requests for triage. -# **Who does it impact**: Docs open source. - -on: - # Needed in lieu of `pull_request` so that PRs from a fork can be triaged. - pull_request_target: - types: - - reopened - - opened - -permissions: - contents: read - issues: write - pull-requests: write - -jobs: - triage_pulls: - if: ${{ github.repository == 'github/docs' }} - runs-on: ubuntu-latest - - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Label new pull requests with 'triage' - uses: ./.github/actions/labeler - with: - addLabels: 'triage' diff --git a/.github/workflows/triage-stale-check.yml b/.github/workflows/triage-stale-check.yml deleted file mode 100644 index e7d2db0765e4..000000000000 --- a/.github/workflows/triage-stale-check.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Stale check for no activity - -# **What it does**: Provides more aggressive stale checks in the open repo. -# **Why we have it**: In the open repo, we want more aggressive stale checking. -# **Who does it impact**: Anyone working in the open repo. - -on: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - -permissions: - contents: read - -jobs: - stale_contributor: - name: Identify and close stale issues and PRs - if: github.repository == 'github/docs' - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - - steps: - - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - days-before-stale: 30 - days-before-close: 7 - - stale-issue-message: 'A stale label has been added to this issue, because it has been open for 30 days with no activity. If you think this issue should remain open, please add a new comment.' - exempt-issue-labels: 'help wanted,never-stale,waiting for review' - stale-issue-label: 'Inactive' - close-issue-label: 'Closed as inactive' - - exempt-pr-labels: 'never-stale,ready to merge,waiting for review' - stale-pr-message: 'A stale label has been added to this pull request because it has been open 30 days with no activity. If you think this pull request should remain open, please add a new comment.' - stale-pr-label: 'Inactive' - close-pr-label: 'Closed as inactive' - - - name: Check out repo - if: ${{ failure() }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} - - stale_staff: - name: Remind staff about PRs waiting for review - if: github.repository == 'github/docs' - runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write - steps: - - uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0 - id: stale - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - only-labels: 'waiting for review' - days-before-pr-stale: 14 - days-before-pr-close: -1 # Never close - operations-per-run: 100 - - stale-pr-message: 'This is a gentle reminder for the Technical Content team that this pull request is waiting for review.' - stale-pr-label: 'Waiting on Technical Content review' - - - name: Print outputs - env: - STALED: ${{ steps.stale.outputs.staled-issues-prs || '0' }} - CLOSED: ${{ steps.stale.outputs.closed-issues-prs || '0' }} - run: echo "Staled issues/PRs:${STALED}, Closed issues/PRs:${CLOSED}" - - - name: Check out repo - if: ${{ failure() }} - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/triage-unallowed-contributions.yml b/.github/workflows/triage-unallowed-contributions.yml deleted file mode 100644 index a11d3277e2e0..000000000000 --- a/.github/workflows/triage-unallowed-contributions.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Check unallowed file changes - -# **What it does**: If someone changes some files in the open repo, we prevent the pull request from merging. -# **Why we have it**: Some files can only be changed in the internal repository for security and workflow reasons. -# **Who does it impact**: Open source contributors. - -on: - # Needed in lieu of `pull_request` so that PRs from a fork can be notified of unallowed changes. - pull_request_target: - -permissions: - contents: read - pull-requests: write - -jobs: - triage: - if: >- - ${{ - github.repository == 'github/docs' && - github.event.pull_request.user.login != 'docs-bot' && - github.event.pull_request.user.login != 'dependabot[bot]' - }} - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Get files changed - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 - id: filter - with: - # Base branch used to get changed files - base: 'main' - - # Enables setting an output in the format in `${FILTER_NAME}_files - # with the names of the matching files formatted as JSON array - list-files: json - - # Returns list of changed files matching each filter - filters: 'src/workflows/unallowed-contribution-filters.yml' - - - name: Set up Node and dependencies - if: ${{ steps.filter.outputs.notAllowed == 'true' || steps.filter.outputs.contentTypes == 'true' }} - uses: ./.github/actions/node-npm-setup - - # When there are changes to files we can't accept, leave a comment - # explaining this to the PR author, and why their PR will close - - name: "Comment about changes we can't accept" - if: ${{ steps.filter.outputs.notAllowed == 'true' || steps.filter.outputs.contentTypes == 'true' }} - run: npm run unallowed-contributions - env: - REPO_OWNER_AND_NAME: ${{ github.repository }} - PR_NUMBER: ${{ github.event.number }} - FILE_PATHS_NOT_ALLOWED: ${{ steps.filter.outputs.notAllowed_files }} - CHANGED_FILE_PATHS: ${{ steps.filter.outputs.contentTypes_files }} - ADDED_CONTENT_FILES: ${{ steps.filter.outputs.added_files }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/validate-asset-images.yml b/.github/workflows/validate-asset-images.yml deleted file mode 100644 index e29eb9eec307..000000000000 --- a/.github/workflows/validate-asset-images.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Validate asset images - -# **What it does**: Run ./src/assets/scripts/validate-asset-images.ts on all images in assets/ -# **Why we have it**: To protect from innocent and potentially malicious bad image assets -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - pull_request: - paths: - - 'assets/**' - - '.github/workflows/validate-asset-images.yml' - -permissions: - contents: read - -jobs: - validate-asset-images: - if: ${{ github.repository == 'github/docs-internal' || github.repository == 'github/docs' }} - runs-on: ubuntu-latest - steps: - - name: Check out repo - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - uses: ./.github/actions/node-npm-setup - - - name: Validate all asset images - run: npm run validate-asset-images diff --git a/.github/workflows/validate-github-github-docs-urls.yml b/.github/workflows/validate-github-github-docs-urls.yml deleted file mode 100644 index b9577e49f7d4..000000000000 --- a/.github/workflows/validate-github-github-docs-urls.yml +++ /dev/null @@ -1,134 +0,0 @@ -name: Validate github/github docs URLs - -# **What it does**: Checks the URLs in docs-urls.json in github/github -# **Why we have it**: To ensure the values in docs-urls.json are perfect. -# **Who does it impact**: Docs content. - -on: - workflow_dispatch: - schedule: - - cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST - # See https://gh.io/AAsyyao before uncommenting: - # pull_request: - # paths: - # - 'content/**' - # # In case a relevant dependency changes - # - 'package*.json' - # # The scripts - # - 'src/links/scripts/validate-github-github-docs-urls/**' - # # The workflow - # - .github/workflows/validate-github-github-docs-urls.yml - -permissions: - contents: read - issues: write - pull-requests: write - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -jobs: - validate_github_github_docs_urls: - name: Validate github/github docs URLs - if: github.repository == 'github/docs-internal' - runs-on: ubuntu-latest - steps: - - name: Check out repo's default branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: ./.github/actions/node-npm-setup - - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - repository: github/github - ref: master - path: github - - - name: Run validation - run: | - # This will generate a .json file which we can use to - # do other things in other steps. - npm run validate-github-github-docs-urls -- validate \ - --output checks.json \ - --ignore-not-found \ - github/config/docs-urls.json - - - name: Update config/docs-urls.json in github/github (possibly) - if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - npm run validate-github-github-docs-urls -- generate-new-json checks.json github/config/docs-urls.json - - git config --global user.name "docs-bot" - git config --global user.email "77750099+docs-bot@users.noreply.github.com" - - cd github - git status - git diff - changes=$(git diff --name-only | wc -l) - if [[ $changes -eq 0 ]]; then - echo "There are no changes to commit after running generate-new-json. Exiting this step" - exit 0 - fi - - current_timestamp=$(date '+%Y-%m-%d-%H%M%S') - branch_name="update-docs-urls-$current_timestamp" - git checkout -b "$branch_name" - current_daystamp=$(date '+%Y-%m-%d') - git commit -a -m "Update Docs URLs from automation ($current_daystamp)" - git push origin "$branch_name" - - # XXX TODO - # Perhaps post an issue somewhere, about that the fact that this - # branch has been created and now needs to be turned into a PR - # that some human can take responsibility for. - - - name: Clean up old branches in github/github - if: ${{ github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' }} - env: - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - run: | - npm run validate-github-github-docs-urls -- clean-up-old-branches --prefix update-docs-urls - - echo "To see them all, go to:" - echo "https://github.com/github/github/branches/all?query=update-docs-urls-" - - # If a PR comes along to github/docs-internal that causes some - # URLs in docs-urls.json (in github/github) to now fail, then - # we'll want to make the PR author+reviewer aware of this. - # For example, you moved a page without setting up a redirect. - # Or you edited a heading that now breaks a URL with fragment. - # In the latter case, you might want to update the URL in docs-urls.json - # after this PR has landed, or consider using `` as a - # workaround for the time being. - # First, gather the URLs that were relevant - - name: Get changed content/data files - if: ${{ github.event_name == 'pull_request' }} - id: changed_files - uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 - with: - files: | - content/** - - - name: Generate PR comment - if: ${{ github.event_name == 'pull_request' && steps.changed_files.outputs.any_modified == 'true' }} - env: - CHANGED_FILES: ${{ steps.changed_files.outputs.all_modified_files }} - GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }} - ISSUE_NUMBER: ${{ github.event.pull_request.number }} - REPOSITORY: ${{ github.repository }} - run: | - npm run validate-github-github-docs-urls -- post-pr-comment checks.json --changed-files $CHANGED_FILES - - - uses: ./.github/actions/create-workflow-failure-issue - id: create-failure-issue - if: ${{ failure() && github.event_name == 'schedule' }} - with: - token: ${{ secrets.DOCS_BOT_PAT_BASE }} - - - uses: ./.github/actions/slack-alert - if: ${{ failure() && github.event_name == 'schedule' }} - with: - slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }} - issue_url: ${{ steps.create-failure-issue.outputs.issue_url }} diff --git a/.github/workflows/validate-openapi-check.yml b/.github/workflows/validate-openapi-check.yml deleted file mode 100644 index b602126df401..000000000000 --- a/.github/workflows/validate-openapi-check.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Validate OpenAPI Check Docker - -# **What it does**: Tests building and running the OpenAPI check Docker container -# **Why we have it**: To ensure the Dockerfile and openapi-check script work correctly -# **Who does it impact**: Docs engineering. - -on: - workflow_dispatch: - pull_request: - paths: - - 'Dockerfile.openapi_decorator' - - 'src/rest/scripts/openapi-check.ts' - - 'src/rest/scripts/utils/get-operations.ts' - - 'src/rest/scripts/utils/operation.ts' - - 'src/rest/fixtures/openapi-check-fixture.json' - - 'package.json' - - 'package-lock.json' - - 'tsconfig.json' - # Self-test - - '.github/workflows/validate-openapi-check.yml' - -permissions: - contents: read - -jobs: - validate-openapi-check: - runs-on: ubuntu-latest - if: github.repository == 'github/docs-internal' - steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - - name: Build Docker image - run: | - docker build -f Dockerfile.openapi_decorator -t openapi-decorator:test . - - - name: Test Docker image with sample OpenAPI file - run: | - docker run --rm openapi-decorator:test -f "src/rest/fixtures/openapi-check-fixture.json" - - - name: Test Docker image with multiple OpenAPI files - run: | - docker run --rm openapi-decorator:test \ - -f "src/rest/fixtures/openapi-check-fixture.json" \ - "src/rest/fixtures/openapi-check-fixture.json" diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml deleted file mode 100644 index 2b13f0935714..000000000000 --- a/.github/workflows/zizmor.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Workflow security lint - -# **What it does**: Runs zizmor to detect security issues in GitHub Actions workflows. -# **Why we have it**: To catch injection vulnerabilities and other security misconfigurations before they ship. -# **Who does it impact**: Docs engineering. - -on: - pull_request: - paths: - - '.github/workflows/**' - - '.github/actions/**' - - '.github/zizmor.yml' - -permissions: - contents: read - -jobs: - zizmor: - if: github.repository == 'github/docs-internal' - name: zizmor - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - uses: zizmorcore/zizmor-action@0dce2577a4760a2749d8cfb7a84b7d5585ebcb7d # v0.5.0 - with: - online-audits: 'false' - advanced-security: 'false' - annotations: 'true' - min-severity: 'high'