4.2 KiB · text History f1c3bee
name: publish

# A tag publishes; master only checks that a publish *would* work.
#
# Cargo refuses to overwrite a published version, and rightly — so a workflow
# that published on every push would fail on its second run and stay failed
# until someone bumped the version. The dry run on master is the useful half of
# that anyway: it catches a manifest that cannot be packaged at the commit that
# broke it, rather than at the tag three weeks later.
on:
  push:
    branches: [master]
    tags: ['v*']

jobs:
  publish:
    runs-on: self-hosted

    env:
      # `cargo publish` needs a host toolchain and nothing else — no ESP
      # anything, since esp-idf-svc is target-scoped in Cargo.toml and a host
      # build compiles only the pure modules.
      #
      # Installed here rather than taken from a `container:` image, because the
      # runner executes JavaScript actions with node inside the job container
      # and `rust:1.90-bookworm` has no node: `actions/checkout@v4` would die
      # before this workflow started. (lambent-flex-c6 hits the same wall from
      # the other side; see its firmware.yml.)
      RUST_VERSION: "1.90.0"
      REGISTRY_NAME: neiam-portal

    steps:
      - uses: actions/checkout@v4

      - name: Resolve the forge URL
        env:
          CI_FORGE_URL: ${{ vars.CI_FORGE_URL }}
        run: |
          set -euo pipefail
          forge_url=${CI_FORGE_URL:-${GITHUB_SERVER_URL:-}}

          if [ -z "$forge_url" ]; then
            echo "No forge URL available." >&2
            echo "Set a CI_FORGE_URL variable on this repository or its org." >&2
            exit 1
          fi

          echo "FORGE_URL=$forge_url" >> "$GITHUB_ENV"

      - name: Cache the toolchain and the registry
        uses: actions/cache@v4
        with:
          path: |
            .home
            target
          key: rust-${{ env.RUST_VERSION }}-${{ hashFiles('Cargo.toml') }}
          restore-keys: rust-${{ env.RUST_VERSION }}-

      - name: Rust
        run: |
          set -euo pipefail
          export RUSTUP_HOME="$PWD/.home/.rustup" CARGO_HOME="$PWD/.home/.cargo"
          echo "RUSTUP_HOME=$RUSTUP_HOME" >> "$GITHUB_ENV"
          echo "CARGO_HOME=$CARGO_HOME" >> "$GITHUB_ENV"
          echo "$CARGO_HOME/bin" >> "$GITHUB_PATH"

          if [ ! -x "$CARGO_HOME/bin/cargo" ]; then
            curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
              | sh -s -- -y --profile minimal --default-toolchain "$RUST_VERSION"
          fi

          "$CARGO_HOME/bin/cargo" --version

      # The registry is per repository: its index lives under this repository's
      # own path, and the name a consumer registers it under is the repository
      # name. Cargo takes an index from configuration only, never a flag — and
      # this goes in CARGO_HOME rather than ./.cargo/config.toml on purpose,
      # because `cargo publish` refuses a dirty working tree and writing into
      # the checkout would make it one.
      - name: Point cargo at the forge
        run: |
          set -euo pipefail
          mkdir -p "$CARGO_HOME"
          cat >> "$CARGO_HOME/config.toml" <<TOML

          [registries.$REGISTRY_NAME]
          index = "sparse+$FORGE_URL/pkg/cargo/${{ github.repository }}/"
          TOML
          cat "$CARGO_HOME/config.toml"

      # `${{ github.token }}` is minted for this job and may write this
      # repository's packages and nothing else, so there is no secret to create
      # first. Cargo reads it from CARGO_REGISTRIES_<NAME>_TOKEN, uppercased
      # with every non-alphanumeric run folded to `_`.
      - name: Publish
        env:
          CARGO_REGISTRIES_NEIAM_PORTAL_TOKEN: ${{ github.token }}
        run: |
          set -euo pipefail

          if [ "${GITHUB_REF_TYPE:-branch}" = "tag" ]; then
            cargo publish --registry "$REGISTRY_NAME"
            echo
            echo "Published. Consumers add:"
            echo "  [registries.$REGISTRY_NAME]"
            echo "  index = \"sparse+$FORGE_URL/pkg/cargo/${{ github.repository }}/\""
          else
            # --dry-run still packages and verify-builds; it just does not
            # upload. That is the whole value of running this on master.
            cargo publish --registry "$REGISTRY_NAME" --dry-run
          fi