diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9c8b6879ee..d7c359fe0e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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 @@ -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 @@ -78,8 +90,8 @@ 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 @@ -87,18 +99,18 @@ jobs: 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 runs-on: ubuntu-latest - timeout-minutes: 30 + timeout-minutes: 60 permissions: contents: read steps: @@ -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 @@ -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: @@ -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: @@ -161,28 +194,48 @@ 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 }} @@ -190,7 +243,7 @@ jobs: - name: Download all build artifacts uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: - pattern: dist-* + pattern: "dist-*" path: packages/opencode/dist/ merge-multiple: true diff --git a/packages/opencode/script/build.ts b/packages/opencode/script/build.ts index e103eec6d4..802f475104 100755 --- a/packages/opencode/script/build.ts +++ b/packages/opencode/script/build.ts @@ -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