@varlock/bumpy 0.0.0 → 0.0.2
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/.claude-plugin/plugin.json +13 -0
- package/dist/add-BjyVIUlr.mjs +175 -0
- package/dist/ai-CQhUyHAG.mjs +82 -0
- package/dist/apply-release-plan-D6TSrcwX.mjs +137 -0
- package/dist/changelog-github-Du62krXi.mjs +193 -0
- package/dist/changeset-UCZdSRDv.mjs +108 -0
- package/dist/check-jIwike9F.mjs +51 -0
- package/dist/ci-D6LQbR38.mjs +585 -0
- package/dist/ci-setup-C6FlOfW5.mjs +211 -0
- package/dist/clack-CDRCHrC-.mjs +1216 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +214 -0
- package/dist/config-BkwIEaQg.mjs +215 -0
- package/dist/dep-graph-E-9-eQ2J.mjs +64 -0
- package/dist/fs-0AtnPUUe.mjs +51 -0
- package/dist/generate-Btrsn1qi.mjs +177 -0
- package/dist/git-CGHVXXKw.mjs +78 -0
- package/dist/index.d.mts +262 -0
- package/dist/index.mjs +9 -0
- package/dist/init-B0q3wEQW.mjs +22 -0
- package/dist/js-yaml-DpZfOoD4.mjs +2031 -0
- package/dist/logger-C2dEe5Su.mjs +135 -0
- package/dist/migrate-CfQNwD0T.mjs +121 -0
- package/dist/names-Ck8cun7B.mjs +144 -0
- package/dist/package-manager-DcI5TdDE.mjs +80 -0
- package/dist/publish-D_7RqEYL.mjs +251 -0
- package/dist/publish-pipeline-ChnqW8nR.mjs +277 -0
- package/dist/release-plan-BEzwApuK.mjs +173 -0
- package/dist/semver-BTzYh8vc.mjs +1360 -0
- package/dist/shell-Dj7JRD_q.mjs +92 -0
- package/dist/status--Q8yAxQ4.mjs +106 -0
- package/dist/version-cAUkfYPx.mjs +120 -0
- package/dist/workspace-CxEKakDm.mjs +107 -0
- package/package.json +38 -6
- package/skills/add-change/SKILL.md +108 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { i as listFiles, l as writeText, o as readText, s as removeFile } from "./fs-0AtnPUUe.mjs";
|
|
2
|
+
import { r as getBumpyDir } from "./config-BkwIEaQg.mjs";
|
|
3
|
+
import { t as jsYaml } from "./js-yaml-DpZfOoD4.mjs";
|
|
4
|
+
import { o as tryRunArgs } from "./shell-Dj7JRD_q.mjs";
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
//#region src/core/changeset.ts
|
|
7
|
+
/** Read all changeset files from .bumpy/ directory, sorted by git creation order */
|
|
8
|
+
async function readChangesets(rootDir) {
|
|
9
|
+
const dir = getBumpyDir(rootDir);
|
|
10
|
+
const files = await listFiles(dir, ".md");
|
|
11
|
+
const changesets = [];
|
|
12
|
+
for (const file of files) {
|
|
13
|
+
if (file === "README.md") continue;
|
|
14
|
+
const cs = await parseChangesetFile(resolve(dir, file));
|
|
15
|
+
if (cs) changesets.push(cs);
|
|
16
|
+
}
|
|
17
|
+
const creationOrder = getChangesetCreationOrder(rootDir);
|
|
18
|
+
if (creationOrder.size > 0) changesets.sort((a, b) => {
|
|
19
|
+
return (creationOrder.get(a.id) ?? Infinity) - (creationOrder.get(b.id) ?? Infinity) || a.id.localeCompare(b.id);
|
|
20
|
+
});
|
|
21
|
+
return changesets;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Use `git log` to get the commit timestamp when each changeset file was first added.
|
|
25
|
+
* Returns a map of changeset ID → unix timestamp (seconds).
|
|
26
|
+
*/
|
|
27
|
+
function getChangesetCreationOrder(rootDir) {
|
|
28
|
+
const order = /* @__PURE__ */ new Map();
|
|
29
|
+
const result = tryRunArgs([
|
|
30
|
+
"git",
|
|
31
|
+
"log",
|
|
32
|
+
"--diff-filter=A",
|
|
33
|
+
"--format=%at",
|
|
34
|
+
"--name-only",
|
|
35
|
+
"--",
|
|
36
|
+
".bumpy/*.md"
|
|
37
|
+
], { cwd: rootDir });
|
|
38
|
+
if (!result) return order;
|
|
39
|
+
let currentTimestamp = 0;
|
|
40
|
+
for (const line of result.split("\n")) {
|
|
41
|
+
const trimmed = line.trim();
|
|
42
|
+
if (!trimmed) continue;
|
|
43
|
+
if (/^\d+$/.test(trimmed)) currentTimestamp = parseInt(trimmed, 10);
|
|
44
|
+
else if (trimmed.startsWith(".bumpy/") && trimmed.endsWith(".md")) {
|
|
45
|
+
const id = trimmed.replace(/^\.bumpy\//, "").replace(/\.md$/, "");
|
|
46
|
+
order.set(id, currentTimestamp);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return order;
|
|
50
|
+
}
|
|
51
|
+
/** Parse a single changeset markdown file */
|
|
52
|
+
async function parseChangesetFile(filePath) {
|
|
53
|
+
return parseChangeset(await readText(filePath), fileToId(filePath));
|
|
54
|
+
}
|
|
55
|
+
/** Parse changeset content (for testing) */
|
|
56
|
+
function parseChangeset(content, id) {
|
|
57
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
58
|
+
if (!match) return null;
|
|
59
|
+
const frontmatter = match[1];
|
|
60
|
+
const summary = match[2].trim();
|
|
61
|
+
const parsed = jsYaml.load(frontmatter);
|
|
62
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
63
|
+
const releases = [];
|
|
64
|
+
for (const [name, value] of Object.entries(parsed)) if (typeof value === "string") releases.push({
|
|
65
|
+
name,
|
|
66
|
+
type: value
|
|
67
|
+
});
|
|
68
|
+
else if (value && typeof value === "object") {
|
|
69
|
+
const obj = value;
|
|
70
|
+
const release = {
|
|
71
|
+
name,
|
|
72
|
+
type: obj.bump,
|
|
73
|
+
cascade: obj.cascade || {}
|
|
74
|
+
};
|
|
75
|
+
releases.push(release);
|
|
76
|
+
}
|
|
77
|
+
if (releases.length === 0) return null;
|
|
78
|
+
return {
|
|
79
|
+
id,
|
|
80
|
+
releases,
|
|
81
|
+
summary
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Write a changeset file */
|
|
85
|
+
async function writeChangeset(rootDir, filename, releases, summary) {
|
|
86
|
+
const filePath = resolve(getBumpyDir(rootDir), `${filename}.md`);
|
|
87
|
+
const frontmatter = {};
|
|
88
|
+
for (const release of releases) if ("cascade" in release && Object.keys(release.cascade).length > 0) frontmatter[release.name] = {
|
|
89
|
+
bump: release.type,
|
|
90
|
+
cascade: release.cascade
|
|
91
|
+
};
|
|
92
|
+
else frontmatter[release.name] = release.type;
|
|
93
|
+
await writeText(filePath, `---\n${jsYaml.dump(frontmatter, {
|
|
94
|
+
lineWidth: -1,
|
|
95
|
+
quotingType: "\""
|
|
96
|
+
}).trim()}\n---\n\n${summary}\n`);
|
|
97
|
+
return filePath;
|
|
98
|
+
}
|
|
99
|
+
/** Delete consumed changeset files */
|
|
100
|
+
async function deleteChangesets(rootDir, ids) {
|
|
101
|
+
const dir = getBumpyDir(rootDir);
|
|
102
|
+
for (const id of ids) await removeFile(resolve(dir, `${id}.md`));
|
|
103
|
+
}
|
|
104
|
+
function fileToId(filePath) {
|
|
105
|
+
return filePath.split("/").pop().replace(/\.md$/, "");
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { writeChangeset as i, parseChangeset as n, readChangesets as r, deleteChangesets as t };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { n as log, t as colorize } from "./logger-C2dEe5Su.mjs";
|
|
2
|
+
import { a as loadConfig } from "./config-BkwIEaQg.mjs";
|
|
3
|
+
import { n as discoverWorkspace } from "./workspace-CxEKakDm.mjs";
|
|
4
|
+
import { r as readChangesets } from "./changeset-UCZdSRDv.mjs";
|
|
5
|
+
import { n as getChangedFiles } from "./git-CGHVXXKw.mjs";
|
|
6
|
+
import { relative } from "node:path";
|
|
7
|
+
//#region src/commands/check.ts
|
|
8
|
+
/**
|
|
9
|
+
* Local check: detect which packages have changed on this branch
|
|
10
|
+
* and verify they have corresponding changesets.
|
|
11
|
+
* Designed for pre-push hooks — no GitHub API needed.
|
|
12
|
+
*/
|
|
13
|
+
async function checkCommand(rootDir) {
|
|
14
|
+
const config = await loadConfig(rootDir);
|
|
15
|
+
const { packages } = await discoverWorkspace(rootDir, config);
|
|
16
|
+
const changesets = await readChangesets(rootDir);
|
|
17
|
+
const coveredPackages = /* @__PURE__ */ new Set();
|
|
18
|
+
for (const cs of changesets) for (const release of cs.releases) coveredPackages.add(release.name);
|
|
19
|
+
const baseBranch = config.baseBranch;
|
|
20
|
+
const changedFiles = getChangedFiles(rootDir, baseBranch);
|
|
21
|
+
if (changedFiles.length === 0) {
|
|
22
|
+
log.info("No changed files detected.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const changedPackages = findChangedPackages(changedFiles, packages, rootDir);
|
|
26
|
+
if (changedPackages.length === 0) {
|
|
27
|
+
log.info("No managed packages have changed.");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const missing = changedPackages.filter((name) => !coveredPackages.has(name));
|
|
31
|
+
if (missing.length === 0) {
|
|
32
|
+
log.success(`All ${changedPackages.length} changed package(s) have changesets.`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
log.warn(`${missing.length} changed package(s) missing changesets:\n`);
|
|
36
|
+
for (const name of missing) console.log(` ${colorize(name, "yellow")}`);
|
|
37
|
+
console.log();
|
|
38
|
+
log.dim("Run `bumpy add` to create a changeset, or `bumpy add --empty` if no release is needed.");
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
/** Map changed files to the packages they belong to */
|
|
42
|
+
function findChangedPackages(changedFiles, packages, rootDir) {
|
|
43
|
+
const changed = /* @__PURE__ */ new Set();
|
|
44
|
+
for (const file of changedFiles) for (const [name, pkg] of packages) {
|
|
45
|
+
const pkgRelDir = relative(rootDir, pkg.dir);
|
|
46
|
+
if (file.startsWith(pkgRelDir + "/")) changed.add(name);
|
|
47
|
+
}
|
|
48
|
+
return [...changed];
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { checkCommand };
|