Skip to content

Commit e432cf4

Browse files
committed
Change the dependency workflow to separate PRs
Previously there was only one main workspace; within the past few months, it was split into three (root, library, and rustbook). These workspaces have somewhat different requirements for what can be updated and what may be problematic, and making one large PR for everything doesn't suit this well. Change the jobs to create separate pull requests for each relevant update. This will also make it easier to create a distinct job for bootstrap.
1 parent 612796c commit e432cf4

File tree

2 files changed

+134
-72
lines changed

2 files changed

+134
-72
lines changed

.github/workflows/dependencies.yml

+84-72
Original file line numberDiff line numberDiff line change
@@ -16,119 +16,131 @@ defaults:
1616
env:
1717
# So cargo doesn't complain about unstable features
1818
RUSTC_BOOTSTRAP: 1
19-
PR_TITLE: Weekly `cargo update`
20-
PR_MESSAGE: |
21-
Automation to keep dependencies in `Cargo.lock` current.
22-
23-
The following is the output from `cargo update`:
24-
COMMIT_MESSAGE: "cargo update \n\n"
2519

2620
jobs:
27-
not-waiting-on-bors:
28-
if: github.repository_owner == 'rust-lang'
29-
name: skip if S-waiting-on-bors
30-
runs-on: ubuntu-latest
31-
steps:
32-
- env:
33-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34-
run: |
35-
# Fetch state and labels of PR
36-
# Or exit successfully if PR does not exist
37-
JSON=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json labels,state || exit 0)
38-
STATE=$(echo "$JSON" | jq -r '.state')
39-
WAITING_ON_BORS=$(echo "$JSON" | jq '.labels[] | any(.name == "S-waiting-on-bors"; .)')
40-
41-
# Exit with error if open and S-waiting-on-bors
42-
if [[ "$STATE" == "OPEN" && "$WAITING_ON_BORS" == "true" ]]; then
43-
exit 1
44-
fi
45-
4621
update:
4722
if: github.repository_owner == 'rust-lang'
4823
name: update dependencies
49-
needs: not-waiting-on-bors
5024
runs-on: ubuntu-latest
25+
outputs:
26+
lockfile_keys: ${{ steps.update_script.outputs.lockfile_keys }}
5127
steps:
5228
- name: checkout the source code
5329
uses: actions/checkout@v4
5430
with:
5531
submodules: recursive
32+
5633
- name: install the bootstrap toolchain
5734
run: |
5835
# Extract the stage0 version
59-
TOOLCHAIN=$(awk -F= '{a[$1]=$2} END {print(a["compiler_version"] "-" a["compiler_date"])}' src/stage0)
36+
toolchain=$(awk -F= '{a[$1]=$2} END {print(a["compiler_version"] "-" a["compiler_date"])}' src/stage0)
6037
# Install and set as default
61-
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
62-
rustup default $TOOLCHAIN
38+
rustup toolchain install --no-self-update --profile minimal "$toolchain"
39+
rustup default "$toolchain"
6340
64-
- name: cargo update
65-
# Remove first line that always just says "Updating crates.io index"
66-
run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
67-
- name: cargo update library
41+
- name: run update script
42+
id: update_script
6843
run: |
69-
echo -e "\nlibrary dependencies:" >> cargo_update.log
70-
cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
71-
- name: cargo update rustbook
72-
run: |
73-
echo -e "\nrustbook dependencies:" >> cargo_update.log
74-
cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
75-
- name: upload Cargo.lock artifact for use in PR
76-
uses: actions/upload-artifact@v4
77-
with:
78-
name: Cargo-lock
79-
path: |
80-
Cargo.lock
81-
library/Cargo.lock
82-
src/tools/rustbook/Cargo.lock
83-
retention-days: 1
84-
- name: upload cargo-update log artifact for use in PR
44+
./src/ci/scripts/update-all-lockfiles.sh
45+
46+
# Save a JSON array of all lockfiles for use in other jobs, so we
47+
# don't need to specify them twice
48+
echo "lockfile_keys=$(jq -c 'keys' update_output.json)" >> "$GITHUB_OUTPUT"
49+
50+
- name: upload output file
8551
uses: actions/upload-artifact@v4
8652
with:
87-
name: cargo-updates
88-
path: cargo_update.log
53+
name: update-output
54+
path: update_output.json
8955
retention-days: 1
9056

91-
pr:
57+
check_bors_status:
9258
if: github.repository_owner == 'rust-lang'
93-
name: amend PR
59+
name: check for S-waiting-on-bors
60+
runs-on: ubuntu-latest
9461
needs: update
62+
outputs:
63+
skip_keys: ${{ steps.check_status.outputs.skip_keys }}
64+
steps:
65+
- env:
66+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
67+
LOCKFILE_KEYS: ${{needs.update.outputs.lockfile_keys}}
68+
id: check_status
69+
run: |
70+
# Build a json array of items to skip
71+
skip_keys="[]"
72+
73+
echo "$LOCKFILE_KEYS" | jq -r '.[]' | while read -r name; do
74+
branch="cargo-update-$name"
75+
76+
# Fetch state and labels of PR
77+
# Or exit successfully if PR does not exist
78+
json=$(gh pr view "$branch" --repo "$GITHUB_REPOSITORY" --json labels,state || exit 0)
79+
state=$(echo "$json" | jq -r '.state')
80+
waiting_on_bors=$(echo "$json" | jq '.labels[] | any(.name == "S-waiting-on-bors"; .)')
81+
82+
if [[ "$state" == "OPEN" && "$waiting_on_bors" == "true" ]]; then
83+
# If open and waiting on bors, add the name to the skip array
84+
skip_keys=$(echo "$skip_keys" | jq -c --arg name "$name" '. + [ $name ]')
85+
fi
86+
done
87+
88+
echo "skip_keys=$skip_keys" >> "$GITHUB_OUTPUT"
89+
90+
pr:
91+
name: amend PR
92+
needs: [update, check_bors_status]
93+
strategy:
94+
fail-fast: false
95+
matrix:
96+
name: ${{ fromJson(needs.update.outputs.lockfile_keys) }}
97+
if: >
98+
github.repository_owner == 'rust-lang' &&
99+
!contains(fromJSON(needs.check_bors_status.outputs.skip_keys), matrix.name)
95100
runs-on: ubuntu-latest
96101
permissions:
97102
contents: write
98103
pull-requests: write
104+
env:
105+
PR_TITLE: Weekly ${{ matrix.name }} `cargo update`
106+
BRANCH: cargo-update-${{ matrix.name }}
99107
steps:
100108
- name: checkout the source code
101109
uses: actions/checkout@v4
102110

