Release #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Explicit version (e.g., 0.2.0). If empty, bump type is used.' | |
| required: false | |
| type: string | |
| bump: | |
| description: 'Version bump type (used if version is empty)' | |
| required: false | |
| default: 'minor' | |
| type: choice | |
| options: | |
| - minor | |
| - patch | |
| - major | |
| dry_run: | |
| description: 'Dry run — skip npm publish, create draft release' | |
| required: false | |
| default: false | |
| type: boolean | |
| env: | |
| NODE_VERSION: '22' | |
| permissions: | |
| contents: write | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Get current version from package.json | |
| id: current_version | |
| run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT" | |
| - name: Calculate new version | |
| id: version | |
| env: | |
| CURRENT_VERSION: ${{ steps.current_version.outputs.version }} | |
| INPUT_VERSION: ${{ github.event.inputs.version }} | |
| BUMP_TYPE: ${{ github.event.inputs.bump }} | |
| run: | | |
| set -euo pipefail | |
| if [[ -n "$INPUT_VERSION" ]]; then | |
| # Validate semver | |
| if ! echo "$INPUT_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then | |
| echo "Error: version must be in semver format X.Y.Z" | |
| exit 1 | |
| fi | |
| echo "version=$INPUT_VERSION" >> "$GITHUB_OUTPUT" | |
| else | |
| IFS='.' read -r major minor patch <<< "$CURRENT_VERSION" | |
| case "$BUMP_TYPE" in | |
| major) echo "version=$((major+1)).0.0" >> "$GITHUB_OUTPUT" ;; | |
| minor) echo "version=$major.$((minor+1)).0" >> "$GITHUB_OUTPUT" ;; | |
| patch) echo "version=$major.$minor.$((patch+1))" >> "$GITHUB_OUTPUT" ;; | |
| *) echo "Error: unknown bump type $BUMP_TYPE"; exit 1 ;; | |
| esac | |
| fi | |
| - name: Show version info | |
| run: | | |
| echo "Current version: ${{ steps.current_version.outputs.version }}" | |
| echo "New version: ${{ steps.version.outputs.version }}" | |
| echo "Dry run: ${{ github.event.inputs.dry_run == 'true' && 'yes' || 'no' }}" | |
| - name: Update package.json version | |
| run: | | |
| node -e " | |
| const pkg = require('./package.json'); | |
| pkg.version = '${{ steps.version.outputs.version }}'; | |
| require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2) + '\n'); | |
| " | |
| - name: Setup Bun | |
| uses: oven-sh/setup-bun@v2 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| registry-url: 'https://registry.npmjs.org' | |
| - name: Install dependencies | |
| run: bun install --frozen-lockfile | |
| - name: Run tests | |
| run: bun run test | |
| - name: Build package | |
| run: bun run build | |
| - name: Commit and tag | |
| env: | |
| VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add package.json | |
| if git ls-files --modified --others | grep -q bun.lock; then | |
| git add bun.lock | |
| fi | |
| git commit -m "chore: release v${VERSION}" | |
| git tag "v${VERSION}" | |
| git push origin "v${VERSION}" | |
| git push origin HEAD:main | |
| - name: Publish to npm | |
| if: ${{ github.event.inputs.dry_run != 'true' }} | |
| run: npm publish --access public | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ steps.version.outputs.version }} | |
| generate_release_notes: true | |
| draft: ${{ github.event.inputs.dry_run == 'true' }} | |
| name: v${{ steps.version.outputs.version }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Send Discord notification | |
| if: ${{ github.event.inputs.dry_run != 'true' }} | |
| env: | |
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ steps.version.outputs.version }} | |
| REPOSITORY: ${{ github.repository }} | |
| run: | | |
| if [ -z "$DISCORD_WEBHOOK_URL" ]; then | |
| echo "DISCORD_WEBHOOK_URL not set; skipping Discord notification." | |
| exit 0 | |
| fi | |
| node - <<'NODE' | |
| (async () => { | |
| const tag = `v${process.env.VERSION}`; | |
| const repo = process.env.REPOSITORY; | |
| const releaseRes = await fetch(`https://api.github.com/repos/${repo}/releases/tags/${tag}`, { | |
| headers: { | |
| Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, | |
| Accept: 'application/vnd.github+json', | |
| }, | |
| }); | |
| if (!releaseRes.ok) { | |
| const body = await releaseRes.text(); | |
| throw new Error(`Failed to fetch release ${tag}: ${releaseRes.status} ${body}`); | |
| } | |
| const release = await releaseRes.json(); | |
| const description = (release.body || `opencode-commandcode ${tag} released.`).slice(0, 4096); | |
| const payload = { | |
| username: 'opencode-commandcode Releases', | |
| embeds: [ | |
| { | |
| title: release.name || `opencode-commandcode ${tag}`, | |
| url: release.html_url, | |
| description, | |
| color: 8244896, | |
| footer: { text: 'opencode-commandcode Changelog' }, | |
| }, | |
| ], | |
| }; | |
| const discordRes = await fetch(process.env.DISCORD_WEBHOOK_URL, { | |
| method: 'POST', | |
| headers: { 'content-type': 'application/json' }, | |
| body: JSON.stringify(payload), | |
| }); | |
| if (!discordRes.ok) { | |
| const body = await discordRes.text(); | |
| throw new Error(`Failed to send Discord notification: ${discordRes.status} ${body}`); | |
| } | |
| console.log('Discord notification sent successfully'); | |
| })().catch((error) => { | |
| console.error(error); | |
| process.exit(1); | |
| }); | |
| NODE |