Skip to content

Commit 451d89f

Browse files
authored
Merge pull request #9 from Kobzol/ci-pull-workflow
Add reusable workflow for performing rustc-pull on CI
2 parents c03ce5e + 115f9e3 commit 451d89f

File tree

2 files changed

+180
-1
lines changed

2 files changed

+180
-1
lines changed

.github/workflows/rustc-pull.yml

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
name: 'Josh Subtree Sync'
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
branch-name:
7+
description: 'Name of the branch to create for the sync'
8+
required: false
9+
default: rustc-pull
10+
type: string
11+
pr-base-branch:
12+
description: 'Base branch for the pull request'
13+
required: false
14+
type: string
15+
default: 'master'
16+
zulip-stream-id:
17+
description: 'Zulip stream ID for notifications'
18+
required: false
19+
type: string
20+
zulip-topic:
21+
description: 'Zulip topic for notifications'
22+
required: false
23+
type: string
24+
default: 'Subtree sync automation'
25+
zulip-bot-email:
26+
description: 'Zulip bot email address'
27+
required: false
28+
type: string
29+
secrets:
30+
token:
31+
description: 'GITHUB_TOKEN from the caller workflow'
32+
required: true
33+
zulip-api-token:
34+
description: 'Zulip API token for authentication'
35+
required: false
36+
37+
jobs:
38+
perform-pull:
39+
runs-on: ubuntu-latest
40+
outputs:
41+
pr_url: ${{ steps.update-pr.outputs.pr_url }}
42+
pull_result: ${{ steps.josh-sync.outputs.pull_result }}
43+
permissions:
44+
contents: write
45+
pull-requests: write
46+
steps:
47+
- uses: actions/checkout@v4
48+
with:
49+
fetch-depth: '0'
50+
51+
- name: Install stable Rust toolchain
52+
run: rustup update stable
53+
54+
- uses: Swatinem/rust-cache@v2
55+
with:
56+
cache-directories: "/home/runner/.cache/rustc-josh"
57+
58+
- name: Setup bot git name and email
59+
run: |
60+
git config --global user.name 'The rustc-josh-sync Cronjob Bot'
61+
git config --global user.email '[email protected]'
62+
63+
- name: Install rustc-josh-sync
64+
run: cargo install --locked --git https://github.com/rust-lang/josh-sync
65+
66+
- name: Perform josh sync
67+
id: josh-sync
68+
shell: bash {0}
69+
run: |
70+
rustc-josh-sync pull
71+
exitcode=$?
72+
73+
if [ $exitcode -eq 0 ]; then
74+
echo "pull_result=pull-finished" >> $GITHUB_OUTPUT
75+
elif [ $exitcode -eq 2 ]; then
76+
echo "pull_result=skipped" >> $GITHUB_OUTPUT
77+
exitcode=0
78+
else
79+
echo "pull_result=failed" >> $GITHUB_OUTPUT
80+
fi
81+
82+
exit ${exitcode}
83+
84+
- name: Push changes to a branch
85+
if: ${{ steps.josh-sync.outputs.pull_result == 'pull-finished' }}
86+
run: |
87+
BRANCH="${{ inputs.branch-name }}"
88+
git switch -c $BRANCH
89+
git push -u origin $BRANCH --force
90+
91+
- name: Create pull request
92+
id: update-pr
93+
if: ${{ steps.josh-sync.outputs.pull_result == 'pull-finished' }}
94+
env:
95+
GITHUB_TOKEN: ${{ secrets.token }}
96+
run: |
97+
# Check if an open pull request already exists
98+
RESULT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | length' --json title`
99+
if [[ "$RESULT" -eq 0 ]]; then
100+
echo "Creating new pull request"
101+
PR_URL=`gh pr create -B ${{ inputs.pr-base-branch }} --title 'Rustc pull update' --body 'Latest update from rustc.'`
102+
echo "Created pull request ${PR_URL}"
103+
echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
104+
else
105+
PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title`
106+
echo "Updating pull request ${PR_URL}"
107+
echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
108+
fi
109+
110+
send-zulip-notification:
111+
needs: [ perform-pull ]
112+
if: ${{ !cancelled() && inputs.zulip-stream-id != '' }}
113+
runs-on: ubuntu-latest
114+
steps:
115+
- uses: actions/checkout@v4
116+
117+
- name: Compute message
118+
id: create-message
119+
env:
120+
GITHUB_TOKEN: ${{ secrets.token }}
121+
run: |
122+
if [ "${{ needs.perform-pull.result }}" == "failure" ]; then
123+
WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
124+
echo "message=Josh subtree sync failed. Check out the [workflow URL]($WORKFLOW_URL)." >> $GITHUB_OUTPUT
125+
else
126+
CREATED_AT=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].createdAt' --json createdAt,title`
127+
PR_URL=`gh pr list --author github-actions[bot] --state open -q 'map(select(.title=="Rustc pull update")) | .[0].url' --json url,title`
128+
week_ago=$(date +%F -d '7 days ago')
129+
130+
# If there is an open PR that is at least a week old, post a message about it
131+
if [[ -n $CREATED_AT && $CREATED_AT < $week_ago ]]; then
132+
echo "message=A PR with a josh subtree sync has been opened for more than a week. Check out the [PR](${PR_URL})." >> $GITHUB_OUTPUT
133+
fi
134+
fi
135+
136+
- name: Send Zulip message
137+
if: ${{ steps.create-message.outputs.message != '' }}
138+
uses: zulip/github-actions-zulip/send-message@e4c8f27c732ba9bd98ac6be0583096dea82feea5
139+
with:
140+
api-key: ${{ secrets.zulip-api-token }}
141+
email: ${{ secrets.zulip-bot-email }}
142+
organization-url: "https://rust-lang.zulipchat.com"
143+
to: ${{ inputs.zulip-stream-id }}
144+
type: "stream"
145+
topic: ${{ inputs.zulip-topic }}
146+
content: ${{ steps.create-message.outputs.message }}

