Skip to content

release

release #330

Workflow file for this run

name: release
run-name: release
on:
push:
# NOTE: pushes from CI without a PAT will not trigger the tags below
tags:
- "jco-v[0-9]+.[0-9]+.[0-9]+*"
- "jco-v[0-9]+.[0-9]+.[0-9]+-*"
- "jco-transpile-v[0-9]+.[0-9]+.[0-9]+*"
- "jco-transpile-v[0-9]+.[0-9]+.[0-9]+-*"
- "jco-std-v[0-9]+.[0-9]+.[0-9]+*"
- "jco-std-v[0-9]+.[0-9]+.[0-9]+-*"
- "preview2-shim-v[0-9]+.[0-9]+.[0-9]+*"
- "preview2-shim-v[0-9]+.[0-9]+.[0-9]+-*"
- "preview3-shim-v[0-9]+.[0-9]+.[0-9]+*"
- "preview3-shim-v[0-9]+.[0-9]+.[0-9]+-*"
- "js-component-bindgen-v[0-9]+.[0-9]+.[0-9]+*"
- "js-component-bindgen-v[0-9]+.[0-9]+.[0-9]+-*"
branches:
- "prep-release-jco-v[0-9]+.[0-9]+.[0-9]+*"
- "prep-release-jco-v[0-9]+.[0-9]+.[0-9]+-*"
- "prep-release-jco-transpile-v[0-9]+.[0-9]+.[0-9]+*"
- "prep-release-jco-transpile-v[0-9]+.[0-9]+.[0-9]+-*"
- "prep-release-jco-std-v[0-9]+.[0-9]+.[0-9]+*"
- "prep-release-jco-std-v[0-9]+.[0-9]+.[0-9]+-*"
- "prep-release-preview2-shim-v[0-9]+.[0-9]+.[0-9]+*"
- "prep-release-preview2-shim-v[0-9]+.[0-9]+.[0-9]+-*"
- "prep-release-preview3-shim-v[0-9]+.[0-9]+.[0-9]+*"
- "prep-release-preview3-shim-v[0-9]+.[0-9]+.[0-9]+-*"
- "prep-release-js-component-bindgen-v[0-9]+.[0-9]+.[0-9]+*"
- "prep-release-js-component-bindgen-v[0-9]+.[0-9]+.[0-9]+-*"
workflow_dispatch:
inputs:
project:
type: choice
required: true
default: "jco"
options:
- jco
- jco-transpile
- jco-std
- js-component-bindgen
- preview2-shim
- preview3-shim
description: |
Project to tag for release (ex. `0.1.0`)
version:
type: string
required: true
description: |
Version tag to release (e.x. `0.1.0`, `0.2.0`)
permissions:
contents: none
jobs:
meta:
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.meta.outputs.version }}
project: ${{ steps.meta.outputs.project }}
project-dir: ${{ steps.project-meta.outputs.project-dir }}
is-js-project: ${{ steps.project-meta.outputs.is-js-project }}
is-rust-project: ${{ steps.project-meta.outputs.is-rust-project }}
artifacts-glob: ${{ steps.project-meta.outputs.artifacts-glob }}
artifact-name: ${{ steps.project-meta.outputs.artifact-name }}
next-release-tag: ${{ steps.project-meta.outputs.next-release-tag }}
is-prerelease: ${{ steps.project-meta.outputs.is-prerelease }}
prerelease-tag: ${{ steps.project-meta.outputs.prerelease-tag }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: install cargo-get
uses: taiki-e/cache-cargo-install-action@417450f3c33ee20393705369577571770643d4c7 # v3.0.7
with:
tool: cargo-get
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ">=22"
- name: Cache npm install
id: cache-node-modules
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: node-modules-dev-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package-lock.json') }}
path: |
node_modules
- name: Install debug NPM packages
run: |
npm install -D
- name: Collect metadata
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
id: meta
with:
script: |
if (context.payload.inputs?.project && context.payload.inputs?.version) {
core.setOutput('project', context.payload.inputs.project);
core.setOutput('version', context.payload.inputs.version);
return;
}
if (context.ref.startsWith('refs/tags/')) {
match = context.ref.replace('refs/tags/', '').match(/^(.*)-v([^\s]+)$/);
} else if (context.ref.startsWith('refs/heads/')) {
match = context.ref.replace('refs/heads/', '').match(/^prep-release-(.+)-v([^\s]+)$/);
} else {
throw new Error(`Unexpected context ref [${context.ref}]`);
}
if (!match) { throw new Error(`Failed to parse tag/branch: [${context.ref}]`); }
const [_, project, version] = match;
core.setOutput('project', project);
core.setOutput('version', version);
- name: Gather project metadata
id: project-meta
env:
NEXT_VERSION: ${{ steps.meta.outputs.version }}
PROJECT: ${{ steps.meta.outputs.project }}
shell: bash
run: |
if [[ $NEXT_VERSION == v* ]]; then
echo "::error::next version [$NEXT_VERSION] starts with 'v' -- enter only the semver version (ex. '0.1.0', not 'v0.1.0')";
exit 1;
fi
case $PROJECT in
jco)
export PROJECT_DIR="$PWD/packages/$PROJECT";
export CURRENT_VERSION=$(node -e "process.stdout.write(require(process.env.PROJECT_DIR + '/package.json').version)");
export IS_JS_PROJECT=true;
export ARTIFACTS_GLOB="packages/jco/bytecodealliance-jco-*.tgz";
export ARTIFACT_NAME="bytecodealliance-jco-$NEXT_VERSION.tgz";
;;
jco-transpile)
export PROJECT_DIR="$PWD/packages/$PROJECT";
export CURRENT_VERSION=$(node -e "process.stdout.write(require(process.env.PROJECT_DIR + '/package.json').version)");
export IS_JS_PROJECT=true;
export ARTIFACTS_GLOB="packages/jco-transpile/bytecodealliance-jco-transpile-*.tgz";
export ARTIFACT_NAME="bytecodealliance-jco-transpile-$NEXT_VERSION.tgz";
;;
jco-std)
export PROJECT_DIR="$PWD/packages/$PROJECT";
export CURRENT_VERSION=$(node -e "process.stdout.write(require(process.env.PROJECT_DIR + '/package.json').version)");
export IS_JS_PROJECT=true;
export ARTIFACTS_GLOB="packages/jco-std/bytecodealliance-jco-std-*.tgz";
export ARTIFACT_NAME="bytecodealliance-jco-std-$NEXT_VERSION.tgz";
;;
preview2-shim)
export PROJECT_DIR="$PWD/packages/$PROJECT";
export CURRENT_VERSION=$(node -e "process.stdout.write(require(process.env.PROJECT_DIR + '/package.json').version)");
export IS_JS_PROJECT=true;
export ARTIFACTS_GLOB="packages/preview2-shim/bytecodealliance-preview2-shim-*.tgz";
export ARTIFACT_NAME="bytecodealliance-preview2-shim-$NEXT_VERSION.tgz";
;;
preview3-shim)
export PROJECT_DIR="$PWD/packages/$PROJECT";
export CURRENT_VERSION=$(node -e "process.stdout.write(require(process.env.PROJECT_DIR + '/package.json').version)");
export IS_JS_PROJECT=true;
export ARTIFACTS_GLOB="packages/preview3-shim/bytecodealliance-preview3-shim-*.tgz";
export ARTIFACT_NAME="bytecodealliance-preview3-shim-$NEXT_VERSION.tgz";
;;
js-component-bindgen)
export PROJECT_DIR="$PWD/crates/${{ steps.meta.outputs.project }}";
export CURRENT_VERSION=$(cargo get package.version --terminator Nul --entry=$PROJECT_DIR);
export IS_RUST_PROJECT=true;
export ARTIFACTS_GLOB="target/package/js-component-bindgen-*.crate";
export ARTIFACT_NAME="js-component-bindgen-$NEXT_VERSION.crate";
;;
*)
echo "unexpected project type (neither Rust nor JS)";
exit 1;
esac
echo -e "project-dir=$PROJECT_DIR" >> $GITHUB_OUTPUT;
echo -e "is-rust-project=$IS_RUST_PROJECT" >> $GITHUB_OUTPUT;
echo -e "is-js-project=$IS_JS_PROJECT" >> $GITHUB_OUTPUT;
echo -e "artifacts-glob=$ARTIFACTS_GLOB" >> $GITHUB_OUTPUT;
echo -e "artifact-name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT;
echo -e "next-release-tag=${PROJECT}-v${NEXT_VERSION}" >> $GITHUB_OUTPUT;
export IS_PRERELEASE=$(node scripts/semver-is-prerelease.mjs $NEXT_VERSION);
echo -e "is-prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT;
export PRERELEASE_TAG=$(node scripts/semver-get-prerelease.mjs $NEXT_VERSION);
echo -e "prerelease-tag=$PRERELEASE_TAG" >> $GITHUB_OUTPUT;
pack-crate-release:
if: ${{ needs.meta.outputs.is-rust-project == 'true' }}
runs-on: ubuntu-24.04
needs:
- meta
permissions:
actions: write
id-token: write
attestations: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
with:
shared-key: jco-${{ hashFiles('Cargo.lock') }}
- name: Release crate (dry run)
working-directory: ${{ needs.meta.outputs.project-dir }}
run: |
cargo publish --locked --dry-run
- name: Create release package
working-directory: ${{ needs.meta.outputs.project-dir }}
run: |
cargo package
- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: ${{ needs.meta.outputs.artifacts-glob }}
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
if-no-files-found: error
name: ${{ needs.meta.outputs.project }}
path: |
${{ needs.meta.outputs.artifacts-glob }}
pack-npm-release:
if: ${{ needs.meta.outputs.is-js-project == 'true' }}
runs-on: ubuntu-24.04
needs:
- meta
permissions:
id-token: write
attestations: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
with:
shared-key: jco-${{ hashFiles('Cargo.lock') }}
# NOTE: we must use a node version new-enough to have --experimental-wasm-jspi
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ">=22"
- name: Cache npm install
id: cache-node-modules
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package-lock.json') }}
path: |
node_modules
- name: Install NPM packages
run: |
npm install
- name: Install NPM packages (project)
working-directory: ${{ needs.meta.outputs.project-dir }}
run: |
npm install
- name: Create release package
working-directory: ${{ needs.meta.outputs.project-dir }}
run: |
npm pack
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
if-no-files-found: error
name: ${{ needs.meta.outputs.project }}
path: |
${{ needs.meta.outputs.artifacts-glob }}
test-crate-release:
runs-on: ubuntu-24.04
needs:
- meta
- pack-crate-release
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
- name: Test built crates.io crate
if: ${{ needs.meta.outputs.project == 'js-component-bindgen' }}
shell: bash
run: |
mkdir -p /tmp/${{ needs.meta.outputs.project }}
cp -r artifacts/* /tmp/${{ needs.meta.outputs.project }}/
cd /tmp/${{ needs.meta.outputs.project }}
tar --strip-components=1 -xvf ${{ needs.meta.outputs.artifact-name }}
rm Cargo.toml.orig
cargo build
test-npm-release:
runs-on: ubuntu-24.04
needs:
- meta
- pack-npm-release
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ">=22"
- name: Test built jco NPM package
if: ${{ needs.meta.outputs.project == 'jco' }}
shell: bash
run: |
export PACKAGE_DIR=${{ github.workspace }}/artifacts/${{ needs.meta.outputs.artifact-name }}
cp -r examples/components/http-hello-world /tmp/test
cd /tmp/test
npm install --save $PACKAGE_DIR
npm run all
- name: Test built jco-transpile NPM package
if: ${{ needs.meta.outputs.project == 'jco-transpile' }}
shell: bash
run: |
export PACKAGE_DIR=${{ github.workspace }}/artifacts/${{ needs.meta.outputs.artifact-name }}
cp -r examples/transpile/adder /tmp/test
cd /tmp/test
npm install --save $PACKAGE_DIR
npm run all
crate-publish:
runs-on: ubuntu-24.04
needs:
- meta
- test-crate-release
permissions:
id-token: write
attestations: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
- uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4
id: auth
- name: Publish ${{ needs.meta.outputs.project }} to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
run: |
export OPT_DRY_RUN="--dry-run"
if [ "tag" == "${{ github.ref_type }}" ]; then
export OPT_DRY_RUN="";
fi
mkdir -p /tmp/${{ needs.meta.outputs.project }}
cp -r artifacts/* /tmp/${{ needs.meta.outputs.project }}/
cd /tmp/${{ needs.meta.outputs.project }}
tar --strip-components=1 -xvf ${{ needs.meta.outputs.artifact-name }}
rm Cargo.toml.orig
cargo publish $OPT_DRY_RUN
npm-publish:
runs-on: ubuntu-24.04
needs:
- meta
- test-npm-release
permissions:
id-token: write
attestations: write
steps:
# NOTE: We need to checkout to pull npmrc
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: ">=22"
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
# NOTE: We install node modules because the pre-pack for various projects may require
# the cargo xtask build in release mode (even though we're using),
- name: Cache npm install
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: node-modules-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package-lock.json') }}
path: |
node_modules
- name: Install NPM packages
run: |
npm install
- name: Install NPM packages (project)
working-directory: ${{ needs.meta.outputs.project-dir }}
run: |
npm install
- name: Publish ${{ needs.meta.outputs.project }} to NPM
shell: bash
run: |
export PACKAGE_FILE_PATH=${{ github.workspace }}/artifacts/${{ needs.meta.outputs.artifact-name }}
export OPT_DRY_RUN="--dry-run"
if [ "tag" == "${{ github.ref_type }}" ]; then
export OPT_DRY_RUN="";
fi
export OPT_RELEASE_TAG=""
if [ "true" == "${{ needs.meta.outputs.is-prerelease }}" ]; then
export OPT_RELEASE_TAG="--tag ${{ needs.meta.outputs.prerelease-tag }}";
fi
npm publish \
--verbose \
-w @bytecodealliance/${{ needs.meta.outputs.project }} \
--access=public \
--provenance \
$OPT_DRY_RUN \
$OPT_RELEASE_TAG \
$PACKAGE_FILE_PATH
create-gh-release:
runs-on: ubuntu-24.04
if: always()
needs:
- meta
- test-crate-release
- test-npm-release
- npm-publish
- crate-publish
permissions:
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: install git-cliff
uses: taiki-e/install-action@c070f87102a1c75b3183910f391c1cb887fe13c8 # v2.77.6
with:
fallback: none
tool: git-cliff
# Re-generate the current changelog so we can use it in the GH release announcement
#
# NOTE: if this workflow is being run due to a tag push, that's an *already committed* release
# tag and likely the one corresponding to this release, so we use the latest
#
- name: Re-generate current changelog
id: changelog-regen
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }}
GITHUB_REPO: ${{ github.repository }}
run: |
export OPT_START=--unreleased;
export OPT_TAG=;
if [ "tag" == "${{ github.ref_type }}" ]; then
export OPT_START=--current;
export OPT_TAG=--tag=${{ needs.meta.outputs.next-release-tag }};
fi
export TAG_PATTERN='^${{ needs.meta.outputs.project }}-v[0-9]+.[0-9]+.[0-9]+$';
if [ "true" == "${{ needs.meta.outputs.is-prerelease }}" ]; then
export TAG_PATTERN='^${{ needs.meta.outputs.project }}-v[0-9]+.[0-9]+.[0-9]+(-beta|-rc|-alpha)?';
export OPT_TAG_PATTERN=--tag-pattern=$TAG_PATTERN;
fi
echo -e "tag-pattern=$TAG_PATTERN" >> $GITHUB_OUTPUT;
git cliff \
--repository=${{ github.workspace }}/.git \
--config=${{ needs.meta.outputs.project-dir }}/cliff.toml \
$OPT_START \
$OPT_TAG \
$OPT_TAG_PATTERN \
> ${{ needs.meta.outputs.project-dir }}/CHANGELOG.current;
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: artifacts
- name: Create GH release
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
with:
token: ${{ secrets.RELEASE_PAT || github.token }}
prerelease: ${{ needs.meta.outputs.is-prerelease == 'true' }}
draft: ${{ github.ref_type != 'tag' }}
tag_name: ${{ needs.meta.outputs.next-release-tag }}
generate_release_notes: false
body_path: ${{ needs.meta.outputs.project-dir }}/CHANGELOG.current
make_latest: ${{ needs.meta.outputs.project == 'jco' && github.ref_type == 'tag' && needs.meta.outputs.is-prerelease == 'false' }}
files: |
./artifacts/*
- name: Cache npm install
continue-on-error: true
id: cache-node-modules
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: node-modules-dev-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('package-lock.json') }}
path: |
node_modules
- name: Install debug NPM packages
run: |
npm install -D
- name: Update related PRs with release note
continue-on-error: true
if: ${{ github.repository_owner == 'bytecodealliance' && github.ref_type == 'tag' }}
env:
IS_PRE_RELEASE: ${{ needs.meta.outputs.is-prerelease }}
GITHUB_TOKEN: ${{ secrets.RELEASE_PAT || github.token }}
GITHUB_OWNER: ${{ github.repository_owner }}
GITHUB_REPO: ${{ github.repository }}
GIT_CLIFF_CONFIG_PATH: ${{ needs.meta.outputs.project-dir }}/cliff.toml
GIT_CLIFF_REPOSITORY: ${{ github.workspace }}/.git
GIT_CLIFF_RELEASE_TAG: ${{ needs.meta.outputs.next-release-tag }}
GIT_CLIFF_TAG_PATTERN: ${{ steps.changelog-regen.outputs.tag-pattern }}
run: |
node scripts/post-release-issue-update.mjs