-
Notifications
You must be signed in to change notification settings - Fork 1
/
action.yml
376 lines (357 loc) · 14.2 KB
/
action.yml
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
name: 'Update CIRCT'
description: 'Update the version of llvm/circt used by a downstream project'
branding:
icon: 'git-pull-request'
color: 'green'
inputs:
user:
description: |
The name that will be associated with any created commits
type: string
required: true
email:
description: |
The email address that will be associated with any created commits
type: string
required: true
pr-reviewers:
description: |
A comma or newline separate list of reviewers for the created Pull
Request
type: string
pr-labels:
description: |
A comma or newline separated list of labels to apply to the created
Pull Request
type: string
staging-branch:
description: |
The name of the branch containing accumulated patches that need to be
applied in order for the latest CIRCT to work with Chisel.
type: string
default: 'ci/ci-circt-nightly'
circt-config:
description: |
The location, within the downstream project repository, of the
configuration file which sets the CIRCT version. This workflow assumes
that this is a JSON object containing a key "version".
type: string
default: './etc/circt.json'
should-create-pr:
description: |
An optional script to decide whether to open the Pull Request or not.
The script must accept a single positional argument (the new CIRCT
version). The script is only run when there is a new version of CIRCT. A
return value of 0 means "open the PR". A return value of 1 means "do not
open the PR". Any other return value will cause the action to exit with
an error. Note, the default value 'true' is the shell built-in, not a
boolean value.
type: string
default: 'true'
github-token:
description: |
A GitHub token with sufficient permissions to create Pull Requests
type: string
required: true
default: ${{ github.token }}
runs:
using: composite
steps:
############################################################################
# These steps examine the upstream project (llvm/circt) and the downstream
# project (the repository in which this action runs) to determine:
#
# 1. the version of the upstream project that the downstream project is
# using
# 2. the latest version of the upstream project that is available
#
# This job has to do a non-shallow checkout of both the upstream and
# downstream projects because it must examine tags.
############################################################################
- name: Clone Downstream Repository
uses: actions/checkout@v4
with:
fetch-depth: 0
path: downstream
- name: Clone Upstream Repository (llvm/circt)
uses: actions/checkout@v4
with:
fetch-depth: 0
repository: llvm/circt
path: circt
- name: Get Current Tag
id: get-version-current
shell: bash
run: |
cd downstream/
VERSION=$(jq -r '.version' < ${{ inputs.circt-config }})
echo version=$VERSION >> $GITHUB_OUTPUT
echo Current version is: \`$VERSION\` >> $GITHUB_STEP_SUMMARY
- name: Get Latest Tag
id: get-version-latest
shell: bash
run: |
cd circt/
VERSION=$(git tag --list 'firtool-*' | tail -n1)
echo version=$VERSION >> $GITHUB_OUTPUT
echo Latest version is: \`$VERSION\` >> $GITHUB_STEP_SUMMARY
- name: Decide whether or not to open PR
id: open-pr
shell: bash
run: |
cd downstream
VERSION=${{ steps.get-version-latest.outputs.version }}
if [[ ${{ steps.get-version-current.outputs.version }} == "$VERSION" ]]; then
echo "::notice::Current version ($VERSION) == latest version, skipping PR creation..."
echo "result=false" >> $GITHUB_OUTPUT
exit 0
fi
if $(${{ inputs.should-create-pr }} "$VERSION"); then
RESULT="0"
else
RESULT=$?
fi
if [[ "$RESULT" -eq "0" ]]; then
echo "result=true" >> $GITHUB_OUTPUT
elif [[ "$RESULT" -eq "1" ]]; then
echo "::notice::User provided ${{ inputs.should-create-pr }} returned 1, skipping PR creation..."
echo "result=false" >> $GITHUB_OUTPUT
else
echo "::error::User provided ${{ inputs.should-create-pr }} returned $RESULT, aborting..."
exit 1
fi
############################################################################
# The rest of this action handles bumping the CIRCT version if a new version
# is available. Logically, this does the following three actions:
#
# 1. Cherry-pick all commits from the staging branch onto a new "compare"
# branch [1].
# 2. Create a new commit that updates the CIRCT version.
# 3. Create a new or update an existing Pull Request (PR) that merges this
# branch with all changes into the `main` "base" branch [2] on GitHub.
#
# These logical steps are facilitated by a prerequisite step that assembles
# a bunch of JSON metadata about what is about to be done. This JSON
# metadata is used to drive the cherry-pick action of (1), the commit
# message of (2), and the PR title and body of (3).
#
# [1]: "compare" is GitHub lingo for "the branch with your changes".
# [2]: "base" is GitHub lingo for "the branch without your changes".
############################################################################
- name: Create PR Metadata
if: steps.open-pr.outputs.result == 'true'
shell: bash
# Write a JSON object to the temporary file `metadata/metadata.json` that
# contains information about what this job is going to do. Populate four
# members:
#
# - "current": a string of the current upstream project release used by
# the downstream project
# - "latest": a string of the latest upstream project release
# - "stagingBranch": the staging branch
# - "releases": an array of releases that will be included
# - "commits": an array of commit objects that will be cherry-picked
#
# As an example, if this step is run where CIRCT will be bumped from
# 1.49.0 (current version) to 1.50.0 (latest version, the JSON object
# could look like:
#
# {
# "current": "firtool-1.48.0",
# "latest": "firtool-1.50.0",
# "stagingBranch" : "ci/ci-circt/nigthly",
# "release" : [
# {
# "text": "firtool-1.49.0",
# "url": "https://github.com/llvm/circt/releases/tag/firtool-1.49.0"
# },
# {
# "text": "firtool-1.50.0",
# "url": "https://github.com/llvm/circt/releases/tag/firtool-1.50.0"
# }
# ],
# "commits": [
# {
# "checksum": "deadbeef",
# "title": "Fixed a command line option that changed"
# },
# {
# "checksum": "0badf00d",
# "title": "Fixed a test which now passes"
# }
# ]
# }
#
# Additionally, Copy the update-circt PR template files into an
# update-circt/ directory. These need to be put in a location that the
# Pandoc Docker container will bind mount. (The actual location is not
# bound!)
run: |
NEW_TAGS=$(
cd circt/ && \
git tag --contains=${{ steps.get-version-current.outputs.version }} | \
tail -n +2
)
JSON=$(
echo '{ "current": "", "latest": "", "stagingBranch": "", "releases": [], "commits": [] }' |
jq \
--arg a ${{ steps.get-version-current.outputs.version }} \
--arg b ${{ steps.get-version-latest.outputs.version }} \
--arg c ${{ inputs.staging-branch }} \
'.current = $a | .latest = $b | .stagingBranch = $c'
)
for tag in $NEW_TAGS; do
URL=$(
curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: ${{ inputs.github-token }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/llvm/circt/releases/tags/$tag | \
jq -r '.html_url'
)
JSON=$(
echo $JSON | \
jq --arg a $tag \
--arg b $URL \
'.releases += [{"text": $a, "url": $b}]'
)
done
cd downstream/
if [[ `git rev-parse --verify origin/${{ inputs.staging-branch }} 2> /dev/null` ]]; then
MERGE_BASE=$(git merge-base HEAD origin/${{ inputs.staging-branch }})
COMMITS=$(git rev-list --reverse $MERGE_BASE..origin/${{ inputs.staging-branch }})
for commit in $COMMITS; do
TITLE=$(git log --pretty=format:%s -n1 $commit)
JSON=$(
echo $JSON | \
jq --arg a $commit \
--arg b "$TITLE" \
'.commits += [{"checksum": $a, "title": $b}]'
)
done
fi
cd ../
mkdir metadata/
echo $JSON | jq -c > metadata/metadata.json
echo "# Pandoc Metadata File" >> $GITHUB_STEP_SUMMARY
echo \`\`\`json >> $GITHUB_STEP_SUMMARY
echo $JSON | jq >> $GITHUB_STEP_SUMMARY
echo \`\`\` >> $GITHUB_STEP_SUMMARY
mkdir update-circt/
cp ${{ github.action_path }}/*.md update-circt/.
# The next three steps use pandoc [3] to populate templates for:
#
# 1. The PR title
# 2. The PR body
# 3. The message of the commit that bumps CIRCT
#
# The templates are defined in the `.github/workflows/cd-circt/` directory.
#
# [3]: https://pandoc.org/
- name: Generate PR Title
if: steps.open-pr.outputs.result == 'true'
uses: docker://pandoc/core
with:
args: >-
--metadata-file=metadata/metadata.json
--template update-circt/pr-title.md
--from=markdown
--wrap=none
-o metadata/pr-title.md
/dev/null
- name: Generate PR Body
if: steps.open-pr.outputs.result == 'true'
uses: docker://pandoc/core
with:
args: >-
--metadata-file=metadata/metadata.json
--template update-circt/pr-body.md
--from=markdown
--wrap=none
-o metadata/pr-body.md
/dev/null
- name: Generate Commit Message
if: steps.open-pr.outputs.result == 'true'
uses: docker://pandoc/core
with:
args: >-
--metadata-file=metadata/metadata.json
--template update-circt/commit-message.md
--from=markdown
-o metadata/commit-message.md
/dev/null
# Print the populated pandoc templates to the GitHub Actions step summary.
# (These will print on the "Summary" of a run of this Action.)
- name: Show Metadata
if: steps.open-pr.outputs.result == 'true'
shell: bash
run: |
echo "# PR Title" >> $GITHUB_STEP_SUMMARY
cat metadata/pr-title.md >> $GITHUB_STEP_SUMMARY
echo "# PR Body" >> $GITHUB_STEP_SUMMARY
cat metadata/pr-body.md >> $GITHUB_STEP_SUMMARY
echo "# Commit Message" >> $GITHUB_STEP_SUMMARY
cat metadata/commit-message.md >> $GITHUB_STEP_SUMMARY
# Using the information in the JSON Metadata, cherry-pick all commits from
# the staging branch.
- name: Cherry Pick Staging Branch Commits
if: steps.open-pr.outputs.result == 'true'
shell: bash
run: |
cd downstream/
git checkout main
git config user.name ${{ inputs.user }}
git config user.email ${{ inputs.email }}
COMMITS=$(jq -r '.commits[].checksum' < ../metadata/metadata.json)
for commit in $COMMITS; do
git cherry-pick $commit
done
# Create unstaged changes that updates the CIRCT version to "latest".
- name: Update Downstream Project to Latest Upstream Release
if: steps.open-pr.outputs.result == 'true'
shell: bash
run: |
cd downstream/
jq '.version = "${{ steps.get-version-latest.outputs.version }}"' < ${{ inputs.circt-config }} > ../metadata/tmp.json
mv ../metadata/tmp.json ${{ inputs.circt-config }}
# Put the pandoc-created PR title and commit message into step outputs so
# that we can pass these to the peter-evans/create-pull-request composite
# action in the next step. Pass the commit message using a HereDoc (as
# GitHub suggests [4]) so that this will show up in a multi-line format
# correctly. Use a unique HereDoc delimiter to avoid collisions with
# anything which may be in the commit message.
#
# The PR body is passed as a file in the next step because the
# peter-evans/create-pull-request composite action supports it.
#
# [4]: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings
- name: Setup Environment with Metadata
if: steps.open-pr.outputs.result == 'true'
id: setup-env
shell: bash
run: |
echo pr-title=$(cat metadata/pr-title.md) >> $GITHUB_OUTPUT
EOF=$(dd if=/dev/urandom bs=1k count=1 2>/dev/null | base64 --wrap=128 -i | head -n8 | tail -n1)
echo $EOF
{
echo "commit-message<<$EOF"
cat metadata/commit-message.md
echo $EOF
} >> $GITHUB_OUTPUT
# Commit unstaged changes, create or update the PR, notify reviewers, and
# add labels.
- name: Create PR
if: steps.open-pr.outputs.result == 'true'
id: create-pr
uses: peter-evans/create-pull-request@v6
with:
path: downstream
token: ${{ inputs.github-token }}
branch: cd/update-circt-from-${{ steps.get-version-current.outputs.version }}-to-${{ steps.get-version-latest.outputs.version }}
author: ${{ inputs.user }} <${{ inputs.email }}>
committer: ${{ inputs.user }} <${{ inputs.email }}>
reviewers: ${{ inputs.pr-reviewers }}
title: ${{ steps.setup-env.outputs.pr-title }}
body-path: metadata/pr-body.md
commit-message: ${{ steps.setup-env.outputs.commit-message }}
labels: ${{ inputs.pr-labels }}