hocon-parser 1.6.1

Full Lightbend HOCON specification-compliant parser for Rust
Documentation
name: Publish

on:
  push:
    tags:
      - "v*"

permissions:
  contents: write
  id-token: write

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: dtolnay/rust-toolchain@stable
      - name: Install cargo-set-version
        run: cargo install cargo-set-version

      - name: Set version from tag
        run: |
          TAG_VERSION="${GITHUB_REF#refs/tags/v}"
          CURRENT=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
          if [ "$TAG_VERSION" != "$CURRENT" ]; then
            cargo set-version "$TAG_VERSION"
          fi

      # Cache is split into restore+save so the save key is content-addressable
      # via the post-fetch hash of `.xx-hocon-version`. On a fresh checkout,
      # `.xx-hocon-version` is gitignored and absent at restore time, so the
      # restore step relies on `restore-keys` to match the most recent entry.
      # Mirrors the test.yml pattern so the publish job doesn't re-fetch on
      # every tag push (avoids GitHub API rate-limit + transient network
      # failures during release). (closes #101)
      - name: Restore expected JSON cache
        uses: actions/cache/restore@v5
        with:
          path: |
            tests/testdata/expected
            .xx-hocon-version
          key: xx-hocon-expected-pending
          restore-keys: xx-hocon-expected-

      - name: Fetch expected JSON sidecars from xx.hocon
        # tests/concat_errors_test.rs, tests/s8_unquoted_starts.rs, and
        # other sidecar-driven conformance tests need `tests/testdata/expected/`
        # populated. That dir is gitignored (repo convention — sidecars are
        # fetched, not vendored), so without this step the publish-time
        # `cargo test` fails with "no expected sidecar" panics on ce01-ce15
        # / us02-us30 etc. Mirrors ts.hocon release.yml fix from v1.2.0
        # publish regression. The Makefile's early-exit on matching pin SHA
        # makes this a no-op when the cache hit above is fresh.
        run: make testdata

      # Default `if: success()` — skip the save if `make testdata` failed so
      # we don't write a partial/missing-pin cache under the empty-hash key
      # (which would collapse to the constant `xx-hocon-expected-` and
      # recreate the bug this PR is fixing). Copilot review thread.
      - name: Save expected JSON cache
        uses: actions/cache/save@v5
        with:
          path: |
            tests/testdata/expected
            .xx-hocon-version
          key: xx-hocon-expected-${{ hashFiles('.xx-hocon-version') }}

      - run: cargo test
      - run: cargo test --features serde

      - name: Extract CHANGELOG section for this tag
        # Pulls the section between `## [VERSION]` and the next `## [`
        # from CHANGELOG.md so the GitHub Release body matches what's
        # already committed and reviewed.
        #
        # Uses `index($0, str) == 1` (prefix match) rather than awk regex
        # so SemVer build metadata (`+...`) and other regex metacharacters
        # in version strings can't break or overmatch the section header.
        #
        # Runs BEFORE `cargo publish` (and the GitHub Release step below)
        # so that a missing/incorrect CHANGELOG heading fails the run
        # without first publishing to crates.io — crates.io doesn't allow
        # republishing the same version, so an irreversible publish
        # followed by a failed release step would leave a half-shipped tag.
        run: |
          VERSION="${GITHUB_REF#refs/tags/v}"
          awk -v ver="$VERSION" '
            index($0, "## [" ver "]") == 1 { flag=1; next }
            flag && index($0, "## [") == 1 { flag=0 }
            flag
          ' CHANGELOG.md > /tmp/release-notes.md
          if [ ! -s /tmp/release-notes.md ]; then
            echo "::error::No CHANGELOG section found for v${VERSION}; aborting release so an empty body doesn't ship"
            exit 1
          fi

      - name: Create GitHub Release
        # Runs before `cargo publish` so a Release-creation failure doesn't
        # leave us with a crate published but no GitHub Release entry
        # (crates.io forbids republishing the same version, so a retry
        # would fail at `cargo publish` and never reach this step again).
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ github.ref_name }}
          name: ${{ github.ref_name }}
          body_path: /tmp/release-notes.md
          fail_on_unmatched_files: false
          make_latest: true

      - name: Authenticate with crates.io
        id: auth
        uses: rust-lang/crates-io-auth-action@v1

      - name: Publish
        run: cargo publish --allow-dirty
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}