srcwalk 0.2.5

Tree-sitter indexed lookups — smart code reading for AI agents
Documentation
name: Release

on:
  push:
    tags: ["v*"]

# Top-level: read-only by default. Jobs opt-in to higher permissions.
permissions:
  contents: read

# Prevent two releases of the same tag racing each other.
concurrency:
  group: release-${{ github.ref }}
  cancel-in-progress: false

env:
  CARGO_TERM_COLOR: always

jobs:
  # Fail fast if Cargo.toml / npm package.json versions don't match the tag.
  version-check:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Verify versions match tag
        run: |
          set -euo pipefail
          TAG="${GITHUB_REF#refs/tags/v}"
          CARGO_VER=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
          NPM_VER=$(node -p "require('./npm/package.json').version")
          echo "Tag: $TAG  Cargo: $CARGO_VER  npm: $NPM_VER"
          if [ "$CARGO_VER" != "$TAG" ]; then
            echo "::error::Cargo.toml version ($CARGO_VER) does not match tag ($TAG)"
            exit 1
          fi
          if [ "$NPM_VER" != "$TAG" ]; then
            echo "::error::npm/package.json version ($NPM_VER) does not match tag ($TAG)"
            exit 1
          fi

  build:
    needs: version-check
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        include:
          - target: x86_64-unknown-linux-musl
            os: ubuntu-latest
            cross: true
          - target: aarch64-unknown-linux-musl
            os: ubuntu-latest
            cross: true
          - target: x86_64-apple-darwin
            os: macos-latest
            cross: false
          - target: aarch64-apple-darwin
            os: macos-latest
            cross: false

    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
        with:
          targets: ${{ matrix.target }}

      - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1
        with:
          key: ${{ matrix.target }}

      # cross pulls a Docker image; pin it via --locked for reproducibility.
      - name: Install cross
        if: matrix.cross
        run: cargo install cross --version 0.2.5 --locked

      - name: Build
        shell: bash
        run: |
          set -euo pipefail
          if [ "${{ matrix.cross }}" = "true" ]; then
            cross build --release --locked --target ${{ matrix.target }} --bin srcwalk
          else
            cargo build --release --locked --target ${{ matrix.target }} --bin srcwalk
          fi

      - name: Package
        shell: bash
        run: |
          set -euo pipefail
          cd target/${{ matrix.target }}/release
          tar czf ../../../srcwalk-${{ matrix.target }}.tar.gz srcwalk
          cd ../../..
          shasum -a 256 srcwalk-${{ matrix.target }}.tar.gz > srcwalk-${{ matrix.target }}.tar.gz.sha256

      - name: Upload artifacts
        uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
        with:
          name: srcwalk-${{ matrix.target }}
          path: |
            srcwalk-${{ matrix.target }}.tar.gz
            srcwalk-${{ matrix.target }}.tar.gz.sha256
          if-no-files-found: ignore
          retention-days: 7

  release:
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: write        # create release + upload assets
      id-token: write        # sign build provenance (SLSA)
      attestations: write    # write attestations to repo
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false

      - name: Download all artifacts
        uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
        with:
          path: dist
          merge-multiple: true

      - name: List artifacts
        run: ls -la dist/

      # SLSA build provenance — binary signed, verifiable via `gh attestation verify`.
      - name: Attest build provenance
        uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
        with:
          subject-path: |
            dist/srcwalk-*.tar.gz

      - name: Build release notes from changelog
        shell: bash
        run: |
          set -euo pipefail
          TAG="${GITHUB_REF_NAME#v}"
          awk -v tag="$TAG" '
            index($0, "## [" tag "]") == 1 { in_section=1; next }
            in_section && index($0, "## [") == 1 { exit }
            in_section { print }
          ' CHANGELOG.md > release-notes.md
          if [ ! -s release-notes.md ]; then
            echo "::error::No CHANGELOG.md section found for $GITHUB_REF_NAME"
            exit 1
          fi

      - name: Create release
        uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
        with:
          files: |
            dist/srcwalk-*.tar.gz
            dist/srcwalk-*.tar.gz.sha256
          body_path: release-notes.md
          fail_on_unmatched_files: true

  publish-crate:
    needs: release
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
      - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
      - run: cargo publish --locked
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

  publish-npm:
    needs: release
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write          # OIDC for npm provenance
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
      - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
        with:
          node-version: 20
          registry-url: https://registry.npmjs.org
      - run: npm publish --provenance --access public
        working-directory: npm
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}