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    if: "github.repository == 'bytecodealliance/wasmtime' || !github.event.schedule"
38    name: Run the release process
39    runs-on: ubuntu-latest
40    steps:
41      - uses: actions/checkout@v4
42        with:
43          submodules: true
44      - name: Setup
45        run: |
46          rustc scripts/publish.rs
47          git config user.name 'Wasmtime Publish'
48          git config user.email '[email protected]'
49          git remote set-url origin https://git:${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/${{ github.repository }}
50
51      - uses: ./.github/actions/install-rust
52      - uses: ./.github/actions/install-cargo-vet
53
54      - name: Bump major version number
55        run: |
56          set -ex
57          # Push the current contents of `main` to a new release branch
58          cur=$(./ci/print-current-version.sh)
59          git push origin HEAD:release-$cur
60
61          # Update version numbers and make a commit indicating that. Note that
62          # on merge this will not trigger a publish.
63          ./publish bump
64          num=$(./ci/print-current-version.sh)
65
66          # Remove all release notes for the current version now that the
67          # release branch has been created. Additionally add an entry in the
68          # list of all versions pointing to the release notes on the newly
69          # created branch.
70          sed -i '0,/-----------/d' RELEASES.md
71          version_with_trailing_x=$(echo $cur | sed 's/.$/x/')
72          sed -i "/ARCHIVE_START/a * [$version_with_trailing_x](https://github.com/${{ github.repository }}/blob/release-$cur/RELEASES.md)" RELEASES.md
73
74          # Use `RELEASES-template.md` as the new release notes and then append
75          # the archive of all historical releases to the end of it.
76          cp RELEASES.md backup-releases
77          sed "s/VERSION/$num/" ci/RELEASES-template.md > RELEASES.md
78          cat backup-releases >> RELEASES.md
79          rm backup-releases
80
81          # Update `cargo vet` entries for all the new crate versions
82          cargo vet
83
84          # Commit all of the above changes.
85          git commit -am "Bump Wasmtime to $num"
86
87          # Push the result to a branch and setup metadata for the step below
88          # that creates a PR
89          git push origin HEAD:ci/bump-to-$num
90          echo "PR_HEAD=ci/bump-to-$num" >> $GITHUB_ENV
91          echo "PR_TITLE=Bump Wasmtime to $num" >> $GITHUB_ENV
92          echo "PR_BASE=main" >> $GITHUB_ENV
93          cat > pr-body <<-EOF
94          This is an [automated pull request][process] from CI which indicates that the next [\`release-$cur\` branch][branch] has been created and the \`main\` branch is getting its version number bumped from $cur to $num.
95
96          Maintainers should take a moment to review the [release notes][RELEASES.md] for $cur and any updates should be made directly to the [release branch][branch].
97
98          Another automated PR will be made in roughly 2 weeks time when for the actual release itself.
99
100          If any issues arise on the \`main\` branch before the release is made then the issue should first be fixed on \`main\` and then backport to the \`release-$cur\` branch.
101
102          [RELEASES.md]: https://github.com/${{ github.repository }}/blob/release-$cur/RELEASES.md
103          [branch]: https://github.com/${{ github.repository }}/tree/release-$cur
104          [process]: https://docs.wasmtime.dev/contributing-release-process.html
105          EOF
106        if: >-
107          github.event.schedule == '0 0 5 * *' ||
108          github.event.inputs.action == 'cut'
109
110      - name: Perform latest release
111        run: |
112          set -ex
113          git fetch origin
114
115          # Determine the latest release branch
116          rustc ci/find-latest-release.rs -o /tmp/find-latest-release
117          cur=`/tmp/find-latest-release`
118
119          # Move to the most recent release branch, update the release date and
120          # commit it, indicating that the commit is what will get tagged and
121          # released
122          git reset --hard origin/release-$cur
123          git submodule update --init --recursive
124          sed -i "s/^Unreleased/Released $(date +'%Y-%m-%d')/" RELEASES.md
125          git commit --allow-empty -a -F-<<EOF
126          Release Wasmtime $cur
127
128          [automatically-tag-and-release-this-commit]
129          EOF
130
131          # Push the result to a branch and setup metadata for the step below
132          # that creates a PR
133          git push origin HEAD:ci/release-$cur
134          echo "PR_HEAD=ci/release-$cur" >> $GITHUB_ENV
135          echo "PR_TITLE=Release Wasmtime $cur" >> $GITHUB_ENV
136          echo "PR_BASE=release-$cur" >> $GITHUB_ENV
137          cat > pr-body <<-EOF
138          This is an [automated pull request][process] from CI which is intended to notify maintainers that it's time to release Wasmtime $cur. The [release branch][branch] was created roughly two weeks ago and it's now time for it to be published and released.
139
140          It's recommended that maintainers double-check that [RELEASES.md] is up-to-date and that there are no known issues before merging this PR. When this PR is merged a release tag will automatically created, crates will be published, and CI artifacts will be produced.
141
142          [RELEASES.md]: https://github.com/${{ github.repository }}/blob/release-$cur/RELEASES.md
143          [process]: https://docs.wasmtime.dev/contributing-release-process.html
144          [branch]: https://github.com/${{ github.repository }}/tree/release-$cur
145          EOF
146        if: >-
147          github.event.schedule == '0 0 20 * *' ||
148          github.event.inputs.action == 'release-latest'
149
150      - name: Bump and release patch version number
151        run: |
152          set -ex
153          # Update version numbers on a patch basis and update RELEASES.md if a
154          # patch release marker is already in there. Note that this commit
155          # message indicates that on-merge a release will be made.
156          ./publish bump-patch
157          # Update `cargo vet` entries for all the new crate versions
158          cargo vet
159          sed -i "s/^Unreleased/Released $(date +'%Y-%m-%d')/" RELEASES.md
160          num=$(./ci/print-current-version.sh)
161          git commit -a -F-<<EOF
162          Release Wasmtime $num
163
164          [automatically-tag-and-release-this-commit]
165          EOF
166
167          # Push the result to a branch and setup metadata for the step below
168          # that creates a PR
169          git push origin HEAD:ci/bump-to-$num
170          echo "PR_HEAD=ci/bump-to-$num" >> $GITHUB_ENV
171          echo "PR_TITLE=Release Wasmtime $num" >> $GITHUB_ENV
172          echo "PR_BASE=${{ github.ref_name }}" >> $GITHUB_ENV
173          cat > pr-body <<-EOF
174          This is an [automated pull request][process] from CI to create a patch release for Wasmtime $num, requested by @${{ github.actor }}.
175
176          It's recommended that maintainers double-check that [RELEASES.md] is up-to-date and that there are no known issues before merging this PR. When this PR is merged a release tag will automatically be created, crates will be published, and CI artifacts will be produced.
177
178          [RELEASES.md]: https://github.com/${{ github.repository }}/blob/release-$num/RELEASES.md
179          [process]: https://docs.wasmtime.dev/contributing-release-process.html
180          EOF
181
182        if: github.event.inputs.action == 'release-patch'
183
184      - name: Make a PR
185        # Note that the syntax here is kinda funky, and the general gist is that
186        # I couldn't figure out a good way to have a multiline string-literal
187        # become a json-encoded string literal to send to GitHub. This
188        # represents my best attempt.
189        run: |
190          set -ex
191          body=$(jq -sR < ./pr-body)
192
193          curl --include --request POST \
194            https://api.github.com/repos/${{ github.repository }}/pulls \
195            --header "Authorization: token ${{ secrets.PERSONAL_ACCESS_TOKEN }}" \
196            --data @- << EOF
197          {
198            "head": "$PR_HEAD",
199            "base": "$PR_BASE",
200            "title": "$PR_TITLE",
201            "body": $body,
202            "maintainer_can_modify": true
203
204          }
205          EOF
206