build: centralize the pinned opencode version (#1075)

Keep OpenCode version selection predictable by reading a single repo-wide constant and packaging that pin into orchestrator builds. Remove env and latest-release fallbacks so desktop, workers, snapshots, and CI stay aligned.

Co-authored-by: Omar McAdam <omar@OpenWork-Studio.localdomain>
This commit is contained in:
Omar McAdam
2026-03-20 12:30:24 -07:00
committed by GitHub
parent a9bf75da0a
commit db10a7b5ba
30 changed files with 186 additions and 392 deletions

View File

@@ -21,7 +21,6 @@ jobs:
env:
OPENCODE_GITHUB_REPO: ${{ vars.OPENCODE_GITHUB_REPO || 'anomalyco/opencode' }}
OPENCODE_VERSION: ${{ vars.OPENCODE_VERSION || '1.2.20' }}
steps:
- name: Checkout
@@ -85,80 +84,27 @@ jobs:
- name: Resolve OpenCode version
id: opencode-version
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
node <<'NODE' >> "$GITHUB_OUTPUT"
const fs = require('fs');
const repo = (process.env.OPENCODE_GITHUB_REPO || 'anomalyco/opencode').trim() || 'anomalyco/opencode';
async function resolveLatest() {
const token = (process.env.GITHUB_TOKEN || '').trim();
const headers = {
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'User-Agent': 'openwork-ci',
};
if (token) headers.Authorization = `Bearer ${token}`;
try {
const res = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, { headers });
if (res.ok) {
const data = await res.json();
const tag = (typeof data.tag_name === 'string' ? data.tag_name : '').trim();
const version = (tag.startsWith('v') ? tag.slice(1) : tag).trim();
if (version) return version;
}
if (res.status !== 403) {
throw new Error(`Failed to resolve latest OpenCode version (HTTP ${res.status})`);
}
} catch {
}
const web = await fetch(`https://github.com/${repo}/releases/latest`, {
headers: { 'User-Agent': 'openwork-ci' },
redirect: 'follow',
});
const url = web && web.url ? String(web.url) : '';
const match = url.match(/\/tag\/v([^/?#]+)/);
if (!match) throw new Error('Failed to resolve latest OpenCode version (web redirect).');
return match[1];
const parsed = JSON.parse(fs.readFileSync('./constants.json', 'utf8'));
const version = String(parsed.opencodeVersion || '').replace(/^v/, '').trim();
if (!version) {
throw new Error('Pinned OpenCode version is missing from constants.json');
}
async function main() {
const pkg = JSON.parse(fs.readFileSync('./apps/desktop/package.json', 'utf8'));
const configuredRaw = (process.env.OPENCODE_VERSION || pkg.opencodeVersion || '').toString().trim();
if (configuredRaw && configuredRaw.toLowerCase() !== 'latest') {
const resolved = (configuredRaw.startsWith('v') ? configuredRaw.slice(1) : configuredRaw).trim();
if (process.env.GITHUB_ENV) {
fs.appendFileSync(process.env.GITHUB_ENV, `OPENCODE_VERSION=${resolved}\n`);
}
console.log('version=' + resolved);
return;
}
const latest = await resolveLatest();
if (process.env.GITHUB_ENV) {
fs.appendFileSync(process.env.GITHUB_ENV, `OPENCODE_VERSION=${latest}\n`);
}
console.log('version=' + latest);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
console.log('version=' + version);
NODE
- name: Download OpenCode sidecar
shell: bash
env:
OPENCODE_VERSION: ${{ steps.opencode-version.outputs.version }}
PINNED_OPENCODE_VERSION: ${{ steps.opencode-version.outputs.version }}
run: |
set -euo pipefail
repo="${OPENCODE_GITHUB_REPO:-anomalyco/opencode}"
opencode_asset="opencode-darwin-arm64.zip"
url="https://github.com/${repo}/releases/download/v${OPENCODE_VERSION}/${opencode_asset}"
url="https://github.com/${repo}/releases/download/v${PINNED_OPENCODE_VERSION}/${opencode_asset}"
tmp_dir="$RUNNER_TEMP/opencode"
extract_dir="$tmp_dir/extracted"
rm -rf "$tmp_dir"

View File

@@ -71,45 +71,18 @@ jobs:
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCODE_GITHUB_REPO: ${{ vars.OPENCODE_GITHUB_REPO || 'anomalyco/opencode' }}
OPENCODE_VERSION: ${{ vars.OPENCODE_VERSION || '1.2.20' }}
run: |
set -euo pipefail
repo="${OPENCODE_GITHUB_REPO:-anomalyco/opencode}"
version="${OPENCODE_VERSION:-}"
if [ -z "$version" ]; then
version="$(node -p "require('./apps/desktop/package.json').opencodeVersion || ''" 2>/dev/null || true)"
fi
version="$(node -e "const fs=require('fs'); const parsed=JSON.parse(fs.readFileSync('constants.json','utf8')); process.stdout.write(String(parsed.opencodeVersion||'').trim().replace(/^v/,''));")"
version="$(echo "$version" | tr -d '\r\n' | sed 's/^v//')"
if [ -z "$version" ] || [ "$version" = "latest" ]; then
latest=""
if [ -n "${GITHUB_TOKEN:-}" ]; then
latest=$(curl -fsSL \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${repo}/releases/latest" \
| sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
else
latest=$(curl -fsSL \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${repo}/releases/latest" \
| sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
fi
if [ -n "$latest" ]; then
version="$latest"
fi
fi
if [ -z "$version" ]; then
echo "Unable to resolve OpenCode version (set OPENCODE_VERSION to pin)." >&2
echo "Unable to resolve OpenCode version from constants.json." >&2
exit 1
fi
# Reuse this resolved version for subsequent steps (e.g. prepare-sidecar).
echo "OPENCODE_VERSION=$version" >> "$GITHUB_ENV"
opencode_asset="opencode-linux-x64-baseline.tar.gz"
url="https://github.com/${repo}/releases/download/v${version}/${opencode_asset}"
tmp_dir="$RUNNER_TEMP/opencode"

View File

@@ -39,40 +39,15 @@ jobs:
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCODE_GITHUB_REPO: ${{ vars.OPENCODE_GITHUB_REPO || 'anomalyco/opencode' }}
OPENCODE_VERSION: ${{ vars.OPENCODE_VERSION || '1.2.20' }}
run: |
set -euo pipefail
repo="${OPENCODE_GITHUB_REPO:-anomalyco/opencode}"
version="${OPENCODE_VERSION:-}"
if [ -z "$version" ]; then
version="$(node -p "require('./apps/desktop/package.json').opencodeVersion || ''" 2>/dev/null || true)"
fi
version="$(node -e "const fs=require('fs'); const parsed=JSON.parse(fs.readFileSync('constants.json','utf8')); process.stdout.write(String(parsed.opencodeVersion||'').trim().replace(/^v/,''));")"
version="$(echo "$version" | tr -d '\r\n' | sed 's/^v//')"
if [ -z "$version" ] || [ "$version" = "latest" ]; then
latest=""
if [ -n "${GITHUB_TOKEN:-}" ]; then
latest=$(curl -fsSL \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${repo}/releases/latest" \
| sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
else
latest=$(curl -fsSL \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/${repo}/releases/latest" \
| sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p')
fi
if [ -n "$latest" ]; then
version="$latest"
fi
fi
if [ -z "$version" ]; then
echo "Unable to resolve OpenCode version (set OPENCODE_VERSION to pin)." >&2
echo "Unable to resolve OpenCode version from constants.json." >&2
exit 1
fi

View File

@@ -20,7 +20,9 @@ jobs:
fetch-depth: 1
- name: Install opencode
run: curl -fsSL https://opencode.ai/install | bash
run: |
version="$(node -e "const fs=require('fs'); const parsed=JSON.parse(fs.readFileSync('constants.json','utf8')); process.stdout.write(String(parsed.opencodeVersion||'').trim().replace(/^v/,''));")"
curl -fsSL https://opencode.ai/install | bash -s -- --version "$version" --no-modify-path
- name: Triage issue
env:
@@ -48,7 +50,9 @@ jobs:
fetch-depth: 1
- name: Install opencode
run: curl -fsSL https://opencode.ai/install | bash
run: |
version="$(node -e "const fs=require('fs'); const parsed=JSON.parse(fs.readFileSync('constants.json','utf8')); process.stdout.write(String(parsed.opencodeVersion||'').trim().replace(/^v/,''));")"
curl -fsSL https://opencode.ai/install | bash -s -- --version "$version" --no-modify-path
- name: Build prompt
env:

View File

@@ -85,7 +85,6 @@ jobs:
RELEASE_BODY: ${{ needs.prepare-release.outputs.release_body }}
MACOS_NOTARIZE: ${{ vars.MACOS_NOTARIZE || 'false' }}
OPENCODE_GITHUB_REPO: ${{ vars.OPENCODE_GITHUB_REPO || 'anomalyco/opencode' }}
OPENCODE_VERSION: ${{ vars.OPENCODE_VERSION || '1.2.20' }}
strategy:
fail-fast: false
@@ -172,78 +171,21 @@ jobs:
- name: Resolve OpenCode version
id: opencode-version
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
node <<'NODE' >> "$GITHUB_OUTPUT"
const fs = require('fs');
const repo = (process.env.OPENCODE_GITHUB_REPO || 'anomalyco/opencode').trim() || 'anomalyco/opencode';
async function resolveLatest() {
const token = (process.env.GITHUB_TOKEN || '').trim();
const headers = {
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'User-Agent': 'openwork-ci',
};
if (token) headers.Authorization = `Bearer ${token}`;
// Prefer API, but fall back to the web "latest" redirect if rate-limited (403) or otherwise blocked.
try {
const res = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, { headers });
if (res.ok) {
const data = await res.json();
const tag = (typeof data.tag_name === 'string' ? data.tag_name : '').trim();
let v = tag.startsWith('v') ? tag.slice(1) : tag;
v = v.trim();
if (v) return v;
}
if (res.status !== 403) {
throw new Error(`Failed to resolve latest OpenCode version (HTTP ${res.status})`);
}
} catch {
// continue to fallback
}
const web = await fetch(`https://github.com/${repo}/releases/latest`, {
headers: { 'User-Agent': 'openwork-ci' },
redirect: 'follow',
});
const url = (web && web.url) ? String(web.url) : '';
const match = url.match(/\/tag\/v([^/?#]+)/);
if (!match) throw new Error('Failed to resolve latest OpenCode version (web redirect).');
return match[1];
const parsed = JSON.parse(fs.readFileSync('./constants.json', 'utf8'));
const version = String(parsed.opencodeVersion || '').replace(/^v/, '').trim();
if (!version) {
throw new Error('Pinned OpenCode version is missing from constants.json');
}
async function main() {
const pkg = JSON.parse(fs.readFileSync('./apps/desktop/package.json', 'utf8'));
const configuredRaw = (process.env.OPENCODE_VERSION || pkg.opencodeVersion || '').toString().trim();
if (configuredRaw && configuredRaw.toLowerCase() !== 'latest') {
const normalized = configuredRaw.startsWith('v') ? configuredRaw.slice(1) : configuredRaw;
const resolved = normalized.trim();
if (process.env.GITHUB_ENV) {
fs.appendFileSync(process.env.GITHUB_ENV, `OPENCODE_VERSION=${resolved}\n`);
}
console.log('version=' + resolved);
return;
}
const latest = await resolveLatest();
if (process.env.GITHUB_ENV) {
fs.appendFileSync(process.env.GITHUB_ENV, `OPENCODE_VERSION=${latest}\n`);
}
console.log('version=' + latest);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
console.log('version=' + version);
NODE
- name: Download OpenCode sidecar
shell: bash
env:
OPENCODE_VERSION: ${{ steps.opencode-version.outputs.version }}
PINNED_OPENCODE_VERSION: ${{ steps.opencode-version.outputs.version }}
run: |
set -euo pipefail
@@ -270,7 +212,7 @@ jobs:
esac
repo="${OPENCODE_GITHUB_REPO:-anomalyco/opencode}"
url="https://github.com/${repo}/releases/download/v${OPENCODE_VERSION}/${opencode_asset}"
url="https://github.com/${repo}/releases/download/v${PINNED_OPENCODE_VERSION}/${opencode_asset}"
tmp_dir="$RUNNER_TEMP/opencode"
extract_dir="$tmp_dir/extracted"
rm -rf "$tmp_dir"

View File

@@ -254,7 +254,6 @@ jobs:
MACOS_NOTARIZE: ${{ needs.resolve-release.outputs.notarize }}
# Ensure Tauri's beforeBuildCommand (prepare:sidecar) uses our fork.
OPENCODE_GITHUB_REPO: ${{ vars.OPENCODE_GITHUB_REPO || 'anomalyco/opencode' }}
OPENCODE_VERSION: ${{ vars.OPENCODE_VERSION || '1.2.20' }}
strategy:
fail-fast: false
@@ -373,80 +372,21 @@ jobs:
- name: Resolve OpenCode version
id: opencode-version
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
OPENCODE_GITHUB_REPO: ${{ vars.OPENCODE_GITHUB_REPO || 'anomalyco/opencode' }}
OPENCODE_VERSION: ${{ vars.OPENCODE_VERSION || '1.2.20' }}
run: |
node <<'NODE' >> "$GITHUB_OUTPUT"
const fs = require('fs');
const repo = (process.env.OPENCODE_GITHUB_REPO || 'anomalyco/opencode').trim() || 'anomalyco/opencode';
async function resolveLatest() {
const token = (process.env.GITHUB_TOKEN || '').trim();
const headers = {
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
'User-Agent': 'openwork-ci',
};
if (token) headers.Authorization = `Bearer ${token}`;
// Prefer API, but fall back to the web "latest" redirect if rate-limited (403) or otherwise blocked.
try {
const res = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, { headers });
if (res.ok) {
const data = await res.json();
const tag = (typeof data.tag_name === 'string' ? data.tag_name : '').trim();
let v = tag.startsWith('v') ? tag.slice(1) : tag;
v = v.trim();
if (v) return v;
}
if (res.status !== 403) {
throw new Error(`Failed to resolve latest OpenCode version (HTTP ${res.status})`);
}
} catch {
// continue to fallback
}
const web = await fetch(`https://github.com/${repo}/releases/latest`, {
headers: { 'User-Agent': 'openwork-ci' },
redirect: 'follow',
});
const url = (web && web.url) ? String(web.url) : '';
const match = url.match(/\/tag\/v([^/?#]+)/);
if (!match) throw new Error('Failed to resolve latest OpenCode version (web redirect).');
return match[1];
const parsed = JSON.parse(fs.readFileSync('./constants.json', 'utf8'));
const version = String(parsed.opencodeVersion || '').replace(/^v/, '').trim();
if (!version) {
throw new Error('Pinned OpenCode version is missing from constants.json');
}
async function main() {
const pkg = JSON.parse(fs.readFileSync('./apps/desktop/package.json', 'utf8'));
const configuredRaw = (process.env.OPENCODE_VERSION || pkg.opencodeVersion || '').toString().trim();
if (configuredRaw && configuredRaw.toLowerCase() !== 'latest') {
const normalized = configuredRaw.startsWith('v') ? configuredRaw.slice(1) : configuredRaw;
const resolved = normalized.trim();
if (process.env.GITHUB_ENV) {
fs.appendFileSync(process.env.GITHUB_ENV, `OPENCODE_VERSION=${resolved}\n`);
}
console.log('version=' + resolved);
return;
}
const latest = await resolveLatest();
if (process.env.GITHUB_ENV) {
fs.appendFileSync(process.env.GITHUB_ENV, `OPENCODE_VERSION=${latest}\n`);
}
console.log('version=' + latest);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});
console.log('version=' + version);
NODE
- name: Download OpenCode sidecar
shell: bash
env:
OPENCODE_VERSION: ${{ steps.opencode-version.outputs.version }}
PINNED_OPENCODE_VERSION: ${{ steps.opencode-version.outputs.version }}
OPENCODE_GITHUB_REPO: ${{ vars.OPENCODE_GITHUB_REPO || 'anomalyco/opencode' }}
run: |
set -euo pipefail
@@ -474,7 +414,7 @@ jobs:
esac
repo="${OPENCODE_GITHUB_REPO:-anomalyco/opencode}"
url="https://github.com/${repo}/releases/download/v${OPENCODE_VERSION}/${opencode_asset}"
url="https://github.com/${repo}/releases/download/v${PINNED_OPENCODE_VERSION}/${opencode_asset}"
tmp_dir="$RUNNER_TEMP/opencode"
extract_dir="$tmp_dir/extracted"
rm -rf "$tmp_dir"