103-
- name: download Cargo.lock from update job
111+
- name: download output file from update job
104112
uses: actions/download-artifact@v4
105113
with:
106-
name: Cargo-lock
107-
- name: download cargo-update log from update job
108-
uses: actions/download-artifact@v4
109-
with:
110-
name: cargo-updates
114+
name: update-output
111115

112116
- name: craft PR body and commit message
113117
run: |
114-
echo "${COMMIT_MESSAGE}" > commit.txt
115-
cat cargo_update.log >> commit.txt
118+
name="${{ matrix.name }}"
119+
path=$(jq -r ".$name.path" update_output.json)
120+
121+
echo "cargo update ${{ matrix.name }}\n\n" > commit.txt
122+
jq -r ".$name.log" update_output.json >> commit.txt
123+
124+
cat << EOF > body.md
125+
Automation to keep dependencies in \`Cargo.lock\` current.
126+
127+
echo "The following is the output from \`cargo update\` in \`$path\`:
116128
117-
echo "${PR_MESSAGE}" > body.md
118-
echo '```txt' >> body.md
119-
cat cargo_update.log >> body.md
120-
echo '```' >> body.md
129+
\`\`\`text
130+
$(jq -r ".$name.log" update_output.json)
131+
\`\`\`
132+
EOF
121133
122134
- name: commit
123135
run: |
124136
git config user.name github-actions
125137
git config user.email [email protected]
126-
git switch --force-create cargo_update
127-
git add ./Cargo.lock ./library/Cargo.lock ./src/tools/rustbook/Cargo.lock
138+
git switch --force-create "$BRANCH"
139+
git add "$(jq -r '.${{ matrix.name }}.lockfile_path' update_output.json)"
128140
git commit --no-verify --file=commit.txt
129141
130142
- name: push
131-
run: git push --no-verify --force --set-upstream origin cargo_update
143+
run: git push --no-verify --force --set-upstream origin "$BRANCH"
132144

133145
- name: edit existing open pull request
134146
id: edit
@@ -138,16 +150,16 @@ jobs:
138150
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
139151
run: |
140152
# Exit with error if PR is closed
141-
STATE=$(gh pr view cargo_update --repo $GITHUB_REPOSITORY --json state --jq '.state')
142-
if [[ "$STATE" != "OPEN" ]]; then
153+
state=$(gh pr view "$BRANCH" --repo "$GITHUB_REPOSITORY" --json state --jq '.state')
154+
if [[ "$state" != "OPEN" ]]; then
143155
exit 1
144156
fi
145157
146-
gh pr edit cargo_update --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
158+
gh pr edit "$BRANCH" --title "$PR_TITLE" --body-file body.md --repo "$GITHUB_REPOSITORY"
147159
148160
- name: open new pull request
149161
# Only run if there wasn't an existing PR
150162
if: steps.edit.outcome != 'success'
151163
env:
152164
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
153-
run: gh pr create --title "${PR_TITLE}" --body-file body.md --repo $GITHUB_REPOSITORY
165+
run: gh pr create --title "$PR_TITLE" --body-file body.md --repo "$GITHUB_REPOSITORY"
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/bin/bash
2+
# Update multiple lockfiles in the repository and record the changes to
3+
# `update_output.json`.
4+
5+
set -euxo pipefail
6+
7+
# Map `name=path`
8+
lockfiles=(
9+
"root=."
10+
"library=library"
11+
"rustbook=src/tools/rustbook"
12+
)
13+
14+
echo "{}" > update_output.json
15+
16+
for item in "${lockfiles[@]}"; do
17+
name=$(echo "$item" | cut -d= -f1)
18+
path=$(echo "$item" | cut -d= -f2)
19+
manifest="$path/Cargo.toml"
20+
lockfile="$path/Cargo.lock"
21+
22+
echo -e "$name dependencies:" >> cargo_update.log
23+
24+
# Remove first line that always just says "Updating crates.io index"
25+
cargo update --manifest-path "$manifest" 2>&1 |
26+
sed '/crates.io index/d' |
27+
tee -a cargo_update.log
28+
29+
jq -n \
30+
--arg path "$path" \
31+
--arg lockfile_path "$lockfile" \
32+
--rawfile lockfile "$lockfile" \
33+
--rawfile log cargo_update.log \
34+
'{ $path, $lockfile_path, $lockfile, $log }' \
35+
> single_update_output.json
36+
37+
38+
jq -n \
39+
--arg name "$name" \
40+
--slurpfile output update_output.json \
41+
--slurpfile value single_update_output.json \
42+
'$output[0] + { $name: $value[0] }' \
43+
> tmp.json
44+
45+
# No inplace editing with jq...
46+
mv tmp.json update_output.json
47+
48+
rm cargo_update.log
49+
rm single_update_output.json
50+
done

0 commit comments

Comments
 (0)