-
Notifications
You must be signed in to change notification settings - Fork 66.9k
154 lines (135 loc) · 6.46 KB
/
content-pipelines.yml
File metadata and controls
154 lines (135 loc) · 6.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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: mcp-server
steps:
- name: Checkout docs-internal
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- 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
env:
UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }}
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 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 main
git branch -D "$UPDATE_BRANCH"
git push origin --delete "$UPDATE_BRANCH" || true
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/
git add "src/content-pipelines/state/${ID}.sha"
if git diff --cached --quiet; then
echo "has_changes=false" >> "$GITHUB_OUTPUT"
echo "No documentation changes to commit"
else
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 }}
run: git push origin "$UPDATE_BRANCH"
- name: Create or update PR
if: steps.commit.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ github.token }}
UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }}
PIPELINE_ID: ${{ matrix.id }}
run: |
PR_NUMBER="${{ steps.check-pr.outputs.pr_number }}"
PR_TITLE="docs: update ${PIPELINE_ID} content from source docs"
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+="## 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+="## Review"$'\n\n'
PR_BODY+="* Review each commit for accuracy — the agent uses AI, so spot-check important changes"$'\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"
if [ -n "$PR_NUMBER" ]; then
echo "PR #$PR_NUMBER already exists — new commit pushed"
else
echo "Creating new PR"
gh pr create \
--title "$PR_TITLE" \
--body "$PR_BODY" \
--base main \
--head "$UPDATE_BRANCH" \
--label "workflow-generated,content-pipeline-update" \
--draft
fi
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}