lechnerio-git-hooks 1.3.1 → 1.3.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/README.md +5 -1
- package/package.json +1 -1
- package/scripts/generate-changelog.mjs +25 -18
package/README.md
CHANGED
|
@@ -34,9 +34,13 @@ On install, the package automatically:
|
|
|
34
34
|
| `commit-msg` | Enforces conventional commits via commitlint |
|
|
35
35
|
| `post-commit` | Interactive version bump (subtle/patch/minor/major), changelog generation with optional skip flag, push/merge prompt |
|
|
36
36
|
|
|
37
|
+
## Changelog versioning model
|
|
38
|
+
|
|
39
|
+
Commits belong to the version that was current while they were made. A Minor or Major bump closes the running version — all work since the previous bump stays under it, including the commit that triggered the bump — and opens the new version with a `Version Upgrade to <version>` marker entry. Future commits then accumulate under the new version.
|
|
40
|
+
|
|
37
41
|
## AI release summaries
|
|
38
42
|
|
|
39
|
-
On Minor and Major version bumps, the `post-commit` hook sends the
|
|
43
|
+
On Minor and Major version bumps, the `post-commit` hook sends the non-skipped commit messages of the version being closed to the Gemini API and stores the result as `summary_en` and `summary_ger` fields (English and German) on that version entry in `data/changelog.json`. This requires `GITHOOKS_GEMINI_API_KEY` in the project's `.env` file or environment; without it the summary step is skipped silently. Run `node scripts/generate-changelog.mjs --summarize-version <version>` to generate the summary for any version by hand (accepts the version with or without the `v` prefix, subtle suffixes are normalized). Summaries are only generated when `summary_en` or `summary_ger` is missing on the entry — to regenerate one, delete both fields from `data/changelog.json` first.
|
|
40
44
|
|
|
41
45
|
## Peer dependencies (auto-installed)
|
|
42
46
|
|
package/package.json
CHANGED
|
@@ -58,23 +58,13 @@ if (process.argv.includes("--skip-last")) {
|
|
|
58
58
|
|
|
59
59
|
const changelog = []
|
|
60
60
|
|
|
61
|
-
const currentVersion = tags[0].replace(/^v/, "")
|
|
62
|
-
const unreleasedRaw = run(`git log --format="%s" ${tags[0]}..HEAD`)
|
|
63
|
-
if (unreleasedRaw) {
|
|
64
|
-
const commits = [...new Set(unreleasedRaw.split("\n").filter(Boolean))].map((message) => ({ message, skip: skipFlags.get(message) ?? false }))
|
|
65
|
-
if (commits.length > 0) {
|
|
66
|
-
const date = run(`git log --format=%ai HEAD -1`).split(" ")[0]
|
|
67
|
-
changelog.push({ version: currentVersion, tag: null, date, commits })
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
61
|
for (let i = 0; i < tags.length; i++) {
|
|
72
62
|
const tag = tags[i]
|
|
63
|
+
const upper = i === 0 ? "HEAD" : tags[i - 1]
|
|
64
|
+
const eraRaw = run(`git log --format="%s" ${tag}..${upper}`)
|
|
65
|
+
const initialRaw = i === tags.length - 1 ? run(`git log --format="%s" ${tag}`) : ""
|
|
66
|
+
const raw = [eraRaw, initialRaw].filter(Boolean).join("\n")
|
|
73
67
|
const date = run(`git log --format=%ai ${tag} -1`).split(" ")[0]
|
|
74
|
-
const prevTag = tags[i + 1]
|
|
75
|
-
|
|
76
|
-
const range = prevTag ? `${prevTag}..${tag}` : tag
|
|
77
|
-
const raw = run(`git log --format="%s" ${range}`)
|
|
78
68
|
|
|
79
69
|
const commits = raw
|
|
80
70
|
? [...new Set(raw.split("\n").filter(Boolean))].map((message) => ({ message, skip: skipFlags.get(message) ?? false }))
|
|
@@ -112,6 +102,14 @@ for (const entry of grouped) {
|
|
|
112
102
|
})
|
|
113
103
|
}
|
|
114
104
|
|
|
105
|
+
for (let i = 0; i < grouped.length - 1; i++) {
|
|
106
|
+
const entry = grouped[i]
|
|
107
|
+
const marker = `Version Upgrade to ${entry.version}`
|
|
108
|
+
if (!entry.commits.some((c) => c.message === marker)) {
|
|
109
|
+
entry.commits.push({ message: marker, skip: skipFlags.get(marker) ?? false })
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
115
113
|
for (const entry of grouped) {
|
|
116
114
|
const saved = summaries.get(entry.version)
|
|
117
115
|
if (saved) {
|
|
@@ -120,13 +118,22 @@ for (const entry of grouped) {
|
|
|
120
118
|
}
|
|
121
119
|
}
|
|
122
120
|
|
|
123
|
-
|
|
121
|
+
const svIndex = process.argv.indexOf("--summarize-version")
|
|
122
|
+
const requestedVersion = svIndex === -1 ? null : process.argv[svIndex + 1] ?? null
|
|
123
|
+
|
|
124
|
+
if (process.argv.includes("--summarize") || svIndex !== -1) {
|
|
124
125
|
const apiKey = loadEnvKey("GITHOOKS_GEMINI_API_KEY")
|
|
125
|
-
if (!
|
|
126
|
+
if (svIndex !== -1 && !requestedVersion) {
|
|
127
|
+
console.warn("--summarize-version requires a version argument")
|
|
128
|
+
} else if (!apiKey) {
|
|
126
129
|
console.warn("GITHOOKS_GEMINI_API_KEY not set, skipping AI summary")
|
|
127
130
|
} else {
|
|
128
|
-
const
|
|
129
|
-
|
|
131
|
+
const closedTag = tags.length > 1 ? tags[1] : tags[0]
|
|
132
|
+
const targetVersion = requestedVersion ? baseVersion(requestedVersion.replace(/^v/, "")) : baseVersion(closedTag.replace(/^v/, ""))
|
|
133
|
+
const target = grouped.find((e) => e.version === targetVersion)
|
|
134
|
+
if (!target) {
|
|
135
|
+
console.warn(`version ${targetVersion} not found in changelog`)
|
|
136
|
+
} else if (!(target.summary_en && target.summary_ger)) {
|
|
130
137
|
const messages = target.commits.filter((c) => !c.skip).map((c) => c.message)
|
|
131
138
|
if (messages.length === 0) {
|
|
132
139
|
console.warn("no commits to summarize")
|