Skip to content

Commit 388e375

Browse files
Serhii DziupinSerhii Dziupin
andcommitted
ci: align release workflow with sibling Otto plugins
Match opencode-claude/cursor release.yml: version info step, Discord notification (optional webhook), and full update-plugin.sh pin refresh. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
1 parent a727a50 commit 388e375

2 files changed

Lines changed: 241 additions & 6 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
run: |
5151
set -euo pipefail
5252
if [[ -n "$INPUT_VERSION" ]]; then
53+
# Validate semver
5354
if ! echo "$INPUT_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
5455
echo "Error: version must be in semver format X.Y.Z"
5556
exit 1
@@ -65,6 +66,12 @@ jobs:
6566
esac
6667
fi
6768
69+
- name: Show version info
70+
run: |
71+
echo "Current version: ${{ steps.current_version.outputs.version }}"
72+
echo "New version: ${{ steps.version.outputs.version }}"
73+
echo "Dry run: ${{ github.event.inputs.dry_run == 'true' && 'yes' || 'no' }}"
74+
6875
- name: Update package.json version
6976
run: |
7077
node -e "
@@ -121,3 +128,59 @@ jobs:
121128
name: v${{ steps.version.outputs.version }}
122129
env:
123130
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
131+
132+
- name: Send Discord notification
133+
if: ${{ github.event.inputs.dry_run != 'true' }}
134+
env:
135+
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
136+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
137+
VERSION: ${{ steps.version.outputs.version }}
138+
REPOSITORY: ${{ github.repository }}
139+
run: |
140+
if [ -z "$DISCORD_WEBHOOK_URL" ]; then
141+
echo "DISCORD_WEBHOOK_URL not set; skipping Discord notification."
142+
exit 0
143+
fi
144+
node - <<'NODE'
145+
(async () => {
146+
const tag = `v${process.env.VERSION}`;
147+
const repo = process.env.REPOSITORY;
148+
const releaseRes = await fetch(`https://api.github.com/repos/${repo}/releases/tags/${tag}`, {
149+
headers: {
150+
Authorization: `Bearer ${process.env.GITHUB_TOKEN}`,
151+
Accept: 'application/vnd.github+json',
152+
},
153+
});
154+
if (!releaseRes.ok) {
155+
const body = await releaseRes.text();
156+
throw new Error(`Failed to fetch release ${tag}: ${releaseRes.status} ${body}`);
157+
}
158+
const release = await releaseRes.json();
159+
const description = (release.body || `opencode-commandcode ${tag} released.`).slice(0, 4096);
160+
const payload = {
161+
username: 'opencode-commandcode Releases',
162+
embeds: [
163+
{
164+
title: release.name || `opencode-commandcode ${tag}`,
165+
url: release.html_url,
166+
description,
167+
color: 8244896,
168+
footer: { text: 'opencode-commandcode Changelog' },
169+
},
170+
],
171+
};
172+
const discordRes = await fetch(process.env.DISCORD_WEBHOOK_URL, {
173+
method: 'POST',
174+
headers: { 'content-type': 'application/json' },
175+
body: JSON.stringify(payload),
176+
});
177+
if (!discordRes.ok) {
178+
const body = await discordRes.text();
179+
throw new Error(`Failed to send Discord notification: ${discordRes.status} ${body}`);
180+
}
181+
console.log('Discord notification sent successfully');
182+
})().catch((error) => {
183+
console.error(error);
184+
process.exit(1);
185+
});
186+
NODE

‎scripts/update-plugin.sh‎

