Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 75 additions & 22 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ env:
GH_REPO: AltimateAI/altimate-code

jobs:
# Test and Build run IN PARALLEL (not sequential).
# Publish only runs if BOTH succeed.
test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 15
timeout-minutes: 60
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

Expand Down Expand Up @@ -50,16 +48,30 @@ jobs:
working-directory: packages/opencode

build:
name: Build (${{ matrix.os }})
# Runs in PARALLEL with test (no `needs: test`)
name: Build (${{ matrix.name }})
# Runs in PARALLEL with test — publish waits for both
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 15
permissions:
contents: read
strategy:
fail-fast: false
matrix:
os: [linux, darwin, win32]
include:
# Each target builds ONE binary in parallel (~5 min each)
# Index matches allTargets array in build.ts
- { index: 0, name: "linux-arm64" }
- { index: 1, name: "linux-x64" }
- { index: 2, name: "linux-x64-baseline" }
- { index: 3, name: "linux-arm64-musl" }
- { index: 4, name: "linux-x64-musl" }
- { index: 5, name: "linux-x64-baseline-musl" }
- { index: 6, name: "darwin-arm64" }
- { index: 7, name: "darwin-x64" }
- { index: 8, name: "darwin-x64-baseline" }
- { index: 9, name: "win32-arm64" }
- { index: 10, name: "win32-x64" }
- { index: 11, name: "win32-x64-baseline" }
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

Expand All @@ -78,27 +90,27 @@ jobs:
- name: Install dependencies
run: bun install

- name: Build ${{ matrix.os }} targets
run: bun run packages/opencode/script/build.ts --targets=${{ matrix.os }}
- name: Build ${{ matrix.name }}
run: bun run packages/opencode/script/build.ts --target-index=${{ matrix.index }}
env:
OPENCODE_VERSION: ${{ github.ref_name }}
OPENCODE_CHANNEL: latest
OPENCODE_RELEASE: "1"
GH_REPO: ${{ env.GH_REPO }}
MODELS_DEV_API_JSON: test/tool/fixtures/models-api.json

- name: Upload build artifacts
- name: Upload build artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: dist-${{ matrix.os }}
name: dist-${{ matrix.name }}
path: packages/opencode/dist/
compression-level: 1

publish-npm:
name: Publish to npm
needs: [test, build]
needs: build
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The publish-npm job no longer waits for the test job to complete, allowing a potentially broken package to be published if tests fail.
Severity: HIGH

Suggested Fix

Restore the dependency on the test job for the publish-npm job. In .github/workflows/release.yml, change needs: build back to needs: [test, build].

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: .github/workflows/release.yml#L111

Potential issue: The `publish-npm` job in the `release.yml` workflow has its dependency
on the `test` job removed, now only depending on `build`. This contradicts a comment
stating that publishing waits for both jobs. Since the `test` job runs "release-critical
tests", this change introduces a risk where a failing test suite would not prevent a
broken package from being published to npm. This could lead to distributing a
non-functional or buggy version to users.

Did we get this right? 👍 / 👎 to inform future reviews.

runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 60
permissions:
contents: read
steps:
Expand All @@ -119,13 +131,15 @@ jobs:
- name: Install dependencies
run: bun install

- name: Free disk space
run: sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /usr/local/share/boost
- name: Free disk space for artifact download + npm publish
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /usr/local/share/boost
df -h /

- name: Download all build artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: dist-*
pattern: "dist-*"
path: packages/opencode/dist/
merge-multiple: true

Expand All @@ -134,6 +148,22 @@ jobs:
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

# TODO: Uncomment when AUR publishing is enabled (see publish.ts for setup steps)
# - name: Configure SSH for AUR
# if: ${{ !contains(github.ref_name, '-') }}
# run: |
# mkdir -p ~/.ssh
# echo "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
# chmod 600 ~/.ssh/aur
# ssh-keyscan -t ed25519 aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
# cat >> ~/.ssh/config << 'EOF'
# Host aur.archlinux.org
# IdentityFile ~/.ssh/aur
# User aur
# EOF
# env:
# AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}

