diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml new file mode 100644 index 00000000..2c8e28c9 --- /dev/null +++ b/.github/workflows/build-docker.yml @@ -0,0 +1,25 @@ +# Bundle the Dockerfile as an artifact for publish-docker.yml to consume. +# Exists as its own job because publish-docker.yml runs with caller-granted +# permissions that do not include `contents: read`, so it cannot check out +# the repo to read the Dockerfile itself. + +name: "[tower] Bundle Docker context" + +on: + workflow_call: + inputs: + plan: + required: true + type: string + workflow_dispatch: + +jobs: + build-docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Upload Docker context + uses: actions/upload-artifact@v6 + with: + name: docker-context + path: Dockerfile diff --git a/.github/workflows/build-wasm.yml b/.github/workflows/build-wasm.yml new file mode 100644 index 00000000..daba7701 --- /dev/null +++ b/.github/workflows/build-wasm.yml @@ -0,0 +1,34 @@ +# Build the tower-package-wasm npm package and upload it as an artifact for +# publish-npm.yml to consume. Exists as its own job because publish-npm.yml runs +# with caller-granted permissions that do not include `contents: read`, so it +# cannot check out the repo or build from source itself. + +name: "[tower] Build wasm npm package" + +on: + workflow_call: + inputs: + plan: + required: true + type: string + workflow_dispatch: + +jobs: + build-wasm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + submodules: recursive + - uses: actions-rust-lang/setup-rust-toolchain@v1.11.0 + with: + target: wasm32-unknown-unknown + - uses: jetli/wasm-pack-action@v0.4.0 + - name: Build wasm package + working-directory: crates/tower-package + run: ./scripts/build.sh bundler + - name: Upload npm package + uses: actions/upload-artifact@v6 + with: + name: npm-package + path: crates/tower-package/pkg diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index e47b062e..aae6a5cb 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -3,6 +3,11 @@ # Assumed to run as a subworkflow of .github/workflows/release.yml; specifically, as a publish job # within `cargo-dist`. Runs after `host`, so the GitHub Release and its binary artifacts exist; # the Dockerfile fetches the prebuilt musl binary from the release at image-build time. +# +# Consumes the `docker-context` artifact produced by build-docker.yml. We do not check out +# the repo here because the caller in release.yml grants only `id-token: write` and +# `packages: write` to custom publish jobs — `contents: read` would exceed that and +# fail workflow validation. name: "[tower] Publish Docker image" @@ -17,10 +22,11 @@ jobs: docker-publish: runs-on: ubuntu-latest permissions: - contents: read packages: write steps: - - uses: actions/checkout@v6 + - uses: actions/download-artifact@v7 + with: + name: docker-context - uses: docker/setup-buildx-action@v3 - uses: docker/login-action@v3 with: diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 9661ac41..36421b77 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -1,6 +1,11 @@ # Publish tower-package-wasm to npm. # Uses OIDC Trusted Publishing — no NPM_TOKEN needed, but the package must have a trusted publisher # configured on npmjs.com matching this repo, this workflow file, and the `release` environment. +# +# Consumes the `npm-package` artifact produced by build-wasm.yml. We do not check out +# the repo here because the caller in release.yml grants only `id-token: write` and +# `packages: write` to custom publish jobs — `contents: read` would exceed that and +# fail workflow validation. name: "[tower] Publish to npm" on: @@ -17,32 +22,18 @@ jobs: environment: name: release permissions: - contents: read id-token: write steps: - - uses: actions/checkout@v6 - - - name: Set up Rust - uses: actions-rust-lang/setup-rust-toolchain@v1.11.0 + - uses: actions/download-artifact@v7 with: - target: wasm32-unknown-unknown - - - name: Install wasm-pack - uses: jetli/wasm-pack-action@v0.4.0 - - - name: Set up Node - uses: actions/setup-node@v4 + name: npm-package + path: pkg + - uses: actions/setup-node@v4 with: node-version: 22 registry-url: 'https://registry.npmjs.org' - - name: Upgrade npm for Trusted Publishing run: npm install -g npm@latest - - - name: Build wasm package - working-directory: crates/tower-package - run: ./scripts/build.sh bundler - - name: Publish to npm - working-directory: crates/tower-package/pkg + working-directory: pkg run: npm publish --access public --provenance diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a0f1b52d..9747bbb1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -173,12 +173,32 @@ jobs: plan: ${{ needs.plan.outputs.val }} secrets: inherit + custom-build-wasm: + needs: + - plan + if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' }} + uses: ./.github/workflows/build-wasm.yml + with: + plan: ${{ needs.plan.outputs.val }} + secrets: inherit + + custom-build-docker: + needs: + - plan + if: ${{ needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload' }} + uses: ./.github/workflows/build-docker.yml + with: + plan: ${{ needs.plan.outputs.val }} + secrets: inherit + # Build and package all the platform-agnostic(ish) things build-global-artifacts: needs: - plan - build-local-artifacts - custom-build-binaries + - custom-build-wasm + - custom-build-docker runs-on: "ubuntu-22.04" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -226,9 +246,11 @@ jobs: - plan - build-local-artifacts - custom-build-binaries + - custom-build-wasm + - custom-build-docker - build-global-artifacts # Only run if we're "publishing", and only if plan, local and global didn't fail (skipped is fine) - if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') }} + if: ${{ always() && needs.plan.result == 'success' && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') && (needs.custom-build-binaries.result == 'skipped' || needs.custom-build-binaries.result == 'success') && (needs.custom-build-wasm.result == 'skipped' || needs.custom-build-wasm.result == 'success') && (needs.custom-build-docker.result == 'skipped' || needs.custom-build-docker.result == 'success') }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} runs-on: "ubuntu-22.04" diff --git a/dist-workspace.toml b/dist-workspace.toml index 5c5cd3b5..93b242f5 100644 --- a/dist-workspace.toml +++ b/dist-workspace.toml @@ -24,7 +24,7 @@ create-release = true # Which actions to run on pull requests pr-run-mode = "skip" # Local artifacts jobs to run in CI -local-artifacts-jobs = ["./build-binaries"] +local-artifacts-jobs = ["./build-binaries", "./build-wasm", "./build-docker"] # Whether to publish prereleases to package managers publish-prereleases = true