100644100755
Lines changed: 178 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,180 @@
11
#!/usr/bin/env bash
2+
#
3+
# update-plugin.sh — Automatically pull the latest opencode-commandcode plugin
4+
# and restart opencode so it picks up the new version.
5+
#
6+
# Usage:
7+
# ./scripts/update-plugin.sh # restart on default port 36889
8+
# ./scripts/update-plugin.sh --port 39981 # restart on a specific port
9+
# ./scripts/update-plugin.sh --hostname 0.0.0.0 --port 39981
10+
# ./scripts/update-plugin.sh --dry-run # only check, don't apply/restart
11+
#
12+
# The script:
13+
# 1. Checks the latest `@otto-assistant/opencode-commandcode` version on npm.
14+
# 2. Git-fetches and rebases onto origin/main (auto-stashes local changes if any).
15+
# 3. Compares the plugin pin in `.opencode/opencode.json` with the npm latest.
16+
# 4. If the pin is stale, updates it, commits the change, and restarts opencode.
17+
# 5. If already up-to-date, reports so and does nothing.
18+
#
19+
220
set -euo pipefail
3-
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
4-
cd "$ROOT"
5-
bun install
6-
bun run build
7-
echo "Built @otto-assistant/opencode-commandcode"
8-
echo "Install into OpenCode with: opencode plugin file://$ROOT"
21+
22+
# ── Config ──────────────────────────────────────────────────────────────────
23+
PLUGIN_NAME="@otto-assistant/opencode-commandcode"
24+
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
25+
OPENCODE_BIN="${OPENCODE_BIN:-$(command -v opencode 2>/dev/null || echo "$HOME/.opencode/bin/opencode")}"
26+
27+
# Default serve flags (overridable via CLI)
28+
PORT="${PORT:-36889}"
29+
HOSTNAME="${HOSTNAME:-127.0.0.1}"
30+
DRY_RUN=false
31+
32+
# ── Parse arguments ─────────────────────────────────────────────────────────
33+
while [[ $# -gt 0 ]]; do
34+
case "$1" in
35+
--port) PORT="$2"; shift 2 ;;
36+
--hostname) HOSTNAME="$2"; shift 2 ;;
37+
--dry-run) DRY_RUN=true; shift ;;
38+
--help|-h)
39+
sed -n '/^#$/q; /^#/p; /^$/q' "$0" | sed 's/^# \?//'
40+
exit 0
41+
;;
42+
*) echo "❌ Unknown option: $1"; exit 1 ;;
43+
esac
44+
done
45+
46+
OPENCODE_JSON="$PROJECT_DIR/.opencode/opencode.json"
47+
PACKAGE_JSON="$PROJECT_DIR/package.json"
48+
49+
# ── Colors ──────────────────────────────────────────────────────────────────
50+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
51+
info() { echo -e "${CYAN}[info]${NC} $*"; }
52+
ok() { echo -e "${GREEN}[ok]${NC} $*"; }
53+
warn() { echo -e "${YELLOW}[warn]${NC} $*"; }
54+
err() { echo -e "${RED}[err]${NC} $*"; }
55+
56+
# ── Step 1: check npm latest ────────────────────────────────────────────────
57+
info "Checking latest npm version of ${PLUGIN_NAME}..."
58+
NPM_LATEST="$(npm view "${PLUGIN_NAME}" version 2>/dev/null || true)"
59+
60+
if [[ -z "$NPM_LATEST" ]]; then
61+
err "Could not fetch latest version from npm. Is the registry reachable?"
62+
exit 1
63+
fi
64+
ok "npm latest: ${NPM_LATEST}"
65+
66+
# ── Step 2: git pull (with stash safety) ─────────────────────────────────────
67+
info "Fetching latest from origin/main..."
68+
69+
if [[ "$DRY_RUN" == true ]]; then
70+
ok "[dry-run] Would run: git fetch origin && git pull --rebase origin main"
71+
else
72+
(
73+
cd "$PROJECT_DIR"
74+
75+
# Stash any local uncommitted changes so git pull won't fail
76+
HAS_LOCAL=false
77+
if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
78+
HAS_LOCAL=true
79+
warn "Local changes detected — stashing them before pull"
80+
git stash push -m "update-plugin.sh: auto-stash before pull $(date +%Y%m%d%H%M%S)" \
81+
2>&1 | sed 's/^/ /'
82+
fi
83+
84+
git fetch origin 2>&1 | sed 's/^/ /'
85+
# Use rebase so local commits (e.g. pin bump) are replayed on top of new remote changes
86+
git pull --rebase origin main 2>&1 | sed 's/^/ /'
87+
88+
# Pop stash if we stashed anything
89+
if [[ "$HAS_LOCAL" == true ]]; then
90+
info "Restoring local changes from stash..."
91+
git stash pop 2>&1 | sed 's/^/ /' || warn "Stash pop had conflicts — resolve manually"
92+
fi
93+
)
94+
ok "Repository is up-to-date with origin/main"
95+
fi
96+
97+
# ── Step 3: read current pin ────────────────────────────────────────────────
98+
CURRENT_PIN="$(grep -oP "${PLUGIN_NAME}@\K[0-9]+\.[0-9]+\.[0-9]+" "$OPENCODE_JSON" 2>/dev/null || true)"
99+
100+
if [[ -z "$CURRENT_PIN" ]]; then
101+
warn "Could not extract current plugin pin from ${OPENCODE_JSON}"
102+
info "Expected a line like: \"${PLUGIN_NAME}@x.y.z\""
103+
exit 1
104+
fi
105+
ok "Current plugin pin: ${CURRENT_PIN}"
106+
107+
# ── Step 4: compare & update ────────────────────────────────────────────────
108+
if [[ "$CURRENT_PIN" == "$NPM_LATEST" ]]; then
109+
ok "Plugin pin is already at ${NPM_LATEST}. Nothing to do."
110+
info "Reboot opencode manually if the running instance is stale."
111+
exit 0
112+
fi
113+
114+
info "Plugin pin ${CURRENT_PIN} → ${NPM_LATEST}"
115+
116+
if [[ "$DRY_RUN" == true ]]; then
117+
ok "[dry-run] Would update ${OPENCODE_JSON}: ${CURRENT_PIN} → ${NPM_LATEST}"
118+
ok "[dry-run] Would commit and restart opencode"
119+
exit 0
120+
fi
121+
122+
# ── Step 5: apply the pin update ────────────────────────────────────────────
123+
sed -i "s|${PLUGIN_NAME}@${CURRENT_PIN}|${PLUGIN_NAME}@${NPM_LATEST}|g" "$OPENCODE_JSON"
124+
ok "Updated ${OPENCODE_JSON}"
125+
126+
# Also sync package.json version if it doesn't match
127+
PKG_VER="$(grep -oP '"version":\s*"\K[0-9]+\.[0-9]+\.[0-9]+' "$PACKAGE_JSON" || true)"
128+
if [[ -n "$PKG_VER" && "$PKG_VER" != "$NPM_LATEST" ]]; then
129+
sed -i "s|\"version\": \"${PKG_VER}\"|\"version\": \"${NPM_LATEST}\"|" "$PACKAGE_JSON"
130+
ok "Synced package.json version: ${PKG_VER} → ${NPM_LATEST}"
131+
fi
132+
133+
# ── Step 6: commit ──────────────────────────────────────────────────────────
134+
(
135+
cd "$PROJECT_DIR"
136+
git add .opencode/opencode.json package.json 2>/dev/null
137+
# Only commit if there's something new
138+
if ! git diff --cached --quiet; then
139+
git commit -m "chore: bump plugin pin to ${NPM_LATEST}" 2>&1 | sed 's/^/ /'
140+
ok "Committed plugin pin update"
141+
else
142+
ok "No new changes to commit (pin already correct)"
143+
fi
144+
)
145+
146+
# ── Step 7: restart opencode ────────────────────────────────────────────────
147+
info "Restarting opencode serve..."
148+
149+
# Kill ALL existing opencode serve processes (they run the old plugin version)
150+
EXISTING_PIDS="$(pgrep -f 'opencode serve' 2>/dev/null || true)"
151+
if [[ -n "$EXISTING_PIDS" ]]; then
152+
# Send SIGTERM first, wait briefly, then SIGKILL survivors
153+
echo "$EXISTING_PIDS" | xargs -r kill 2>/dev/null || true
154+
sleep 2
155+
SURVIVORS="$(pgrep -f 'opencode serve' 2>/dev/null || true)"
156+
if [[ -n "$SURVIVORS" ]]; then
157+
echo "$SURVIVORS" | xargs -r kill -9 2>/dev/null || true
158+
sleep 1
159+
fi
160+
ok "Stopped old opencode serve processes"
161+
fi
162+
163+
# Start a new opencode serve instance
164+
info "Starting: ${OPENCODE_BIN} serve --hostname ${HOSTNAME} --port ${PORT}"
165+
nohup "${OPENCODE_BIN}" serve --hostname "$HOSTNAME" --port "$PORT" \
166+
>> "${HOME}/.opencode-serve.log" 2>&1 &
167+
NEW_PID=$!
168+
169+
# Give it a moment to start
170+
sleep 2
171+
if kill -0 "$NEW_PID" 2>/dev/null; then
172+
ok "opencode serve started (PID ${NEW_PID}) on ${HOSTNAME}:${PORT}"
173+
info "Logs: ~/.opencode-serve.log"
174+
else
175+
err "opencode serve failed to start. Check ~/.opencode-serve.log"
176+
exit 1
177+
fi
178+
179+
echo ""
180+
echo -e "${GREEN}✅ Done. Plugin ${PLUGIN_NAME} updated to ${NPM_LATEST} and opencode restarted.${NC}"

0 commit comments

Comments
 (0)