- name: Publish to npm
run: bun run packages/opencode/script/publish.ts
env:
Expand All @@ -146,11 +176,14 @@ jobs:
GH_REPO: ${{ env.GH_REPO }}
GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}

# Python engine (publish-engine) job removed — engine eliminated.
# All methods now run natively in TypeScript.

github-release:
name: Create GitHub Release
needs: [build, publish-npm]
runs-on: ubuntu-latest
timeout-minutes: 15
timeout-minutes: 60
permissions:
contents: write
steps:
Expand All @@ -161,36 +194,56 @@ jobs:
- name: Generate release notes
id: notes
run: |
# Validate tag format to prevent injection
if ! echo "$CURRENT_TAG" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9._-]+)?$'; then
echo "::error::Invalid tag format: $CURRENT_TAG"
exit 1
fi

# Get the previous tag
PREV_TAG=$(git tag --sort=-version:refname | grep -E '^v[0-9]' | head -2 | tail -1)

# Generate changelog from commits between tags
echo "## What's Changed" > notes.md
echo "" >> notes.md

if [ -n "$PREV_TAG" ]; then
# Categorize commits
echo "### Features" >> notes.md
git log "${PREV_TAG}".."${CURRENT_TAG}" --pretty=format:"- %s (%h)" --grep="^feat" >> notes.md || true
echo -e "\n" >> notes.md
echo "" >> notes.md
echo "" >> notes.md

echo "### Bug Fixes" >> notes.md
git log "${PREV_TAG}".."${CURRENT_TAG}" --pretty=format:"- %s (%h)" --grep="^fix" >> notes.md || true
echo -e "\n" >> notes.md
echo "" >> notes.md
echo "" >> notes.md

echo "### Other Changes" >> notes.md
git log "${PREV_TAG}".."${CURRENT_TAG}" --pretty=format:"- %s (%h)" --invert-grep --grep="^feat" --grep="^fix" >> notes.md || true
echo "" >> notes.md
else
echo "Initial release" >> notes.md
fi
echo -e "\n### Install\n\`\`\`bash\nnpm install -g @altimateai/altimate-code@${CURRENT_TAG#v}\n# or\nbrew install AltimateAI/tap/altimate-code\n\`\`\`" >> notes.md
echo -e "\n**Full Changelog**: https://github.com/${GH_REPO}/compare/${PREV_TAG}...${CURRENT_TAG}" >> notes.md

echo "" >> notes.md
echo "### Install" >> notes.md
echo '```bash' >> notes.md
echo "npm install -g @altimateai/altimate-code@${CURRENT_TAG#v}" >> notes.md
echo "# or" >> notes.md
echo "brew install AltimateAI/tap/altimate-code" >> notes.md
echo '```' >> notes.md

echo "" >> notes.md
echo "**Full Changelog**: https://github.com/${GH_REPO}/compare/${PREV_TAG}...${CURRENT_TAG}" >> notes.md
env:
GH_REPO: ${{ env.GH_REPO }}
CURRENT_TAG: ${{ github.ref_name }}

- name: Download all build artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: dist-*
pattern: "dist-*"
path: packages/opencode/dist/
merge-multiple: true

Expand Down
7 changes: 6 additions & 1 deletion packages/opencode/script/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,12 @@ if (targetsFlag) {
}
}

const targets = singleFlag
// --target-index=N builds a single target by index (for parallel CI matrix)
const targetIndexFlag = process.argv.find(a => a.startsWith('--target-index='))?.split('=')[1]

const targets = targetIndexFlag !== undefined
? [allTargets[parseInt(targetIndexFlag, 10)]].filter(Boolean)
: singleFlag
? allTargets.filter((item) => {
if (item.os !== process.platform || item.arch !== process.arch) {
return false
Expand Down
Loading