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
105 changes: 93 additions & 12 deletions .github/workflows/beta.yml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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
43 changes: 39 additions & 4 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -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"]
}
]
]
}
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
101 changes: 101 additions & 0 deletions docs/RELEASE_STRATEGY.md
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down