Skip to content

Commit 970b1bf

Browse files
authored
Auto-update snapshots when syncing typeshed (#25841)
## Summary I previously tried to implement this in #20892, but it never worked correctly, and I couldn't figure out why. So we ended up reverting it in #22090. I set Codex on it, and it figured out that the reason is that `CI: "true"` is set in GitHub Actions as an environment variable, and that currently takes precedence over the `--accept` flag passed to `cargo insta`. That seems like a bug in `cargo-insta` (which I've proposed a fix for in mitsuhiko/insta#924) -- CLI flags should usually take precedence over environment variables. But for now, this is easily worked around by setting `CI: "0"` in the workflow. Another reason why we ended up reverting this in #22090 was that the test was causing the workflow to take ages; it was actually timing out in some situations. This redo attempts to mitigate that by: - Running the tests as a fourth step on a depot linux runner, instead of a GitHub MacOS runner - Sharing the rust-cache with builds on the `main` branch and on PRs: this workflow only usually happens every two weeks, so the default rust-cache settings wouldn't be effective for it
1 parent 0785793 commit 970b1bf

1 file changed

Lines changed: 110 additions & 18 deletions

File tree

.github/workflows/sync_typeshed.yaml

Lines changed: 110 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ name: Sync typeshed
1616
# 3. Once the Windows worker is done, a MacOS worker:
1717
# a. Checks out the branch created by the Linux worker
1818
# b. Syncs all docstrings available on MacOS that are not available on Linux or Windows
19-
# c. Formats the code again
20-
# d. Commits and pushes the completed sync to the same upstream branch
21-
# e. Applies the typeshed patches in a standalone commit
22-
# f. Pushes the patch commit and creates a PR against the `main` branch
23-
# 4. If any of steps 1-3 failed, an issue is created in the `astral-sh/ruff` repository
19+
# c. Formats the code again and pushes the completed sync
20+
# d. Applies the typeshed patches in a standalone commit and pushes it
21+
# 4. A second Linux worker attempts to update and push any snapshots that changed
22+
# (this step is allowed to fail)
23+
# 5. Once the snapshot update finishes, fails, or times out, a third Linux worker creates a PR
24+
# against the `main` branch as long as step 3 succeeded
25+
# 6. If any required step failed, an issue is created in the `astral-sh/ruff` repository
2426

2527
on:
2628
workflow_dispatch:
@@ -36,16 +38,19 @@ permissions: {}
3638

3739
env:
3840
# Don't set this flag globally for the workflow: it does strange things
39-
# to the snapshots in the `cargo insta test --accept` step in the MacOS job.
41+
# to the snapshots in the `cargo insta test --accept` step in the snapshot job.
4042
#
4143
# FORCE_COLOR: 1
4244

45+
CARGO_NET_RETRY: 10
46+
CARGO_PROFILE_DEV_DEBUG: line-tables-only
4347
CARGO_TERM_COLOR: always
4448
NEXTEST_PROFILE: "ci"
49+
RUSTUP_MAX_RETRIES: 10
4550
GH_TOKEN: ${{ github.token }}
4651

4752
# The name of the upstream branch that the first worker creates,
48-
# and which all three workers push to.
53+
# and which the later jobs update.
4954
UPSTREAM_BRANCH: typeshedbot/sync-typeshed
5055

5156
# The path to the directory that contains the vendored typeshed stubs,
@@ -153,10 +158,12 @@ jobs:
153158
git commit -am "Sync Windows docstrings" --allow-empty
154159
git push
155160
156-
# Checkout the branch created by the sync job,
157-
# and sync all docstrings available on macOS that are not available on Linux or Windows.
158-
# Push the changes to the same branch and create a PR against the `main` branch using that branch.
159-
docstrings-macos-and-pr:
161+
# - Checkout the branch created by the sync job.
162+
# - Sync all docstrings available on macOS that are not available on Linux or Windows.
163+
# - Format the stubs.
164+
# - Apply the typeshed patches.
165+
# - Push the changes to the same branch.
166+
docstrings-macos:
160167
runs-on: macos-latest
161168
timeout-minutes: 20
162169
needs: [sync, docstrings-windows]
@@ -169,7 +176,6 @@ jobs:
169176

170177
permissions:
171178
contents: write # to push back to the repository
172-
pull-requests: write # to create a PR
173179
steps:
174180
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
175181
name: Checkout Ruff
@@ -214,24 +220,110 @@ jobs:
214220
- name: Push synced changes upstream
215221
if: ${{ success() }}
216222
run: git push
217-
- name: Apply typeshed patches
223+
- name: Apply and push typeshed patches
218224
if: ${{ success() }}
219225
run: |
220226
git apply --directory="${VENDORED_TYPESHED}" crates/ty_vendored/typeshed_patches/*.patch
221227
git add "${VENDORED_TYPESHED}"
222228
git commit -m "Apply typeshed patches"
223-
- name: Push changes upstream and create a PR
229+
git push
230+
231+
# Best-effort snapshot update. A failure or timeout here must not prevent PR creation.
232+
update-snapshots:
233+
name: Update snapshots
234+
# Use a beefier depot runner if possible, because Rust compile times are really slow on GitHub runners
235+
runs-on: ${{ github.repository == 'astral-sh/ruff' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }}
236+
timeout-minutes: 20
237+
needs: [sync, docstrings-windows, docstrings-macos]
238+
239+
# Don't run the cron job on forks.
240+
# The job will also be skipped if the docstrings-macos job failed.
241+
if: ${{ github.repository == 'astral-sh/ruff' || github.event_name != 'schedule' }}
242+
243+
# Allow any failure in this best-effort job without failing the overall workflow.
244+
# This does not automatically cause later steps to run after a failure; a step-level
245+
# `continue-on-error: true` is also required for that (which we do below for one of the steps).
246+
continue-on-error: true
247+
248+
permissions:
249+
contents: write # to push back to the repository
250+
steps:
251+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
252+
name: Checkout Ruff
253+
with:
254+
persist-credentials: true
255+
ref: ${{ env.UPSTREAM_BRANCH}}
256+
- name: Setup git
257+
run: |
258+
git config --global user.name typeshedbot
259+
git config --global user.email '<>'
260+
- uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
261+
with:
262+
# Reuse the cache populated by the `cargo test (linux)` CI job on `main`.
263+
shared-key: ruff-linux-debug
264+
# This infrequent workflow should not overwrite the shared cache.
265+
save-if: false
266+
- name: "Install Rust toolchain"
267+
run: rustup show
268+
- name: "Install mold"
269+
uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1
270+
- name: "Install cargo nextest"
271+
uses: taiki-e/install-action@25435dc8dd3baed7417e0c96d3fe89013a5b2e09 # v2.81.3
272+
with:
273+
tool: cargo-nextest
274+
- name: "Install cargo insta"
275+
uses: taiki-e/install-action@25435dc8dd3baed7417e0c96d3fe89013a5b2e09 # v2.81.3
276+
with:
277+
tool: cargo-insta
278+
- name: Update snapshots
279+
# Snapshot failures are force-passed by cargo-insta, but other tests might still fail
280+
# in this test, causing the step overall to fail. We want to continue to later steps
281+
# anyway here, so that snapshots are updated and pushed even if other tests fail.
282+
continue-on-error: true
283+
env:
284+
# Work around https://github.com/mitsuhiko/insta/pull/924 until its fix is released.
285+
CI: "0"
286+
MDTEST_UPDATE_SNAPSHOTS: "1"
287+
run: cargo insta test --accept --all-features --test-runner nextest --disable-nextest-doctest
288+
- name: Commit and push snapshot changes
224289
if: ${{ success() }}
225290
run: |
226-
git push
291+
git add --all
292+
if git diff --cached --quiet; then
293+
echo "No snapshot changes to commit"
294+
else
295+
git commit -m "Update snapshots"
296+
git push
297+
fi
298+
299+
# Publish the required changes even if the best-effort snapshot update failed or timed out.
300+
create-pr:
301+
name: Create PR
302+
runs-on: ubuntu-latest
303+
timeout-minutes: 5
304+
needs: [sync, docstrings-windows, docstrings-macos, update-snapshots]
305+
306+
# update-snapshots is deliberately NOT included here: it shouldn't block PR creation if it fails or times out.
307+
if: ${{ always() && needs.sync.result == 'success' && needs.docstrings-windows.result == 'success' && needs.docstrings-macos.result == 'success' && (github.repository == 'astral-sh/ruff' || github.event_name != 'schedule') }}
308+
309+
permissions:
310+
contents: read
311+
pull-requests: write # to create a PR
312+
steps:
313+
- name: Create a PR
314+
run: |
227315
gh pr list --repo "${GITHUB_REPOSITORY}" --head "${UPSTREAM_BRANCH}" --json id --jq length | grep 1 && exit 0 # exit if there is existing pr
228-
gh pr create --title "[ty] Sync vendored typeshed stubs" --body "Close and reopen this PR to trigger CI" --label "ty"
316+
gh pr create --repo "${GITHUB_REPOSITORY}" --base main --head "${UPSTREAM_BRANCH}" --title "[ty] Sync vendored typeshed stubs" --body "Close and reopen this PR to trigger CI" --label "ty"
229317
230318
create-issue-on-failure:
231319
name: Create an issue if the typeshed sync failed
232320
runs-on: ubuntu-latest
233-
needs: [sync, docstrings-windows, docstrings-macos-and-pr]
234-
if: ${{ github.repository == 'astral-sh/ruff' && always() && github.event_name == 'schedule' && (needs.sync.result != 'success' || needs.docstrings-windows.result != 'success' || needs.docstrings-macos-and-pr.result != 'success') }}
321+
needs: [sync, docstrings-windows, docstrings-macos, create-pr]
322+
323+
# update-snapshots is deliberately NOT included here: it shouldn't block PR creation if it fails or times out,
324+
# so there's no need for the bot to create an issue if that happens.
325+
if: ${{ github.repository == 'astral-sh/ruff' && always() && github.event_name == 'schedule' && (needs.sync.result != 'success' || needs.docstrings-windows.result != 'success' || needs.docstrings-macos.result != 'success' || needs.create-pr.result != 'success') }}
326+
235327
permissions:
236328
issues: write # to create an issue on failure
237329
steps:

0 commit comments

Comments
 (0)