@varlock/bumpy 0.0.1 → 1.0.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.
Files changed (44) hide show
  1. package/.claude-plugin/plugin.json +2 -2
  2. package/dist/add-CgCjs4d-.mjs +313 -0
  3. package/dist/{ai-B8ZL2x8z.mjs → ai-sMYUf3lP.mjs} +22 -5
  4. package/dist/{apply-release-plan-DtU3rVyL.mjs → apply-release-plan-CczGWJTk.mjs} +34 -25
  5. package/dist/bump-file-CCLXMLA8.mjs +143 -0
  6. package/dist/changelog-github-Cd8uJHZI.mjs +195 -0
  7. package/dist/{check-CkRubvuk.mjs → check-BOoxpWqk.mjs} +11 -17
  8. package/dist/ci-Bhx--Tj6.mjs +629 -0
  9. package/dist/ci-setup-qz4Y3v7T.mjs +211 -0
  10. package/dist/clack-CDRCHrC-.mjs +1216 -0
  11. package/dist/cli.mjs +37 -31
  12. package/dist/{config-CJ2orhTL.mjs → config-XZWUL3ma.mjs} +28 -23
  13. package/dist/fs-DYR2XuFE.mjs +81 -0
  14. package/dist/{generate-oOFD9ABC.mjs → generate-gYKTpvex.mjs} +31 -12
  15. package/dist/git-CGHVXXKw.mjs +78 -0
  16. package/dist/index.d.mts +63 -37
  17. package/dist/index.mjs +9 -9
  18. package/dist/{init-Blw2GfC_.mjs → init-lA9E5pEc.mjs} +3 -3
  19. package/dist/logger-C2dEe5Su.mjs +135 -0
  20. package/dist/{migrate-DvOrXSw0.mjs → migrate-DmOYgmfD.mjs} +23 -16
  21. package/dist/{names-C-u50ofE.mjs → names-9VubBmL0.mjs} +3 -2
  22. package/dist/package-manager-VCe10bjc.mjs +80 -0
  23. package/dist/{publish-DZ3m7qkX.mjs → publish-Cun-zQ1b.mjs} +90 -35
  24. package/dist/{publish-pipeline-1M5GmbdP.mjs → publish-pipeline-BwBuKCIk.mjs} +56 -65
  25. package/dist/release-plan-Bi5QNSEo.mjs +264 -0
  26. package/dist/{semver-DWO6NFKN.mjs → semver-DfQyVLM_.mjs} +14 -4
  27. package/dist/shell-Dj7JRD_q.mjs +92 -0
  28. package/dist/{status-DRpq_Mha.mjs → status-CfE63ti5.mjs} +27 -23
  29. package/dist/version-19vVt9dv.mjs +124 -0
  30. package/dist/workspace-C5ULTyUN.mjs +107 -0
  31. package/package.json +16 -2
  32. package/skills/add-change/SKILL.md +8 -12
  33. package/dist/add-u5V9V3L7.mjs +0 -131
  34. package/dist/changelog-github-n-3zV1p9.mjs +0 -59
  35. package/dist/changeset-ClCYsChu.mjs +0 -75
  36. package/dist/ci-8KWWhjXl.mjs +0 -224
  37. package/dist/fs-DbNNEyzq.mjs +0 -51
  38. package/dist/logger-ZqggsyGZ.mjs +0 -176
  39. package/dist/prompt-BP8toAOI.mjs +0 -46
  40. package/dist/release-plan-CFnutSHD.mjs +0 -173
  41. package/dist/shell-DPlltpzb.mjs +0 -44
  42. package/dist/version-CJwf8XIA.mjs +0 -81
  43. package/dist/workspace-mVjawG8g.mjs +0 -183
  44. /package/dist/{dep-graph-DiLeAhl9.mjs → dep-graph-E-9-eQ2J.mjs} +0 -0
