Skip to content

Commit 22b1d89

Browse files
authored
ci: document and script the release process (#295)
Previously, the release process for wasi-sdk was undocumented and manual. The `RELEASING.md` document in this commit describes the steps necessary to publish a new version of `wasi-sdk` as a GitHub release and provides helpful scripts to automate some of the steps. With this in place, a future change could add a workflow trigger that allows running the steps automatically in GitHub actions. Keeping the steps as scripts in the repository, however, allows developers to re-run steps themselves in the (likely) case that something goes awry.
1 parent 7ef7e94 commit 22b1d89

File tree

5 files changed

+276
-7
lines changed

5 files changed

+276
-7
lines changed

README.md

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,24 @@ The Wasm-sdk's build process needs some packages :
3838
* `clang`
3939
* `ninja`
4040

41-
Please refer to your OS documentation to install those packages.
41+
Please refer to your OS documentation to install those packages.
4242

43-
## Build
43+
## Build
4444

45-
To build the full package
45+
To build the full package:
4646

4747
```shell script
4848
cd wasi-sdk
4949
NINJA_FLAGS=-v make package
5050
```
5151

52-
The built package can be found into `dist` directory.
52+
The built package can be found into `dist` directory. For releasing a new
53+
version of the package on GitHub, see [RELEASING.md](RELEASING.md).
5354

5455
## Install
5556

5657
A typical installation from the release binaries might look like the following:
58+
5759
```shell script
5860
export WASI_VERSION=14
5961
export WASI_VERSION_FULL=${WASI_VERSION}.0
@@ -64,13 +66,16 @@ tar xvf wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz
6466
## Use
6567

6668
Use the clang installed in the wasi-sdk directory:
69+
6770
```shell script
6871
export WASI_SDK_PATH=`pwd`/wasi-sdk-${WASI_VERSION_FULL}
6972
CC="${WASI_SDK_PATH}/bin/clang --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot"
7073
$CC foo.c -o foo.wasm
7174
```
72-
Note: `${WASI_SDK_PATH}/share/wasi-sysroot` contains the WASI-specific includes/libraries/etc. The `--sysroot=...` option
73-
is not necessary if `WASI_SDK_PATH` is `/opt/wasi-sdk`.
75+
76+
Note: `${WASI_SDK_PATH}/share/wasi-sysroot` contains the WASI-specific
77+
includes/libraries/etc. The `--sysroot=...` option is not necessary if
78+
`WASI_SDK_PATH` is `/opt/wasi-sdk`.
7479

7580
## Notes for Autoconf
7681

@@ -104,7 +109,7 @@ disabled in a configure step before building with wasi-sdk.
104109

105110
This repository does not yet support C++ exceptions. C++ code is
106111
supported only with -fno-exceptions for now. Similarly, there is not
107-
yet support for setjmp/longjmp. Work on support for [exception handling]
112+
yet support for setjmp/longjmp. Work on support for [exception handling]
108113
is underway at the language level which will support both of these
109114
features.
110115

RELEASING.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Release Process
2+
3+
To publish a new version of `wasi-sdk` as a GitHub release:
4+
5+
1. Tag a commit with an annotated tag. Note that this must be an annotated tag,
6+
not a lightweight tag, so that `version.sh` can use it for calculating the
7+
package version (use `git show wasi-sdk-...` to show other tag messages).
8+
9+
```shell script
10+
TAG=wasi-sdk-1
11+
git tag -a $TAG
12+
git push origin $TAG
13+
```
14+
15+
2. Find a successful workflow that CI has run for the tag. That successful
16+
workflow run will have build artifacts that need to be attached to the
17+
release. One could search around in the GitHub [actions], but the following
18+
script will list completed workflows for a tag (get a token [here][tokens]):
19+
20+
```shell script
21+
ci/get-workflows-for-tag.sh $TAG $GITHUB_TOKEN
22+
```
23+
24+
[actions]: https://github.com/WebAssembly/wasi-sdk/actions
25+
[tokens]: https://github.com/settings/tokens
26+
27+
3. Download and unzip the workflow artifacts. Note that artifacts with `+m` or
28+
`.m` suffixes indicate that the Git tree was modified. Expect some duplicates
29+
since some of the same artifacts are built on multiple CI runners (e.g.,
30+
Windows, MacOS, Linux). The following script does all of this automatically:
31+
32+
```shell script
33+
ci/download-workflow-artifacts.sh $TAG $WORKFLOW_RUN_ID $GITHUB_TOKEN
34+
```
35+
36+
4. Draft a new release. This could be done [manually][releases] but the
37+
following script simplifies the uploading of all the files and auto-generates
38+
the release description:
39+
40+
```shell script
41+
ci/draft-release.sh $TAG $ARTIFACTS_DIR $GITHUB_TOKEN
42+
```
43+
44+
[releases]: https://github.com/WebAssembly/wasi-sdk/releases
45+
46+
5. Publish the release; the previous step only creates a draft. Follow the link
47+
in the previous step or navigate to the GitHub [releases] to review the
48+
description, commit, tag, and assets before clicking "Publish"

ci/download-workflow-artifacts.sh

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# This script downloads and unzips the artifacts produced in a workflow run. It
5+
# also checks that the workflow commit corresponds to the tag commit that these
6+
# artifacts will be released under. The script has several pre-requisites:
7+
# - some standard Bash tools (curl, unzip) and one slightly more rare one (jq)
8+
# - an already-created tag in the repository (this marks the code to release)
9+
# - the ID of a workflow run that has run successfully--this is where we
10+
# retrieve the artifacts from
11+
# - a GitHub access token, see https://github.com/settings/tokens
12+
#
13+
# Usage: download-workflow-artifacts.sh <release tag> <workflow run ID> <token>
14+
15+
TAG=$1
16+
WORKFLOW_RUN_ID=$2
17+
GITHUB_TOKEN=$3
18+
GITHUB_API_VERSION=2022-11-28
19+
GITHUB_API_URL=https://api.github.com/repos/WebAssembly/wasi-sdk
20+
TMP_DIR=$(mktemp -d -t wasi-sdk-artifacts.XXXXXXX)
21+
22+
if [ -z "${TAG}" ] || [ -z "${WORKFLOW_RUN_ID}" ] || [ -z "${GITHUB_TOKEN}" ]; then
23+
>&2 echo "Missing parameter; exiting..."
24+
>&2 echo "Usage: download-worfklow-artifacts.sh <release tag> <workflow run ID> <token>"
25+
exit 1
26+
fi
27+
28+
# Get the commit SHA for the passed tag.
29+
# See https://docs.github.com/en/rest/commits/commits#get-a-commit
30+
MATCHING_COMMIT=$(curl \
31+
-H "Accept: application/vnd.github+json" \
32+
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
33+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
34+
"${GITHUB_API_URL}/commits/${TAG}")
35+
COMMIT=$(echo $MATCHING_COMMIT | jq -r '.sha')
36+
>&2 echo "===== Found commit for tag ${TAG}: ${COMMIT} ====="
37+
38+
# Check that the commit of the workflow run matches the tag commit and that the
39+
# workflow was successful.
40+
# See https://docs.github.com/en/rest/actions/workflow-runs#get-a-workflow-run
41+
WORKFLOW_RUN=$(curl \
42+
-H "Accept: application/vnd.github+json" \
43+
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
44+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
45+
"${GITHUB_API_URL}/actions/runs/${WORKFLOW_RUN_ID}")
46+
WORKFLOW_COMMIT=$(echo $WORKFLOW_RUN | jq -r '.head_sha')
47+
WORKFLOW_STATUS=$(echo $WORKFLOW_RUN | jq -r '.status')
48+
>&2 echo "===== Found commit for workflow ${WORKFLOW_RUN_ID}: ${WORKFLOW_COMMIT} ====="
49+
if [ "${COMMIT}" != "${WORKFLOW_COMMIT}" ]; then
50+
>&2 echo "Commit at tag ${TAG} did not match the commit for workflow ${WORKFLOW_RUN_ID}, exiting...:"
51+
>&2 echo " ${COMMIT} != ${WORKFLOW_COMMIT}"
52+
exit 1
53+
fi
54+
if [ "${WORKFLOW_STATUS}" != "completed" ]; then
55+
>&2 echo "Workflow ${WORKFLOW_RUN_ID} did not end successfully, exiting...:"
56+
>&2 echo " status = ${WORKFLOW_STATUS}"
57+
exit 1
58+
fi
59+
60+
# List out the artifacts in the given workflow run.
61+
# See https://docs.github.com/en/rest/actions/artifacts#list-workflow-run-artifacts
62+
ARTIFACTS=$(curl \
63+
-H "Accept: application/vnd.github+json" \
64+
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
65+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
66+
"${GITHUB_API_URL}/actions/runs/${WORKFLOW_RUN_ID}/artifacts" \
67+
| jq -r '.artifacts[] | [(.id|tostring), .name, .archive_download_url] | join(",")')
68+
69+
for A in $ARTIFACTS; do
70+
ID=$(echo $A | cut -d ',' -f 1)
71+
NAME=$(echo $A | cut -d ',' -f 2)
72+
URL=$(echo $A | cut -d ',' -f 3)
73+
TO=$TMP_DIR/$NAME.zip
74+
>&2 echo "===== Downloading: ${TO} ====="
75+
76+
# Download the artifacts to the temporary directory.
77+
# See https://docs.github.com/en/rest/actions/artifacts#download-an-artifact
78+
curl \
79+
-H "Accept: application/vnd.github+json" \
80+
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
81+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
82+
--location --output "${TO}" \
83+
"${GITHUB_API_URL}/actions/artifacts/${ID}/zip"
84+
done
85+
86+
# Unzip the workflow artifacts into a `release` directory.
87+
pushd $TMP_DIR > /dev/null
88+
mkdir release
89+
ls -1 *.zip | xargs -n1 unzip -q -o -d release
90+
# Some explanation:
91+
# -1 prints each file on a separate line
92+
# -n1 runs the command once for each item
93+
# -q means quietly
94+
# -o allows unzip to overwrite existing files (e.g., multiple copies of `libclang_rt.builtins-wasm32-wasi-...`)
95+
# -d tells unzip which directory to place things in
96+
>&2 echo "===== Files to release: ${TMP_DIR}/release ====="
97+
>&2 ls -1 release
98+
popd > /dev/null
99+
100+
>&2 echo
101+
>&2 echo "Ensure the above artifacts look correct, then run \`draft-release.sh\` with the following directory:"
102+
echo "${TMP_DIR}/release"

ci/draft-release.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# This script creates a draft pre-release with the artifacts produced in a
5+
# workflow run (see `download-workflow-artifacts.sh`). Note that the pre-release
6+
# is not published publicly--this is kept as a manual step as a safeguard. The
7+
# script has several pre-requisites:
8+
# - some standard Bash tools (curl, unzip) and one slightly more rare one (jq)
9+
# - an already-created tag in the repository (this marks the code to release)
10+
# - a directory containing the artifacts to attach to the release.
11+
# - a GitHub access token, see https://github.com/settings/tokens
12+
#
13+
# Usage: draft-release.sh <release tag> <artifacts dir> <token>
14+
15+
TAG=$1
16+
ARTIFACTS_DIR=$2
17+
GITHUB_TOKEN=$3
18+
GITHUB_API_VERSION=2022-11-28
19+
GITHUB_API_URL=https://api.github.com/repos/WebAssembly/wasi-sdk
20+
TMP_DIR=$(mktemp -d -t release.sh.XXXXXXX)
21+
22+
if [ -z "${TAG}" ] || [ -z "${ARTIFACTS_DIR}" ] || [ -z "${GITHUB_TOKEN}" ]; then
23+
>&2 echo "Missing parameter; exiting..."
24+
>&2 echo "Usage: draft-release.sh <release tag> <artifacts dir> <token>"
25+
exit 1
26+
fi
27+
28+
# Get the commit SHA for the passed tag.
29+
# See https://docs.github.com/en/rest/commits/commits#get-a-commit
30+
MATCHING_COMMIT=$(curl \
31+
-H "Accept: application/vnd.github+json" \
32+
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
33+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
34+
"${GITHUB_API_URL}/commits/${TAG}")
35+
COMMIT=$(echo $MATCHING_COMMIT | jq -r '.sha')
36+
>&2 echo "===== Found commit for tag ${TAG}: ${COMMIT} ====="
37+
38+
# Create a draft pre-release for this commit.
39+
# See https://docs.github.com/en/rest/releases/releases#create-a-release
40+
RELEASE_JSON=$(curl \
41+
-X POST \
42+
-H "Accept: application/vnd.github+json" \
43+
-H "Authorization: Bearer ${GITHUB_TOKEN}"\
44+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
45+
"${GITHUB_API_URL}/releases" \
46+
-d '{"tag_name":"'${TAG}'","target_commitish":"'${COMMIT}'","name":"'${TAG}'","draft":true,"prerelease":true,"generate_release_notes":true}')
47+
UPLOAD_URL=$(echo $RELEASE_JSON | jq -r '.upload_url')
48+
# Remove the "helpful" but invalid URL suffix that GitHub adds:
49+
UPLOAD_URL=${UPLOAD_URL/\{?name,label\}}
50+
HTML_URL=$(echo $RELEASE_JSON | jq -r '.html_url')
51+
>&2 echo "===== Created draft release: ${HTML_URL} ====="
52+
53+
# Upload the unzipped artifact files to the release.
54+
# See https://docs.github.com/en/rest/releases/assets#upload-a-release-asset
55+
for FILE in $(ls "${ARTIFACTS_DIR}"); do
56+
FROM=$ARTIFACTS_DIR/$FILE
57+
>&2 echo "===== Uploading: ${FROM} ====="
58+
UPLOADED=$(curl \
59+
-X POST \
60+
-H "Accept: application/vnd.github+json" \
61+
-H "Authorization: Bearer ${GITHUB_TOKEN}"\
62+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
63+
-H "Content-Type: application/octet-stream" \
64+
"${UPLOAD_URL}?name=${FILE}" \
65+
--data-binary "@${FROM}")
66+
done
67+
68+
>&2 echo
69+
>&2 echo "===== Completed ====="
70+
>&2 echo "This created a draft release, do not forget to manually publish it at:"
71+
echo "${HTML_URL}"

ci/get-workflows-for-tag.sh

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# This script retrieves a list of GitHub workflow runs that have successfully completed for a given
5+
# Git tag. The list is printed to stdout (all other output to stderr). It has several
6+
# pre-requisites:
7+
# - some standard Bash tools (curl) and one slightly more rare one (jq)
8+
# - an already-created tag in the repository (this marks the code to release)
9+
# - a GitHub access token, see https://github.com/settings/tokens
10+
#
11+
# Usage: get-workflows-for-tag.sh <tag> <token>
12+
13+
TAG=$1
14+
GITHUB_TOKEN=$2
15+
GITHUB_API_VERSION=2022-11-28
16+
GITHUB_API_URL=https://api.github.com/repos/WebAssembly/wasi-sdk
17+
18+
if [ -z "${TAG}" ] || [ -z "${GITHUB_TOKEN}" ]; then
19+
>&2 echo "Missing parameter; exiting..."
20+
>&2 echo "Usage: get-workflows-for-tag.sh <tag> <token>"
21+
exit 1
22+
fi
23+
24+
# Get the commit SHA for the passed tag.
25+
# See https://docs.github.com/en/rest/commits/commits#get-a-commit
26+
MATCHING_COMMIT=$(curl \
27+
-H "Accept: application/vnd.github+json" \
28+
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
29+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
30+
"${GITHUB_API_URL}/commits/${TAG}")
31+
COMMIT=$(echo $MATCHING_COMMIT | jq -r '.sha')
32+
>&2 echo "===== Found commit for tag ${TAG}: ${COMMIT} ====="
33+
34+
# Find the workflow runs matching the tag commit.
35+
# See https://docs.github.com/en/rest/actions/workflow-runs#list-workflow-runs-for-a-repository
36+
MATCHING_WORKFLOWS=$(curl \
37+
-H "Accept: application/vnd.github+json" \
38+
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
39+
-H "X-GitHub-Api-Version: ${GITHUB_API_VERSION}" \
40+
"${GITHUB_API_URL}/actions/runs?head_sha=${COMMIT}&status=success")
41+
WORKFLOW_RUN_IDS=$(echo $MATCHING_WORKFLOWS | jq -r '.workflow_runs[].id')
42+
>&2 echo "===== Matching workflow run IDs: ====="
43+
echo "$WORKFLOW_RUN_IDS"

0 commit comments

Comments
 (0)