-
Notifications
You must be signed in to change notification settings - Fork 66.8k
191 lines (168 loc) · 8.34 KB
/
content-pipelines.yml
File metadata and controls
191 lines (168 loc) · 8.34 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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
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
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+="## 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"$'\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/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 }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}