name: Build release artifacts
on:
workflow_dispatch:
push:
tags:
- "v*"
permissions:
contents: read
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
quality:
name: Release acceptance gates
runs-on: ubuntu-24.04
timeout-minutes: 45
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- uses: actions/setup-node@v6
with:
node-version: "24"
package-manager-cache: false
- uses: Swatinem/rust-cache@v2
with:
key: release-quality
cache-targets: false
- name: Viewer
working-directory: web
run: |
npm ci
npm test
npm run typecheck
npm run build
git diff --exit-code -- dist
- name: Format
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --locked --all-targets --all-features -- -D warnings
- name: Full test suite
run: cargo test --locked --all-targets --all-features
- name: npm package
run: node --test tests/npm_package.mjs
- name: Fallback build and tests
run: cargo test --locked --all-targets --no-default-features
- name: Release graph benchmark budgets
run: >-
cargo test --locked --release --test graph_benchmark
external_graph_rebuild_and_update_are_document_granular
-- --ignored --nocapture
- name: Package verification
env:
CARGO_TARGET_DIR: ${{ runner.temp }}/lwc-package-target
run: cargo package --locked
build:
needs: quality
name: ${{ matrix.target }}
strategy:
fail-fast: false
matrix:
include:
- runner: macos-15-intel
target: x86_64-apple-darwin
archive: tar
- runner: macos-15
target: aarch64-apple-darwin
archive: tar
- runner: ubuntu-24.04
target: x86_64-unknown-linux-gnu
archive: tar
- runner: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
archive: tar
- runner: windows-2025
target: x86_64-pc-windows-msvc
archive: zip
- runner: windows-11-arm
target: aarch64-pc-windows-msvc
archive: zip
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
steps:
- uses: actions/checkout@v7
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Test
run: cargo test --locked --release --target ${{ matrix.target }}
- name: Build
run: cargo build --locked --release --target ${{ matrix.target }} --bins
- name: Smoke test Unix binary
if: matrix.archive == 'tar'
shell: bash
run: |
project="$(mktemp -d)"
cd "$project"
"${GITHUB_WORKSPACE}/target/${{ matrix.target }}/release/lwc" init
"${GITHUB_WORKSPACE}/target/${{ matrix.target }}/release/lwc" config show
"${GITHUB_WORKSPACE}/target/${{ matrix.target }}/release/lwc" graph status
- name: Smoke test Windows binary
if: matrix.archive == 'zip'
shell: pwsh
run: |
$project = Join-Path $env:RUNNER_TEMP "lwc-smoke"
New-Item -ItemType Directory -Force -Path $project | Out-Null
Push-Location $project
& "$env:GITHUB_WORKSPACE\target\${{ matrix.target }}\release\lwc.exe" init
& "$env:GITHUB_WORKSPACE\target\${{ matrix.target }}\release\lwc.exe" config show
& "$env:GITHUB_WORKSPACE\target\${{ matrix.target }}\release\lwc.exe" graph status
Pop-Location
- name: Package Unix archive
if: matrix.archive == 'tar'
shell: bash
run: |
version="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -1)"
archive="lwc-${version}-${{ matrix.target }}"
mkdir -p "dist/${archive}"
cp "target/${{ matrix.target }}/release/lwc" "dist/${archive}/"
cp README.md README.zh-CN.md LICENSE "dist/${archive}/"
tar -C dist -czf "dist/${archive}.tar.gz" "${archive}"
cd dist
shasum -a 256 "${archive}.tar.gz" > "${archive}.tar.gz.sha256"
cd ..
for plugin in tutor book practice; do
archive="lwc-${plugin}-${version}-${{ matrix.target }}"
mkdir -p "dist/${archive}"
cp "target/${{ matrix.target }}/release/lwc-${plugin}" "dist/${archive}/"
tar -C dist -czf "dist/${archive}.tar.gz" "${archive}"
(
cd dist
shasum -a 256 "${archive}.tar.gz" > "${archive}.tar.gz.sha256"
)
done
- name: Package Windows archive
if: matrix.archive == 'zip'
shell: pwsh
run: |
$version = (Select-String '^version = "([^"]+)"' Cargo.toml).Matches[0].Groups[1].Value
$archive = "lwc-$version-${{ matrix.target }}"
$stage = Join-Path dist $archive
New-Item -ItemType Directory -Force -Path $stage | Out-Null
Copy-Item "target\${{ matrix.target }}\release\lwc.exe" $stage
Copy-Item README.md, README.zh-CN.md, LICENSE $stage
Compress-Archive -Path $stage -DestinationPath "dist\$archive.zip"
$hash = (Get-FileHash "dist\$archive.zip" -Algorithm SHA256).Hash.ToLower()
"$hash $archive.zip" | Set-Content "dist\$archive.zip.sha256" -Encoding ascii
foreach ($plugin in @("tutor", "book", "practice")) {
$archive = "lwc-$plugin-$version-${{ matrix.target }}"
$stage = Join-Path dist $archive
New-Item -ItemType Directory -Force -Path $stage | Out-Null
Copy-Item "target\${{ matrix.target }}\release\lwc-$plugin.exe" $stage
Compress-Archive -Path $stage -DestinationPath "dist\$archive.zip"
$hash = (Get-FileHash "dist\$archive.zip" -Algorithm SHA256).Hash.ToLower()
"$hash $archive.zip" | Set-Content "dist\$archive.zip.sha256" -Encoding ascii
}
- name: Upload archive
uses: actions/upload-artifact@v4
with:
name: lwc-${{ matrix.target }}
path: |
dist/*.tar.gz
dist/*.tar.gz.sha256
dist/*.zip
dist/*.zip.sha256
if-no-files-found: error
compression-level: 0
checksums:
name: Combined checksums
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/download-artifact@v4
with:
pattern: lwc-*
path: artifacts
merge-multiple: true
- name: Combine checksums
run: find artifacts -type f -name '*.sha256' -exec cat {} + | tr -d '\r' | sort -k2 > SHA256SUMS
- uses: actions/upload-artifact@v4
with:
name: lwc-checksums
path: SHA256SUMS
if-no-files-found: error
release:
name: Publish GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
needs:
- build
- checksums
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/download-artifact@v4
with:
pattern: lwc-*
path: release-assets
merge-multiple: true
- uses: actions/setup-node@v6
with:
node-version: "24"
package-manager-cache: false
- name: Validate annotated release notes
shell: bash
run: |
test "$(git cat-file -t "${GITHUB_REF_NAME}")" = "tag"
notes="$(git for-each-ref --format='%(contents)' "refs/tags/${GITHUB_REF_NAME}")"
test -n "$(printf '%s' "$notes" | tr -d '[:space:]')"
printf '%s\n' "$notes" > "${RUNNER_TEMP}/release-notes.md"
- name: Publish release assets
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "${GITHUB_REF_NAME}" \
--repo "${GITHUB_REPOSITORY}" \
--verify-tag \
--title "lwc ${GITHUB_REF_NAME}" \
--notes-file "${RUNNER_TEMP}/release-notes.md" \
release-assets/*.tar.gz \
release-assets/*.zip \
release-assets/SHA256SUMS \
install.sh
- name: Smoke npm installer against release assets
run: |
npm install --global ./npm --prefix "${RUNNER_TEMP}/lwc-npm"
"${RUNNER_TEMP}/lwc-npm/bin/lwc" --version