ref(mcp): drop the root .mcp.json compat copy (#319) #70
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
| # Deploy per-agent plugin distributions to their own repositories. | |
| # | |
| # This repository is the single source of truth (skills + routing metadata, | |
| # feeding skills.sentry.dev). Each AI assistant needs the plugin in a different | |
| # shape, so this workflow builds each one and deploys it to a dedicated | |
| # repository whose ROOT is exactly that agent's plugin: | |
| # | |
| # claude -> getsentry/plugin-claude | |
| # cursor -> getsentry/plugin-cursor | |
| # codex -> getsentry/plugin-codex | |
| # grok -> getsentry/plugin-grok | |
| # | |
| # Each plugin repository carries two rolling branches, and which one a run writes | |
| # is the whole difference between a deploy and a release: | |
| # | |
| # develop every push to this repo's main, so its tip is always the latest | |
| # build. Nothing installs from it by default; it is where a change is | |
| # visible and testable before it ships. | |
| # main release tags only, driven by release-plugins.yml. This is the branch | |
| # consumers resolve -- Anthropic's marketplace pins plugin-claude by | |
| # SHA, the installer clones plugin-cursor, and the codex/grok CLIs | |
| # install by repository -- so it moves when we say a version is out, | |
| # not on every merge. | |
| # | |
| # A release also tags the plugin repository (`v<version>`), giving each shipped | |
| # version an addressable ref for pinning and rollback. | |
| # | |
| # Marketplaces consume `getsentry/plugin-<agent>` by git ref. Each job builds its | |
| # agent's tree from this repo, then commits it onto the target branch of the | |
| # target repo, replacing the previous contents. The four jobs target four | |
| # different repos, so they run in parallel without contention. | |
| # | |
| # Cross-repo writes use a GitHub App token scoped per-job to a single plugin | |
| # repo; the default GITHUB_TOKEN cannot push to other repositories. The app must | |
| # be installed on the org with contents:write on the four plugin repos, its ID | |
| # stored as the PLUGIN_DEPLOY_APP_ID variable and its private key as the | |
| # PLUGIN_DEPLOY_KEY secret. Each target repo must already exist with `main` as | |
| # its default branch; `develop` is branched off it on the first deploy. | |
| name: Deploy plugins | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - "src/skills/**" | |
| - "src/references/**" | |
| - "src/SKILL_TREE.md" | |
| - "src/plugins/**" | |
| - "assets/**" | |
| - "LICENSE" | |
| - "*.json" | |
| - "scripts/**" | |
| - ".github/workflows/deploy-plugins.yml" | |
| workflow_dispatch: | |
| # Called by release-plugins.yml to publish a tagged tree. A tag push cannot | |
| # drive this directly: `paths` filters do not match a push that adds no | |
| # commits, so a tag pointing at an existing commit would silently skip the | |
| # deploy. The release workflow calls in with an explicit ref instead. | |
| workflow_call: | |
| inputs: | |
| ref: | |
| description: Ref of this repository to build from. | |
| type: string | |
| required: true | |
| target_branch: | |
| description: Branch to publish onto in each plugin repository. | |
| type: string | |
| required: true | |
| dist_tag: | |
| description: Tag to create in each plugin repository. Empty creates none. | |
| type: string | |
| required: false | |
| default: "" | |
| permissions: | |
| contents: read | |
| jobs: | |
| deploy: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| agent: [claude, cursor, codex, grok] | |
| concurrency: | |
| group: deploy-plugin-${{ matrix.agent }}-${{ inputs.target_branch || 'develop' }} | |
| cancel-in-progress: false | |
| steps: | |
| - name: Checkout source | |
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| ref: ${{ inputs.ref || github.sha }} | |
| # scripts/dev-version.sh derives the develop stamp from `git describe`, | |
| # which needs the tags and the commits since the last one. | |
| fetch-depth: 0 | |
| - name: Mint deploy token | |
| id: token | |
| uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 | |
| with: | |
| app-id: ${{ vars.PLUGIN_DEPLOY_APP_ID }} | |
| private-key: ${{ secrets.PLUGIN_DEPLOY_KEY }} | |
| owner: getsentry | |
| repositories: plugin-${{ matrix.agent }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 # v8.2.0 | |
| - name: Build and deploy plugin-${{ matrix.agent }} | |
| env: | |
| AGENT: ${{ matrix.agent }} | |
| TARGET_BRANCH: ${{ inputs.target_branch || 'develop' }} | |
| DIST_TAG: ${{ inputs.dist_tag || '' }} | |
| GH_TOKEN: ${{ steps.token.outputs.token }} | |
| run: | | |
| set -euo pipefail | |
| TARGET_REPO="plugin-${AGENT}" | |
| WORKTREE="$(mktemp -d)/dist" | |
| # Read the built commit out of the checkout rather than github.sha, | |
| # which in a called workflow reports the caller's commit instead. | |
| SRC_SHA="$(git rev-parse HEAD)" | |
| # A release stamps the version being released; anything else is a | |
| # develop build and gets labelled with its distance from the last tag. | |
| if [[ -z "$DIST_TAG" ]]; then | |
| PLUGIN_VERSION="$(scripts/dev-version.sh)" | |
| export PLUGIN_VERSION | |
| echo "::notice::stamping develop build as ${PLUGIN_VERSION}" | |
| fi | |
| # Clone the target repo (lands on its default branch, `main`). | |
| git clone "https://x-access-token:${GH_TOKEN}@github.com/getsentry/${TARGET_REPO}.git" "$WORKTREE" | |
| git -C "$WORKTREE" config user.name "github-actions[bot]" | |
| git -C "$WORKTREE" config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| # Land on the target branch, branching it off the default branch on the | |
| # first deploy that needs it. | |
| if git -C "$WORKTREE" ls-remote --exit-code --heads origin "$TARGET_BRANCH" > /dev/null; then | |
| git -C "$WORKTREE" checkout "$TARGET_BRANCH" | |
| else | |
| echo "::notice::${TARGET_REPO} has no ${TARGET_BRANCH} yet; creating it" | |
| git -C "$WORKTREE" checkout -b "$TARGET_BRANCH" | |
| fi | |
| # Rewrite the whole tree: clear tracked content (preserve the .git | |
| # dir), then repopulate from source via the agent's build script. | |
| git -C "$WORKTREE" rm -rfq --ignore-unmatch . | |
| "src/plugins/${AGENT}/build.sh" "$WORKTREE" | |
| # Validate the built tree against the agent's schema/validator before | |
| # it can be deployed. | |
| "src/plugins/${AGENT}/validate.sh" "$WORKTREE" | |
| # Commit only if something changed. | |
| git -C "$WORKTREE" add -A | |
| if git -C "$WORKTREE" diff --cached --quiet; then | |
| echo "::notice::${TARGET_REPO} ${TARGET_BRANCH} unchanged; nothing to commit" | |
| elif [[ -n "$DIST_TAG" ]]; then | |
| git -C "$WORKTREE" commit -m "build: release ${DIST_TAG} from getsentry/sentry-for-ai@${SRC_SHA}" | |
| else | |
| git -C "$WORKTREE" commit -m "build: deploy from getsentry/sentry-for-ai@${SRC_SHA}" | |
| fi | |
| git -C "$WORKTREE" push origin "$TARGET_BRANCH" | |
| echo "::notice::deployed ${TARGET_REPO} ${TARGET_BRANCH}" | |
| if [[ -z "$DIST_TAG" ]]; then | |
| exit 0 | |
| fi | |
| # Tag wherever the branch now points, whether or not this run made a | |
| # commit: a release whose tree already matches main still has to end up | |
| # tagged, and re-running a failed release has to converge on the tag | |
| # rather than skip it. | |
| # | |
| # An existing tag on a different commit is a conflict, not a converged | |
| # retry -- skipping it would leave v<version> naming something other | |
| # than the tree that just shipped. The peeled `^{}` line is what makes | |
| # the comparison hold for an annotated tag, whose own object sha is not | |
| # the commit sha. | |
| TARGET_COMMIT="$(git -C "$WORKTREE" rev-parse HEAD)" | |
| EXISTING_TAG_COMMIT="$(git -C "$WORKTREE" ls-remote --tags origin \ | |
| "refs/tags/${DIST_TAG}" "refs/tags/${DIST_TAG}^{}" | tail -1 | cut -f1)" | |
| if [[ -n "$EXISTING_TAG_COMMIT" ]]; then | |
| if [[ "$EXISTING_TAG_COMMIT" != "$TARGET_COMMIT" ]]; then | |
| echo "::error::${TARGET_REPO} ${DIST_TAG} points at ${EXISTING_TAG_COMMIT}, not the ${TARGET_COMMIT} just published" | |
| exit 1 | |
| fi | |
| echo "::notice::${TARGET_REPO} already tagged ${DIST_TAG}" | |
| exit 0 | |
| fi | |
| git -C "$WORKTREE" tag "$DIST_TAG" | |
| git -C "$WORKTREE" push origin "$DIST_TAG" | |
| echo "::notice::tagged ${TARGET_REPO} ${DIST_TAG}" |