README.md

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,40 @@ A push operation takes changes performed in the subtree repository and merges th
3636
- The branch with the push contents will be created in `https://github.com/<your-github-username>/rust` fork, in the `<branch>` branch.
3737
3) Send a PR to [rust-lang/rust]
3838

39+
## Automating pulls on CI
40+
41+
This repository contains a reusable workflow for performing the `pull` operation from CI. The workflow does the following:
42+
43+
1) Installs `rustc-josh-sync` and `josh`
44+
2) Performs a `pull` operation
45+
3) Either creates a new PR (if it did not exist) with the resulting pull branch or force-pushes to an existing PR on the subtree repository
46+
4) (optional) If a failure (usually a merge conflict) has happened, or a PR has been opened for more than a week without a merge, it posts a message to a Zulip stream
47+
48+
Here is an example of how you can use the workflow in a subtree repository:
49+
50+
```yaml
51+
name: rustc-pull
52+
53+
on:
54+
workflow_dispatch:
55+
schedule:
56+
# Run at 04:00 UTC every Monday and Thursday
57+
- cron: '0 4 * * 1,4'
58+
59+
jobs:
60+
pull:
61+
uses: rust-lang/josh-sync/.github/workflows/rustc-pull.yml@master
62+
with:
63+
# If you want the Zulip post functionality
64+
#zulip-stream-id: 1234 # optional
65+
#zulip-bot-email: [email protected] # optional
66+
pr-base-branch: master # optional
67+
branch-name: rustc-pull # optional
68+
secrets:
69+
#zulip-api-token: <Zulip API TOKEN> # optional
70+
token: ${{ secrets.GITHUB_TOKEN }}
71+
```
72+
3973
## Git peculiarities
4074
4175
NOTE: If you use Git/SSH protocol to push to your fork of [rust-lang/rust],
@@ -59,5 +93,4 @@ To minimize the likelihood of this happening, you may wish to keep a separate *m
5993
GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' rustc-josh-sync ...
6094
```
6195

62-
6396
[rust-lang/rust]: (https://github.com/rust-lang/rust)

0 commit comments

Comments
 (0)