|
4 | 4 | # (--no-interactive) so it installs the Sentry plugin for every detected agent |
5 | 5 | # without a prompt, and verifies each plugin actually landed. |
6 | 6 | # |
7 | | -# Claude Code, Codex, Grok, and Pi ship cross-platform npm CLIs, so they get a |
8 | | -# real install against their package sources. Cursor has no headless CLI to |
| 7 | +# Claude Code, Codex, Grok, OpenCode V1, and Pi ship cross-platform npm CLIs, so |
| 8 | +# they get real CLI installs. Cursor has no headless CLI to |
9 | 9 | # install in CI, but our Cursor install is only a `git clone` of the public |
10 | 10 | # plugin repo into ~/.cursor/plugins/local/sentry — so we put a `cursor` stub on |
11 | 11 | # PATH to satisfy detection and verify the real clone (this is what exercises |
12 | 12 | # the per-OS path handling, including Windows). |
| 13 | +# |
| 14 | +# OpenCode V2 currently recommends WSL on Windows and cannot share V1's MCP |
| 15 | +# config shape, so it runs in a separate Linux smoke job. The OpenCode target |
| 16 | +# repositories are replaced with temporary local git repositories in both jobs; |
| 17 | +# this tests the real clone flow before those generated repositories are first |
| 18 | +# deployed. |
13 | 19 |
|
14 | 20 | name: Smoke installer |
15 | 21 |
|
|
57 | 63 | - name: Build |
58 | 64 | run: pnpm --filter @sentry/ai build |
59 | 65 |
|
60 | | - - name: Install Claude Code, Codex, Grok, and Pi CLIs |
61 | | - run: npm install -g @anthropic-ai/claude-code @openai/codex @xai-official/grok @earendil-works/pi-coding-agent |
| 66 | + - name: Install Claude Code, Codex, Grok, OpenCode V1, and Pi CLIs |
| 67 | + run: npm install -g @anthropic-ai/claude-code @openai/codex @xai-official/grok opencode-ai@1.18.0 @earendil-works/pi-coding-agent |
| 68 | + |
| 69 | + - name: Prepare local OpenCode V1 distribution |
| 70 | + run: | |
| 71 | + set -euo pipefail |
| 72 | + repo="$RUNNER_TEMP/plugin-opencode" |
| 73 | + mkdir -p "$repo/skills/sentry-installer-smoke" |
| 74 | + printf '1\n' > "$repo/.sentry-opencode-v1" |
| 75 | + printf '%s\n' '---' 'name: sentry-installer-smoke' 'description: Verify the Sentry OpenCode installer' '---' '' '# Sentry installer smoke' > "$repo/skills/sentry-installer-smoke/SKILL.md" |
| 76 | + git -C "$repo" init -q |
| 77 | + git -C "$repo" config user.name smoke-test |
| 78 | + git -C "$repo" config user.email smoke@example.com |
| 79 | + git -C "$repo" add . |
| 80 | + git -C "$repo" commit -qm 'test: seed OpenCode bundle' |
| 81 | + repo_url="$(node -e 'console.log(require("node:url").pathToFileURL(process.argv[1]).href)' "$repo")" |
| 82 | + git config --global protocol.file.allow always |
| 83 | + git config --global "url.${repo_url}.insteadOf" https://github.com/getsentry/plugin-opencode.git |
62 | 84 |
|
63 | 85 | - name: Put a Cursor stub on PATH |
64 | 86 | run: | |
@@ -100,4 +122,72 @@ jobs: |
100 | 122 | pi list --no-approve |
101 | 123 | pi list --no-approve | grep -iq 'getsentry/plugin-pi' || { echo "pi: sentry package missing"; exit 1; } |
102 | 124 |
|
| 125 | + echo "== opencode ==" |
| 126 | + opencode debug skill > "$RUNNER_TEMP/opencode-skills.json" |
| 127 | + grep -q 'sentry-installer-smoke' "$RUNNER_TEMP/opencode-skills.json" || { echo "opencode: sentry skill missing"; exit 1; } |
| 128 | + node - <<'NODE' |
| 129 | + const fs = require("node:fs"); |
| 130 | + const path = require("node:path"); |
| 131 | + const os = require("node:os"); |
| 132 | + const root = path.join(os.homedir(), ".config", "opencode"); |
| 133 | + const file = ["opencode.json", "opencode.jsonc"].map((name) => path.join(root, name)).find(fs.existsSync); |
| 134 | + if (!file) throw new Error("opencode: global config missing"); |
| 135 | + const config = JSON.parse(fs.readFileSync(file, "utf8")); |
| 136 | + if (!config.mcp?.sentry?.url?.includes("mcp.sentry.dev")) throw new Error("opencode: Sentry MCP missing"); |
| 137 | + NODE |
| 138 | +
|
103 | 139 | echo "All agents have the Sentry plugin." |
| 140 | +
|
| 141 | + smoke-opencode2: |
| 142 | + name: OpenCode V2 beta |
| 143 | + runs-on: ubuntu-latest |
| 144 | + env: |
| 145 | + SENTRY_DSN: "" |
| 146 | + steps: |
| 147 | + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 |
| 148 | + |
| 149 | + - uses: pnpm/action-setup@a15d269cd4658e1107c09f1fabf4cbd7bd1f308a # v4.4.0 |
| 150 | + |
| 151 | + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 |
| 152 | + with: |
| 153 | + node-version: 24 |
| 154 | + cache: pnpm |
| 155 | + |
| 156 | + - run: pnpm install --frozen-lockfile |
| 157 | + - run: pnpm --filter @sentry/ai build |
| 158 | + - run: npm install -g @opencode-ai/cli@0.0.0-next-16420 |
| 159 | + |
| 160 | + - name: Prepare local OpenCode V2 distribution |
| 161 | + run: | |
| 162 | + set -euo pipefail |
| 163 | + repo="$RUNNER_TEMP/plugin-opencode2" |
| 164 | + mkdir -p "$repo/skills/sentry-installer-smoke" |
| 165 | + printf '2\n' > "$repo/.sentry-opencode-v2" |
| 166 | + printf '%s\n' '---' 'name: sentry-installer-smoke' 'description: Verify the Sentry OpenCode V2 installer' 'metadata:' ' opencode/autoinvoke: "false"' '---' '' '# Sentry installer smoke' > "$repo/skills/sentry-installer-smoke/SKILL.md" |
| 167 | + git -C "$repo" init -q |
| 168 | + git -C "$repo" config user.name smoke-test |
| 169 | + git -C "$repo" config user.email smoke@example.com |
| 170 | + git -C "$repo" add . |
| 171 | + git -C "$repo" commit -qm 'test: seed OpenCode V2 bundle' |
| 172 | + repo_url="$(node -e 'console.log(require("node:url").pathToFileURL(process.argv[1]).href)' "$repo")" |
| 173 | + git config --global protocol.file.allow always |
| 174 | + git config --global "url.${repo_url}.insteadOf" https://github.com/getsentry/plugin-opencode2.git |
| 175 | +
|
| 176 | + - name: Run installer (non-interactive) |
| 177 | + run: node packages/installer/dist/index.js install --no-interactive |
| 178 | + |
| 179 | + - name: Verify OpenCode V2 installation |
| 180 | + run: | |
| 181 | + set -euo pipefail |
| 182 | + node - <<'NODE' |
| 183 | + const fs = require("node:fs"); |
| 184 | + const path = require("node:path"); |
| 185 | + const os = require("node:os"); |
| 186 | + const bundle = path.join(os.homedir(), ".config", "opencode", "skills", "sentry", "skills", "sentry-installer-smoke", "SKILL.md"); |
| 187 | + if (!fs.existsSync(bundle)) throw new Error(`opencode2: Sentry skill missing at ${bundle}`); |
| 188 | + const root = path.join(os.homedir(), ".config", "opencode"); |
| 189 | + const file = ["opencode.json", "opencode.jsonc"].map((name) => path.join(root, name)).find(fs.existsSync); |
| 190 | + if (!file) throw new Error("opencode2: global config missing"); |
| 191 | + const config = JSON.parse(fs.readFileSync(file, "utf8")); |
| 192 | + if (!config.mcp?.servers?.sentry?.url?.includes("mcp.sentry.dev")) throw new Error("opencode2: Sentry MCP missing"); |
| 193 | + NODE |
0 commit comments