@@ -0,0 +1,211 @@
1
+ import { n as log, o as __toESM, r as require_picocolors } from "./logger-C2dEe5Su.mjs";
2
+ import { t as detectPackageManager } from "./package-manager-VCe10bjc.mjs";
3
+ import { o as tryRunArgs } from "./shell-Dj7JRD_q.mjs";
4
+ import { a as fe, c as ot, i as _t, n as O, o as gt, r as Ot, s as mt, t as unwrap, u as wt } from "./clack-CDRCHrC-.mjs";
5
+ //#region src/commands/ci-setup.ts
6
+ var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
7
+ const PAT_PERMISSIONS = [
8
+ "contents: read & write",
9
+ "pull requests: read & write",
10
+ "metadata: read (selected automatically)"
11
+ ];
12
+ async function ciSetupCommand(rootDir) {
13
+ mt(import_picocolors.default.bgCyan(import_picocolors.default.black(" bumpy ci setup ")));
14
+ const repo = detectRepo(rootDir);
15
+ if (!repo) {
16
+ log.error("Could not detect a GitHub repository.\n This command currently only supports GitHub-hosted repos.\n Make sure you have a GitHub remote (git remote -v).");
17
+ process.exit(1);
18
+ }
19
+ const pm = await detectPackageManager(rootDir);
20
+ O.info(`Detected repository: ${import_picocolors.default.cyan(repo)}`);
21
+ O.info("");
22
+ O.info("To trigger CI checks on the version PR, bumpy needs a token\nthat bypasses GitHub's default anti-recursion guard.\nYou can use a fine-grained PAT or a GitHub App installation token.");
23
+ if (unwrap(await _t({
24
+ message: "How would you like to authenticate?",
25
+ options: [{
26
+ label: "Fine-grained Personal Access Token (PAT)",
27
+ value: "pat",
28
+ hint: "recommended — quick and simple"
29
+ }, {
30
+ label: "GitHub App installation token",
31
+ value: "app",
32
+ hint: "advanced — not tied to a personal account"
33
+ }]
34
+ })) === "pat") await setupPat(rootDir, repo, pm);
35
+ else await setupApp(rootDir, repo, pm);
36
+ }
37
+ async function setupPat(rootDir, repo, pm) {
38
+ const patUrl = "https://github.com/settings/personal-access-tokens/new";
39
+ O.info("");
40
+ wt([
41
+ `1. Open: ${import_picocolors.default.cyan(patUrl)}`,
42
+ "",
43
+ `2. Set a name, e.g. ${import_picocolors.default.dim("\"bumpy-ci\"")}`,
44
+ "",
45
+ `3. Under ${import_picocolors.default.bold("Resource owner")}, select the org or account that owns ${import_picocolors.default.cyan(repo)}`,
46
+ "",
47
+ `4. Set ${import_picocolors.default.bold("Expiration")} — choose a longer duration to avoid frequent rotation`,
48
+ ` (you'll need to regenerate and update the secret when it expires)`,
49
+ "",
50
+ `5. Under ${import_picocolors.default.bold("Repository access")}, select ${import_picocolors.default.bold("\"Only select repositories\"")}`,
51
+ ` and choose ${import_picocolors.default.cyan(repo)}`,
52
+ "",
53
+ `6. Under ${import_picocolors.default.bold("Permissions → Repository permissions")}, grant:`,
54
+ ...PAT_PERMISSIONS.map((perm) => ` • ${import_picocolors.default.bold(perm)}`),
55
+ "",
56
+ "7. Click \"Generate token\" and copy the value",
57
+ "",
58
+ import_picocolors.default.dim("Note: if the resource owner is an org, an admin may need to approve"),
59
+ import_picocolors.default.dim("the token request before it can be used."),
60
+ "",
61
+ import_picocolors.default.dim("Tip: enable branch protection rules on your main branch to prevent"),
62
+ import_picocolors.default.dim("direct pushes — the PAT will only be used to push the version branch.")
63
+ ].join("\n"), "Create a fine-grained PAT");
64
+ if (unwrap(await ot({ message: "Open the token creation page in your browser?" }))) openBrowser(patUrl);
65
+ await storeSecret(rootDir, repo, unwrap(await Ot({
66
+ message: "Paste your token:",
67
+ placeholder: "github_pat_...",
68
+ validate: (value) => {
69
+ if (!value?.trim()) return "Token is required";
70
+ if (!value?.startsWith("github_pat_")) return "Expected a fine-grained PAT (starts with github_pat_)";
71
+ }
72
+ })), pm);
73
+ }
74
+ async function setupApp(rootDir, repo, pm) {
75
+ const owner = repo.split("/")[0];
76
+ const appUrl = `https://github.com/organizations/${owner}/settings/apps/new`;
77
+ const createUrl = unwrap(await ot({
78
+ message: `Is ${import_picocolors.default.cyan(owner)} a GitHub organization?`,
79
+ initialValue: true
80
+ })) ? appUrl : `https://github.com/settings/apps/new`;
81
+ O.info("");
82
+ wt([
83
+ "If you already have a GitHub App, skip to step 2.",
84
+ "",
85
+ import_picocolors.default.bold("Step 1: Create a GitHub App"),
86
+ "",
87
+ `1. Open: ${import_picocolors.default.cyan(createUrl)}`,
88
+ `2. Set the name, e.g. ${import_picocolors.default.dim(`"${owner}-bumpy-ci"`)}`,
89
+ "3. Uncheck \"Active\" under Webhooks (not needed)",
90
+ "4. Under Permissions → Repository permissions, grant:",
91
+ ...PAT_PERMISSIONS.map((perm) => ` • ${import_picocolors.default.bold(perm)}`),
92
+ "5. Under \"Where can this app be installed?\" select \"Only on this account\"",
93
+ "6. Click \"Create GitHub App\"",
94
+ "7. Note the App ID shown on the settings page",
95
+ "8. Generate a private key and download the .pem file",
96
+ "",
97
+ import_picocolors.default.bold("Step 2: Install the App"),
98
+ "",
99
+ `Install the app on ${import_picocolors.default.cyan(repo)} from the app's "Install App" tab.`,
100
+ "",
101
+ import_picocolors.default.bold("Step 3: Add secrets"),
102
+ "",
103
+ "You'll need to add two repository secrets:",
104
+ ` • ${import_picocolors.default.bold("BUMPY_APP_ID")} — the App ID`,
105
+ ` • ${import_picocolors.default.bold("BUMPY_APP_PRIVATE_KEY")} — contents of the .pem file`
106
+ ].join("\n"), "GitHub App setup");
107
+ if (unwrap(await ot({ message: "Open the app creation page in your browser?" }))) openBrowser(createUrl);
108
+ if (unwrap(await ot({ message: "Have you added the BUMPY_APP_ID and BUMPY_APP_PRIVATE_KEY secrets?" }))) printAppWorkflowSnippet(pm);
109
+ else {
110
+ O.info("You can add them later. Once ready, update your release workflow:");
111
+ printAppWorkflowSnippet(pm);
112
+ }
113
+ gt(import_picocolors.default.green("GitHub App setup complete!"));
114
+ }
115
+ async function storeSecret(rootDir, repo, token, pm) {
116
+ if (!tryRunArgs(["gh", "--version"])) {
117
+ O.warn("`gh` CLI not found — you'll need to add the secret manually.");
118
+ wt(`Go to: https://github.com/${repo}/settings/secrets/actions/new\nName: ${import_picocolors.default.bold("BUMPY_GH_TOKEN")}\nValue: (the token you just created)`, "Add repository secret manually");
119
+ printPatWorkflowSnippet(pm);
120
+ gt(import_picocolors.default.green("Setup complete!"));
121
+ return;
122
+ }
123
+ const isReplacing = tryRunArgs([
124
+ "gh",
125
+ "secret",
126
+ "list",
127
+ "--repo",
128
+ repo
129
+ ], { cwd: rootDir })?.includes("BUMPY_GH_TOKEN") ?? false;
130
+ const spin = fe();
131
+ spin.start(isReplacing ? "Replacing BUMPY_GH_TOKEN repository secret..." : "Storing BUMPY_GH_TOKEN as a repository secret...");
132
+ try {
133
+ tryRunArgs([
134
+ "gh",
135
+ "secret",
136
+ "set",
137
+ "BUMPY_GH_TOKEN",
138
+ "--repo",
139
+ repo
140
+ ], {
141
+ cwd: rootDir,
142
+ input: token
143
+ });
144
+ spin.stop(isReplacing ? "Secret replaced!" : "Secret stored!");
145
+ } catch {
146
+ spin.stop("Failed to store secret");
147
+ O.warn("Could not store the secret automatically.");
148
+ wt(`Go to: https://github.com/${repo}/settings/secrets/actions/new\nName: ${import_picocolors.default.bold("BUMPY_GH_TOKEN")}\nValue: (the token you just created)`, "Add repository secret manually");
149
+ }
150
+ printPatWorkflowSnippet(pm);
151
+ gt(import_picocolors.default.green("Setup complete!"));
152
+ }
153
+ function printPatWorkflowSnippet(pm) {
154
+ const runCmd = pmxCommand(pm);
155
+ wt([
156
+ "In your release workflow, pass the token to bumpy:",
157
+ "",
158
+ import_picocolors.default.dim("# .github/workflows/release.yaml"),
159
+ import_picocolors.default.dim(`- run: ${runCmd} ci release`),
160
+ import_picocolors.default.dim(" env:"),
161
+ import_picocolors.default.dim(" GH_TOKEN: ${{ github.token }}"),
162
+ import_picocolors.default.green(" BUMPY_GH_TOKEN: ${{ secrets.BUMPY_GH_TOKEN }}")
163
+ ].join("\n"), "Update your workflow");
164
+ }
165
+ function printAppWorkflowSnippet(pm) {
166
+ const runCmd = pmxCommand(pm);
167
+ wt([
168
+ "In your release workflow, generate a token and pass it to bumpy:",
169
+ "",
170
+ import_picocolors.default.dim("# .github/workflows/release.yaml"),
171
+ import_picocolors.default.green("- uses: actions/create-github-app-token@v2"),
172
+ import_picocolors.default.green(" id: app-token"),
173
+ import_picocolors.default.green(" with:"),
174
+ import_picocolors.default.green(" app-id: ${{ secrets.BUMPY_APP_ID }}"),
175
+ import_picocolors.default.green(" private-key: ${{ secrets.BUMPY_APP_PRIVATE_KEY }}"),
176
+ "",
177
+ import_picocolors.default.dim(`- run: ${runCmd} ci release`),
178
+ import_picocolors.default.dim(" env:"),
179
+ import_picocolors.default.dim(" GH_TOKEN: ${{ github.token }}"),
180
+ import_picocolors.default.green(" BUMPY_GH_TOKEN: ${{ steps.app-token.outputs.token }}")
181
+ ].join("\n"), "Update your workflow");
182
+ }
183
+ /** Package-manager-appropriate command for running bumpy in CI workflows */
184
+ function pmxCommand(pm) {
185
+ if (pm === "bun") return "bunx @varlock/bumpy";
186
+ if (pm === "pnpm") return "pnpm exec bumpy";
187
+ if (pm === "yarn") return "yarn bumpy";
188
+ return "npx @varlock/bumpy";
189
+ }
190
+ function detectRepo(rootDir) {
191
+ if (process.env.GITHUB_REPOSITORY) return process.env.GITHUB_REPOSITORY;
192
+ const remote = tryRunArgs([
193
+ "git",
194
+ "remote",
195
+ "get-url",
196
+ "origin"
197
+ ], { cwd: rootDir });
198
+ if (!remote) return null;
199
+ const sshMatch = remote.match(/github\.com[:/](.+?)(?:\.git)?$/);
200
+ if (sshMatch) return sshMatch[1];
201
+ const httpsMatch = remote.match(/github\.com\/(.+?)(?:\.git)?$/);
202
+ if (httpsMatch) return httpsMatch[1];
203
+ return null;
204
+ }
205
+ function openBrowser(url) {
206
+ try {
207
+ tryRunArgs([process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open", url]);
208
+ } catch {}
209
+ }
210
+ //#endregion
211
+ export { ciSetupCommand };