-
Notifications
You must be signed in to change notification settings - Fork 31
184 lines (167 loc) · 7.24 KB
/
Copy pathgitbook.yml
File metadata and controls
184 lines (167 loc) · 7.24 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
name: GitBook
# GitBook publishes this repo through Git sync (.gitbook.yaml -> SUMMARY.md), so
# whatever lands on main is what readers see — there is no build step in between
# to catch a stale table of contents or a link to a folder that was renamed.
# This workflow is that missing build step:
#
# * on pull requests -> validate only, so a bad TOC never reaches main
# * on push to main -> regenerate the navigation, commit any drift, then
# dispatch the swe-site rebuild
#
# Regenerating on main is what actually "updates GitBook": the commit this job
# makes is the trigger. No GitBook API token is involved.
#
# The swe-site rebuild is dispatched from here, at the end of the publish job,
# rather than from its own workflow. Chaining it guarantees swe-site pulls the
# regenerated SUMMARY.md instead of racing the commit that fixes it. This
# replaces the old trigger-site-deploy.yml.
#
# The bot commit does not re-run this workflow: GitHub suppresses workflow
# triggers for pushes made with the default GITHUB_TOKEN, so there is no loop.
on:
push:
branches: [main]
paths:
- "Easy/**"
- "Medium/**"
- "Hard/**"
- "README.md"
- "SUMMARY.md"
- "_sidebar.md"
- ".gitbook.yaml"
- ".gitbook/**"
- "tools/**"
- ".github/workflows/gitbook.yml"
pull_request:
paths:
- "Easy/**"
- "Medium/**"
- "Hard/**"
- "README.md"
- "SUMMARY.md"
- "_sidebar.md"
- ".gitbook.yaml"
- ".gitbook/**"
- "tools/**"
- ".github/workflows/gitbook.yml"
workflow_dispatch:
# Never let two runs race to commit regenerated navigation.
concurrency:
group: gitbook-${{ github.ref }}
cancel-in-progress: false
jobs:
validate:
name: Validate GitBook sources
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check navigation, links, counts and math
run: ./tools/check-nav.sh
- name: Explain how to fix
if: failure()
run: |
echo "::notice::Run './tools/gen-summary.sh && ./tools/gen-sidebar.sh && ./tools/mathfix.py' locally, then commit the result."
publish:
name: Regenerate navigation and sync
# Guarded on main so a manual run from a branch never pushes a commit there.
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
# A real token is needed so the commit below is pushed as a normal
# commit that GitBook's Git sync app can see.
token: ${{ secrets.GITHUB_TOKEN }}
- name: Normalize math for GitBook
run: ./tools/mathfix.py
- name: Regenerate SUMMARY.md and _sidebar.md
run: |
./tools/gen-summary.sh
./tools/gen-sidebar.sh
- name: Commit drift, if any
id: commit
run: |
if git diff --quiet; then
echo "Navigation already up to date; nothing to push."
echo "changed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add SUMMARY.md _sidebar.md Easy Medium Hard
git commit -m "Regenerate GitBook navigation"
git push
echo "changed=true" >> "$GITHUB_OUTPUT"
- name: Verify the state GitBook will sync
run: ./tools/check-nav.sh
- name: Trigger swe-site rebuild
env:
SITE_DISPATCH_TOKEN: ${{ secrets.SITE_DISPATCH_TOKEN }}
run: |
if [ -z "${SITE_DISPATCH_TOKEN}" ]; then
echo "::error::SITE_DISPATCH_TOKEN is not set — swe-site will not rebuild."
echo "Add a fine-grained PAT for lyxuansang91/swe-site with 'Contents: read and write'."
exit 1
fi
# No -f here: it suppresses the response body, and GitHub puts the
# actual reason for a 4xx in that body. Capture status, body and the
# x-accepted-github-permissions header (which names the exact
# permission the endpoint wanted) so failures are self-diagnosing.
resp="$(mktemp)"
headers="$(mktemp)"
code="$(curl -sS -X POST \
-o "$resp" -D "$headers" -w '%{http_code}' \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "Authorization: Bearer ${SITE_DISPATCH_TOKEN}" \
https://api.github.com/repos/lyxuansang91/swe-site/dispatches \
-d '{"event_type":"content-updated"}')"
if [ "$code" = "204" ]; then
echo "Dispatched content-updated to lyxuansang91/swe-site."
exit 0
fi
echo "GitHub returned HTTP $code"
echo "--- response body ---"
cat "$resp"; echo
echo "--- permissions GitHub expected ---"
grep -i '^x-accepted-github-permissions:' "$headers" || echo "(header not present)"
# Which account does the stored secret actually belong to? This repo
# runs Actions under the software-engineer-learning org, while the
# dispatch target is a personal repo, so the usual mistake is that the
# org secret holds a different token than the one being tested locally.
# Printing the resolved login (never the token) settles that instantly.
echo "--- identity of the stored token ---"
who="$(curl -sS -H "Authorization: Bearer ${SITE_DISPATCH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/user \
| sed -n 's/.*"login": *"\([^"]*\)".*/\1/p' | head -1)"
echo "SITE_DISPATCH_TOKEN authenticates as: ${who:-<could not resolve>}"
echo "It must be a token owned by the account that can write to lyxuansang91/swe-site."
case "$code" in
401)
echo "::error::SITE_DISPATCH_TOKEN was rejected (401). The token is invalid, expired, or stored with stray whitespace. Re-create it and re-save the secret." ;;
403)
echo "::error::Token authenticated but is not authorized (403). Fine-grained PATs need lyxuansang91/swe-site listed under 'Repository access' AND 'Contents: Read and write'. Check both." ;;
404)
echo "::error::Repository not visible to this token (404). Fine-grained PATs return 404 for private repos they were not granted access to — add swe-site to the token's selected repositories." ;;
*)
echo "::error::Dispatch to swe-site failed with HTTP $code." ;;
esac
exit 1
- name: Summary
run: |
{
echo "### GitBook sync"
echo
if [ "${{ steps.commit.outputs.changed }}" = "true" ]; then
echo "Navigation had drifted; regenerated and pushed a commit."
echo "GitBook Git sync picks this up on the new push."
else
echo "Navigation was already correct — GitBook syncs this commit as-is."
fi
echo
echo "Dispatched \`content-updated\` to swe-site."
} >> "$GITHUB_STEP_SUMMARY"