1# The purpose of this workflow is to orchestrate Wasmtime's release process as
2# much as possible. This specific workflow is responsible for a few timed parts
3# of the process:
4#
5# * On the 5th of every month a new release branch is automatically created and
6#   the version number of the `main` branch is increased
7# * On the 20th of every month the previous release branch is published.
8#
9# This automation is all done through PRs except for the creation of the release
10# branch itself which is an write-action performed by this script. Otherwise
11# humans are ideally reviewing and rubber-stamping the output of the script all
12# other steps of the way.
13#
14# Note that this script also helps manage patch releases by sending a PR to the
15# release branch with a bumped version number for all crates with a patch-bump.
16
17name: "Automated Release Process"
18on:
19  schedule:
20    # “At 00:00 on day-of-month 5.”
21    #
22    # https://crontab.guru/#0_0_5_*_*
23    - cron: '0 0 5 * *'
24    - cron: '0 0 20 * *'
25
26  # Allow manually triggering this request via the button at
27  # https://github.com/bytecodealliance/wasmtime/actions/workflows/release-process.yml
28  workflow_dispatch:
29    inputs:
30      action:
31        description: 'Publish script argument: "cut", "release-latest", or "release-patch"'
32        required: false
33        default: 'cut'
34
35jobs:
36  release_process:
37    name: Run the release process
38    runs-on: ubuntu-latest
39    steps:
40      - uses: actions/checkout@v2
41        with:
42          submodules: true
43      - name: Setup
44        run: |
45          rustc scripts/publish.rs
46          git config user.name 'Wasmtime Publish'
47          git config user.email '[email protected]'
48          git remote set-url origin https://git:${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/${{ github.repository }}
49
50      - name: Bump major version number
51        run: |
52          # Push the current contents of `main` to a new release branch
53          cur=$(./ci/print-current-version.sh)
54          git push origin HEAD:release-$cur
55
56          # Update version numbers and make a commit indicating that. Note that
57          # on merge this will not trigger a publish.
58          ./publish bump
59          num=$(./ci/print-current-version.sh)
60
61          # Add a new section to the release notes for the new version.
62          cp RELEASES.md backup-releases
63          sed "s/VERSION/$num/" ci/RELEASES-template.md > RELEASES.md
64          cat backup-releases >> RELEASES.md
65          rm backup-releases
66
67          # Commit all of the above changes.
68          git commit -am "Bump Wasmtime to $num"
69
70          # Push the result to a branch and setup metadata for the step below
71          # that creates a PR
72          git push origin HEAD:ci/bump-to-$num
73          echo "PR_HEAD=ci/bump-to-$num" >> $GITHUB_ENV
74          echo "PR_TITLE=Bump Wasmtime to $num" >> $GITHUB_ENV
75          echo "PR_BASE=main" >> $GITHUB_ENV
76          cat > pr-body <<-EOF
77          This is an [automated pull request][process] from CI which indicates
78          that the next [\`release-$cur\` branch][branch] has been created and
79          the \`main\` branch is getting its version number bumped from $cur to
80          $num.
81
82          Maintainers should take a moment to review the [release
83          notes][RELEASES.md] for $cur, and if any changes are necessary send
84          PRs to the \`main\` branch to update [RELEASES.md] and then backport
85          these PRs to the [release branch][branch].
86
87          Maintainers should also review that aarch64-apple-darwin builds
88          are passing via [embark's CI](https://buildkite.com/embark-studios/wasmtime-aarch64-apple-darwin).
89
90          Another automated PR will be made in roughly 2 weeks time when for
91          the actual release itself.
92
93          If any issues arise on the \`main\` branch before the release is made
94          then the issue should first be fixed on \`main\` and then backported
95          to the \`release-$cur\` branch.
96
97          [RELEASES.md]: https://github.com/${{ github.repository }}/blob/main/RELEASES.md
98          [branch]: https://github.com/${{ github.repository }}/tree/release-$cur
99          [process]: https://docs.wasmtime.dev/contributing-release-process.html
100          EOF
101        if: >-
102          github.event.schedule == '0 0 5 * *' ||
103          github.event.inputs.action == 'cut'
104
105      - name: Perform latest release
106        run: |
107          git fetch origin
108          cur=$(git for-each-ref --sort=-committerdate refs/remotes/origin --format '%(refname)' | grep release | head -n 1 | sed 's/.*release-//')
109
110          # Update the release date for $cur on the `main` branch. Note that the
111          # sed here is a little complicated because we will have two entries in
112          # `RELEASES.md`, one for $cur+1 which `main` is at plus one for $cur
113          # which we're about to release. We only want to update the release
114          # date of the second one.
115          sed -i "/^##.*$cur/,+3 s/^Unreleased/Released $(date +'%Y-%m-%d')/" RELEASES.md
116          git commit -a -F-<<EOF
117          Update release date of Wasmtime $cur
118
119          [skip ci]
120          EOF
121          git push origin HEAD:ci/release-date-for-$cur
122
123          # In addition to the PR we'll make below to perform the actual release
124          # make a second PR to the `main` branch to note the release date in
125          # the release notes.
126          cat > pr-body <<-EOF
127          This is an [automated pull request][process] from CI which is updating
128          the release date of Wasmtime $cur to today. This PR's base branch
129          is \`main\` and a second PR will be coming to perform the actual
130          release which will be targeted at \`release-$cur\`.
131
132          [process]: https://docs.wasmtime.dev/contributing-release-process.html
133          EOF
134          body=$(jq -sR < ./pr-body)
135          curl --include --request POST \
136            https://api.github.com/repos/${{ github.repository }}/pulls \
137            --header "Authorization: token ${{ secrets.PERSONAL_ACCESS_TOKEN }}" \
138            --data @- << EOF
139          {
140            "head": "ci/release-date-for-$cur",
141            "base": "main",
142            "title": "Update release date of Wasmtime $cur",
143            "body": $body,
144            "maintainer_can_modify": true
145          }
146          EOF
147
148          # Move to the most recent release branch, update the release date and
149          # commit it, indicating that the commit is what will get tagged and
150          # released
151          git reset --hard origin/release-$cur
152          sed -i "s/^Unreleased/Released $(date +'%Y-%m-%d')/" RELEASES.md
153          git commit -a -F-<<EOF
154          Release Wasmtime $cur
155
156          [automatically-tag-and-release-this-commit]
157          EOF
158
159          # Push the result to a branch and setup metadata for the step below
160          # that creates a PR
161          git push origin HEAD:ci/release-$cur
162          echo "PR_HEAD=ci/release-$cur" >> $GITHUB_ENV
163          echo "PR_TITLE=Release Wasmtime $cur" >> $GITHUB_ENV
164          echo "PR_BASE=release-$cur" >> $GITHUB_ENV
165          cat > pr-body <<-EOF
166          This is an [automated pull request][process] from CI which is
167          intended to notify maintainers that it's time to release Wasmtime
168          $cur. The [release branch][branch] was created roughly two weeks ago
169          and it's now time for it to be published and released.
170
171          It's recommended that maintainers double-check that [RELEASES.md]
172          is up-to-date and that there are no known issues before merging this
173          PR. When this PR is merged a release tag will automatically be
174          created, crates will be published, and CI artifacts will be produced.
175
176          [RELEASES.md]: https://github.com/${{ github.repository }}/blob/main/RELEASES.md
177          [process]: https://docs.wasmtime.dev/contributing-release-process.html
178          [branch]: https://github.com/${{ github.repository }}/tree/release-$cur
179          EOF
180        if: >-
181          github.event.schedule == '0 0 20 * *' ||
182          github.event.inputs.action == 'release-latest'
183
184      - name: Bump and release patch version number
185        run: |
186          # Update version numbers on a patch basis and update RELEASES.md if a
187          # patch release marker is already in there. Note that this commit
188          # message indicates that on-merge a release will be made.
189          ./publish bump-patch
190          sed -i "s/^Unreleased/Released $(date +'%Y-%m-%d')/" RELEASES.md
191          num=$(./ci/print-current-version.sh)
192          git commit -a -F-<<EOF
193          Release Wasmtime $num
194
195          [automatically-tag-and-release-this-commit]
196          EOF
197
198          # Push the result to a branch and setup metadata for the step below
199          # that creates a PR
200          git push origin HEAD:ci/bump-to-$num
201          echo "PR_HEAD=ci/bump-to-$num" >> $GITHUB_ENV
202          echo "PR_TITLE=Release Wasmtime $num" >> $GITHUB_ENV
203          echo "PR_BASE=${{ github.ref_name }}" >> $GITHUB_ENV
204          cat > pr-body <<-EOF
205          This is an [automated pull request][process] from CI to create a patch
206          release for Wasmtime $num, requested by @${{ github.actor }}.
207
208          It's recommended that maintainers double-check that [RELEASES.md]
209          is up-to-date and that there are no known issues before merging this
210          PR. When this PR is merged a release tag will automatically be
211          created, crates will be published, and CI artifacts will be produced.
212
213          [RELEASES.md]: https://github.com/${{ github.repository }}/blob/main/RELEASES.md
214          [process]: https://docs.wasmtime.dev/contributing-release-process.html
215          EOF
216
217        if: github.event.inputs.action == 'release-patch'
218
219      - name: Make a PR
220        # Note that the syntax here is kinda funky, and the general gist is that
221        # I couldn't figure out a good way to have a multiline string-literal
222        # become a json-encoded string literal to send to GitHub. This
223        # represents my best attempt.
224        run: |
225          body=$(jq -sR < ./pr-body)
226
227          curl --include --request POST \
228            https://api.github.com/repos/${{ github.repository }}/pulls \
229            --header "Authorization: token ${{ secrets.PERSONAL_ACCESS_TOKEN }}" \
230            --data @- << EOF
231          {
232            "head": "$PR_HEAD",
233            "base": "$PR_BASE",
234            "title": "$PR_TITLE",
235            "body": $body,
236            "maintainer_can_modify": true
237
238          }
239          EOF
240