fix(rules): flag removed top-level iii sandbox with replacement; ad…
#59
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: release | |
| on: | |
| push: | |
| # Patch tags only (X.Y.Z), not the X.Y / X floats. `on.push.tags` | |
| # uses glob syntax (NOT regex), so `+` and `[0-9]` quantifier-style | |
| # forms don't work — `v*.*.*` is the semver-shaped glob that | |
| # requires two dots and excludes `v0.4` / `v0`. | |
| # | |
| # Force-pushing `v0.4` to roll the float forward previously fired | |
| # this workflow with `v*` and created a duplicate release titled | |
| # "v0.4", which broke `/releases/latest` resolution for consumers | |
| # (ci-install.sh couldn't parse the two-component version). | |
| tags: ["v*.*.*"] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag to release (e.g. v0.1.0)" | |
| required: true | |
| permissions: | |
| contents: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| build: | |
| name: build ${{ matrix.target }} | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: aarch64-apple-darwin | |
| # macos-14 was hitting a consistent setup-rust-toolchain | |
| # failure where `cargo` on PATH resolved to `rustup-init` | |
| # (the installer) instead of the rustup proxy — every | |
| # `cargo metadata` / `cargo build` invocation errored with | |
| # "unexpected argument 'metadata'/'build' found" against | |
| # rustup-init's flag set. Image was broken across two | |
| # back-to-back v0.4.2 release attempts on 2026-05-14. | |
| # macos-15 is the current Apple-silicon runner and works. | |
| runner: macos-15 | |
| use_cross: false | |
| # x86_64-apple-darwin temporarily removed — GitHub's macos-13 | |
| # runners aren't reliably building this target. Re-add when the | |
| # runner availability stabilises (Intel Mac users can use the | |
| # linux-x86_64 binary via Rosetta in the meantime). | |
| - target: x86_64-unknown-linux-gnu | |
| runner: ubuntu-latest | |
| use_cross: false | |
| - target: aarch64-unknown-linux-gnu | |
| runner: ubuntu-latest | |
| use_cross: true | |
| - target: x86_64-unknown-linux-musl | |
| runner: ubuntu-latest | |
| use_cross: false | |
| apt: musl-tools | |
| - target: aarch64-unknown-linux-musl | |
| runner: ubuntu-latest | |
| use_cross: true | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| target: ${{ matrix.target }} | |
| # Cache ~/.cargo/{registry,git} and target/. Keyed on Cargo.lock + | |
| # target triple so a `cargo update` invalidates correctly. Cross-rs | |
| # targets benefit primarily from the registry cache (the build itself | |
| # runs inside a Docker container, so target/ reuse there is partial). | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: ${{ matrix.target }} | |
| shared-key: release | |
| # The macos GitHub runner images (both macos-14 and macos-15) | |
| # intermittently leave the cargo proxy in a broken state where | |
| # `cargo build` fails with "rustup-init: unexpected argument | |
| # 'build' found" — the proxy is resolving to the multi-call | |
| # installer binary with no default toolchain set, so it can't | |
| # dispatch the subcommand. setup-rust-toolchain reports success | |
| # but the next cargo invocation fails. | |
| # | |
| # The recovery must run *after* Swatinem/rust-cache@v2 because | |
| # rust-cache has `cache-bin: true` and will restore a stale | |
| # `~/.cargo/bin` from a previous cache hit, overwriting any | |
| # earlier reinstall. We run last so whatever rust-cache restored | |
| # is the final state we're fixing up. | |
| # | |
| # Probe with a real subcommand. `cargo metadata --no-deps | |
| # --format-version 1` requires a working toolchain to parse the | |
| # manifest — rustup-init's multi-call binary can't fake it. | |
| # `cargo --version` is fooled because rustup-init recognizes | |
| # `--version` as one of its own flags and prints with exit 0. | |
| # | |
| # Linux runners haven't shown this flake; gating on apple-darwin | |
| # keeps the workaround surgical and the linux builds free of the | |
| # extra step. Healthy macos runs hit the probe-passes path and | |
| # no-op past the curl. | |
| - name: Recover from broken rustup state (macos) | |
| if: contains(matrix.target, 'apple-darwin') | |
| shell: bash | |
| run: | | |
| if ! cargo metadata --no-deps --format-version 1 >/dev/null 2>&1; then | |
| echo "::warning::cargo proxy is broken (rustup-init shadowing with no default toolchain). Reinstalling stable." | |
| curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | |
| | sh -s -- -y --no-modify-path --default-toolchain stable --profile minimal | |
| echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" | |
| export PATH="$HOME/.cargo/bin:$PATH" | |
| rustup default stable | |
| rustup target add "${{ matrix.target }}" | |
| fi | |
| rustup show | |
| cargo metadata --no-deps --format-version 1 >/dev/null | |
| echo "cargo proxy verified" | |
| which cargo | |
| - name: Install apt packages | |
| if: matrix.apt | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y ${{ matrix.apt }} | |
| - name: Install cross | |
| if: matrix.use_cross | |
| run: cargo install cross --locked | |
| - name: Resolve version | |
| id: ver | |
| shell: bash | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| tag="${{ inputs.tag }}" | |
| else | |
| tag="${GITHUB_REF_NAME}" | |
| fi | |
| version="${tag#v}" | |
| echo "tag=$tag" >> "$GITHUB_OUTPUT" | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| - name: Build | |
| shell: bash | |
| env: | |
| # Bake the released tag's version (without the v prefix) into the | |
| # binary via option_env!("RELEASE_VERSION"). The runtime update | |
| # check uses this to decide whether the running binary is current. | |
| RELEASE_VERSION: ${{ steps.ver.outputs.version }} | |
| run: | | |
| if [ "${{ matrix.use_cross }}" = "true" ]; then | |
| cross build --release --workspace --target ${{ matrix.target }} | |
| else | |
| cargo build --release --workspace --target ${{ matrix.target }} | |
| fi | |
| - name: Package tarball | |
| id: pkg | |
| shell: bash | |
| run: | | |
| name="skills-and-validation-${{ steps.ver.outputs.version }}-${{ matrix.target }}" | |
| mkdir -p "$name/bin" "$name/content" "$name/templates" | |
| cp "target/${{ matrix.target }}/release/iii-skill-check" "$name/bin/" | |
| cp "target/${{ matrix.target }}/release/iii-skill-render" "$name/bin/" | |
| cp -r content/. "$name/content/" | |
| cp -r templates/. "$name/templates/" | |
| echo "${{ steps.ver.outputs.version }}" > "$name/VERSION" | |
| tar -czf "$name.tar.gz" "$name" | |
| if command -v sha256sum >/dev/null 2>&1; then | |
| sha256sum "$name.tar.gz" > "$name.tar.gz.sha256" | |
| else | |
| shasum -a 256 "$name.tar.gz" > "$name.tar.gz.sha256" | |
| fi | |
| cat "$name.tar.gz.sha256" | |
| echo "name=$name" >> "$GITHUB_OUTPUT" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: ${{ steps.pkg.outputs.name }} | |
| path: | | |
| ${{ steps.pkg.outputs.name }}.tar.gz | |
| ${{ steps.pkg.outputs.name }}.tar.gz.sha256 | |
| retention-days: 7 | |
| if-no-files-found: error | |
| release: | |
| name: publish release | |
| needs: build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v5 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| - name: Resolve tag | |
| id: ver | |
| shell: bash | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| tag="${{ inputs.tag }}" | |
| else | |
| tag="${GITHUB_REF_NAME}" | |
| fi | |
| echo "tag=$tag" >> "$GITHUB_OUTPUT" | |
| - name: Create or update release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| shell: bash | |
| run: | | |
| tag="${{ steps.ver.outputs.tag }}" | |
| if ! gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then | |
| gh release create "$tag" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --title "$tag" \ | |
| --generate-notes | |
| fi | |
| for f in dist/*.tar.gz dist/*.tar.gz.sha256; do | |
| [ -f "$f" ] || continue | |
| gh release upload "$tag" "$f" --repo "$GITHUB_REPOSITORY" --clobber | |
| done | |
| # Re-point floating tags so consumers can pin a moving target: | |
| # `vMAJOR.MINOR` (e.g. v0.1) tracks every patch on its line — | |
| # used by `uses: iii-hq/skills-and-validation@v0.1` and | |
| # `version: 0.1` in .skill-check.yaml. | |
| # `latest` tracks the most recent stable release across all | |
| # versions — used by install.sh's default install path. | |
| - name: Force-update floating tags | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| shell: bash | |
| run: | | |
| tag="${{ steps.ver.outputs.tag }}" | |
| if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "tag '$tag' is not vMAJOR.MINOR.PATCH; skipping floating tags" | |
| exit 0 | |
| fi | |
| sha="${{ github.sha }}" | |
| minor=$(echo "$tag" | sed -E 's/^(v[0-9]+\.[0-9]+)\.[0-9]+$/\1/') | |
| repoint() { | |
| local ref="$1" | |
| if gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/${ref}" >/dev/null 2>&1; then | |
| gh api -X PATCH "repos/${GITHUB_REPOSITORY}/git/refs/tags/${ref}" \ | |
| -f sha="$sha" -F force=true | |
| echo "updated floating tag ${ref} -> $sha" | |
| else | |
| gh api -X POST "repos/${GITHUB_REPOSITORY}/git/refs" \ | |
| -f ref="refs/tags/${ref}" -f sha="$sha" | |
| echo "created floating tag ${ref} -> $sha" | |
| fi | |
| } | |
| repoint "$minor" | |
| repoint latest |