@tertium/gith 0.1.0 → 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 +4 -0
- package/bin/gith.js +150 -41
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -70,6 +70,7 @@ gith remove --obsolete # remove branches untouched for 90 days, on
|
|
|
70
70
|
gith remove --obsolete --local # the same, here only
|
|
71
71
|
gith remove --obsolete -days 30 # untouched for 30 days instead
|
|
72
72
|
gith remove --detached # pick local branches that have no origin copy
|
|
73
|
+
gith remove --detached --all # remove all of them: lists them, then asks Y/n
|
|
73
74
|
|
|
74
75
|
# Look at the repo
|
|
75
76
|
gith status # branch vs origin, and staged, unstaged and untracked counts
|
|
@@ -92,6 +93,8 @@ gith stat --last-week -limit 50 # the same for last week, looking at no more
|
|
|
92
93
|
gith sync # fetch all remotes and tags, prune stale refs
|
|
93
94
|
gith open # open origin in the browser
|
|
94
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
|
|
95
98
|
|
|
96
99
|
# Help
|
|
97
100
|
gith help # full usage
|
|
@@ -155,6 +158,7 @@ Commands that choose between flags (for example `create -b`, `-r` and `-h`, or `
|
|
|
155
158
|
- **`stat`** reads the history of the current branch and prints a table of facts: commit count, top author, the biggest commit (lines added and removed), average size, the most changed file, the busiest day, weekday and hour, the longest streak of days with a commit, night owl and weekend commits, and the conventional commit types. The period is one switch: `--overall` (the default), `--current-year`, `--current-month`, `--current-week` (weeks start on Monday), or the matching `--last-` switch for the previous year, month or week. `-limit <n>` looks only at the last `n` commits. Stat changes nothing.
|
|
156
159
|
- **`unstash`** runs `git stash pop`. If it conflicts, git keeps the stash in the list.
|
|
157
160
|
- **`remove --obsolete`** fetches and prunes origin, then lists the branches untouched for `-days` (default 90): no commit newer than the cutoff on either side. Each line shows the sides and the last commit date, and the command asks `Remove these N branches here and on origin? [Y/n]`. Enter means yes. `--local` looks at and removes only local branches. `-limit` shows only the first `n`, and the prompt covers only those. `main`, `develop`, `release/*` and `hotfix/*` are never removed, and neither is the checked-out branch. Each branch is deleted locally first (`git branch -d`), so a branch that git does not see as merged stops the run before its origin copy is touched.
|
|
161
|
+
- **`remove --detached --all`** fetches and prunes origin, lists every local branch with no origin copy, and asks `Remove these N branches? [Y/n]` once. Nothing is deleted without the yes, and `--all` can't be combined with `-limit`.
|
|
158
162
|
- **`remove --detached`** fetches and prunes origin, then lists local branches that have no origin copy and lets you pick from them, the same as `remove --branch --local` but for branches with no origin copy only.
|
|
159
163
|
- **Every removal shows what it will remove** before deleting anything, including the direct `remove -b` form. The picker and the prompt both show it first.
|
|
160
164
|
- **`open`** opens origin in the browser, turning an `ssh` or `https` remote into a web address. GitHub and GitLab style addresses work.
|
package/bin/gith.js
CHANGED
|
@@ -30,6 +30,8 @@ var SPECS = new Map([
|
|
|
30
30
|
["current-hotfix", "switch"],
|
|
31
31
|
["pockets", "switch"],
|
|
32
32
|
["detached", "switch"],
|
|
33
|
+
["all", "switch"],
|
|
34
|
+
["no-commit", "switch"],
|
|
33
35
|
["overall", "switch"],
|
|
34
36
|
["current-year", "switch"],
|
|
35
37
|
["current-month", "switch"],
|
|
@@ -118,6 +120,10 @@ function onlyOne(flags, names) {
|
|
|
118
120
|
return present[0];
|
|
119
121
|
}
|
|
120
122
|
|
|
123
|
+
// src/components/changelog/changelog.ts
|
|
124
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
125
|
+
import path from "node:path";
|
|
126
|
+
|
|
121
127
|
// src/components/git/git.ts
|
|
122
128
|
import { execFileSync } from "node:child_process";
|
|
123
129
|
var verbose = false;
|
|
@@ -215,6 +221,92 @@ function act(args, options = {}) {
|
|
|
215
221
|
execFileSync("git", args, { stdio: "inherit", ...options });
|
|
216
222
|
}
|
|
217
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
|
+
|
|
218
310
|
// src/components/doctor/doctor.utils.ts
|
|
219
311
|
function check(name, test, failure = "fail") {
|
|
220
312
|
return {
|
|
@@ -945,8 +1037,10 @@ async function remove(flags) {
|
|
|
945
1037
|
throw new Error("use only one of: --obsolete, --detached.");
|
|
946
1038
|
if (flags.has("days") && !obsoleteOn)
|
|
947
1039
|
throw new Error("-days only applies to --obsolete.");
|
|
1040
|
+
if (flags.has("all") && !detachedOn)
|
|
1041
|
+
throw new Error("--all only applies to --detached.");
|
|
948
1042
|
if (obsoleteOn || detachedOn) {
|
|
949
|
-
const usage = detachedOn ? "usage: gith remove --detached [-l <n>]" : "usage: gith remove --obsolete [--local] [-days <n>] [-l <n>]";
|
|
1043
|
+
const usage = detachedOn ? "usage: gith remove --detached [--all | -l <n>]" : "usage: gith remove --obsolete [--local] [-days <n>] [-l <n>]";
|
|
950
1044
|
if (name !== undefined || obsoleteOn && side === "remote" || detachedOn && side)
|
|
951
1045
|
throw new Error(usage);
|
|
952
1046
|
if (detachedOn)
|
|
@@ -1038,7 +1132,7 @@ function pick(scope, limit) {
|
|
|
1038
1132
|
const remote = scope === "local" ? [] : remoteBranches();
|
|
1039
1133
|
return choose(candidates(scope, localBranches(), remote, currentBranch2()), limit);
|
|
1040
1134
|
}
|
|
1041
|
-
async function removeBranches(scope, names,
|
|
1135
|
+
async function removeBranches(scope, names, ask = true) {
|
|
1042
1136
|
const plan = names.map((name) => {
|
|
1043
1137
|
if (scope === "remote")
|
|
1044
1138
|
return { name, local: false, origin: true };
|
|
@@ -1053,7 +1147,7 @@ async function removeBranches(scope, names, ask2 = true) {
|
|
|
1053
1147
|
});
|
|
1054
1148
|
if (plan.length > 0)
|
|
1055
1149
|
console.log("Will remove:");
|
|
1056
|
-
if (
|
|
1150
|
+
if (ask && plan.length > 0 && !await confirm(plan.length === 1 ? "Remove this branch? [Y/n] " : `Remove these ${plan.length} branches? [Y/n] `)) {
|
|
1057
1151
|
console.log("Nothing removed.");
|
|
1058
1152
|
return;
|
|
1059
1153
|
}
|
|
@@ -1103,9 +1197,19 @@ async function obsolete(flags, scope) {
|
|
|
1103
1197
|
await removeBranches(scope, shown.map((option) => option.name), false);
|
|
1104
1198
|
}
|
|
1105
1199
|
async function detached(flags) {
|
|
1106
|
-
requireTerminal();
|
|
1107
1200
|
gitArgs(["fetch", "--prune", "origin"]);
|
|
1108
1201
|
const options = detachedOptions(readTimes(), currentBranch2());
|
|
1202
|
+
if (flags.has("all")) {
|
|
1203
|
+
if (flags.has("limit"))
|
|
1204
|
+
throw new Error("use only one of: --all, -limit.");
|
|
1205
|
+
if (options.length === 0) {
|
|
1206
|
+
console.log("No detached branches to remove.");
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
await removeBranches("local", options.map((option) => option.name));
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
requireTerminal();
|
|
1109
1213
|
await removeBranches("local", await choose(options, parseLimit(flags)));
|
|
1110
1214
|
}
|
|
1111
1215
|
function switchToCommit(ref) {
|
|
@@ -1264,8 +1368,8 @@ function startOfWeek(date) {
|
|
|
1264
1368
|
}
|
|
1265
1369
|
function dayKey(date) {
|
|
1266
1370
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
1267
|
-
const
|
|
1268
|
-
return `${date.getFullYear()}-${month}-${
|
|
1371
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
1372
|
+
return `${date.getFullYear()}-${month}-${day}`;
|
|
1269
1373
|
}
|
|
1270
1374
|
function top(counts) {
|
|
1271
1375
|
let best;
|
|
@@ -1347,57 +1451,57 @@ function parseLog(output) {
|
|
|
1347
1451
|
function longestStreak(dates) {
|
|
1348
1452
|
const days = [...new Set(dates.map(dayKey))].sort();
|
|
1349
1453
|
let best = 0;
|
|
1350
|
-
let
|
|
1454
|
+
let run = 0;
|
|
1351
1455
|
let previous = -Infinity;
|
|
1352
1456
|
for (const key of days) {
|
|
1353
1457
|
const [y = 0, m = 1, d = 1] = key.split("-").map(Number);
|
|
1354
1458
|
const ms = Date.UTC(y, m - 1, d) / 86400000;
|
|
1355
|
-
|
|
1356
|
-
best = Math.max(best,
|
|
1459
|
+
run = ms - previous === 1 ? run + 1 : 1;
|
|
1460
|
+
best = Math.max(best, run);
|
|
1357
1461
|
previous = ms;
|
|
1358
1462
|
}
|
|
1359
1463
|
return best;
|
|
1360
1464
|
}
|
|
1361
|
-
function summarize(
|
|
1362
|
-
if (
|
|
1465
|
+
function summarize(commits) {
|
|
1466
|
+
if (commits.length === 0)
|
|
1363
1467
|
return [];
|
|
1364
1468
|
const rows = [];
|
|
1365
1469
|
const add = (stat, value, detail = "") => rows.push({ stat, value, detail });
|
|
1366
|
-
const authors = count(
|
|
1470
|
+
const authors = count(commits.map((c) => c.author));
|
|
1367
1471
|
const topAuthor = top(authors);
|
|
1368
|
-
const oldest =
|
|
1369
|
-
const newest =
|
|
1370
|
-
const added =
|
|
1371
|
-
const deleted =
|
|
1372
|
-
add("Commits", String(
|
|
1472
|
+
const oldest = commits.reduce((a, b) => a.date <= b.date ? a : b);
|
|
1473
|
+
const newest = commits.reduce((a, b) => a.date >= b.date ? a : b);
|
|
1474
|
+
const added = commits.reduce((sum, c) => sum + c.added, 0);
|
|
1475
|
+
const deleted = commits.reduce((sum, c) => sum + c.deleted, 0);
|
|
1476
|
+
add("Commits", String(commits.length), `${dayKey(oldest.date)} to ${dayKey(newest.date)}`);
|
|
1373
1477
|
add("Authors", String(authors.size));
|
|
1374
1478
|
if (topAuthor)
|
|
1375
1479
|
add("Top author", topAuthor[0], `${topAuthor[1]} commits`);
|
|
1376
|
-
const biggest =
|
|
1480
|
+
const biggest = commits.reduce((a, b) => b.added + b.deleted > a.added + a.deleted ? b : a);
|
|
1377
1481
|
add("Biggest commit", `+${biggest.added} -${biggest.deleted}`, `${biggest.hash.slice(0, 7)} ${biggest.subject} (${biggest.author})`);
|
|
1378
|
-
add("Average size", `${Math.round((added + deleted) /
|
|
1379
|
-
const files = count(
|
|
1482
|
+
add("Average size", `${Math.round((added + deleted) / commits.length)} lines`, `per commit; +${added} -${deleted} in total`);
|
|
1483
|
+
const files = count(commits.flatMap((c) => c.files));
|
|
1380
1484
|
const topFile = top(files);
|
|
1381
1485
|
add("Files touched", String(files.size), topFile ? `most changed: ${topFile[0]} (${topFile[1]} commits)` : "");
|
|
1382
|
-
const busiestDay = top(count(
|
|
1486
|
+
const busiestDay = top(count(commits.map((c) => dayKey(c.date))));
|
|
1383
1487
|
if (busiestDay)
|
|
1384
1488
|
add("Busiest day", busiestDay[0], `${busiestDay[1]} commits`);
|
|
1385
|
-
const weekday = top(count(
|
|
1489
|
+
const weekday = top(count(commits.map((c) => DAYS[c.date.getDay()] ?? "")));
|
|
1386
1490
|
if (weekday)
|
|
1387
1491
|
add("Busiest weekday", weekday[0], `${weekday[1]} commits`);
|
|
1388
|
-
const hour = top(count(
|
|
1492
|
+
const hour = top(count(commits.map((c) => String(c.date.getHours()).padStart(2, "0"))));
|
|
1389
1493
|
if (hour)
|
|
1390
1494
|
add("Peak hour", `${hour[0]}:00`, `${hour[1]} commits`);
|
|
1391
|
-
const streak = longestStreak(
|
|
1495
|
+
const streak = longestStreak(commits.map((c) => c.date));
|
|
1392
1496
|
add("Longest streak", `${streak} ${streak === 1 ? "day" : "days"}`, "in a row with a commit");
|
|
1393
|
-
const nightOwl =
|
|
1394
|
-
const weekend =
|
|
1497
|
+
const nightOwl = commits.filter((c) => c.date.getHours() >= 22 || c.date.getHours() < 5).length;
|
|
1498
|
+
const weekend = commits.filter((c) => c.date.getDay() === 0 || c.date.getDay() === 6).length;
|
|
1395
1499
|
add("Night owl", `${nightOwl} commits`, "between 22:00 and 05:00");
|
|
1396
1500
|
add("Weekend", `${weekend} commits`, "on Saturday or Sunday");
|
|
1397
|
-
const types = count(
|
|
1501
|
+
const types = count(commits.map((c) => /^(\w+)(\([^)]*\))?!?:/.exec(c.subject)?.[1]?.toLowerCase() ?? "").filter(Boolean));
|
|
1398
1502
|
if (types.size > 0) {
|
|
1399
|
-
const
|
|
1400
|
-
add("Commit types",
|
|
1503
|
+
const list = [...types.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, 4).map(([type, n]) => `${type} ${n}`).join(", ");
|
|
1504
|
+
add("Commit types", list, "from conventional prefixes");
|
|
1401
1505
|
}
|
|
1402
1506
|
return rows;
|
|
1403
1507
|
}
|
|
@@ -1432,13 +1536,13 @@ function stat(flags) {
|
|
|
1432
1536
|
args.push(`--until=${range.until}`);
|
|
1433
1537
|
if (limit !== undefined)
|
|
1434
1538
|
args.push(`-n${limit}`);
|
|
1435
|
-
const
|
|
1436
|
-
if (
|
|
1539
|
+
const commits = parseLog(captureArgs(args));
|
|
1540
|
+
if (commits.length === 0) {
|
|
1437
1541
|
console.log(`No commits ${range.label === "overall" ? "yet" : `in ${range.label}`}.`);
|
|
1438
1542
|
return;
|
|
1439
1543
|
}
|
|
1440
1544
|
console.log(`gith stat, ${range.label}${limit === undefined ? "" : `, last ${limit} commits`}`);
|
|
1441
|
-
console.log(table(summarize(
|
|
1545
|
+
console.log(table(summarize(commits)));
|
|
1442
1546
|
}
|
|
1443
1547
|
|
|
1444
1548
|
// src/components/status/status.ts
|
|
@@ -1556,7 +1660,7 @@ function tree(flags) {
|
|
|
1556
1660
|
}
|
|
1557
1661
|
|
|
1558
1662
|
// src/components/version/version.ts
|
|
1559
|
-
import { readFileSync as
|
|
1663
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
1560
1664
|
|
|
1561
1665
|
// src/components/version/version.constants.ts
|
|
1562
1666
|
var MASCOT = [
|
|
@@ -1571,19 +1675,19 @@ var MASCOT = [
|
|
|
1571
1675
|
];
|
|
1572
1676
|
|
|
1573
1677
|
// src/components/version/version.utils.ts
|
|
1574
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1575
|
-
import
|
|
1678
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
1679
|
+
import path2 from "node:path";
|
|
1576
1680
|
import { fileURLToPath } from "node:url";
|
|
1577
1681
|
function packageJsonPath() {
|
|
1578
|
-
let dir =
|
|
1682
|
+
let dir = path2.dirname(fileURLToPath(import.meta.url));
|
|
1579
1683
|
for (;; ) {
|
|
1580
|
-
const candidate =
|
|
1581
|
-
if (
|
|
1582
|
-
const pkg = JSON.parse(
|
|
1684
|
+
const candidate = path2.join(dir, "package.json");
|
|
1685
|
+
if (existsSync2(candidate)) {
|
|
1686
|
+
const pkg = JSON.parse(readFileSync2(candidate, "utf8"));
|
|
1583
1687
|
if (pkg.name === "@tertium/gith")
|
|
1584
1688
|
return candidate;
|
|
1585
1689
|
}
|
|
1586
|
-
const parent =
|
|
1690
|
+
const parent = path2.dirname(dir);
|
|
1587
1691
|
if (parent === dir)
|
|
1588
1692
|
throw new Error("gith package.json not found");
|
|
1589
1693
|
dir = parent;
|
|
@@ -1592,7 +1696,7 @@ function packageJsonPath() {
|
|
|
1592
1696
|
|
|
1593
1697
|
// src/components/version/version.ts
|
|
1594
1698
|
function readVersion() {
|
|
1595
|
-
const pkg = JSON.parse(
|
|
1699
|
+
const pkg = JSON.parse(readFileSync3(packageJsonPath(), "utf8"));
|
|
1596
1700
|
return pkg.version ?? "unknown";
|
|
1597
1701
|
}
|
|
1598
1702
|
function versionText() {
|
|
@@ -1638,6 +1742,7 @@ Clean up branches (every removal shows what it will remove first)
|
|
|
1638
1742
|
gith remove --branch --remote pick from origin branches
|
|
1639
1743
|
gith remove --obsolete [--local] [-days <n>] remove branches untouched for 90 days, after Y/n
|
|
1640
1744
|
gith remove --detached [-l <n>] pick local branches that have no origin copy
|
|
1745
|
+
gith remove --detached --all remove all of them, after listing them and a Y/n question
|
|
1641
1746
|
gith rm alias of remove
|
|
1642
1747
|
|
|
1643
1748
|
Look at the repo
|
|
@@ -1656,6 +1761,7 @@ Remote and health
|
|
|
1656
1761
|
gith sync fetch all remotes and tags, prune stale refs
|
|
1657
1762
|
gith open open origin in the browser
|
|
1658
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)
|
|
1659
1765
|
|
|
1660
1766
|
Help
|
|
1661
1767
|
gith help show this help
|
|
@@ -1739,6 +1845,9 @@ try {
|
|
|
1739
1845
|
case "open":
|
|
1740
1846
|
open2(parseFlags(rest));
|
|
1741
1847
|
break;
|
|
1848
|
+
case "changelog":
|
|
1849
|
+
changelog(parseFlags(rest));
|
|
1850
|
+
break;
|
|
1742
1851
|
case "doctor":
|
|
1743
1852
|
if (!doctor(parseFlags(rest)))
|
|
1744
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": {
|
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
"test": "bun test --no-coverage",
|
|
16
16
|
"lint": "biome check src",
|
|
17
17
|
"lint:fix": "biome check --write src",
|
|
18
|
-
"typecheck": "tsc --noEmit"
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"release:patch": "node bin/gith.js release --patch",
|
|
20
|
+
"release:minor": "node bin/gith.js release --minor",
|
|
21
|
+
"release:major": "node bin/gith.js release --major",
|
|
22
|
+
"version": "bun run build && node bin/gith.js changelog"
|
|
19
23
|
},
|
|
20
24
|
"license": "ISC",
|
|
21
25
|
"author": "Vitalii Balabanov",
|