diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 22cbc30..75f3c5a 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -1,18 +1,22 @@ -name: Beta Prerelease +name: Alpha/Beta Prerelease on: push: branches: - - 'story/**' - 'feature/**' - - 'release/**' + - 'beta/**' + pull_request: + types: [closed] + branches: + - 'beta/**' + - 'main' jobs: - beta: - if: github.event_name == 'push' + prerelease: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.merged == true) runs-on: ubuntu-latest permissions: - contents: read + contents: write id-token: write steps: - uses: actions/checkout@v4 @@ -29,14 +33,73 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} run: npm whoami || true - run: npm run build --if-present - - name: Bump prerelease version (beta) without tagging + + - name: Determine release type + id: release-type + shell: bash + run: | + if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == refs/heads/feature/* ]]; then + echo "type=alpha" >> $GITHUB_OUTPUT + echo "preid=alpha" >> $GITHUB_OUTPUT + echo "tag=alpha" >> $GITHUB_OUTPUT + echo "Release type: ALPHA (experimental features)" + elif [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" == refs/heads/beta/* ]]; then + echo "type=beta" >> $GITHUB_OUTPUT + echo "preid=beta" >> $GITHUB_OUTPUT + echo "tag=beta" >> $GITHUB_OUTPUT + echo "Release type: BETA (testing phase - direct push)" + elif [[ "${{ github.event_name }}" == "pull_request" && "${{ github.base_ref }}" == "beta" ]]; then + echo "type=beta" >> $GITHUB_OUTPUT + echo "preid=beta" >> $GITHUB_OUTPUT + echo "tag=beta" >> $GITHUB_OUTPUT + echo "Release type: BETA (testing phase - PR merge)" + elif [[ "${{ github.event_name }}" == "pull_request" && "${{ github.base_ref }}" == "main" ]]; then + echo "type=stable" >> $GITHUB_OUTPUT + echo "preid=" >> $GITHUB_OUTPUT + echo "tag=latest" >> $GITHUB_OUTPUT + echo "Release type: STABLE (production ready)" + else + echo "type=unknown" >> $GITHUB_OUTPUT + echo "Unknown trigger pattern, skipping release" + exit 1 + fi + + - name: Bump prerelease version shell: bash run: | CURRENT=$(node -p "require('./package.json').version") echo "Current version: $CURRENT" - npm version prerelease --preid=beta --no-git-tag-version - NEW=$(node -p "require('./package.json').version") - echo "New version: $NEW" + + # Get the latest alpha version from NPM + PKG=$(node -p "require('./package.json').name") + PREID="${{ steps.release-type.outputs.preid }}" + + # Get the latest alpha version (only 0.x.x versions) + LATEST_ALPHA=$(npm view "$PKG" versions --json | jq -r ".[] | select(startswith(\"0.\") and contains(\"-$PREID.\"))" | tail -1) || echo "" + + if [ -n "$LATEST_ALPHA" ]; then + echo "Latest alpha version: $LATEST_ALPHA" + # Extract the prerelease number and increment it + PRERELEASE_NUM=$(echo "$LATEST_ALPHA" | sed "s/.*-$PREID\.//") + NEW_PRERELEASE_NUM=$((PRERELEASE_NUM + 1)) + # Extract base version (e.g., 0.1.1 from 0.1.1-alpha.1) + BASE_VERSION=$(echo "$LATEST_ALPHA" | sed "s/-$PREID\..*//") + NEW_VERSION="$BASE_VERSION-$PREID.$NEW_PRERELEASE_NUM" + else + # No alpha version exists, create first one + npm version patch --no-git-tag-version + PATCH_VERSION=$(node -p "require('./package.json').version") + npm version prerelease --preid=$PREID --no-git-tag-version + NEW=$(node -p "require('./package.json').version") + echo "Created first alpha version: $NEW" + exit 0 + fi + + echo "Setting version to: $NEW_VERSION" + npm version "$NEW_VERSION" --no-git-tag-version + VERIFIED=$(node -p "require('./package.json').version") + echo "Verified version: $VERIFIED" + - name: Skip if version already exists id: exists shell: bash @@ -49,9 +112,27 @@ jobs: else echo "exists=false" >> $GITHUB_OUTPUT fi - - name: Publish to npm (beta tag) + + - name: Publish to npm if: steps.exists.outputs.exists == 'false' env: NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} NPM_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} - run: npm publish --tag beta --provenance --access public + run: npm publish --tag ${{ steps.release-type.outputs.tag }} --provenance --access public + + - name: Create GitHub Release + if: steps.exists.outputs.exists == 'false' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PKG=$(node -p "require('./package.json').name") + VER=$(node -p "require('./package.json').version") + TAG="v$VER" + TYPE="${{ steps.release-type.outputs.type }}" + TYPE_UPPER=$(echo "$TYPE" | tr '[:lower:]' '[:upper:]') + + # Create GitHub release + gh release create "$TAG" \ + --title "$TAG" \ + --notes "**${TYPE_UPPER} Release** - ${TYPE_UPPER} version $VER" \ + --prerelease diff --git a/.releaserc.json b/.releaserc.json index 29a946b..3bdd97d 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,10 +1,45 @@ { - "branches": ["main"], + "branches": [ + "main", + { + "name": "beta", + "prerelease": true + } + ], "plugins": [ - ["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }], + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "releaseRules": [ + { "type": "feat", "release": "minor" }, + { "type": "fix", "release": "patch" }, + { "type": "perf", "release": "patch" }, + { "type": "revert", "release": "patch" }, + { "type": "docs", "release": "patch" }, + { "type": "style", "release": "patch" }, + { "type": "chore", "release": "patch" }, + { "type": "refactor", "release": "patch" }, + { "type": "test", "release": "patch" }, + { "type": "build", "release": "patch" }, + { "type": "ci", "release": "patch" } + ] + } + ], ["@semantic-release/release-notes-generator", { "preset": "conventionalcommits" }], ["@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" }], - "@semantic-release/npm", - ["@semantic-release/github", { "assets": [] }] + [ + "@semantic-release/npm", + { + "npmPublish": true, + "tarballDir": "dist" + } + ], + [ + "@semantic-release/github", + { + "assets": ["dist/*.tgz"] + } + ] ] } diff --git a/README.md b/README.md index 6a235b0..7ea5926 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,23 @@ You can change your model any time. In a terminal, run `openrouter models` to br ## Install +### Stable Release (Recommended) + - Global: `npm i -g @letuscode/openrouter-cli` - One‑off: `npx @letuscode/openrouter-cli --help` +### Beta Release (Testing) + +- Global: `npm i -g @letuscode/openrouter-cli@beta` +- One‑off: `npx @letuscode/openrouter-cli@beta --help` + +### Alpha Release (Experimental) + +- Global: `npm i -g @letuscode/openrouter-cli@alpha` +- One‑off: `npx @letuscode/openrouter-cli@alpha --help` + +> **Note**: This project is in MVP development. Alpha releases are experimental, beta releases are for testing, and stable releases are for general use. See [Release Strategy](docs/RELEASE_STRATEGY.md) for details. + Tip: Running `openrouter` with no args starts the setup wizard and then opens the REPL (in a terminal). ### Requirements @@ -97,3 +111,13 @@ Pick 1-10 or type a model id: ## License - MIT + +# Test alpha release + +# Testing GitHub release creation + +# Final test of alpha workflow + +# Testing improved version bumping + +# Testing version increment diff --git a/docs/RELEASE_STRATEGY.md b/docs/RELEASE_STRATEGY.md new file mode 100644 index 0000000..6ca6e26 --- /dev/null +++ b/docs/RELEASE_STRATEGY.md @@ -0,0 +1,101 @@ +# Release Strategy + +This document outlines our release strategy for the OpenRouter CLI project during its MVP development phase. + +## Branch Strategy + +### Feature Branches (`feature/*`) + +- **Purpose**: Experimental features and new functionality +- **Release Type**: Alpha releases +- **NPM Tag**: `alpha` +- **Version Pattern**: `0.1.0-alpha.1`, `0.1.0-alpha.2`, etc. +- **When to use**: When developing new features that may have breaking changes + +### Beta Branches (`beta/*`) + +- **Purpose**: Feature-complete functionality ready for testing +- **Release Type**: Beta releases +- **NPM Tag**: `beta` +- **Version Pattern**: `0.1.0-beta.1`, `0.1.0-beta.2`, etc. +- **When to use**: When features are complete and ready for broader testing + +### Main Branch (`main`) + +- **Purpose**: Stable, production-ready releases +- **Release Type**: Stable releases +- **NPM Tag**: `latest` +- **Version Pattern**: `0.1.0`, `0.1.1`, `0.2.0`, etc. +- **When to use**: When features are thoroughly tested and stable + +## Development Workflow + +1. **Create feature branch**: `feature/your-feature-name` +2. **Develop feature**: Push commits → Automatic alpha releases +3. **Merge to beta**: `beta/your-feature-name` +4. **Test thoroughly**: Push commits → Automatic beta releases +5. **Merge to main**: When ready → Automatic stable release + +## Quality Gates + +### Alpha Releases + +- ✅ Feature implemented +- ⚠️ May have breaking changes +- ⚠️ May have bugs +- 🎯 Target: Early adopters and internal testing + +### Beta Releases + +- ✅ Feature complete +- ✅ Basic testing done +- ⚠️ May have minor bugs +- 🎯 Target: Broader testing community + +### Stable Releases + +- ✅ Feature complete +- ✅ Thoroughly tested +- ✅ No known critical bugs +- ✅ Documentation updated +- 🎯 Target: General users + +## Version Constraints + +- **No 1.x.x releases** until truly production-ready +- **Stays in 0.x.x range** during MVP development +- **Semantic versioning** within 0.x.x range + +## NPM Installation + +```bash +# Install latest stable release +npm install @letuscode/openrouter-cli + +# Install latest beta release +npm install @letuscode/openrouter-cli@beta + +# Install latest alpha release +npm install @letuscode/openrouter-cli@alpha + +# Install specific version +npm install @letuscode/openrouter-cli@0.1.0-beta.1 +``` + +## GitHub Releases + +- **Alpha/Beta**: Created automatically on feature/beta branches +- **Stable**: Created automatically on main branch +- **Tags**: Follow semantic versioning (v0.1.0, v0.1.0-alpha.1, etc.) + +## When to Release to Main + +A feature is ready for main when: + +- [ ] Feature is complete and tested +- [ ] No breaking changes (or breaking changes are documented) +- [ ] All tests pass +- [ ] Documentation is updated +- [ ] Beta testing shows no critical issues +- [ ] Performance is acceptable +- [ ] Security review completed (if applicable) diff --git a/package.json b/package.json index f3433e3..5d0a043 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@letuscode/openrouter-cli", - "version": "1.0.0-beta.1", + "version": "0.1.0", "description": "CLI tool for OpenRouter (OpenAI-compatible)", "bin": { "openrouter": "bin/openrouter"