litelite 0.2.0

A kit for purpose-sized languages: buy total verification with smallness. Diagnostics, lexing, parsing, fuel, and capability tables — the invariants paid once.
Documentation
name: release

# Pushing the tag `v0.1.0` publishes 0.1.0. NOTHING else does — and publishing
# is forever, so every gate CI runs runs here too, plus two more: the tag must
# agree with the workspace version, and CHANGELOG must have that section.
on:
  push:
    tags: ["v*"]
  # Rehearse the whole path (gates + a real dry-run publish) with no side
  # effects. Safe from ANY ref, tags included: the publish steps below key on
  # the EVENT, never on the ref shape, because GitHub happily dispatches a
  # workflow against a tag — and "I pressed rehearse" must never upload.
  workflow_dispatch:

permissions:
  contents: write # create the GitHub release

# One release at a time, and NEVER cancel one in flight: a half-cancelled
# publish leaves crate names claimed with no release to show for it. The
# rate-limited first publish can run for an hour; a re-pushed tag waits.
concurrency:
  group: release
  cancel-in-progress: false

jobs:
  release:
    runs-on: ubuntu-latest
    env:
      # The real thing only on a pushed tag. Every irreversible step tests
      # this one variable, so the rehearsal path cannot drift into uploading.
      SHIPPING: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') }}
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy
          targets: wasm32-unknown-unknown

      # A release is not a reason to skip the gates.
      - run: cargo fmt --check
      - run: cargo clippy --workspace --all-targets -- -D warnings
      - run: cargo test --workspace
      - run: cargo check --workspace --target wasm32-unknown-unknown
      - run: bash scripts/caps.sh

      - name: The tag is a version claim — check it
        if: env.SHIPPING == 'true'
        run: |
          want="${GITHUB_REF_NAME#v}"
          got=$(cargo tree --workspace --depth 0 |
            awk '$1 == "litelite" {print substr($2, 2); exit}')
          if [ "$want" != "$got" ]; then
            echo "FAIL: tag ${GITHUB_REF_NAME} claims $want, the workspace says $got"
            exit 1
          fi
          echo "tag ${GITHUB_REF_NAME} == workspace $got"

      # Exact field match, not a regex: a version's dots are not wildcards,
      # and `## 0.2.0` with no date suffix is still a real section.
      - name: The tag has release notes — check it
        if: env.SHIPPING == 'true'
        run: |
          awk -v v="${GITHUB_REF_NAME#v}" \
            '$1 == "##" && $2 == v {f = 1; next} /^## /{f = 0} f' CHANGELOG.md > NOTES.md
          if [ ! -s NOTES.md ]; then
            echo "FAIL: CHANGELOG.md has no '## ${GITHUB_REF_NAME#v}' section"
            exit 1
          fi
          cat NOTES.md

      # Manual runs stop here: gates + a real dry-run upload, no side effects.
      - name: Rehearse the publish
        if: env.SHIPPING != 'true'
        run: bash scripts/publish.sh

      # crates.io rate-limits NEW crates, so the first release may stop
      # partway. Re-run this job: publish.sh skips whatever is already live.
      - name: Publish to crates.io
        if: env.SHIPPING == 'true'
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: |
          if [ -z "${CARGO_REGISTRY_TOKEN}" ]; then
            echo "FAIL: the CARGO_REGISTRY_TOKEN secret is not set"
            exit 1
          fi
          bash scripts/publish.sh --execute

      # Last, so a release never claims what crates.io refused. Idempotent:
      # re-running a job whose publish already finished must not fail here.
      - name: GitHub release
        if: env.SHIPPING == 'true'
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then
            echo "release ${GITHUB_REF_NAME} already exists — leaving it alone"
            exit 0
          fi
          gh release create "${GITHUB_REF_NAME}" \
            --title "litelite ${GITHUB_REF_NAME}" \
            --notes-file NOTES.md \
            --verify-tag