@tertium/gith 0.1.1 → 0.2.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/README.md +2 -0
- package/bin/gith.js +104 -9
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -93,6 +93,8 @@ gith stat --last-week -limit 50 # the same for last week, looking at no more
|
|
|
93
93
|
gith sync # fetch all remotes and tags, prune stale refs
|
|
94
94
|
gith open # open origin in the browser
|
|
95
95
|
gith doctor # check the repo is ready for the branch flow
|
|
96
|
+
gith changelog --dry-run # preview the CHANGELOG.md entry for package.json's version
|
|
97
|
+
gith changelog # write it as its own commit (docs(changelog): <version>); --no-commit only writes
|
|
96
98
|
|
|
97
99
|
# Help
|
|
98
100
|
gith help # full usage
|
package/bin/gith.js
CHANGED
|
@@ -31,6 +31,7 @@ var SPECS = new Map([
|
|
|
31
31
|
["pockets", "switch"],
|
|
32
32
|
["detached", "switch"],
|
|
33
33
|
["all", "switch"],
|
|
34
|
+
["no-commit", "switch"],
|
|
34
35
|
["overall", "switch"],
|
|
35
36
|
["current-year", "switch"],
|
|
36
37
|
["current-month", "switch"],
|
|
@@ -119,6 +120,10 @@ function onlyOne(flags, names) {
|
|
|
119
120
|
return present[0];
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
// src/components/changelog/changelog.ts
|
|
124
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
125
|
+
import path from "node:path";
|
|
126
|
+
|
|
122
127
|
// src/components/git/git.ts
|
|
123
128
|
import { execFileSync } from "node:child_process";
|
|
124
129
|
var verbose = false;
|
|
@@ -216,6 +221,92 @@ function act(args, options = {}) {
|
|
|
216
221
|
execFileSync("git", args, { stdio: "inherit", ...options });
|
|
217
222
|
}
|
|
218
223
|
|
|
224
|
+
// src/components/changelog/changelog.constants.ts
|
|
225
|
+
var CHANGELOG_FILE_NAME = "CHANGELOG.md";
|
|
226
|
+
var CHANGELOG_TITLE = "# Changelog";
|
|
227
|
+
var SEMVER_ONLY_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
228
|
+
|
|
229
|
+
// src/components/changelog/changelog.utils.ts
|
|
230
|
+
function filterCommitSubjects(rawLog) {
|
|
231
|
+
if (!rawLog.trim())
|
|
232
|
+
return [];
|
|
233
|
+
return rawLog.split(`
|
|
234
|
+
`).map((line) => line.trim()).filter((line) => line.length > 0 && !SEMVER_ONLY_PATTERN.test(line));
|
|
235
|
+
}
|
|
236
|
+
function buildEntry(notes) {
|
|
237
|
+
const bullets = notes.subjects.length > 0 ? notes.subjects.map((subject) => `- ${subject}`).join(`
|
|
238
|
+
`) : "- (no changes recorded)";
|
|
239
|
+
return `## ${notes.version} - ${notes.date}
|
|
240
|
+
|
|
241
|
+
${bullets}
|
|
242
|
+
`;
|
|
243
|
+
}
|
|
244
|
+
function mergeChangelogContent(existing, entry) {
|
|
245
|
+
const heading = `${CHANGELOG_TITLE}
|
|
246
|
+
`;
|
|
247
|
+
if (existing === null)
|
|
248
|
+
return `${heading}
|
|
249
|
+
${entry}
|
|
250
|
+
`;
|
|
251
|
+
const body = existing.startsWith(heading) ? existing.slice(heading.length).replace(/^\n+/, "") : existing;
|
|
252
|
+
return `${heading}
|
|
253
|
+
${entry}
|
|
254
|
+
${body}`;
|
|
255
|
+
}
|
|
256
|
+
function parsePackageVersion(rawPackageJson) {
|
|
257
|
+
const pkg = JSON.parse(rawPackageJson);
|
|
258
|
+
if (!pkg.version)
|
|
259
|
+
throw new Error('No "version" field found in package.json');
|
|
260
|
+
return pkg.version;
|
|
261
|
+
}
|
|
262
|
+
function todayIso(date = new Date) {
|
|
263
|
+
return date.toISOString().slice(0, 10);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/components/changelog/changelog.ts
|
|
267
|
+
function previousTag() {
|
|
268
|
+
try {
|
|
269
|
+
return captureArgs(["describe", "--tags", "--abbrev=0"]);
|
|
270
|
+
} catch {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function commitSubjectsSince(tag) {
|
|
275
|
+
const range = tag ? `${tag}..HEAD` : "HEAD";
|
|
276
|
+
return filterCommitSubjects(captureArgs(["log", range, "--no-merges", "--pretty=format:%s"]));
|
|
277
|
+
}
|
|
278
|
+
function changelog(flags) {
|
|
279
|
+
const noCommit = flags.has("no-commit");
|
|
280
|
+
if (flags.size > (noCommit ? 1 : 0))
|
|
281
|
+
throw new Error("usage: gith changelog [--dry-run] [--no-commit]");
|
|
282
|
+
const root = process.cwd();
|
|
283
|
+
const version = parsePackageVersion(readFileSync(path.join(root, "package.json"), "utf8"));
|
|
284
|
+
const entry = buildEntry({
|
|
285
|
+
version,
|
|
286
|
+
date: todayIso(),
|
|
287
|
+
subjects: commitSubjectsSince(previousTag())
|
|
288
|
+
});
|
|
289
|
+
if (isDryRun()) {
|
|
290
|
+
console.log(entry);
|
|
291
|
+
console.log(`dry run: would update ${CHANGELOG_FILE_NAME}`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const file = path.join(root, CHANGELOG_FILE_NAME);
|
|
295
|
+
const existing = existsSync(file) ? readFileSync(file, "utf8") : null;
|
|
296
|
+
writeFileSync(file, mergeChangelogContent(existing, entry));
|
|
297
|
+
console.log(`✅ ${CHANGELOG_FILE_NAME} updated for ${version}`);
|
|
298
|
+
if (noCommit)
|
|
299
|
+
return;
|
|
300
|
+
gitArgs(["add", "--", CHANGELOG_FILE_NAME]);
|
|
301
|
+
gitArgs([
|
|
302
|
+
"commit",
|
|
303
|
+
"-m",
|
|
304
|
+
`docs(changelog): ${version}`,
|
|
305
|
+
"--",
|
|
306
|
+
CHANGELOG_FILE_NAME
|
|
307
|
+
]);
|
|
308
|
+
}
|
|
309
|
+
|
|
219
310
|
// src/components/doctor/doctor.utils.ts
|
|
220
311
|
function check(name, test, failure = "fail") {
|
|
221
312
|
return {
|
|
@@ -1569,7 +1660,7 @@ function tree(flags) {
|
|
|
1569
1660
|
}
|
|
1570
1661
|
|
|
1571
1662
|
// src/components/version/version.ts
|
|
1572
|
-
import { readFileSync as
|
|
1663
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
1573
1664
|
|
|
1574
1665
|
// src/components/version/version.constants.ts
|
|
1575
1666
|
var MASCOT = [
|
|
@@ -1584,19 +1675,19 @@ var MASCOT = [
|
|
|
1584
1675
|
];
|
|
1585
1676
|
|
|
1586
1677
|
// src/components/version/version.utils.ts
|
|
1587
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1588
|
-
import
|
|
1678
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
1679
|
+
import path2 from "node:path";
|
|
1589
1680
|
import { fileURLToPath } from "node:url";
|
|
1590
1681
|
function packageJsonPath() {
|
|
1591
|
-
let dir =
|
|
1682
|
+
let dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
1592
1683
|
for (;; ) {
|
|
1593
|
-
const candidate =
|
|
1594
|
-
if (
|
|
1595
|
-
const pkg = JSON.parse(
|
|
1684
|
+
const candidate = path2.join(dir, "package.json");
|
|
1685
|
+
if (existsSync2(candidate)) {
|
|
1686
|
+
const pkg = JSON.parse(readFileSync2(candidate, "utf8"));
|
|
1596
1687
|
if (pkg.name === "@tertium/gith")
|
|
1597
1688
|
return candidate;
|
|
1598
1689
|
}
|
|
1599
|
-
const parent =
|
|
1690
|
+
const parent = path2.dirname(dir);
|
|
1600
1691
|
if (parent === dir)
|
|
1601
1692
|
throw new Error("gith package.json not found");
|
|
1602
1693
|
dir = parent;
|
|
@@ -1605,7 +1696,7 @@ function packageJsonPath() {
|
|
|
1605
1696
|
|
|
1606
1697
|
// src/components/version/version.ts
|
|
1607
1698
|
function readVersion() {
|
|
1608
|
-
const pkg = JSON.parse(
|
|
1699
|
+
const pkg = JSON.parse(readFileSync3(packageJsonPath(), "utf8"));
|
|
1609
1700
|
return pkg.version ?? "unknown";
|
|
1610
1701
|
}
|
|
1611
1702
|
function versionText() {
|
|
@@ -1670,6 +1761,7 @@ Remote and health
|
|
|
1670
1761
|
gith sync fetch all remotes and tags, prune stale refs
|
|
1671
1762
|
gith open open origin in the browser
|
|
1672
1763
|
gith doctor check the repo is ready for the branch flow (exit 1 on failures)
|
|
1764
|
+
gith changelog [--dry-run] add an entry for package.json's version to CHANGELOG.md (commits since the last tag)
|
|
1673
1765
|
|
|
1674
1766
|
Help
|
|
1675
1767
|
gith help show this help
|
|
@@ -1753,6 +1845,9 @@ try {
|
|
|
1753
1845
|
case "open":
|
|
1754
1846
|
open2(parseFlags(rest));
|
|
1755
1847
|
break;
|
|
1848
|
+
case "changelog":
|
|
1849
|
+
changelog(parseFlags(rest));
|
|
1850
|
+
break;
|
|
1756
1851
|
case "doctor":
|
|
1757
1852
|
if (!doctor(parseFlags(rest)))
|
|
1758
1853
|
exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tertium/gith",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Git helper: branch flow with goal branches, release and hotfix containers, and everyday git commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"typecheck": "tsc --noEmit",
|
|
19
19
|
"release:patch": "node bin/gith.js release --patch",
|
|
20
20
|
"release:minor": "node bin/gith.js release --minor",
|
|
21
|
-
"release:major": "node bin/gith.js release --major"
|
|
21
|
+
"release:major": "node bin/gith.js release --major",
|
|
22
|
+
"version": "bun run build && node bin/gith.js changelog"
|
|
22
23
|
},
|
|
23
24
|
"license": "ISC",
|
|
24
25
|
"author": "Vitalii Balabanov",
|