Skip to content
Open
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
22 changes: 15 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ jobs:
# Generate AI-powered release notes using Claude API
generate-notes:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
# Stable releases only — RC/prerelease tags (v*-rc.*) are handled by prerelease.yml.
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')
outputs:
notes: ${{ steps.generate.outputs.notes }}
notes_file: ${{ steps.generate.outputs.notes_file }}
Expand Down Expand Up @@ -187,8 +188,8 @@ jobs:

build:
environment: production
# Only run on version tags
if: startsWith(github.ref, 'refs/tags/v')
# Only run on stable version tags — RC/prerelease tags (v*-rc.*) go through prerelease.yml.
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -961,7 +962,8 @@ jobs:
needs: build
runs-on: ubuntu-latest
environment: production
if: startsWith(github.ref, 'refs/tags/v')
# Stable releases only — RC tags are signed via prerelease.yml.
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')
strategy:
matrix:
arch: [amd64, arm64]
Expand Down Expand Up @@ -1057,6 +1059,9 @@ jobs:
needs: [build, sign-windows, generate-notes] # add build-docker when server MVP is ready
runs-on: ubuntu-latest
environment: production
# Explicit guard (belt-and-suspenders on top of the cascade from needs:) — RC tags
# publish via prerelease.yml's own release step, never through this stable channel.
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')
outputs:
# base64-encoded checksums.txt — consumed by the SLSA provenance job (WP-C3)
hashes: ${{ steps.checksums.outputs.hashes }}
Expand Down Expand Up @@ -1598,7 +1603,8 @@ jobs:
deploy-docs:
needs: release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v') && github.repository == 'smart-mcp-proxy/mcpproxy-go'
# Stable releases only — don't publish docs for RC/prerelease tags.
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-') && github.repository == 'smart-mcp-proxy/mcpproxy-go'
# Non-blocking: docs failure doesn't block release
continue-on-error: true

Expand Down Expand Up @@ -1643,7 +1649,8 @@ jobs:
trigger-marketing-update:
needs: release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v') && github.repository == 'smart-mcp-proxy/mcpproxy-go'
# Stable releases only — don't fire marketing automation for RC/prerelease tags.
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-') && github.repository == 'smart-mcp-proxy/mcpproxy-go'
# Non-blocking: marketing update failure doesn't block release
continue-on-error: true

Expand All @@ -1660,7 +1667,8 @@ jobs:
name: Publish to MCP Registry
needs: release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
# Stable releases only — never publish an RC to the official MCP registry.
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')
continue-on-error: true
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
Expand Down
3 changes: 1 addition & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Expand Down Expand Up @@ -723,8 +723,7 @@
## Prerelease Builds

- **`main` branch**: Stable releases
- **`next` branch**: Prerelease builds with latest features
- macOS DMG installers are signed and notarized
- **`next` branch** + `v*-rc.*` tags: GitHub pre-releases, opt-in, NOT on stable channels; RC tags skip `release.yml` (brew/linux/registry)

See `docs/prerelease-builds.md` for download instructions.

Expand Down
47 changes: 45 additions & 2 deletions docs/prerelease-builds.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,49 @@ gh run download <RUN_ID> --name versioned-linux-amd64 # Linux
- Example: `v0.8.4-next.5b63e2d`
- Version embedded in both `mcpproxy` and `mcpproxy-tray` binaries

## Release Candidate (RC) Builds

Release candidates are opt-in, fully-built prereleases published to the GitHub **pre-release** channel for testers who want to validate an upcoming version before it ships to stable.

### Version scheme

- Format: **semver** `vMAJOR.MINOR.PATCH-rc.N` — e.g. `v0.37.0-rc.1`, `v0.37.0-rc.2`.
- The `-rc.N` suffix (hyphen + dot before the number) is required. It is what keeps RC tags off the stable channels: the Homebrew, Linux-repo, docs, marketing, MCP-registry, and core build/release jobs in `release.yml` are gated on `!contains(github.ref_name, '-')`.
- Do **not** use forms like `v0.37.0.RC1` or `v0.37.0RC1` — without the hyphen they read as stable tags and would bypass those guards.

### What an RC publishes

A `v*-rc.*` tag runs **only** `prerelease.yml`, which mirrors the full stable build matrix:

| Platform | Artifacts | Signing |
|----------|-----------|---------|
| macOS (arm64, amd64) | DMG + PKG installers, tar.gz | Apple Developer ID signed **and notarized** |
| Linux (arm64, amd64) | tar.gz, `.deb`, `.rpm` | — |
| Windows (arm64, amd64) | `.zip`, installer (`.exe`) | **Not** SignPath-signed (see note below) |

The GitHub release is created with `prerelease: true`, so it does **not** become `releases/latest`.

> **Windows signing:** stable releases are Authenticode-signed via a dedicated SignPath job (`sign-windows`) in `release.yml`. `prerelease.yml` intentionally omits that step (SignPath signing adds ~1h per arch), so **RC Windows installers are unsigned** and will trigger a SmartScreen prompt. If signed Windows RCs become a requirement, port the `sign-windows` job into `prerelease.yml`.

### What an RC does NOT do

- Not published to **Homebrew** (`update-homebrew` guarded).
- Not published to the **Linux apt/rpm repos** (`publish-linux-repos` guarded).
- Not published to the **official MCP registry** (`mcp-registry` guarded).
- Does not deploy docs or trigger marketing automation (`deploy-docs`, `trigger-marketing-update` guarded).
- Not offered as an update on **stable channels**:
- The macOS tray uses GitHub `releases/latest`, which excludes prereleases (`native/macos/MCPProxy/MCPProxy/Services/UpdateService.swift`), plus a semver downgrade guard so an `-rc` is never treated as "newer" than the matching stable.
- The backend/tray update check is stable-only by default (`internal/tray/tray.go` → `releases/latest`). Set `MCPPROXY_ALLOW_PRERELEASE_UPDATES=true` to opt in to RC update offers.

### Installing an RC

Download the assets directly from the pre-release on the [Releases page](https://github.com/smart-mcp-proxy/mcpproxy-go/releases), or with the CLI:

```bash
gh release list --repo smart-mcp-proxy/mcpproxy-go # pre-releases are tagged "Pre-release"
gh release download v0.37.0-rc.1 --repo smart-mcp-proxy/mcpproxy-go
```

## Security Features

- **macOS DMG installers**: Signed with Apple Developer ID and notarized
Expand All @@ -45,7 +88,7 @@ gh run download <RUN_ID> --name versioned-linux-amd64 # Linux

## GitHub Workflows

- **Prerelease workflow**: Triggered on `next` branch pushes
- **Release workflow**: Triggered on `main` branch tags
- **Prerelease workflow** (`prerelease.yml`): Triggered on `next` branch pushes and on `v*-rc.*` / `v*-next.*` tags. Publishes a GitHub pre-release.
- **Release workflow** (`release.yml`): Triggered on `v*` tags, but every job is gated on `!contains(github.ref_name, '-')` so RC/prerelease tags are skipped — a `v*-rc.*` tag therefore fires **only** `prerelease.yml`, never the stable release pipeline.
- **Unit Tests**: Run on all branches with comprehensive test coverage
- **Frontend CI**: Validates web UI components and build process
Loading