@regardio/dev 2.1.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/ship/hotfix.bin.mjs +20 -48
- package/dist/bin/ship/production.bin.mjs +20 -51
- package/dist/bin/ship/staging.bin.mjs +1 -1
- package/dist/bin/ship/utils-VktE94Vs.mjs +115 -0
- package/docs/en/README.md +14 -11
- package/docs/en/standards/commits.md +1 -1
- package/docs/en/tools/releases.md +91 -147
- package/package.json +8 -4
- package/templates/github/release.yml +10 -19
- package/templates/versionrc/.versionrc.json +16 -0
- package/dist/bin/ship/utils-BQ-JZ2D5.mjs +0 -45
- package/templates/changeset/README.md +0 -14
- package/templates/changeset/config.json +0 -11
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as
|
|
3
|
-
import { execFileSync, execSync } from "node:child_process";
|
|
4
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
-
import { join } from "node:path";
|
|
2
|
+
import { a as git, c as runScript, i as getWorkspacePackages, n as chooseForEach, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-VktE94Vs.mjs";
|
|
6
3
|
//#region src/bin/ship/hotfix.ts
|
|
7
4
|
/**
|
|
8
5
|
* ship-hotfix: Manage hotfix branches based on production code.
|
|
@@ -14,10 +11,10 @@ import { join } from "node:path";
|
|
|
14
11
|
* GitLab workflow:
|
|
15
12
|
* production → hotfix/<name> → production → staging → main
|
|
16
13
|
*
|
|
17
|
-
* During a hotfix,
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* CI on `production` handles
|
|
14
|
+
* During a hotfix, commit your fix with conventional commits. `ship-hotfix
|
|
15
|
+
* finish` runs `pnpm release` to bump the version based on those commits,
|
|
16
|
+
* updates CHANGELOG.md, then propagates the hotfix through
|
|
17
|
+
* production → staging → main. CI on `production` handles publishing to npm.
|
|
21
18
|
*/
|
|
22
19
|
function runShipHotfix(subcommand, subArgs, cwd = process.cwd()) {
|
|
23
20
|
if (subcommand === "start") {
|
|
@@ -41,7 +38,7 @@ function runShipHotfix(subcommand, subArgs, cwd = process.cwd()) {
|
|
|
41
38
|
git("pull", "--ff-only", "origin", "production");
|
|
42
39
|
git("checkout", "-b", hotfixBranch);
|
|
43
40
|
console.log(`\n✅ Hotfix branch "${hotfixBranch}" created from production.`);
|
|
44
|
-
console.log("Apply your fix
|
|
41
|
+
console.log("Apply your fix using conventional commits, then run:");
|
|
45
42
|
console.log(" ship-hotfix finish");
|
|
46
43
|
process.exit(0);
|
|
47
44
|
}
|
|
@@ -55,14 +52,6 @@ function runShipHotfix(subcommand, subArgs, cwd = process.cwd()) {
|
|
|
55
52
|
console.error("Working directory has uncommitted changes. Commit or stash them first.");
|
|
56
53
|
process.exit(1);
|
|
57
54
|
}
|
|
58
|
-
if (!existsSync(join(cwd, ".changeset"))) {
|
|
59
|
-
console.error("\nNo .changeset/ directory found. This tooling requires Changesets.\nCopy the template from @regardio/dev/templates/changeset and run:\n pnpm changeset init");
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
if (execFileSync("sh", ["-c", `ls .changeset/*.md 2>/dev/null | grep -v README.md | wc -l | tr -d ' '`], { encoding: "utf-8" }).trim() === "0") {
|
|
63
|
-
console.error("\nNo pending changesets. Run `pnpm changeset` before finishing the hotfix.");
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
66
55
|
console.log("\nRunning quality checks...");
|
|
67
56
|
try {
|
|
68
57
|
runQualityChecks();
|
|
@@ -71,37 +60,19 @@ function runShipHotfix(subcommand, subArgs, cwd = process.cwd()) {
|
|
|
71
60
|
process.exit(1);
|
|
72
61
|
}
|
|
73
62
|
console.log("✅ Quality checks passed");
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
76
|
-
console.error("No
|
|
63
|
+
const packages = getWorkspacePackages(cwd);
|
|
64
|
+
if (packages.length === 0) {
|
|
65
|
+
console.error("No publishable workspace packages found.");
|
|
77
66
|
process.exit(1);
|
|
78
67
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const changedFiles = gitRead("diff", "--cached", "--name-only").split("\n").filter(Boolean);
|
|
88
|
-
for (const file of changedFiles) {
|
|
89
|
-
if (file.endsWith(".json")) try {
|
|
90
|
-
execSync(`npx biome check --write ${file}`, {
|
|
91
|
-
cwd,
|
|
92
|
-
stdio: "inherit"
|
|
93
|
-
});
|
|
94
|
-
} catch {}
|
|
95
|
-
if (file.endsWith(".md")) try {
|
|
96
|
-
execSync(`npx markdownlint-cli2 --fix ${file}`, {
|
|
97
|
-
cwd,
|
|
98
|
-
stdio: "inherit"
|
|
99
|
-
});
|
|
100
|
-
} catch {}
|
|
101
|
-
}
|
|
102
|
-
} catch {}
|
|
103
|
-
git("add", "-A");
|
|
104
|
-
git("commit", "-m", "chore(hotfix): version packages");
|
|
68
|
+
console.log("\nSelect a version bump for each package (or skip):");
|
|
69
|
+
const bumps = chooseForEach(packages);
|
|
70
|
+
if (bumps.length === 0) {
|
|
71
|
+
console.log("\nNo packages selected for release. Aborted.");
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
74
|
+
console.log("\nBumping versions and updating CHANGELOGs...");
|
|
75
|
+
for (const { package: pkg, bump } of bumps) runScript(`--filter ${pkg.name} release:${bump}`);
|
|
105
76
|
console.log("\nFetching latest state from origin...");
|
|
106
77
|
git("fetch", "origin");
|
|
107
78
|
console.log("\nMerging hotfix into production...");
|
|
@@ -118,12 +89,13 @@ function runShipHotfix(subcommand, subArgs, cwd = process.cwd()) {
|
|
|
118
89
|
git("checkout", "main");
|
|
119
90
|
git("pull", "--ff-only", "origin", "main");
|
|
120
91
|
git("merge", "--no-ff", "staging", "-m", "chore(hotfix): merge staging into main");
|
|
121
|
-
git("push", "origin", "main");
|
|
92
|
+
git("push", "--follow-tags", "origin", "main");
|
|
122
93
|
git("branch", "-d", currentBranch);
|
|
123
94
|
try {
|
|
124
95
|
git("push", "origin", "--delete", currentBranch);
|
|
125
96
|
} catch {}
|
|
126
|
-
|
|
97
|
+
const shipped = bumps.map((b) => b.package.name).join(", ");
|
|
98
|
+
console.log(`\n✅ Hotfix ${shipped} shipped to production → staging → main`);
|
|
127
99
|
console.log("CI will publish changed packages to npm.");
|
|
128
100
|
console.log("You are on main and ready to keep working.");
|
|
129
101
|
process.exit(0);
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as
|
|
3
|
-
import { execFileSync, execSync } from "node:child_process";
|
|
4
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
-
import { join } from "node:path";
|
|
2
|
+
import { a as git, c as runScript, i as getWorkspacePackages, n as chooseForEach, o as gitRead, r as confirm, s as runQualityChecks, t as branchExists } from "./utils-VktE94Vs.mjs";
|
|
6
3
|
//#region src/bin/ship/production.ts
|
|
7
4
|
/**
|
|
8
5
|
* ship-production: Promote main to production following the GitLab workflow.
|
|
@@ -10,12 +7,12 @@ import { join } from "node:path";
|
|
|
10
7
|
* Usage: ship-production
|
|
11
8
|
*
|
|
12
9
|
* GitLab workflow:
|
|
13
|
-
* main → (
|
|
10
|
+
* main → (commit-and-tag-version) → production → staging → main
|
|
14
11
|
*
|
|
15
|
-
* Versioning is driven by
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* CI on `production` handles
|
|
12
|
+
* Versioning is driven by commit-and-tag-version. Running `pnpm release`
|
|
13
|
+
* at ship time reads conventional commits since the last tag, bumps the
|
|
14
|
+
* version, updates CHANGELOG.md, and commits the result on `main` before
|
|
15
|
+
* merging to `production`. CI on `production` handles publishing to npm.
|
|
19
16
|
*/
|
|
20
17
|
function runShipProduction(cwd = process.cwd()) {
|
|
21
18
|
const currentBranch = gitRead("branch", "--show-current");
|
|
@@ -45,22 +42,18 @@ function runShipProduction(cwd = process.cwd()) {
|
|
|
45
42
|
}
|
|
46
43
|
console.log("\nCommits to be shipped to production:");
|
|
47
44
|
console.log(ahead);
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
console.error("No
|
|
45
|
+
const packages = getWorkspacePackages(cwd);
|
|
46
|
+
if (packages.length === 0) {
|
|
47
|
+
console.error("No publishable workspace packages found.");
|
|
51
48
|
process.exit(1);
|
|
52
49
|
}
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
console.error("\nNo pending changesets. Run `pnpm changeset` before shipping to production.");
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
console.log(`\n${pendingChangesets} pending changeset(s) will be consumed.`);
|
|
50
|
+
console.log("\nSelect a version bump for each package (or skip):");
|
|
51
|
+
const bumps = chooseForEach(packages);
|
|
52
|
+
if (bumps.length === 0) {
|
|
53
|
+
console.log("\nNo packages selected for release. Aborted.");
|
|
54
|
+
process.exit(0);
|
|
62
55
|
}
|
|
63
|
-
if (!confirm(
|
|
56
|
+
if (!confirm(`\nShip to production?\n${bumps.map((b) => ` ${b.package.name} → ${b.bump}`).join("\n")}\n`)) {
|
|
64
57
|
console.log("Aborted.");
|
|
65
58
|
process.exit(0);
|
|
66
59
|
}
|
|
@@ -72,33 +65,8 @@ function runShipProduction(cwd = process.cwd()) {
|
|
|
72
65
|
process.exit(1);
|
|
73
66
|
}
|
|
74
67
|
console.log("✅ Quality checks passed");
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
runScript("changeset version");
|
|
78
|
-
try {
|
|
79
|
-
runScript("fix:pkg");
|
|
80
|
-
} catch {}
|
|
81
|
-
try {
|
|
82
|
-
git("add", "-A");
|
|
83
|
-
const changedFiles = gitRead("diff", "--cached", "--name-only").split("\n").filter(Boolean);
|
|
84
|
-
for (const file of changedFiles) {
|
|
85
|
-
if (file.endsWith(".json")) try {
|
|
86
|
-
execSync(`npx biome check --write ${file}`, {
|
|
87
|
-
cwd,
|
|
88
|
-
stdio: "inherit"
|
|
89
|
-
});
|
|
90
|
-
} catch {}
|
|
91
|
-
if (file.endsWith(".md")) try {
|
|
92
|
-
execSync(`npx markdownlint-cli2 --fix ${file}`, {
|
|
93
|
-
cwd,
|
|
94
|
-
stdio: "inherit"
|
|
95
|
-
});
|
|
96
|
-
} catch {}
|
|
97
|
-
}
|
|
98
|
-
} catch {}
|
|
99
|
-
git("add", "-A");
|
|
100
|
-
git("commit", "-m", "chore(release): version packages");
|
|
101
|
-
}
|
|
68
|
+
console.log("\nBumping versions and updating CHANGELOGs...");
|
|
69
|
+
for (const { package: pkg, bump } of bumps) runScript(`--filter ${pkg.name} release:${bump}`);
|
|
102
70
|
console.log("\nMerging main into production...");
|
|
103
71
|
git("checkout", "production");
|
|
104
72
|
git("pull", "--ff-only", "origin", "production");
|
|
@@ -110,8 +78,9 @@ function runShipProduction(cwd = process.cwd()) {
|
|
|
110
78
|
git("merge", "--ff-only", "production");
|
|
111
79
|
git("push", "origin", "staging");
|
|
112
80
|
git("checkout", "main");
|
|
113
|
-
git("push", "origin", "main");
|
|
114
|
-
|
|
81
|
+
git("push", "--follow-tags", "origin", "main");
|
|
82
|
+
const shipped = bumps.map((b) => b.package.name).join(", ");
|
|
83
|
+
console.log(`\n✅ Shipped ${shipped} to production. CI will publish changed packages to npm.`);
|
|
115
84
|
console.log("You are on main and ready to keep working.");
|
|
116
85
|
}
|
|
117
86
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as git, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-VktE94Vs.mjs";
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
//#region src/bin/ship/staging.ts
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execFileSync, execSync } from "node:child_process";
|
|
3
|
+
import { closeSync, openSync, readSync } from "node:fs";
|
|
4
|
+
//#region src/bin/ship/utils.ts
|
|
5
|
+
/**
|
|
6
|
+
* Shared utilities for ship-staging, ship-production, and ship-hotfix.
|
|
7
|
+
*
|
|
8
|
+
* Git commands use execFileSync (not a shell string) so user-provided
|
|
9
|
+
* strings such as commit messages are never interpolated by the shell.
|
|
10
|
+
* pnpm script invocations use execSync via shell since script names are
|
|
11
|
+
* developer-controlled and pnpm itself is resolved through PATH.
|
|
12
|
+
*/
|
|
13
|
+
const git = (...args) => {
|
|
14
|
+
console.log(`$ git ${args.join(" ")}`);
|
|
15
|
+
execFileSync("git", args, { stdio: "inherit" });
|
|
16
|
+
};
|
|
17
|
+
const gitRead = (...args) => execFileSync("git", args, { encoding: "utf-8" }).trim();
|
|
18
|
+
const runScript = (script) => {
|
|
19
|
+
console.log(`$ pnpm ${script}`);
|
|
20
|
+
execSync(`pnpm ${script}`, { stdio: "inherit" });
|
|
21
|
+
};
|
|
22
|
+
const runQualityChecks = () => {
|
|
23
|
+
runScript("build");
|
|
24
|
+
runScript("typecheck");
|
|
25
|
+
runScript("test");
|
|
26
|
+
};
|
|
27
|
+
const getWorkspacePackages = (cwd = process.cwd()) => {
|
|
28
|
+
const raw = execFileSync("pnpm", [
|
|
29
|
+
"list",
|
|
30
|
+
"--recursive",
|
|
31
|
+
"--json",
|
|
32
|
+
"--depth",
|
|
33
|
+
"0"
|
|
34
|
+
], {
|
|
35
|
+
cwd,
|
|
36
|
+
encoding: "utf-8"
|
|
37
|
+
});
|
|
38
|
+
return JSON.parse(raw).filter((p) => p.private !== true && p.name !== void 0).map(({ name, path }) => ({
|
|
39
|
+
name,
|
|
40
|
+
path
|
|
41
|
+
}));
|
|
42
|
+
};
|
|
43
|
+
const chooseForEach = (packages, ttyPath = "/dev/tty") => {
|
|
44
|
+
const bumps = [];
|
|
45
|
+
const options = [
|
|
46
|
+
{
|
|
47
|
+
label: "skip",
|
|
48
|
+
value: "skip"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
label: "patch — bug fixes",
|
|
52
|
+
value: "patch"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: "minor — new features",
|
|
56
|
+
value: "minor"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
label: "major — breaking changes",
|
|
60
|
+
value: "major"
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
for (const pkg of packages) {
|
|
64
|
+
const answer = choose(`\n${pkg.name}:`, [...options], ttyPath);
|
|
65
|
+
if (answer !== "skip") bumps.push({
|
|
66
|
+
bump: answer,
|
|
67
|
+
package: pkg
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return bumps;
|
|
71
|
+
};
|
|
72
|
+
const branchExists = (name) => gitRead("branch", "--list", name) !== "" || gitRead("branch", "--list", "--remotes", `origin/${name}`) !== "";
|
|
73
|
+
const confirm = (prompt, ttyPath = "/dev/tty") => {
|
|
74
|
+
process.stdout.write(`${prompt} (y/N) `);
|
|
75
|
+
const buf = Buffer.alloc(1024);
|
|
76
|
+
let fd;
|
|
77
|
+
let shouldClose = false;
|
|
78
|
+
try {
|
|
79
|
+
fd = openSync(ttyPath, "r");
|
|
80
|
+
shouldClose = true;
|
|
81
|
+
} catch {
|
|
82
|
+
fd = process.stdin.fd;
|
|
83
|
+
}
|
|
84
|
+
const bytesRead = readSync(fd, buf, 0, buf.length, null);
|
|
85
|
+
if (shouldClose) closeSync(fd);
|
|
86
|
+
const answer = buf.slice(0, bytesRead).toString().trim();
|
|
87
|
+
return answer === "y" || answer === "Y";
|
|
88
|
+
};
|
|
89
|
+
const choose = (prompt, options, ttyPath = "/dev/tty") => {
|
|
90
|
+
const keys = options.map((_, i) => String(i + 1));
|
|
91
|
+
const optionList = options.map((o, i) => ` ${i + 1}) ${o.label}`).join("\n");
|
|
92
|
+
process.stdout.write(`${prompt}\n${optionList}\nChoice [${keys.join("/")}]: `);
|
|
93
|
+
const buf = Buffer.alloc(1024);
|
|
94
|
+
let fd;
|
|
95
|
+
let shouldClose = false;
|
|
96
|
+
try {
|
|
97
|
+
fd = openSync(ttyPath, "r");
|
|
98
|
+
shouldClose = true;
|
|
99
|
+
} catch {
|
|
100
|
+
fd = process.stdin.fd;
|
|
101
|
+
}
|
|
102
|
+
const bytesRead = readSync(fd, buf, 0, buf.length, null);
|
|
103
|
+
if (shouldClose) closeSync(fd);
|
|
104
|
+
const answer = buf.slice(0, bytesRead).toString().trim();
|
|
105
|
+
const index = keys.indexOf(answer);
|
|
106
|
+
if (index === -1) {
|
|
107
|
+
console.error(`\nInvalid choice: "${answer}". Expected one of: ${keys.join(", ")}`);
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
const chosen = options[index];
|
|
111
|
+
if (!chosen) process.exit(1);
|
|
112
|
+
return chosen.value;
|
|
113
|
+
};
|
|
114
|
+
//#endregion
|
|
115
|
+
export { git as a, runScript as c, getWorkspacePackages as i, chooseForEach as n, gitRead as o, confirm as r, runQualityChecks as s, branchExists as t };
|
package/docs/en/README.md
CHANGED
|
@@ -46,18 +46,21 @@ Configuration and usage for each tool in the stack:
|
|
|
46
46
|
### Commands
|
|
47
47
|
|
|
48
48
|
```bash
|
|
49
|
-
pnpm build
|
|
50
|
-
pnpm dev
|
|
51
|
-
pnpm fix
|
|
52
|
-
pnpm lint
|
|
53
|
-
pnpm report
|
|
54
|
-
pnpm
|
|
55
|
-
pnpm
|
|
56
|
-
pnpm
|
|
49
|
+
pnpm build # Build all packages
|
|
50
|
+
pnpm dev # Start development
|
|
51
|
+
pnpm fix # Run all fixes and linting
|
|
52
|
+
pnpm lint # Run linting only
|
|
53
|
+
pnpm report # Run tests with coverage
|
|
54
|
+
pnpm release # Bump version from conventional commits, update CHANGELOG.md
|
|
55
|
+
pnpm release:patch # Force a patch bump
|
|
56
|
+
pnpm release:minor # Force a minor bump
|
|
57
|
+
pnpm release:major # Force a major bump
|
|
58
|
+
pnpm ship:staging # Deploy main to staging for validation (optional)
|
|
59
|
+
pnpm ship:production # Bump version, merge main → production, trigger publish
|
|
57
60
|
pnpm ship:hotfix start <name> # Start an urgent fix from production
|
|
58
|
-
pnpm ship:hotfix finish
|
|
59
|
-
pnpm test
|
|
60
|
-
pnpm typecheck
|
|
61
|
+
pnpm ship:hotfix finish # Propagate the hotfix back through production → staging → main
|
|
62
|
+
pnpm test # Run tests
|
|
63
|
+
pnpm typecheck # TypeScript type checking
|
|
61
64
|
```
|
|
62
65
|
|
|
63
66
|
### Config Files
|
|
@@ -97,7 +97,7 @@ Commit messages are validated by [Commitlint](../tools/commitlint.md) through gi
|
|
|
97
97
|
|
|
98
98
|
## Changelog generation
|
|
99
99
|
|
|
100
|
-
Changelogs are generated
|
|
100
|
+
Changelogs are generated by [commit-and-tag-version](../tools/releases.md) from conventional commit subjects. `ship-production` runs `pnpm release` at ship time, which reads commits since the last tag and writes them into `CHANGELOG.md`. The commit subject is what users read, so write it for that reader from the start.
|
|
101
101
|
|
|
102
102
|
## Related
|
|
103
103
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
|
|
3
3
|
title: "Release Workflow"
|
|
4
|
-
description: "Branch-based release workflow for Regardio packages — main → staging → production, driven by
|
|
4
|
+
description: "Branch-based release workflow for Regardio packages — main → staging → production, driven by commit-and-tag-version."
|
|
5
5
|
publishedAt: 2026-04-17
|
|
6
6
|
language: "en"
|
|
7
7
|
status: "published"
|
|
@@ -11,7 +11,7 @@ area: "dev"
|
|
|
11
11
|
|
|
12
12
|
# Release Workflow
|
|
13
13
|
|
|
14
|
-
Branch-based release workflow for Regardio packages. `main` → `staging` → `production`.
|
|
14
|
+
Branch-based release workflow for Regardio packages. `main` → `staging` → `production`. `commit-and-tag-version` reads conventional commits to determine the version bump; quality gates run locally before any branch promotion. Nothing broken reaches a shared branch.
|
|
15
15
|
|
|
16
16
|
## Overview
|
|
17
17
|
|
|
@@ -21,119 +21,111 @@ Branches mirror deployment environments:
|
|
|
21
21
|
main → staging (optional) → production
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
- **`main`** — active development, always deployable.
|
|
24
|
+
- **`main`** — active development, always deployable. Version bumps happen at ship time, not per-commit.
|
|
25
25
|
- **`staging`** — optional validation environment. No versioning happens here.
|
|
26
26
|
- **`production`** — versioned, published code only.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
When `ship-production` runs, it discovers all publishable workspace packages and asks you to assign a bump type — `skip`, `patch`, `minor`, or `major` — to each one individually. Packages you skip are left untouched. For each package with a bump, it calls `pnpm --filter <package> release:<type>`, which bumps that package's version, rewrites its `CHANGELOG.md` using commits since its last scoped tag, and commits on `main`. The branches merge once after all bumps are applied. CI on `production` publishes only the packages whose version changed.
|
|
29
29
|
|
|
30
30
|
## How It Works
|
|
31
31
|
|
|
32
32
|
### Design principles
|
|
33
33
|
|
|
34
34
|
1. **Branches mirror environments.** `staging` reflects what is deployed to the staging server (when used); `production` always reflects what is published to npm. There is never ambiguity about what is running where.
|
|
35
|
-
2. **
|
|
36
|
-
3. **Version numbers are a production guarantee.** Bumps are applied only at `ship-production` time.
|
|
37
|
-
4. **Staging is optional.** You can ship directly from `main` to `production`. Use `ship-staging` when you want to test changes in a staging environment first.
|
|
38
|
-
5. **Tests are a local gate, not a CI gate.** Quality checks (`build`, `typecheck`, `test`) run on your machine before any commit is made. Broken code cannot enter the repository.
|
|
35
|
+
2. **You choose the bump per package at ship time.** When running `ship-production` or `ship-hotfix finish`, every publishable package is listed and you assign it `skip`, `patch`, `minor`, or `major`. Packages you skip are untouched. The conventional commits in the log inform each choice; the decisions are always explicit.
|
|
36
|
+
3. **Version numbers are a production guarantee.** Bumps are applied only at `ship-production` time. Every version tag in git and every release on npm corresponds to code that has been validated and shipped.
|
|
37
|
+
4. **Staging is optional.** You can ship directly from `main` to `production`. Use `ship-staging` when you want to test changes in a staging environment first.
|
|
38
|
+
5. **Tests are a local gate, not a CI gate.** Quality checks (`build`, `typecheck`, `test`) run on your machine before any commit is made. Broken code cannot enter the repository.
|
|
39
39
|
6. **You always land back on `main`.** Every command returns you to `main` when it finishes.
|
|
40
40
|
|
|
41
41
|
### Full flow diagram
|
|
42
42
|
|
|
43
43
|
```text
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
hotfix/fix-name ────┤ bumps + CHANGELOG.md ├──► production → staging → main
|
|
87
|
-
│ merge to production │
|
|
88
|
-
│ propagate to staging │
|
|
89
|
-
│ propagate to main │
|
|
90
|
-
└──────────────────────────┘
|
|
44
|
+
ship-staging (OPTIONAL)
|
|
45
|
+
┌──────────────────────────┐
|
|
46
|
+
main ───────────┤ quality checks pass ├──► staging (pushed)
|
|
47
|
+
│ ff-merge main → staging │
|
|
48
|
+
└──────────────────────────┘
|
|
49
|
+
│
|
|
50
|
+
(validated in staging)
|
|
51
|
+
│
|
|
52
|
+
▼
|
|
53
|
+
ship-production
|
|
54
|
+
┌──────────────────────────┐
|
|
55
|
+
│ quality checks on main │
|
|
56
|
+
│ pnpm release │
|
|
57
|
+
main ───────────┤ bumps version + ├──► production
|
|
58
|
+
│ rewrites CHANGELOG.md │
|
|
59
|
+
│ ff-merge main → prod │
|
|
60
|
+
│ ff-merge prod → staging │
|
|
61
|
+
│ push --follow-tags main │
|
|
62
|
+
└──────────────────────────┘
|
|
63
|
+
│
|
|
64
|
+
(CI: pnpm -r publish → npm)
|
|
65
|
+
▼
|
|
66
|
+
production
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
ship-hotfix start fix-name
|
|
70
|
+
┌──────────────────────────┐
|
|
71
|
+
production ─────┤ create hotfix/fix-name ├──► hotfix/fix-name
|
|
72
|
+
└──────────────────────────┘
|
|
73
|
+
│
|
|
74
|
+
(author fixes with conventional commits)
|
|
75
|
+
│
|
|
76
|
+
ship-hotfix finish
|
|
77
|
+
┌──────────────────────────┐
|
|
78
|
+
│ quality checks │
|
|
79
|
+
│ pnpm release │
|
|
80
|
+
hotfix/fix-name ┤ bumps version + ├──► production → staging → main
|
|
81
|
+
│ rewrites CHANGELOG.md │
|
|
82
|
+
│ merge to production │
|
|
83
|
+
│ propagate to staging │
|
|
84
|
+
│ propagate to main │
|
|
85
|
+
└──────────────────────────┘
|
|
91
86
|
```
|
|
92
87
|
|
|
93
88
|
### What each branch represents at any point in time
|
|
94
89
|
|
|
95
90
|
| Branch | Contains | Version bumped? |
|
|
96
91
|
|--------|----------|-----------------|
|
|
97
|
-
| `main` | All committed, tested work
|
|
92
|
+
| `main` | All committed, tested work | Only after `ship-production` / `ship-hotfix finish` |
|
|
98
93
|
| `staging` | Synced from `production` after each ship, or from `main` via `ship-staging` | After a ship propagates |
|
|
99
94
|
| `production` | Only shipped, versioned releases | Yes — always |
|
|
100
95
|
|
|
101
96
|
### CI role
|
|
102
97
|
|
|
103
|
-
CI is intentionally minimal.
|
|
98
|
+
CI is intentionally minimal. On push to `production` it:
|
|
104
99
|
|
|
105
100
|
1. Installs dependencies and builds
|
|
106
|
-
2. Runs `pnpm
|
|
107
|
-
3.
|
|
101
|
+
2. Runs `pnpm -r publish --access public --no-git-checks` — publishes every workspace package whose current version is not yet on npm, skipping `private: true` packages
|
|
102
|
+
3. Tags are already present (pushed by `ship-production` via `--follow-tags`)
|
|
108
103
|
|
|
109
104
|
## Commands
|
|
110
105
|
|
|
111
106
|
| Command | Usage | Purpose |
|
|
112
107
|
|---------|-------|---------|
|
|
113
|
-
| `pnpm
|
|
108
|
+
| `pnpm release` | auto | Bump version from conventional commits, update CHANGELOG.md, commit |
|
|
109
|
+
| `pnpm release:patch` | explicit | Force a patch bump |
|
|
110
|
+
| `pnpm release:minor` | explicit | Force a minor bump |
|
|
111
|
+
| `pnpm release:major` | explicit | Force a major bump |
|
|
114
112
|
| `ship-staging` | `ship-staging` | (Optional) Deploy changes to staging for testing |
|
|
115
|
-
| `ship-production` | `ship-production` |
|
|
113
|
+
| `ship-production` | `ship-production` | Bump version, merge main → production, trigger publish |
|
|
116
114
|
| `ship-hotfix start <name>` | `ship-hotfix start <name>` | Create a hotfix branch from production |
|
|
117
|
-
| `ship-hotfix finish` | `ship-hotfix finish` |
|
|
118
|
-
|
|
119
|
-
Bump types (`patch` / `minor` / `major`) are no longer passed on the command line — they come from the changeset files.
|
|
115
|
+
| `ship-hotfix finish` | `ship-hotfix finish` | Bump version, propagate hotfix through production → staging → main |
|
|
120
116
|
|
|
121
117
|
## Typical Release Flow
|
|
122
118
|
|
|
123
|
-
### 1.
|
|
119
|
+
### 1. Develop with conventional commits
|
|
124
120
|
|
|
125
|
-
On `main
|
|
121
|
+
On `main`, use conventional commits so the bump type is inferred automatically:
|
|
126
122
|
|
|
127
123
|
```bash
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
git commit -m "feat: ..."
|
|
132
|
-
git push
|
|
124
|
+
feat: add user authentication # → minor bump
|
|
125
|
+
fix: resolve login redirect loop # → patch bump
|
|
126
|
+
feat!: redesign authentication API # → major bump
|
|
133
127
|
```
|
|
134
128
|
|
|
135
|
-
A file like `.changeset/lively-otters-hop.md` is committed with the change.
|
|
136
|
-
|
|
137
129
|
### 2. Ship to production
|
|
138
130
|
|
|
139
131
|
```bash
|
|
@@ -144,16 +136,17 @@ This will:
|
|
|
144
136
|
|
|
145
137
|
1. Guard: must be on `main`, working tree clean
|
|
146
138
|
2. Fetch and verify `staging` + `production` branches exist
|
|
147
|
-
3. Show commits to be shipped
|
|
148
|
-
4.
|
|
149
|
-
5.
|
|
150
|
-
6.
|
|
151
|
-
7.
|
|
139
|
+
3. Show commits to be shipped
|
|
140
|
+
4. For each publishable package: choose `skip / patch / minor / major`
|
|
141
|
+
5. Confirm the planned bumps — abort if declined or all skipped
|
|
142
|
+
6. Run full quality suite on `main` — aborts on failure
|
|
143
|
+
7. For each non-skipped package: run `pnpm --filter <pkg> release:<type>` — bumps version, rewrites `CHANGELOG.md`, commits
|
|
152
144
|
8. Fast-forward merge `main` into `production` and push
|
|
153
145
|
9. Sync `staging` with `production`
|
|
154
|
-
10.
|
|
146
|
+
10. Push `main` with `--follow-tags` to push all new version tags
|
|
147
|
+
11. Return to `main`
|
|
155
148
|
|
|
156
|
-
CI on `production` runs `pnpm
|
|
149
|
+
CI on `production` runs `pnpm -r publish` to push changed packages to npm.
|
|
157
150
|
|
|
158
151
|
### Option: Test in staging first
|
|
159
152
|
|
|
@@ -169,32 +162,26 @@ For urgent fixes that must go directly to production:
|
|
|
169
162
|
|
|
170
163
|
```bash
|
|
171
164
|
pnpm ship:hotfix start fix-auth-bug
|
|
172
|
-
# apply your fix
|
|
173
|
-
pnpm changeset # describe the fix and the bump
|
|
165
|
+
# apply your fix with conventional commits
|
|
174
166
|
git add . && git commit -m "fix: ..."
|
|
175
167
|
pnpm ship:hotfix finish
|
|
176
168
|
```
|
|
177
169
|
|
|
178
|
-
`finish`
|
|
170
|
+
`finish` asks you to assign a bump type (`skip`, `patch`, `minor`, or `major`) to each publishable package, runs `pnpm --filter <pkg> release:<type>` for each non-skipped one to bump versions and update `CHANGELOG.md`, then merges `hotfix → production → staging → main` and deletes the hotfix branch. CI publishes from `production`.
|
|
179
171
|
|
|
180
172
|
## Adoption
|
|
181
173
|
|
|
182
174
|
Install `@regardio/dev` and:
|
|
183
175
|
|
|
184
|
-
1. **
|
|
185
|
-
|
|
186
|
-
```bash
|
|
187
|
-
cp -r node_modules/@regardio/dev/templates/changeset .changeset
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
2. **Add the scripts to `package.json`**:
|
|
176
|
+
1. **Add the scripts to `package.json`**:
|
|
191
177
|
|
|
192
178
|
```json
|
|
193
179
|
{
|
|
194
180
|
"scripts": {
|
|
195
|
-
"
|
|
196
|
-
"
|
|
197
|
-
"
|
|
181
|
+
"release": "commit-and-tag-version",
|
|
182
|
+
"release:major": "commit-and-tag-version --release-as major",
|
|
183
|
+
"release:minor": "commit-and-tag-version --release-as minor",
|
|
184
|
+
"release:patch": "commit-and-tag-version --release-as patch",
|
|
198
185
|
"ship:hotfix": "ship-hotfix",
|
|
199
186
|
"ship:production": "ship-production",
|
|
200
187
|
"ship:staging": "ship-staging"
|
|
@@ -202,6 +189,15 @@ Install `@regardio/dev` and:
|
|
|
202
189
|
}
|
|
203
190
|
```
|
|
204
191
|
|
|
192
|
+
2. **Add a `.versionrc.json` to each publishable package** with a scoped `tagPrefix` so tags and changelogs stay isolated per package:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
cp node_modules/@regardio/dev/templates/versionrc/.versionrc.json packages/my-pkg/.versionrc.json
|
|
196
|
+
# then set "tagPrefix": "@my-scope/my-pkg@v" inside that file
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
For a single-package repo, put `.versionrc.json` at the root instead.
|
|
200
|
+
|
|
205
201
|
3. **Create the branches**:
|
|
206
202
|
|
|
207
203
|
```bash
|
|
@@ -210,7 +206,7 @@ Install `@regardio/dev` and:
|
|
|
210
206
|
git checkout main
|
|
211
207
|
```
|
|
212
208
|
|
|
213
|
-
4. **Copy the release workflow** for your forge
|
|
209
|
+
4. **Copy the release workflow** for your forge:
|
|
214
210
|
|
|
215
211
|
```bash
|
|
216
212
|
# GitHub
|
|
@@ -222,8 +218,6 @@ Install `@regardio/dev` and:
|
|
|
222
218
|
cp node_modules/@regardio/dev/templates/github/release.yml .forgejo/workflows/release.yml
|
|
223
219
|
```
|
|
224
220
|
|
|
225
|
-
For other CI systems, treat the template as a reference: the workflow installs dependencies, builds, runs `pnpm changeset publish`, and pushes tags on every push to `production`.
|
|
226
|
-
|
|
227
221
|
5. **First publish of any new package must be done locally**:
|
|
228
222
|
|
|
229
223
|
```bash
|
|
@@ -242,57 +236,7 @@ pnpm test # Must succeed
|
|
|
242
236
|
|
|
243
237
|
## Private Packages
|
|
244
238
|
|
|
245
|
-
Packages that should never be published to npm must set `"private": true` in `package.json`. `
|
|
246
|
-
|
|
247
|
-
## Workspace-Level Automation
|
|
248
|
-
|
|
249
|
-
The meta-workspace (`workspace/`) provides scripts that operate across all repos at once. Run these from the `workspace/` directory.
|
|
250
|
-
|
|
251
|
-
### Daily maintenance: safe-upgrade-and-ship
|
|
252
|
-
|
|
253
|
-
After a dependency upgrade cycle, ship everything to staging in one command:
|
|
254
|
-
|
|
255
|
-
```bash
|
|
256
|
-
cd workspace
|
|
257
|
-
pnpm safe-upgrade-and-ship
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
What it does:
|
|
261
|
-
|
|
262
|
-
1. Runs `pnpm safe-upgrade` — upgrades all dependencies, runs build + lint + test + typecheck across the full workspace. Aborts if anything fails.
|
|
263
|
-
2. For every repo (workspace itself, commons, ensemble, system, channels/*): checks `git status`.
|
|
264
|
-
3. If only `package.json` and/or `pnpm-lock.yaml` changed: commits with `chore: upgrade dependencies`, pushes `main` to origin, fast-forward merges `main → staging`, pushes `staging`, returns to `main`.
|
|
265
|
-
4. If unexpected files are uncommitted: skips that repo and reports it.
|
|
266
|
-
|
|
267
|
-
No further interaction needed — husky pre-commit hooks run on the commit step, and the full quality suite already passed in step 1.
|
|
268
|
-
|
|
269
|
-
### Selective staging ship
|
|
270
|
-
|
|
271
|
-
If changes are already committed and ready:
|
|
272
|
-
|
|
273
|
-
```bash
|
|
274
|
-
cd workspace
|
|
275
|
-
pnpm ship:staging
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
Delegates to each repo's `ship:staging` (which re-runs quality checks per repo). Workspace itself is handled directly to avoid recursion.
|
|
279
|
-
|
|
280
|
-
### Production ship
|
|
281
|
-
|
|
282
|
-
```bash
|
|
283
|
-
cd workspace
|
|
284
|
-
pnpm ship:production
|
|
285
|
-
```
|
|
286
|
-
|
|
287
|
-
Calls each sub-repo's `ship:production` in sequence, then promotes workspace itself (`main → production → staging`). For repos with Changesets (commons), this triggers the full version-bump flow. For app repos without Changesets (ensemble, system, channels), it promotes the branch without versioning.
|
|
288
|
-
|
|
289
|
-
### When to use each command
|
|
290
|
-
|
|
291
|
-
| Command | When |
|
|
292
|
-
|---------|------|
|
|
293
|
-
| `pnpm safe-upgrade-and-ship` | Daily/weekly dependency maintenance — upgrade all, verify all, ship all to staging |
|
|
294
|
-
| `pnpm ship:staging` | Changes are already committed; just push everything to staging |
|
|
295
|
-
| `pnpm ship:production` | Ready to go to production across all repos |
|
|
239
|
+
Packages that should never be published to npm must set `"private": true` in `package.json`. `pnpm -r publish` skips them automatically. The git flow (`ship-staging`, `ship-production`, `ship-hotfix`) works identically — version bumps and branch promotion continue as normal; only the npm publish step is skipped.
|
|
296
240
|
|
|
297
241
|
## Related
|
|
298
242
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "@regardio/dev",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Regardio development presets: biome, typescript, commitlint, markdownlint, vitest, playwright, sqlfluff, husky, and GitLab-flow ship tooling",
|
|
7
7
|
"keywords": [
|
|
@@ -66,7 +66,8 @@
|
|
|
66
66
|
"src/markdownlint",
|
|
67
67
|
"src/typescript",
|
|
68
68
|
"docs",
|
|
69
|
-
"templates"
|
|
69
|
+
"templates",
|
|
70
|
+
"pnpm-lock.yaml"
|
|
70
71
|
],
|
|
71
72
|
"devDependencies": {
|
|
72
73
|
"@total-typescript/ts-reset": "0.6.1",
|
|
@@ -77,13 +78,12 @@
|
|
|
77
78
|
},
|
|
78
79
|
"peerDependencies": {
|
|
79
80
|
"@biomejs/biome": ">=2",
|
|
80
|
-
"@changesets/changelog-git": ">=0.2",
|
|
81
|
-
"@changesets/cli": ">=2",
|
|
82
81
|
"@commitlint/cli": ">=20",
|
|
83
82
|
"@commitlint/config-conventional": ">=20",
|
|
84
83
|
"@playwright/test": ">=1",
|
|
85
84
|
"@testing-library/jest-dom": ">=6",
|
|
86
85
|
"@testing-library/react": ">=16",
|
|
86
|
+
"commit-and-tag-version": ">=12",
|
|
87
87
|
"husky": ">=9",
|
|
88
88
|
"jsdom": ">=29",
|
|
89
89
|
"markdownlint-cli2": ">=0.22",
|
|
@@ -98,6 +98,10 @@
|
|
|
98
98
|
"clean": "rimraf .turbo dist",
|
|
99
99
|
"dev": "tsdown --watch",
|
|
100
100
|
"fix": "run-s fix:pkg fix:md fix:biome",
|
|
101
|
+
"release": "commit-and-tag-version",
|
|
102
|
+
"release:major": "commit-and-tag-version --release-as major",
|
|
103
|
+
"release:minor": "commit-and-tag-version --release-as minor",
|
|
104
|
+
"release:patch": "commit-and-tag-version --release-as patch",
|
|
101
105
|
"fix:biome": "biome check --write --unsafe .",
|
|
102
106
|
"fix:md": "markdownlint-cli2 --config ../../.markdownlint-cli2.jsonc --fix",
|
|
103
107
|
"fix:pkg": "sort-package-json",
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
# Copy this file to .github/workflows/release.yml
|
|
3
3
|
#
|
|
4
4
|
# Required setup:
|
|
5
|
-
# 1.
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# "
|
|
9
|
-
# "
|
|
5
|
+
# 1. Add these scripts to package.json:
|
|
6
|
+
# "release": "commit-and-tag-version",
|
|
7
|
+
# "release:major": "commit-and-tag-version --release-as major",
|
|
8
|
+
# "release:minor": "commit-and-tag-version --release-as minor",
|
|
9
|
+
# "release:patch": "commit-and-tag-version --release-as patch",
|
|
10
10
|
# "ship:staging": "ship-staging",
|
|
11
11
|
# "ship:production": "ship-production",
|
|
12
12
|
# "ship:hotfix": "ship-hotfix"
|
|
13
|
+
# 2. Copy .versionrc.json from node_modules/@regardio/dev/templates/versionrc/.versionrc.json
|
|
13
14
|
# 3. Create the branches:
|
|
14
15
|
# git checkout -b staging && git push -u origin staging
|
|
15
16
|
# git checkout -b production && git push -u origin production
|
|
@@ -17,10 +18,9 @@
|
|
|
17
18
|
# must be done locally (`npm publish --access public`).
|
|
18
19
|
#
|
|
19
20
|
# Usage:
|
|
20
|
-
# -
|
|
21
|
-
# - `pnpm ship:
|
|
22
|
-
#
|
|
23
|
-
# to production. This workflow then publishes to npm.
|
|
21
|
+
# - `pnpm ship:staging` deploys to staging for validation (optional)
|
|
22
|
+
# - `pnpm ship:production` runs commit-and-tag-version locally, bumps the version,
|
|
23
|
+
# merges to production. This workflow then publishes to npm.
|
|
24
24
|
|
|
25
25
|
name: Release
|
|
26
26
|
|
|
@@ -62,16 +62,7 @@ jobs:
|
|
|
62
62
|
run: pnpm -r build
|
|
63
63
|
|
|
64
64
|
- name: Publish changed public packages
|
|
65
|
-
|
|
66
|
-
# - walks the workspace topologically
|
|
67
|
-
# - replaces `workspace:*` with real versions
|
|
68
|
-
# - skips packages where the current version already exists on npm
|
|
69
|
-
# - skips packages marked `"private": true`
|
|
70
|
-
# - creates git tags like `@scope/pkg@1.2.3` for each published package
|
|
71
|
-
run: pnpm changeset publish
|
|
65
|
+
run: pnpm -r publish --access public --no-git-checks
|
|
72
66
|
env:
|
|
73
67
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
74
68
|
NPM_CONFIG_PROVENANCE: "true"
|
|
75
|
-
|
|
76
|
-
- name: Push tags
|
|
77
|
-
run: git push --tags
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"commitAll": false,
|
|
3
|
+
"sign": false,
|
|
4
|
+
"tagPrefix": "v",
|
|
5
|
+
"types": [
|
|
6
|
+
{ "section": "Features", "type": "feat" },
|
|
7
|
+
{ "section": "Bug Fixes", "type": "fix" },
|
|
8
|
+
{ "section": "Performance", "type": "perf" },
|
|
9
|
+
{ "section": "Refactoring", "type": "refactor" },
|
|
10
|
+
{ "hidden": false, "section": "Chores", "type": "chore" },
|
|
11
|
+
{ "hidden": true, "type": "docs" },
|
|
12
|
+
{ "hidden": true, "type": "style" },
|
|
13
|
+
{ "hidden": true, "type": "test" },
|
|
14
|
+
{ "hidden": true, "type": "ci" }
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { execFileSync, execSync } from "node:child_process";
|
|
3
|
-
import { closeSync, openSync, readSync } from "node:fs";
|
|
4
|
-
//#region src/bin/ship/utils.ts
|
|
5
|
-
/**
|
|
6
|
-
* Shared utilities for ship-staging, ship-production, and ship-hotfix.
|
|
7
|
-
*
|
|
8
|
-
* Git commands use execFileSync (not a shell string) so user-provided
|
|
9
|
-
* strings such as commit messages are never interpolated by the shell.
|
|
10
|
-
* pnpm script invocations use execSync via shell since script names are
|
|
11
|
-
* developer-controlled and pnpm itself is resolved through PATH.
|
|
12
|
-
*/
|
|
13
|
-
const git = (...args) => {
|
|
14
|
-
console.log(`$ git ${args.join(" ")}`);
|
|
15
|
-
execFileSync("git", args, { stdio: "inherit" });
|
|
16
|
-
};
|
|
17
|
-
const gitRead = (...args) => execFileSync("git", args, { encoding: "utf-8" }).trim();
|
|
18
|
-
const runScript = (script) => {
|
|
19
|
-
console.log(`$ pnpm ${script}`);
|
|
20
|
-
execSync(`pnpm ${script}`, { stdio: "inherit" });
|
|
21
|
-
};
|
|
22
|
-
const runQualityChecks = () => {
|
|
23
|
-
runScript("build");
|
|
24
|
-
runScript("typecheck");
|
|
25
|
-
runScript("test");
|
|
26
|
-
};
|
|
27
|
-
const branchExists = (name) => gitRead("branch", "--list", name) !== "" || gitRead("branch", "--list", "--remotes", `origin/${name}`) !== "";
|
|
28
|
-
const confirm = (prompt, ttyPath = "/dev/tty") => {
|
|
29
|
-
process.stdout.write(`${prompt} (y/N) `);
|
|
30
|
-
const buf = Buffer.alloc(1024);
|
|
31
|
-
let fd;
|
|
32
|
-
let shouldClose = false;
|
|
33
|
-
try {
|
|
34
|
-
fd = openSync(ttyPath, "r");
|
|
35
|
-
shouldClose = true;
|
|
36
|
-
} catch {
|
|
37
|
-
fd = process.stdin.fd;
|
|
38
|
-
}
|
|
39
|
-
const bytesRead = readSync(fd, buf, 0, buf.length, null);
|
|
40
|
-
if (shouldClose) closeSync(fd);
|
|
41
|
-
const answer = buf.slice(0, bytesRead).toString().trim();
|
|
42
|
-
return answer === "y" || answer === "Y";
|
|
43
|
-
};
|
|
44
|
-
//#endregion
|
|
45
|
-
export { runQualityChecks as a, gitRead as i, confirm as n, runScript as o, git as r, branchExists as t };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Changesets
|
|
2
|
-
|
|
3
|
-
Pending version bumps live here as small Markdown files. Add one with `pnpm changeset` whenever you make a version-worthy change.
|
|
4
|
-
|
|
5
|
-
## How it fits the GitLab flow
|
|
6
|
-
|
|
7
|
-
- On `main`, authors run `pnpm changeset` alongside their change to describe the bump.
|
|
8
|
-
- `ship-staging` deploys to staging without touching versions.
|
|
9
|
-
- `ship-production` runs quality checks, consumes pending changesets (bumping versions and updating each package's `CHANGELOG.md`), commits the bumps on `main`, and merges to `production`.
|
|
10
|
-
- CI on `production` runs `changeset publish` to push the new versions to npm.
|
|
11
|
-
|
|
12
|
-
## Skipping a release
|
|
13
|
-
|
|
14
|
-
If a commit is tooling-only and should not trigger a release, don't add a changeset.
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json",
|
|
3
|
-
"access": "public",
|
|
4
|
-
"baseBranch": "main",
|
|
5
|
-
"changelog": "@changesets/changelog-git",
|
|
6
|
-
"commit": false,
|
|
7
|
-
"fixed": [],
|
|
8
|
-
"ignore": [],
|
|
9
|
-
"linked": [],
|
|
10
|
-
"updateInternalDependencies": "patch"
|
|
11
|
-
}
|