Skip to content

Commit 46f6aea

Browse files
rmnunesclaude
andcommitted
Switch to tag-triggered releases (drop release-please)
release-please's cargo-workspace plugin had two compounding issues that weren't worth fighting through: 1. It can't resolve \`version.workspace = true\` inheritance, forcing us to either declare versions per crate or write fragile config. 2. \`extra-files\` paths don't allow \`..\`, so a root-level CHANGELOG can't be written from a package declared at \`src-tauri/\`. Tag-driven release is simpler, more honest, and doesn't impose Conventional Commits as a hard rule: pnpm release patch # bumps all 7 version locations + Cargo.lock git commit -am "chore: release v0.1.1" git tag v0.1.1 git push --follow-tags The tag push triggers .github/workflows/release.yml, which runs tauri-action on Windows / macOS / Linux and attaches the .msi / .dmg / .AppImage / .deb / .rpm bundles to a new GitHub Release. scripts/bump-version.mjs centralizes the version-sync work — package.json, src-tauri/tauri.conf.json, all five Cargo.tomls' [package].version, plus Cargo.lock via cargo update -w. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 00773b2 commit 46f6aea

6 files changed

Lines changed: 130 additions & 109 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,15 @@ name: Release
22

33
on:
44
push:
5-
branches: [main]
5+
tags:
6+
- "v*.*.*"
67

78
permissions:
89
contents: write
9-
pull-requests: write
1010

1111
jobs:
12-
# Step 1: release-please watches main, opens a "chore(main): release X.Y.Z" PR
13-
# that bumps Cargo.toml + Cargo.lock + package.json + tauri.conf.json and
14-
# appends to CHANGELOG.md based on Conventional Commits since the last tag.
15-
# When the PR is merged, it tags the repo and creates a GitHub Release —
16-
# which is what the build job below latches onto.
17-
release-please:
18-
name: Release-please PR / Release
19-
runs-on: ubuntu-latest
20-
outputs:
21-
release_created: ${{ steps.release.outputs.release_created }}
22-
tag_name: ${{ steps.release.outputs.tag_name }}
23-
upload_url: ${{ steps.release.outputs.upload_url }}
24-
steps:
25-
- uses: googleapis/release-please-action@v4
26-
id: release
27-
with:
28-
config-file: .release-please-config.json
29-
manifest-file: .release-please-manifest.json
30-
31-
# Step 2: when release-please publishes a release, build the Tauri bundles on
32-
# each OS and upload them to that release. Users on the Releases page see
33-
# the .msi/.nsis (Windows), .dmg/.app (macOS), and .deb/.AppImage (Linux)
34-
# next to the auto-generated changelog.
3512
build:
3613
name: Build (${{ matrix.os }})
37-
needs: release-please
38-
if: needs.release-please.outputs.release_created
3914
strategy:
4015
fail-fast: false
4116
matrix:
@@ -74,12 +49,21 @@ jobs:
7449

7550
- run: pnpm install --frozen-lockfile
7651

77-
- name: Build and upload Tauri bundles
52+
# tauri-action runs `pnpm tauri build`, then either creates or updates a
53+
# GitHub Release for the pushed tag and attaches the platform-native
54+
# bundles (.msi/.exe on Windows, .dmg/.app.tar.gz on macOS, .deb/.rpm/
55+
# .AppImage on Linux). The first job to reach this step creates the
56+
# release; subsequent jobs upload to the same one (matched by tagName).
57+
- name: Build and publish Tauri bundles
7858
uses: tauri-apps/tauri-action@v0
7959
env:
8060
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8161
with:
82-
tagName: ${{ needs.release-please.outputs.tag_name }}
83-
releaseName: ${{ needs.release-please.outputs.tag_name }}
62+
tagName: ${{ github.ref_name }}
63+
releaseName: ${{ github.ref_name }}
64+
releaseBody: |
65+
See [CHANGELOG.md](https://github.com/rmnunes/pg-shell/blob/main/CHANGELOG.md) for details.
66+
67+
**Downloads** — pick the file for your OS below.
8468
releaseDraft: false
8569
prerelease: false

‎.release-please-config.json‎

Lines changed: 0 additions & 49 deletions
This file was deleted.

‎.release-please-manifest.json‎

Lines changed: 0 additions & 7 deletions
This file was deleted.

‎CONTRIBUTING.md‎

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,37 +62,45 @@ If you're not sure which crate a change belongs in, the rule of thumb: anything
6262
4. Fill in the PR template — especially the "what I tested" section.
6363
5. CI must be green before review.
6464

65-
## Releases & versioning
65+
## Releases
6666

67-
Releases are automated via [release-please](https://github.com/googleapis/release-please) and [tauri-action](https://github.com/tauri-apps/tauri-action).
67+
Releases are tag-triggered. Pushing a `vX.Y.Z` tag to `main` kicks off `.github/workflows/release.yml`, which uses [tauri-action](https://github.com/tauri-apps/tauri-action) to build on Windows / macOS / Linux runners and attach the platform-native bundles to a GitHub Release:
6868

69-
**The flow:**
69+
- Windows: `.msi` + `.exe` (NSIS)
70+
- macOS: `.dmg` + `.app.tar.gz`
71+
- Linux: `.deb` + `.AppImage` + `.rpm`
7072

71-
1. Land commits on `main` using [Conventional Commits](https://www.conventionalcommits.org/):
72-
- `feat: …` → minor bump (under v1.0 it's a patch, see config)
73-
- `fix: …` → patch bump
74-
- `feat!: …` or a `BREAKING CHANGE:` footer → major bump
75-
- `chore:`, `docs:`, `refactor:`, `test:` → no version bump
76-
2. release-please keeps a PR titled `chore(main): release X.Y.Z` open. It bumps `Cargo.toml`, `Cargo.lock`, `package.json`, and `src-tauri/tauri.conf.json`, and updates `CHANGELOG.md`.
77-
3. **Merging that PR** is the act of releasing. release-please tags `vX.Y.Z` and creates a GitHub Release.
78-
4. The release event triggers `tauri-action` on Windows / macOS / Linux runners. It builds and uploads:
79-
- Windows: `.msi` + `.exe` (NSIS)
80-
- macOS: `.dmg` + `.app.tar.gz`
81-
- Linux: `.deb` + `.AppImage` + `.rpm`
82-
5. Users download from the [Releases page](https://github.com/rmnunes/pg-shell/releases).
73+
Users download from the [Releases page](https://github.com/rmnunes/pg-shell/releases).
8374

84-
**Manual release** (escape hatch — only if release-please is wedged):
75+
### Cutting a release
76+
77+
Versions live in five places that have to stay in lockstep: `package.json`, `src-tauri/tauri.conf.json`, and the `[package].version` of each Cargo manifest (`src-tauri/Cargo.toml` + the four crates under `crates/`). The `pnpm release` script handles all of them plus regenerating `Cargo.lock`:
78+
79+
```sh
80+
pnpm release patch # 0.1.0 -> 0.1.1
81+
pnpm release minor # 0.1.0 -> 0.2.0
82+
pnpm release major # 0.1.0 -> 1.0.0
83+
pnpm release 1.2.3 # set explicitly
84+
```
85+
86+
After the script finishes:
8587

8688
```sh
87-
# Bump versions in Cargo.toml workspace.package, package.json, src-tauri/tauri.conf.json,
88-
# update CHANGELOG.md, then:
89+
git diff # sanity check
90+
git commit -am "chore: release v0.1.1"
8991
git tag v0.1.1
90-
git push --tags
91-
# Then create the GitHub Release manually; tauri-action will not fire on bare tag pushes
92-
# in the current setup — only on releases created by release-please.
92+
git push --follow-tags
9393
```
9494

95-
If you want manual tag-triggered builds, switch the `release.yml` `build` job's trigger to `on: push: tags: ['v*']` and remove the `needs: release-please` gate.
95+
The release workflow takes ~10–15 minutes per OS.
96+
97+
### Versioning rules of thumb
98+
99+
We're pre-1.0, so:
100+
101+
- **Breaking change** (IPC contract, profile JSON shape, persistence format): minor bump.
102+
- **New feature, bug fix, performance improvement**: patch bump.
103+
- Once we hit 1.0, switch to standard SemVer.
96104

97105
## Reporting bugs
98106

‎package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"dev": "vite",
88
"build": "tsc -b && vite build",
99
"preview": "vite preview",
10-
"tauri": "tauri"
10+
"tauri": "tauri",
11+
"release": "node scripts/bump-version.mjs"
1112
},
1213
"dependencies": {
1314
"@monaco-editor/react": "^4.7.0",

‎scripts/bump-version.mjs‎

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env node
2+
// Bump version across every file that needs to stay in lockstep:
3+
// - package.json
4+
// - src-tauri/tauri.conf.json
5+
// - src-tauri/Cargo.toml + crates/*/Cargo.toml ([package].version)
6+
// - Cargo.lock (regenerated via `cargo update -w`)
7+
//
8+
// Usage: node scripts/bump-version.mjs <patch|minor|major|x.y.z>
9+
//
10+
// After this script, review the diff, commit with `chore: release vX.Y.Z`,
11+
// then `git tag vX.Y.Z && git push --follow-tags` to kick off the release
12+
// workflow.
13+
14+
import { readFileSync, writeFileSync } from "node:fs";
15+
import { execSync } from "node:child_process";
16+
import { resolve, dirname } from "node:path";
17+
import { fileURLToPath } from "node:url";
18+
19+
const __dirname = dirname(fileURLToPath(import.meta.url));
20+
const repoRoot = resolve(__dirname, "..");
21+
22+
const arg = process.argv[2];
23+
if (!arg) {
24+
console.error("usage: bump-version.mjs <patch|minor|major|x.y.z>");
25+
process.exit(1);
26+
}
27+
28+
const pkg = JSON.parse(readFileSync(resolve(repoRoot, "package.json"), "utf8"));
29+
const current = pkg.version;
30+
const next = computeNext(current, arg);
31+
32+
console.log(`${current} -> ${next}`);
33+
34+
const cargoTomls = [
35+
"src-tauri/Cargo.toml",
36+
"crates/pg-core/Cargo.toml",
37+
"crates/pg-intellisense/Cargo.toml",
38+
"crates/pg-schema-cache/Cargo.toml",
39+
"crates/pg-profiles/Cargo.toml",
40+
];
41+
42+
for (const path of cargoTomls) {
43+
const full = resolve(repoRoot, path);
44+
const content = readFileSync(full, "utf8");
45+
const updated = content.replace(
46+
/^version\s*=\s*"[^"]+"/m,
47+
`version = "${next}"`,
48+
);
49+
if (updated === content) {
50+
console.error(`[!] no [package].version line found in ${path}`);
51+
process.exit(1);
52+
}
53+
writeFileSync(full, updated);
54+
}
55+
56+
pkg.version = next;
57+
writeFileSync(
58+
resolve(repoRoot, "package.json"),
59+
JSON.stringify(pkg, null, 2) + "\n",
60+
);
61+
62+
const tauriConfPath = resolve(repoRoot, "src-tauri/tauri.conf.json");
63+
const tauriConf = JSON.parse(readFileSync(tauriConfPath, "utf8"));
64+
tauriConf.version = next;
65+
writeFileSync(tauriConfPath, JSON.stringify(tauriConf, null, 2) + "\n");
66+
67+
console.log("regenerating Cargo.lock...");
68+
execSync("cargo update -w", { cwd: repoRoot, stdio: "inherit" });
69+
70+
console.log("");
71+
console.log(`done. Review the diff, then:`);
72+
console.log(` git commit -am "chore: release v${next}"`);
73+
console.log(` git tag v${next}`);
74+
console.log(` git push --follow-tags`);
75+
76+
function computeNext(curr, bump) {
77+
if (/^\d+\.\d+\.\d+/.test(bump)) return bump;
78+
const [maj, min, pat] = curr.split(".").map(Number);
79+
if (bump === "patch") return `${maj}.${min}.${pat + 1}`;
80+
if (bump === "minor") return `${maj}.${min + 1}.0`;
81+
if (bump === "major") return `${maj + 1}.0.0`;
82+
console.error(`unknown bump: ${bump}`);
83+
process.exit(1);
84+
}

0 commit comments

Comments
 (0)