-
Notifications
You must be signed in to change notification settings - Fork 0
ci: add dev prerelease flow and release runbook #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: Windows-Support
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,10 @@ | ||
| name: CI | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main, dev] | ||
| pull_request: | ||
| branches: [main] | ||
| branches: [main, dev] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
@@ -16,14 +18,14 @@ jobs: | |
| matrix: | ||
| os: [ubuntu-latest, windows-latest] | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest | ||
|
|
||
| - name: Install Rust toolchain | ||
| uses: dtolnay/rust-action@stable | ||
| uses: dtolnay/rust-toolchain@v1 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 All three workflow files ( Root Cause and ImpactThe Affected files:
Impact: Every workflow that needs Rust will fail at the "Install Rust toolchain" step because the action ref cannot be resolved. This breaks CI, stable publishing, and dev prerelease publishing. Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||
|
|
||
| - name: Install dependencies (Ubuntu only) | ||
| if: matrix.os == 'ubuntu-latest' | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| name: Release Dev | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - dev | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| concurrency: | ||
| group: release-dev-${{ github.ref }} | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| prepare: | ||
| name: Prepare dev release | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| release_tag: ${{ steps.meta.outputs.release_tag }} | ||
| release_name: ${{ steps.meta.outputs.release_name }} | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest | ||
|
|
||
| - run: bun install --frozen-lockfile | ||
|
|
||
| - name: Type-check and build | ||
| run: bun run build | ||
|
|
||
| - name: Run tests | ||
| run: bun run test | ||
|
Comment on lines
+32
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Dev prerelease workflow missing The Detailed ExplanationLooking at Impact: Low — the prepare job validates frontend code and version alignment, not the full Tauri build. But if any test depends on bundled plugin files existing, it would fail. Was this helpful? React with 👍 or 👎 to provide feedback. |
||
|
|
||
| - name: Validate version alignment | ||
| shell: bash | ||
| run: | | ||
| TAURI_CONF_VERSION=$(node -p 'require("./src-tauri/tauri.conf.json").version') | ||
| CARGO_VERSION=$(awk -F'"' '/^version =/ { print $2; exit }' ./src-tauri/Cargo.toml) | ||
| PKG_VERSION=$(node -p 'require("./package.json").version') | ||
|
|
||
| if [[ "$TAURI_CONF_VERSION" != "$CARGO_VERSION" ]]; then | ||
| echo "src-tauri/tauri.conf.json version ($TAURI_CONF_VERSION) != Cargo.toml version ($CARGO_VERSION)" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ "$TAURI_CONF_VERSION" != "$PKG_VERSION" ]]; then | ||
| echo "src-tauri/tauri.conf.json version ($TAURI_CONF_VERSION) != package.json version ($PKG_VERSION)" | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Compute dev release metadata | ||
| id: meta | ||
| shell: bash | ||
| run: | | ||
| APP_VERSION=$(node -p 'require("./src-tauri/tauri.conf.json").version') | ||
| SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7) | ||
| DATE_UTC=$(date -u +%Y%m%d) | ||
| RELEASE_TAG="dev-v${APP_VERSION}-${DATE_UTC}-${SHORT_SHA}" | ||
| RELEASE_NAME="Dev ${APP_VERSION} (${SHORT_SHA})" | ||
|
|
||
| echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT" | ||
| echo "release_name=$RELEASE_NAME" >> "$GITHUB_OUTPUT" | ||
|
|
||
| publish: | ||
| name: Publish dev binaries (${{ matrix.target }}) | ||
| needs: prepare | ||
| runs-on: ${{ matrix.platform }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: | ||
| - platform: macos-latest | ||
| target: aarch64-apple-darwin | ||
| args: --target aarch64-apple-darwin | ||
| - platform: macos-latest | ||
| target: x86_64-apple-darwin | ||
| args: --target x86_64-apple-darwin | ||
| - platform: windows-latest | ||
| target: x86_64-pc-windows-msvc | ||
| args: --target x86_64-pc-windows-msvc | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - uses: oven-sh/setup-bun@v2 | ||
| with: | ||
| bun-version: latest | ||
|
|
||
| - run: bun install --frozen-lockfile | ||
|
|
||
| - uses: dtolnay/rust-toolchain@v1 | ||
| with: | ||
| targets: ${{ matrix.target }} | ||
|
|
||
| - uses: swatinem/rust-cache@v2 | ||
| with: | ||
| workspaces: "./src-tauri -> target" | ||
|
|
||
| - name: Bundle plugins | ||
| run: bun run bundle:plugins | ||
|
|
||
| - name: Validate updater signing key | ||
| shell: bash | ||
| env: | ||
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | ||
| run: | | ||
| if [[ -z "$TAURI_SIGNING_PRIVATE_KEY" ]]; then | ||
| echo "Missing TAURI_SIGNING_PRIVATE_KEY secret." | ||
| exit 1 | ||
| fi | ||
|
|
||
| - uses: tauri-apps/tauri-action@v0 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | ||
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | ||
| with: | ||
| tagName: ${{ needs.prepare.outputs.release_tag }} | ||
| releaseName: ${{ needs.prepare.outputs.release_name }} | ||
| releaseDraft: false | ||
| prerelease: true | ||
| includeUpdaterJson: true | ||
| args: ${{ matrix.args }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # Release Flow | ||
|
|
||
| Two-channel delivery flow: | ||
|
|
||
| - `dev` branch: prerelease builds for testing and staging | ||
| - `main` branch + `v*` tags: stable production releases | ||
|
|
||
| ## Branch Strategy | ||
|
|
||
| 1. Feature PRs merge into `dev`. | ||
| 2. `dev` triggers CI and prerelease desktop binaries (`Release Dev` workflow). | ||
| 3. Once validated, merge `dev` into `main`. | ||
| 4. Create and push a semantic tag (`vX.Y.Z`) from `main` to publish stable binaries. | ||
|
|
||
| ## Workflows | ||
|
|
||
| - `ci.yml`: runs checks on pushes and PRs for `main` and `dev` | ||
| - `release-dev.yml`: publishes prerelease artifacts from `dev` | ||
| - `publish.yml`: publishes stable artifacts from tags | ||
|
|
||
| ## Version Sync | ||
|
|
||
| Keep versions aligned before stable tags: | ||
|
|
||
| ```bash | ||
| bun run release:version 0.6.3 | ||
| ``` | ||
|
|
||
| This updates: | ||
|
|
||
| - `package.json` | ||
| - `src-tauri/tauri.conf.json` | ||
| - `src-tauri/Cargo.toml` | ||
|
|
||
| Then commit, tag, and push: | ||
|
|
||
| ```bash | ||
| git add . | ||
| git commit -m "release: prepare v0.6.3" | ||
| git tag v0.6.3 | ||
| git push origin main --follow-tags | ||
| ``` | ||
|
|
||
| ## Required Secrets | ||
|
|
||
| - `TAURI_SIGNING_PRIVATE_KEY` | ||
| - `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | ||
|
|
||
| Optional platform-signing secrets can be added as needed for platform notarization/certificate requirements. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| import { readFile, writeFile } from "node:fs/promises"; | ||
| import path from "node:path"; | ||
| import process from "node:process"; | ||
|
|
||
| const VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/; | ||
|
|
||
| function fail(message) { | ||
| console.error(message); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| function absolutePath(relativePath) { | ||
| return path.resolve(process.cwd(), relativePath); | ||
| } | ||
|
|
||
| async function updateJsonVersion(filePath, version) { | ||
| const source = await readFile(absolutePath(filePath), "utf8"); | ||
| const parsed = JSON.parse(source); | ||
|
|
||
| if (typeof parsed !== "object" || parsed === null || !("version" in parsed)) { | ||
| fail(`Missing version field in ${filePath}`); | ||
| } | ||
|
|
||
| parsed.version = version; | ||
| await writeFile(absolutePath(filePath), `${JSON.stringify(parsed, null, 2)}\n`, "utf8"); | ||
| } | ||
|
|
||
| async function updateCargoVersion(filePath, version) { | ||
| const source = await readFile(absolutePath(filePath), "utf8"); | ||
| const updated = source.replace(/^version\s*=\s*"[^"]+"/m, `version = "${version}"`); | ||
|
|
||
| if (updated === source) { | ||
| fail(`Could not locate package version in ${filePath}`); | ||
| } | ||
|
|
||
| await writeFile(absolutePath(filePath), updated, "utf8"); | ||
| } | ||
|
|
||
| async function main() { | ||
| const version = process.argv[2]?.trim(); | ||
|
|
||
| if (!version) { | ||
| fail("Usage: bun run release:version <version>"); | ||
| } | ||
|
|
||
| if (!VERSION_PATTERN.test(version)) { | ||
| fail(`Invalid version '${version}'. Expected semantic version like 1.2.3 or 1.2.3-beta.1`); | ||
| } | ||
|
|
||
| await updateJsonVersion("package.json", version); | ||
| await updateJsonVersion("src-tauri/tauri.conf.json", version); | ||
| await updateCargoVersion("src-tauri/Cargo.toml", version); | ||
|
|
||
| console.log(`Synchronized release version to ${version}`); | ||
| } | ||
|
|
||
| main().catch((error) => { | ||
| console.error(error instanceof Error ? error.message : error); | ||
| process.exit(1); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴
actions/checkout@v6references a non-existent major versionAll workflow files were changed from
actions/checkout@v4toactions/checkout@v6. As of February 2026, the latest major version ofactions/checkoutis v4. There is no v6 tag.Root Cause and Impact
The
actions/checkoutaction uses semantic versioning with major version tags (v1, v2, v3, v4). The PR bumped all references to@v6which does not exist. This affects:.github/workflows/ci.yml:21.github/workflows/publish.yml:33.github/workflows/release-dev.yml:24.github/workflows/release-dev.yml:86Impact: Every workflow job will fail at the checkout step because GitHub Actions cannot resolve the
v6tag. No CI checks, no publishing, and no dev releases will work.Prompt for agents
Was this helpful? React with 👍 or 👎 to provide feedback.