fix(install): write --mcp flag to claude_desktop_config.json (v0.9.1) #28
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
| # Copyright (c) 2025-2026 Anton Kundenko <singaraiona@gmail.com> | |
| # All rights reserved. | |
| # | |
| # Permission is hereby granted, free of charge, to any person obtaining a copy | |
| # of this software and associated documentation files (the "Software"), to deal | |
| # in the Software without restriction, including without limitation the rights | |
| # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| # copies of the Software, and to permit persons to whom the Software is | |
| # furnished to do so, subject to the following conditions: | |
| # | |
| # The above copyright notice and this permission notice shall be included in all | |
| # copies or substantial portions of the Software. | |
| # | |
| # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| # SOFTWARE. | |
| # Tag-driven release pipeline. Push a `vX.Y.Z` tag and this workflow: | |
| # 1. Verifies the tag matches Cargo.toml's version field. | |
| # 2. Vendors rayforce at the SHA pinned in `.rayforce-version`. | |
| # 3. Runs cargo test. | |
| # 4. Publishes the crate to crates.io (idempotent: skips if already there). | |
| # 5. Generates release notes from conventional commits since the previous tag. | |
| # 6. Creates the GitHub Release with those notes. | |
| # 7. Smoke-tests the published crate (cargo install + cargo check as dep). | |
| # | |
| # Manual dry-run available via the workflow_dispatch trigger; that path | |
| # does `cargo publish --dry-run` and skips release-creation. | |
| name: publish | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| inputs: | |
| dry_run: | |
| description: "Run publish + smoke commands with --dry-run" | |
| required: true | |
| type: boolean | |
| default: true | |
| concurrency: | |
| group: publish-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| publish: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # needed for `gh release create` | |
| steps: | |
| - name: Checkout raysense | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 # full history needed for changelog generation | |
| - name: Resolve target version | |
| id: version | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| cargo_version="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)" | |
| if [[ -z "$cargo_version" ]]; then | |
| echo "::error::Could not parse version from Cargo.toml" >&2 | |
| exit 1 | |
| fi | |
| echo "value=$cargo_version" >> "$GITHUB_OUTPUT" | |
| if [[ "${GITHUB_REF}" == refs/tags/v* ]]; then | |
| tag_version="${GITHUB_REF_NAME#v}" | |
| if [[ "$tag_version" != "$cargo_version" ]]; then | |
| echo "::error::Tag $GITHUB_REF_NAME implies version $tag_version but Cargo.toml has $cargo_version. Bump Cargo.toml or retag." >&2 | |
| exit 1 | |
| fi | |
| echo "is_tag=true" >> "$GITHUB_OUTPUT" | |
| echo "tag=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "is_tag=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "Resolved version: $cargo_version" | |
| - name: Vendor rayforce at pinned SHA | |
| # The published .crate must contain the rayforce source so end users | |
| # can `cargo install raysense` without network access. Clone it | |
| # here, strip .git/, and let `cargo package` pick it up via the | |
| # Cargo.toml `include` whitelist (vendor/ is gitignored otherwise). | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| sha="$(cat .rayforce-version | tr -d '[:space:]')" | |
| if [[ -z "$sha" ]]; then | |
| echo "::error::.rayforce-version is empty" >&2 | |
| exit 1 | |
| fi | |
| mkdir -p vendor | |
| rm -rf vendor/rayforce | |
| git -c advice.detachedHead=false clone --quiet \ | |
| https://github.com/RayforceDB/rayforce.git vendor/rayforce | |
| git -C vendor/rayforce checkout --quiet "$sha" | |
| rm -rf vendor/rayforce/.git | |
| test -f vendor/rayforce/Makefile || { echo "::error::Makefile missing" >&2; exit 1; } | |
| - name: Test | |
| run: cargo test | |
| - name: Publish to crates.io | |
| shell: bash | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| DRY_RUN: ${{ inputs.dry_run || 'false' }} | |
| VERSION: ${{ steps.version.outputs.value }} | |
| run: | | |
| set -euo pipefail | |
| already_published() { | |
| cargo search raysense --limit 1 | grep -q "^raysense = \"$VERSION\"" | |
| } | |
| # `--allow-dirty` is required because the CI vendor step writes | |
| # vendor/rayforce/ at clone time, but vendor/ is in .gitignore | |
| # (the source of truth is upstream + .rayforce-version, not the | |
| # committed tree). cargo package would otherwise refuse to ship | |
| # what it sees as "uncommitted changes". | |
| if [[ "$DRY_RUN" == "true" ]]; then | |
| echo "::notice::Dry run: cargo package + cargo publish --dry-run" | |
| cargo package --allow-dirty | |
| cargo publish --dry-run --allow-dirty | |
| exit 0 | |
| fi | |
| if already_published; then | |
| echo "raysense $VERSION is already on crates.io, skipping publish" | |
| exit 0 | |
| fi | |
| cargo package --allow-dirty | |
| cargo publish --allow-dirty | |
| # Wait for the registry index to catch up before declaring success. | |
| for delay in 10 20 30 60 90; do | |
| if already_published; then | |
| echo "raysense $VERSION is now visible on crates.io" | |
| exit 0 | |
| fi | |
| sleep "$delay" | |
| done | |
| echo "::error::raysense $VERSION did not appear in the registry index in time" >&2 | |
| exit 1 | |
| - name: Generate release notes | |
| if: steps.version.outputs.is_tag == 'true' | |
| id: notes | |
| shell: bash | |
| env: | |
| TAG: ${{ steps.version.outputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| # Pick the closest tag that strictly precedes HEAD (i.e. the | |
| # previous release). On the first ever release there is none, | |
| # so fall back to the full history. | |
| prev_tag="$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || true)" | |
| if [[ -n "$prev_tag" ]]; then | |
| range="${prev_tag}..HEAD" | |
| compare_url="https://github.com/${GITHUB_REPOSITORY}/compare/${prev_tag}...${TAG}" | |
| else | |
| range="HEAD" | |
| compare_url="https://github.com/${GITHUB_REPOSITORY}/commits/${TAG}" | |
| fi | |
| # Group commits by conventional-commit type. Each group emits | |
| # only if it had any matching commits. | |
| notes=release-notes.md | |
| : > "$notes" | |
| emit_section() { | |
| local heading="$1" pattern="$2" entries | |
| entries="$(git log --pretty='format:- %s (%h)' "$range" \ | |
| | grep -E "^- ${pattern}(\([^)]*\))?(!)?: " \ | |
| | sed -E "s/^- ${pattern}(\([^)]*\))?(!)?: /- /" || true)" | |
| if [[ -n "$entries" ]]; then | |
| { | |
| echo "### $heading" | |
| echo | |
| echo "$entries" | |
| echo | |
| } >> "$notes" | |
| fi | |
| } | |
| { | |
| echo "## What's changed" | |
| echo | |
| } >> "$notes" | |
| emit_section "Features" "feat" | |
| emit_section "Bug fixes" "fix" | |
| emit_section "Performance" "perf" | |
| emit_section "Refactoring" "refactor" | |
| emit_section "Documentation" "docs" | |
| emit_section "Build & CI" "build|ci" | |
| emit_section "Chores" "chore|style|test" | |
| # Catch-all for anything that did not match the patterns above. | |
| other="$(git log --pretty='format:- %s (%h)' "$range" \ | |
| | grep -vE "^- (feat|fix|perf|refactor|docs|build|ci|chore|style|test)(\([^)]*\))?(!)?: " || true)" | |
| if [[ -n "$other" ]]; then | |
| { | |
| echo "### Other" | |
| echo | |
| echo "$other" | |
| echo | |
| } >> "$notes" | |
| fi | |
| { | |
| echo "**Full changelog:** $compare_url" | |
| } >> "$notes" | |
| echo "Generated notes:" | |
| cat "$notes" | |
| echo "notes_file=$notes" >> "$GITHUB_OUTPUT" | |
| - name: Create GitHub Release | |
| if: steps.version.outputs.is_tag == 'true' && (inputs.dry_run != true) | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAG: ${{ steps.version.outputs.tag }} | |
| NOTES_FILE: ${{ steps.notes.outputs.notes_file }} | |
| run: | | |
| set -euo pipefail | |
| if gh release view "$TAG" >/dev/null 2>&1; then | |
| echo "Release $TAG already exists, updating notes" | |
| gh release edit "$TAG" --notes-file "$NOTES_FILE" | |
| else | |
| gh release create "$TAG" \ | |
| --title "raysense $TAG" \ | |
| --notes-file "$NOTES_FILE" | |
| fi | |
| - name: Smoke test the published crate | |
| if: inputs.dry_run != true | |
| shell: bash | |
| env: | |
| VERSION: ${{ steps.version.outputs.value }} | |
| run: | | |
| set -euo pipefail | |
| smoke_dir="$(mktemp -d)" | |
| cargo install raysense --version "$VERSION" --root "$smoke_dir/install" | |
| "$smoke_dir/install/bin/raysense" --version | |
| cargo new "$smoke_dir/library-smoke" | |
| cd "$smoke_dir/library-smoke" | |
| cargo add "raysense@$VERSION" | |
| cargo check |