mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
feat(release): automate OSS release pipeline with just release (#757)
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
name: Auto-tag on Release PR Merge
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
auto-tag:
|
||||
if: >
|
||||
github.event.pull_request.merged == true &&
|
||||
startsWith(github.event.pull_request.head.ref, 'version-bump/')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.merge_commit_sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Extract version from branch name
|
||||
env:
|
||||
BRANCH: ${{ github.event.pull_request.head.ref }}
|
||||
run: |
|
||||
VERSION="${BRANCH#version-bump/}"
|
||||
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then
|
||||
echo "::error::Invalid version in branch name: '$VERSION'"
|
||||
exit 1
|
||||
fi
|
||||
echo "version=$VERSION" >> "$GITHUB_ENV"
|
||||
echo "Tagging v${VERSION}"
|
||||
|
||||
- name: Create and push tag
|
||||
env:
|
||||
VERSION: ${{ env.version }}
|
||||
run: |
|
||||
EXISTING_SHA="$(git ls-remote --tags origin "refs/tags/v$VERSION" | awk '{print $1}')"
|
||||
if [ -n "$EXISTING_SHA" ]; then
|
||||
if [ "$EXISTING_SHA" = "$GITHUB_SHA" ]; then
|
||||
echo "Tag v$VERSION already exists at $GITHUB_SHA — skipping tag creation"
|
||||
exit 0
|
||||
else
|
||||
echo "::error::Tag v$VERSION already exists at $EXISTING_SHA (expected $GITHUB_SHA)"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config user.name "github-actions[bot]"
|
||||
git tag "v$VERSION"
|
||||
git push origin "v$VERSION"
|
||||
|
||||
- name: Trigger release build
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION: ${{ env.version }}
|
||||
run: |
|
||||
gh workflow run release.yml \
|
||||
-f version="$VERSION" \
|
||||
-f ref="v$VERSION"
|
||||
@@ -1,13 +1,16 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9]*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Semver version (e.g. 0.4.0)"
|
||||
description: "Semver version (e.g. 0.4.0) — only for manual runs"
|
||||
required: true
|
||||
ref:
|
||||
description: "Branch, tag, or SHA to build"
|
||||
description: "Branch, tag, or SHA to build — only for manual runs"
|
||||
default: main
|
||||
required: true
|
||||
|
||||
@@ -19,10 +22,25 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write # required by block/apple-codesign-action for OIDC
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Determine version
|
||||
id: version
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
INPUT_VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
if [[ "$EVENT_NAME" == "push" ]]; then
|
||||
VERSION="${GITHUB_REF_NAME#v}"
|
||||
else
|
||||
VERSION="$INPUT_VERSION"
|
||||
fi
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Validate version
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
if ! echo "$VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then
|
||||
echo "::error::Invalid version '$VERSION'. Expected semver (e.g. 0.4.0 or 1.0.0-beta.1)"
|
||||
@@ -31,7 +49,7 @@ jobs:
|
||||
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
ref: ${{ github.event_name == 'push' && github.ref || inputs.ref }}
|
||||
persist-credentials: false
|
||||
|
||||
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
|
||||
@@ -40,6 +58,8 @@ jobs:
|
||||
run: just desktop-install-ci
|
||||
|
||||
- name: Patch version
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
cd desktop && node scripts/set-version-from-tag.mjs "$VERSION"
|
||||
cd src-tauri && cargo update --workspace
|
||||
@@ -153,20 +173,26 @@ jobs:
|
||||
> latest.json
|
||||
cat latest.json
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
SIG_PATH: ${{ steps.artifacts.outputs.sig }}
|
||||
ARCHIVE_NAME: ${{ steps.artifacts.outputs.archive_name }}
|
||||
|
||||
- name: Create versioned GitHub release
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DMG_PATH: ${{ steps.artifacts.outputs.dmg }}
|
||||
run: |
|
||||
RELEASE_SHA=$(git rev-parse HEAD)
|
||||
NOTES=$(awk "/^## v${VERSION}$/,/^## v/" CHANGELOG.md | head -n -1)
|
||||
if [[ -z "$NOTES" ]]; then
|
||||
NOTES="Sprout Desktop v${VERSION}"
|
||||
fi
|
||||
gh release create "v${VERSION}" \
|
||||
--target "$RELEASE_SHA" \
|
||||
--title "Sprout Desktop v${VERSION}" \
|
||||
--notes "Sprout Desktop v${VERSION}" \
|
||||
--notes "$NOTES" \
|
||||
"$DMG_PATH"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DMG_PATH: ${{ steps.artifacts.outputs.dmg }}
|
||||
|
||||
- name: Update rolling release for auto-updater
|
||||
run: |
|
||||
@@ -192,12 +218,10 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
ref: ${{ github.event_name == 'push' && github.ref || inputs.ref }}
|
||||
persist-credentials: false
|
||||
|
||||
- uses: cashapp/activate-hermit@e49f5cb4dd64ff0b0b659d1d8df499595451155a # v1
|
||||
@@ -237,6 +261,8 @@ jobs:
|
||||
run: just desktop-install-ci
|
||||
|
||||
- name: Patch version
|
||||
env:
|
||||
VERSION: ${{ needs.release.outputs.version }}
|
||||
run: |
|
||||
cd desktop && node scripts/set-version-from-tag.mjs "$VERSION"
|
||||
cd src-tauri && cargo update --workspace
|
||||
@@ -271,12 +297,13 @@ jobs:
|
||||
echo "appimage=$APPIMAGE" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload Linux artifacts to versioned GitHub release
|
||||
run: |
|
||||
gh release upload "v${VERSION}" \
|
||||
"$DEB_PATH" \
|
||||
"$APPIMAGE_PATH" \
|
||||
--clobber
|
||||
env:
|
||||
VERSION: ${{ needs.release.outputs.version }}
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DEB_PATH: ${{ steps.linux-artifacts.outputs.deb }}
|
||||
APPIMAGE_PATH: ${{ steps.linux-artifacts.outputs.appimage }}
|
||||
run: |
|
||||
gh release upload "v$VERSION" \
|
||||
"$DEB_PATH" \
|
||||
"$APPIMAGE_PATH" \
|
||||
--clobber
|
||||
|
||||
@@ -6,6 +6,30 @@ code style, PR process, architecture), see [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
---
|
||||
|
||||
## Ecosystem
|
||||
|
||||
Sprout spans five repos. This one (`block/sprout`) is the OSS source for the relay, desktop, mobile, and CLI. The others handle internal builds and deployment:
|
||||
|
||||
| Repo | Purpose |
|
||||
|------|---------|
|
||||
| [block/sprout](https://github.com/block/sprout) | OSS source — relay, desktop app, mobile app, CLI, agent harness |
|
||||
| [squareup/sprout-releases](https://github.com/squareup/sprout-releases) | Buildkite pipeline producing Block-signed macOS + iOS builds with `-block` version suffix |
|
||||
| [squareup/sprout-oss](https://github.com/squareup/sprout-oss) | CI pipeline building the relay Docker image and pushing to internal ECR |
|
||||
| [squareup/block-coder-tf-stacks](https://github.com/squareup/block-coder-tf-stacks) | Terraform + ArgoCD deploying the relay to the staging Kubernetes cluster |
|
||||
| [squareup/sprout-backend-blox](https://github.com/squareup/sprout-backend-blox) | Desktop backend provider script connecting Blox workstation agents to the relay |
|
||||
|
||||
```
|
||||
block/sprout (source)
|
||||
├─► sprout-releases (desktop + mobile builds → Artifactory, GitHub, Mobile Releases)
|
||||
├─► sprout-oss (relay Docker image → ECR)
|
||||
│ └─► block-coder-tf-stacks (Helm chart → ArgoCD → staging cluster)
|
||||
└─── sprout-backend-blox (Blox compute provider for Desktop agent launch)
|
||||
```
|
||||
|
||||
See [RELEASING.md](RELEASING.md) for the desktop release flow across `block/sprout` and `sprout-releases`.
|
||||
|
||||
---
|
||||
|
||||
## Repo Structure
|
||||
|
||||
```
|
||||
@@ -281,4 +305,5 @@ Or from repo root: `just mobile-fmt` (auto-fix), `just mobile-check` (lint + fmt
|
||||
- [CONTRIBUTING.md](CONTRIBUTING.md) — setup, code style, PR process, how to add event kinds / CLI subcommands / API endpoints
|
||||
- [TESTING.md](TESTING.md) — multi-agent E2E test guide
|
||||
- [ARCHITECTURE.md](ARCHITECTURE.md) — system design and component relationships
|
||||
- [RELEASING.md](RELEASING.md) — release process: `just release`, auto-tag, internal builds
|
||||
- [README.md](README.md) — project overview and quick start
|
||||
|
||||
+82
-78
@@ -1,51 +1,82 @@
|
||||
# Releasing Sprout Desktop
|
||||
|
||||
This document describes how to create a new OSS release of the Sprout
|
||||
desktop app.
|
||||
## Quick Start
|
||||
|
||||
```sh
|
||||
# Regular release (next minor version)
|
||||
just release
|
||||
|
||||
# Patch release
|
||||
just release patch
|
||||
|
||||
# Explicit version
|
||||
just release 1.0.0
|
||||
```
|
||||
|
||||
This creates a `version-bump/<version>` PR that bumps all version manifests, regenerates lockfiles, and appends a changelog entry. Merge the PR to trigger the build automatically.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
## How It Works
|
||||
|
||||
- **Write access** to the `block/sprout` GitHub repository. Only
|
||||
collaborators with push permissions can trigger the release workflow.
|
||||
- The following **GitHub Actions secrets** must be configured on the repo
|
||||
(Settings > Secrets and variables > Actions):
|
||||
1. **`just release`** runs locally on `main` — computes the next version, creates a `version-bump/<version>` branch, bumps versions in all manifests, regenerates lockfiles, generates a changelog entry, commits, pushes, and opens a PR.
|
||||
|
||||
| Secret | Purpose |
|
||||
|--------|---------|
|
||||
| `SPROUT_UPDATER_PUBLIC_KEY` | Tauri updater public key (minisign) |
|
||||
| `TAURI_SIGNING_PRIVATE_KEY` | Tauri updater private key (used to sign the update archive) |
|
||||
| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | Password for the private key |
|
||||
2. **Merge the PR** — the `auto-tag-on-release-pr-merge` workflow detects the `version-bump/*` branch merge and pushes a `v<version>` tag.
|
||||
|
||||
3. **Tag triggers `release.yml`** — the existing release workflow builds, signs, notarizes, and publishes the desktop app for macOS and Linux.
|
||||
|
||||
---
|
||||
|
||||
## Creating a Release
|
||||
## Release Types
|
||||
|
||||
1. Go to **Actions > Release** in the GitHub UI:\
|
||||
`https://github.com/block/sprout/actions/workflows/release.yml`
|
||||
| Command | Version | Example |
|
||||
|---------|---------|---------|
|
||||
| `just release` | Next minor | `0.3.0` → `0.4.0` |
|
||||
| `just release patch` | Next patch | `0.3.0` → `0.3.1` |
|
||||
| `just release 1.0.0` | Explicit | `1.0.0` |
|
||||
|
||||
2. Click **"Run workflow"**.
|
||||
---
|
||||
|
||||
3. Fill in the inputs:
|
||||
- **version** — a semver version string, e.g. `0.4.0` or `1.0.0-beta.1`.
|
||||
Do not include a `v` prefix.
|
||||
- **ref** — the branch, tag, or commit SHA to build from. Defaults to
|
||||
`main`.
|
||||
## Version Files
|
||||
|
||||
4. Click **"Run workflow"** to start the build.
|
||||
`just bump-version <version>` updates these files:
|
||||
|
||||
The workflow will:
|
||||
| File | Field |
|
||||
|------|-------|
|
||||
| `desktop/package.json` | `"version"` |
|
||||
| `desktop/src-tauri/tauri.conf.json` | `"version"` |
|
||||
| `desktop/src-tauri/Cargo.toml` | `version` (under `[package]`) |
|
||||
| `mobile/pubspec.yaml` | `version:` (preserves build number) |
|
||||
|
||||
- Validate the version string
|
||||
- Check out the specified ref
|
||||
- Patch the version into `package.json`, `tauri.conf.json`, and `Cargo.toml`
|
||||
- Build all sidecar binaries (`sprout-acp`, `sprout-mcp`,
|
||||
`git-credential-nostr`)
|
||||
- Build the Tauri desktop app with updater signing enabled
|
||||
- Create a versioned GitHub release (`v0.4.0`) with the `.dmg` installer
|
||||
- Update the rolling `sprout-desktop-latest` release with the signed
|
||||
update archive and `latest.json` manifest for the auto-updater
|
||||
It also regenerates `pnpm-lock.yaml`, `desktop/src-tauri/Cargo.lock`, and `mobile/pubspec.lock`.
|
||||
|
||||
---
|
||||
|
||||
## Manual Fallback
|
||||
|
||||
If the automated flow isn't suitable (e.g., building from a non-main ref):
|
||||
|
||||
1. Go to **Actions > Release** in the GitHub UI
|
||||
2. Click **Run workflow**
|
||||
3. Provide the semver version (no `v` prefix) and the ref to build from
|
||||
|
||||
---
|
||||
|
||||
## Internal Releases
|
||||
|
||||
After the OSS release ships, trigger an internal build via the **sprout-releases** Buildkite pipeline:
|
||||
|
||||
1. Go to the [sprout-releases pipeline](https://buildkite.com/runway/sprout-releases) and click **New Build**
|
||||
2. Fill in the input fields:
|
||||
|
||||
| Field | Value | Notes |
|
||||
|-------|-------|-------|
|
||||
| `version` | `0.3.0` | Semver, no `v` prefix |
|
||||
| `sprout_ref` | `v0.3.0` | The OSS git tag — use the tag, not a branch name |
|
||||
| `relay_url` | *(default)* | Pre-filled with the production relay; usually leave as-is |
|
||||
| `publish_latest` | `true` | Updates `latest.json` on Artifactory so installed apps auto-update. Set to `false` for test builds. |
|
||||
|
||||
Internal desktop builds display a `-block` suffix in the version (e.g., `v0.3.0-block` in the Settings panel). This distinguishes them from OSS builds at a glance. iOS builds and GitHub release tags use the clean version (`0.3.0`) since Apple's `CFBundleShortVersionString` rejects pre-release suffixes.
|
||||
|
||||
---
|
||||
|
||||
@@ -53,63 +84,36 @@ The workflow will:
|
||||
|
||||
Each release produces two GitHub releases:
|
||||
|
||||
1. **`v<version>`** (e.g. `v0.4.0`) — the user-facing release with the
|
||||
`.dmg` installer. This is what users download manually.
|
||||
1. **`v<version>`** — the user-facing release with the `.dmg` installer (macOS) and `.deb`/`.AppImage` (Linux).
|
||||
|
||||
2. **`sprout-desktop-latest`** — a rolling pre-release used by the Tauri
|
||||
auto-updater. Contains `latest.json`, the signed `.tar.gz` archive,
|
||||
and its `.sig` signature. Users should not download from this release
|
||||
directly.
|
||||
2. **`sprout-desktop-latest`** — a rolling pre-release for the Tauri auto-updater containing `latest.json`, the signed `.tar.gz` archive, and its `.sig` signature.
|
||||
|
||||
---
|
||||
|
||||
## Platform Support
|
||||
## Prerequisites
|
||||
|
||||
The release workflow currently builds for **macOS ARM64 only**
|
||||
(`darwin-aarch64`). Intel Mac (`darwin-x86_64`) support would require
|
||||
adding a matrix build to the workflow.
|
||||
- **Write access** to the `block/sprout` GitHub repository
|
||||
- **`gh` CLI** authenticated (`gh auth status`)
|
||||
- The following **GitHub Actions secrets** must be configured:
|
||||
|
||||
## Code Signing (macOS)
|
||||
|
||||
OSS release builds use **ad-hoc code signing** (`signingIdentity: "-"`)
|
||||
rather than a Developer ID certificate. This means the app is not
|
||||
notarized by Apple.
|
||||
|
||||
On first launch, macOS Gatekeeper will block the app with a "damaged" or
|
||||
"unidentified developer" message. Users can bypass this by
|
||||
**right-clicking the app > Open** (or via System Settings > Privacy &
|
||||
Security). After the first launch the app will open normally.
|
||||
|
||||
---
|
||||
|
||||
## Auto-Updater
|
||||
|
||||
The desktop app checks for updates by fetching `latest.json` from the
|
||||
`sprout-desktop-latest` release:
|
||||
|
||||
```
|
||||
https://github.com/block/sprout/releases/download/sprout-desktop-latest/latest.json
|
||||
```
|
||||
|
||||
When a new version is available, the app downloads the signed archive,
|
||||
verifies the signature against the embedded public key, and applies the
|
||||
update.
|
||||
| Secret | Purpose |
|
||||
|--------|---------|
|
||||
| `SPROUT_UPDATER_PUBLIC_KEY` | Tauri updater public key (minisign) |
|
||||
| `TAURI_SIGNING_PRIVATE_KEY` | Tauri updater private key |
|
||||
| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | Password for the private key |
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build fails at "Validate version"
|
||||
The version string must be valid semver: `MAJOR.MINOR.PATCH` with an
|
||||
optional pre-release suffix (e.g. `1.0.0-beta.1`). Do not include a `v`
|
||||
prefix.
|
||||
### `just release` fails with "must be on main branch"
|
||||
Switch to `main` and pull latest before running `just release`.
|
||||
|
||||
### Build fails at "Build Tauri app"
|
||||
Check that the signing secrets are configured correctly. The build
|
||||
requires `TAURI_SIGNING_PRIVATE_KEY` and
|
||||
`TAURI_SIGNING_PRIVATE_KEY_PASSWORD` to be set.
|
||||
### `just release` fails with "working tree is dirty"
|
||||
Commit or stash your changes before running `just release`.
|
||||
|
||||
### Build fails at "Validate version"
|
||||
The version string must be valid semver: `MAJOR.MINOR.PATCH` with an optional pre-release suffix. Do not include a `v` prefix.
|
||||
|
||||
### Auto-updater reports "no update available"
|
||||
Verify that the `sprout-desktop-latest` release exists and contains a
|
||||
valid `latest.json`. If the user is on Intel Mac, no update will be
|
||||
found (ARM64 only).
|
||||
Verify that the `sprout-desktop-latest` release exists and contains a valid `latest.json`.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "sprout",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"version": "0.3.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
Generated
+254
-609
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
|
||||
[package]
|
||||
name = "sprout-desktop"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
description = "Sprout desktop app"
|
||||
authors = ["you"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Sprout",
|
||||
"version": "0.1.0",
|
||||
"version": "0.3.0",
|
||||
"identifier": "xyz.block.sprout.app",
|
||||
"build": {
|
||||
"beforeDevCommand": {
|
||||
|
||||
@@ -308,6 +308,139 @@ clean:
|
||||
check-compile:
|
||||
cargo check --workspace --all-targets
|
||||
|
||||
# ─── Release ─────────────────────────────────────────────────────────────────
|
||||
|
||||
# Read the current desktop version from package.json
|
||||
get-current-version:
|
||||
@node -p "require('./desktop/package.json').version"
|
||||
|
||||
# Compute next minor version (e.g., 0.3.0 → 0.4.0)
|
||||
get-next-minor-version:
|
||||
@python3 -c "v='$(just get-current-version)'.split('.'); print(f'{v[0]}.{int(v[1])+1}.0')"
|
||||
|
||||
# Compute next patch version (e.g., 0.3.0 → 0.3.1)
|
||||
get-next-patch-version:
|
||||
@python3 -c "v='$(just get-current-version)'.split('.'); print(f'{v[0]}.{v[1]}.{int(v[2])+1}')"
|
||||
|
||||
# Update version in all package manifests and regenerate lockfiles
|
||||
bump-version version:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
# Validate semver format
|
||||
if ! echo "{{ version }}" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then
|
||||
echo "Error: '{{ version }}' is not valid semver (expected X.Y.Z)"
|
||||
exit 1
|
||||
fi
|
||||
# desktop/package.json
|
||||
cd desktop && npm pkg set "version={{ version }}" && cd ..
|
||||
# desktop/src-tauri/tauri.conf.json
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const p = 'desktop/src-tauri/tauri.conf.json';
|
||||
const c = JSON.parse(fs.readFileSync(p, 'utf8'));
|
||||
c.version = '{{ version }}';
|
||||
fs.writeFileSync(p, JSON.stringify(c, null, 2) + '\n');
|
||||
"
|
||||
# desktop/src-tauri/Cargo.toml — only first version line (under [package])
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const p = 'desktop/src-tauri/Cargo.toml';
|
||||
let t = fs.readFileSync(p, 'utf8');
|
||||
t = t.replace(/^version = \".*\"/m, 'version = \"{{ version }}\"');
|
||||
fs.writeFileSync(p, t);
|
||||
"
|
||||
# mobile/pubspec.yaml — bump version but preserve build number
|
||||
sed -i '' "s/^version: .*/version: {{ version }}+1/" mobile/pubspec.yaml
|
||||
# Regenerate lockfiles
|
||||
pnpm install --lockfile-only
|
||||
cargo update -p sprout-desktop --manifest-path desktop/src-tauri/Cargo.toml
|
||||
(unset GIT_DIR GIT_WORK_TREE; cd mobile && flutter pub get)
|
||||
echo "Bumped all manifests to {{ version }} and regenerated lockfiles"
|
||||
|
||||
# Create a release PR that bumps version and generates changelog
|
||||
release *ARGS:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
# Determine target version
|
||||
ARG="{{ ARGS }}"
|
||||
if [[ -z "$ARG" ]]; then
|
||||
VERSION=$(just get-next-minor-version)
|
||||
elif [[ "$ARG" == "patch" ]]; then
|
||||
VERSION=$(just get-next-patch-version)
|
||||
else
|
||||
VERSION="$ARG"
|
||||
fi
|
||||
echo "Preparing release v${VERSION}..."
|
||||
# Ensure on main branch
|
||||
CURRENT_BRANCH=$(git symbolic-ref --short HEAD)
|
||||
if [[ "$CURRENT_BRANCH" != "main" ]]; then
|
||||
echo "Error: must be on main branch (currently on '$CURRENT_BRANCH')"
|
||||
exit 1
|
||||
fi
|
||||
# Ensure local main is up-to-date
|
||||
git fetch origin main --quiet
|
||||
if [[ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]]; then
|
||||
echo "Error: local main is not up-to-date with origin/main. Run 'git pull' first."
|
||||
exit 1
|
||||
fi
|
||||
# Ensure clean working tree
|
||||
if ! git diff --quiet || ! git diff --cached --quiet; then
|
||||
echo "Error: working tree is dirty. Commit or stash changes first."
|
||||
exit 1
|
||||
fi
|
||||
# Create version-bump branch
|
||||
BRANCH="version-bump/${VERSION}"
|
||||
git switch -c "$BRANCH"
|
||||
# Bump versions and lockfiles
|
||||
just bump-version "$VERSION"
|
||||
# Generate changelog
|
||||
LAST_TAG=$(git describe --tags --abbrev=0 --match 'v[0-9]*' 2>/dev/null || echo "")
|
||||
TMPFILE=$(mktemp)
|
||||
{
|
||||
echo "# Changelog"
|
||||
echo ""
|
||||
echo "## v${VERSION}"
|
||||
echo ""
|
||||
if [[ -n "$LAST_TAG" ]]; then
|
||||
git log "${LAST_TAG}..HEAD" --oneline --no-merges
|
||||
else
|
||||
echo "Initial release"
|
||||
fi
|
||||
echo ""
|
||||
if [[ -f CHANGELOG.md ]]; then
|
||||
tail -n +2 CHANGELOG.md
|
||||
fi
|
||||
} > "$TMPFILE"
|
||||
mv "$TMPFILE" CHANGELOG.md
|
||||
# Commit
|
||||
git add \
|
||||
desktop/package.json \
|
||||
desktop/src-tauri/tauri.conf.json \
|
||||
desktop/src-tauri/Cargo.toml \
|
||||
desktop/src-tauri/Cargo.lock \
|
||||
mobile/pubspec.yaml \
|
||||
mobile/pubspec.lock \
|
||||
pnpm-lock.yaml \
|
||||
CHANGELOG.md
|
||||
git commit -m "chore(release): release version ${VERSION}"
|
||||
# Push and open PR
|
||||
git push -u origin "$BRANCH"
|
||||
# Build PR body
|
||||
PR_BODY="## Release v${VERSION}"$'\n\n'
|
||||
if [[ -n "$LAST_TAG" ]]; then
|
||||
PR_BODY+="### Changes since ${LAST_TAG}:"$'\n\n'
|
||||
PR_BODY+="$(git log "${LAST_TAG}..HEAD~1" --oneline --no-merges)"$'\n\n'
|
||||
else
|
||||
PR_BODY+="Initial release."$'\n\n'
|
||||
fi
|
||||
PR_BODY+="**To release:** merge this PR. The tag and build will happen automatically."
|
||||
PR_URL=$(gh pr create \
|
||||
--title "chore(release): release version ${VERSION}" \
|
||||
--body "$PR_BODY")
|
||||
echo ""
|
||||
echo "Release PR opened: ${PR_URL}"
|
||||
echo "Merge it to trigger the release build."
|
||||
|
||||
# ─── Agent Harness ────────────────────────────────────────────────────────────
|
||||
|
||||
# Run a goose agent connected to a Sprout relay (foreground)
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
name: sprout_mobile
|
||||
description: Sprout mobile client
|
||||
publish_to: 'none'
|
||||
version: 0.1.0+1
|
||||
version: 0.3.0+1
|
||||
|
||||
environment:
|
||||
sdk: ^3.11.4
|
||||
|
||||
Reference in New Issue
Block a user