glab-setup-git-identity 0.6.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/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/.github/workflows/release.yml +372 -0
- package/.husky/pre-commit +1 -0
- package/.jscpd.json +20 -0
- package/.prettierignore +7 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +143 -0
- package/LICENSE +24 -0
- package/README.md +455 -0
- package/bunfig.toml +3 -0
- package/deno.json +7 -0
- package/docs/case-studies/issue-13/README.md +195 -0
- package/docs/case-studies/issue-13/hive-mind-issue-960.json +23 -0
- package/docs/case-studies/issue-13/hive-mind-pr-961-diff.txt +773 -0
- package/docs/case-studies/issue-13/hive-mind-pr-961.json +126 -0
- package/docs/case-studies/issue-21/README.md +384 -0
- package/docs/case-studies/issue-21/ci-logs/run-20803315337.txt +1188 -0
- package/docs/case-studies/issue-21/ci-logs/run-20885464993.txt +1310 -0
- package/docs/case-studies/issue-21/issue-111-data.txt +15 -0
- package/docs/case-studies/issue-21/issue-113-data.txt +15 -0
- package/docs/case-studies/issue-21/pr-112-data.json +109 -0
- package/docs/case-studies/issue-21/pr-112-diff.patch +1336 -0
- package/docs/case-studies/issue-21/pr-114-data.json +126 -0
- package/docs/case-studies/issue-21/pr-114-diff.patch +879 -0
- package/docs/case-studies/issue-3/README.md +338 -0
- package/docs/case-studies/issue-3/created-issues.md +32 -0
- package/docs/case-studies/issue-3/issue-data.json +29 -0
- package/docs/case-studies/issue-3/original-format-release-notes.mjs +212 -0
- package/docs/case-studies/issue-3/reference-pr-59-diff.txt +614 -0
- package/docs/case-studies/issue-3/reference-pr-59.json +109 -0
- package/docs/case-studies/issue-3/release-v0.1.0.json +9 -0
- package/docs/case-studies/issue-3/repositories-with-same-script.json +22 -0
- package/docs/case-studies/issue-3/research-notes.md +33 -0
- package/docs/case-studies/issue-7/BEST-PRACTICES-COMPARISON.md +334 -0
- package/docs/case-studies/issue-7/FORMATTER-COMPARISON.md +649 -0
- package/docs/case-studies/issue-7/current-repository-analysis.json +70 -0
- package/docs/case-studies/issue-7/effect-template-analysis.json +178 -0
- package/eslint.config.js +91 -0
- package/examples/basic-usage.js +64 -0
- package/experiments/test-changeset-scripts.mjs +303 -0
- package/experiments/test-failure-detection.mjs +143 -0
- package/experiments/test-format-major-changes.mjs +49 -0
- package/experiments/test-format-minor-changes.mjs +52 -0
- package/experiments/test-format-no-hash.mjs +43 -0
- package/experiments/test-format-patch-changes.mjs +46 -0
- package/package.json +80 -0
- package/scripts/changeset-version.mjs +75 -0
- package/scripts/check-changesets.mjs +67 -0
- package/scripts/check-version.mjs +129 -0
- package/scripts/create-github-release.mjs +93 -0
- package/scripts/create-manual-changeset.mjs +89 -0
- package/scripts/detect-code-changes.mjs +194 -0
- package/scripts/format-github-release.mjs +83 -0
- package/scripts/format-release-notes.mjs +219 -0
- package/scripts/instant-version-bump.mjs +172 -0
- package/scripts/js-paths.mjs +177 -0
- package/scripts/merge-changesets.mjs +263 -0
- package/scripts/publish-to-npm.mjs +302 -0
- package/scripts/setup-npm.mjs +37 -0
- package/scripts/validate-changeset.mjs +265 -0
- package/scripts/version-and-commit.mjs +284 -0
- package/src/cli.js +386 -0
- package/src/index.d.ts +255 -0
- package/src/index.js +563 -0
- package/tests/index.test.js +137 -0
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
diff --git a/.changeset/fix-release-formatting.md b/.changeset/fix-release-formatting.md
|
|
2
|
+
new file mode 100644
|
|
3
|
+
index 0000000..cc77f79
|
|
4
|
+
--- /dev/null
|
|
5
|
+
+++ b/.changeset/fix-release-formatting.md
|
|
6
|
+
@@ -0,0 +1,5 @@
|
|
7
|
+
+---
|
|
8
|
+
+'@link-assistant/agent': patch
|
|
9
|
+
+---
|
|
10
|
+
+
|
|
11
|
+
+Fix GitHub release formatting to remove incorrect title for major/minor/patch versions and properly link related pull requests
|
|
12
|
+
diff --git a/CLAUDE.md b/CLAUDE.md
|
|
13
|
+
new file mode 100644
|
|
14
|
+
index 0000000..bc80f9c
|
|
15
|
+
--- /dev/null
|
|
16
|
+
+++ b/CLAUDE.md
|
|
17
|
+
@@ -0,0 +1,5 @@
|
|
18
|
+
+Issue to solve: https://github.com/link-assistant/agent/issues/58
|
|
19
|
+
+Your prepared branch: issue-58-bc11cbdc23dd
|
|
20
|
+
+Your prepared working directory: /tmp/gh-issue-solver-1765919093804
|
|
21
|
+
+
|
|
22
|
+
+Proceed.
|
|
23
|
+
diff --git a/docs/case-studies/issue-58/README.md b/docs/case-studies/issue-58/README.md
|
|
24
|
+
new file mode 100644
|
|
25
|
+
index 0000000..e1dfa5d
|
|
26
|
+
--- /dev/null
|
|
27
|
+
+++ b/docs/case-studies/issue-58/README.md
|
|
28
|
+
@@ -0,0 +1,227 @@
|
|
29
|
+
+# Case Study: Issue #58 - Release 0.1.0 Title and PR Link Bug
|
|
30
|
+
+
|
|
31
|
+
+## Issue Overview
|
|
32
|
+
+
|
|
33
|
+
+**Issue:** [#58](https://github.com/link-assistant/agent/issues/58)
|
|
34
|
+
+**Title:** Release 0.1.0 does show a title `Minor changes` and no linked pull request
|
|
35
|
+
+**Status:** In Progress
|
|
36
|
+
+**Created:** 2025-12-16
|
|
37
|
+
+
|
|
38
|
+
+### Problem Statement
|
|
39
|
+
+
|
|
40
|
+
+The release v0.1.0 shows two bugs:
|
|
41
|
+
+
|
|
42
|
+
+1. **Incorrect Title Display:** The release notes show "### Minor Changes" as a section header, but according to project requirements, there should be NO title for major/minor/patch version releases.
|
|
43
|
+
+2. **Missing PR Link:** The related pull request should be detected and shown in the release notes, but it is not present.
|
|
44
|
+
+
|
|
45
|
+
+## Timeline of Events
|
|
46
|
+
+
|
|
47
|
+
+### December 16, 2025
|
|
48
|
+
+
|
|
49
|
+
+1. **20:24:31 UTC** - Release v0.1.0 created by github-actions[bot]
|
|
50
|
+
+2. **20:26:20 UTC** - Release v0.1.0 published
|
|
51
|
+
+3. **Issue reported** - User identified that release has incorrect formatting
|
|
52
|
+
+
|
|
53
|
+
+## Data Collection
|
|
54
|
+
+
|
|
55
|
+
+### Release Data
|
|
56
|
+
+
|
|
57
|
+
+**Release URL:** https://github.com/link-assistant/agent/releases/tag/v0.1.0
|
|
58
|
+
+
|
|
59
|
+
+**Release Body (Raw):**
|
|
60
|
+
+
|
|
61
|
+
+```
|
|
62
|
+
+### Minor Changes
|
|
63
|
+
+
|
|
64
|
+
+- 2bcef5f: Add support for google/gemini-3-pro model alias
|
|
65
|
+
+ - Added `google/gemini-3-pro` as an alias to `gemini-3-pro-preview`
|
|
66
|
+
+ - Updated README.md with Google Gemini usage examples
|
|
67
|
+
+ - Created comprehensive case study in docs/case-studies/issue-53/
|
|
68
|
+
+ - Fixes ProviderModelNotFoundError when using google/gemini-3-pro
|
|
69
|
+
+
|
|
70
|
+
+ This change allows users to use the commonly expected model name `gemini-3-pro` while maintaining compatibility with Google's official `gemini-3-pro-preview` identifier.
|
|
71
|
+
+```
|
|
72
|
+
+
|
|
73
|
+
+### CHANGELOG.md Content
|
|
74
|
+
+
|
|
75
|
+
+The CHANGELOG.md file (lines 1-14) shows:
|
|
76
|
+
+
|
|
77
|
+
+```markdown
|
|
78
|
+
+# Changelog
|
|
79
|
+
+
|
|
80
|
+
+## 0.1.0
|
|
81
|
+
+
|
|
82
|
+
+### Minor Changes
|
|
83
|
+
+
|
|
84
|
+
+- 2bcef5f: Add support for google/gemini-3-pro model alias
|
|
85
|
+
+ - Added `google/gemini-3-pro` as an alias to `gemini-3-pro-preview`
|
|
86
|
+
+ - Updated README.md with Google Gemini usage examples
|
|
87
|
+
+ - Created comprehensive case study in docs/case-studies/issue-53/
|
|
88
|
+
+ - Fixes ProviderModelNotFoundError when using google/gemini-3-pro
|
|
89
|
+
+
|
|
90
|
+
+ This change allows users to use the commonly expected model name `gemini-3-pro` while maintaining compatibility with Google's official `gemini-3-pro-preview` identifier.
|
|
91
|
+
+```
|
|
92
|
+
+
|
|
93
|
+
+## Root Cause Analysis
|
|
94
|
+
+
|
|
95
|
+
+### Bug #1: Incorrect "### Minor Changes" Title
|
|
96
|
+
+
|
|
97
|
+
+**File:** `scripts/format-release-notes.mjs`
|
|
98
|
+
+**Lines:** 92-115
|
|
99
|
+
+
|
|
100
|
+
+The script only handles `### Patch Changes` section:
|
|
101
|
+
+
|
|
102
|
+
+```javascript
|
|
103
|
+
+// Extract the patch changes section
|
|
104
|
+
+// This regex handles two formats:
|
|
105
|
+
+// 1. With commit hash: "- abc1234: Description"
|
|
106
|
+
+// 2. Without commit hash: "- Description"
|
|
107
|
+
+const patchChangesMatchWithHash = currentBody.match(
|
|
108
|
+
+ /### Patch Changes\s*\n\s*-\s+([a-f0-9]+):\s+(.+?)$/s
|
|
109
|
+
+);
|
|
110
|
+
+const patchChangesMatchNoHash = currentBody.match(
|
|
111
|
+
+ /### Patch Changes\s*\n\s*-\s+(.+?)$/s
|
|
112
|
+
+);
|
|
113
|
+
+```
|
|
114
|
+
+
|
|
115
|
+
+**Root Cause:**
|
|
116
|
+
+
|
|
117
|
+
+- The script ONLY matches `### Patch Changes` sections
|
|
118
|
+
+- When a release contains `### Minor Changes` or `### Major Changes`, the regex doesn't match
|
|
119
|
+
+- The script exits early with "⚠️ Could not parse patch changes from release notes" (line 113)
|
|
120
|
+
+- As a result, the formatting never happens and the "### Minor Changes" title remains in the release
|
|
121
|
+
+
|
|
122
|
+
+### Bug #2: Missing PR Link
|
|
123
|
+
+
|
|
124
|
+
+**Related to Bug #1**
|
|
125
|
+
+
|
|
126
|
+
+Because the script exits early when it can't find `### Patch Changes`, it never reaches the PR detection logic (lines 136-182). Therefore:
|
|
127
|
+
+
|
|
128
|
+
+- No commit SHA is extracted
|
|
129
|
+
+- No PR lookup is performed
|
|
130
|
+
+- No PR link is added to the release notes
|
|
131
|
+
+
|
|
132
|
+
+## Comparison with Template Repository
|
|
133
|
+
+
|
|
134
|
+
+### Template Repository Analysis
|
|
135
|
+
+
|
|
136
|
+
+**Repository:** https://github.com/link-foundation/js-ai-driven-development-pipeline-template
|
|
137
|
+
+**Latest Release:** v0.1.0 (2025-12-13)
|
|
138
|
+
+
|
|
139
|
+
+The template repository has the **EXACT SAME BUG**:
|
|
140
|
+
+
|
|
141
|
+
+```
|
|
142
|
+
+### Minor Changes
|
|
143
|
+
+
|
|
144
|
+
+- 65d76dc: Initial template setup with complete AI-driven development pipeline
|
|
145
|
+
+ ...
|
|
146
|
+
+```
|
|
147
|
+
+
|
|
148
|
+
+The template's `scripts/format-release-notes.mjs` has identical code (lines 92-115) that only handles `### Patch Changes`.
|
|
149
|
+
+
|
|
150
|
+
+**Conclusion:** This bug exists in the upstream template and was inherited by our repository.
|
|
151
|
+
+
|
|
152
|
+
+## Proposed Solution
|
|
153
|
+
+
|
|
154
|
+
+### Fix for Our Repository
|
|
155
|
+
+
|
|
156
|
+
+Modify `scripts/format-release-notes.mjs` to:
|
|
157
|
+
+
|
|
158
|
+
+1. **Match all changeset types** (Major, Minor, Patch)
|
|
159
|
+
+2. **Remove the section header** (### Major Changes, ### Minor Changes, ### Patch Changes)
|
|
160
|
+
+3. **Extract commit hash and description** from any changeset type
|
|
161
|
+
+4. **Continue with PR detection and formatting**
|
|
162
|
+
+
|
|
163
|
+
+### Implementation Strategy
|
|
164
|
+
+
|
|
165
|
+
+1. Replace single regex patterns with a more flexible approach:
|
|
166
|
+
+ - Match `### (Major|Minor|Patch) Changes` pattern
|
|
167
|
+
+ - Extract the description regardless of the section type
|
|
168
|
+
+ - Remove the section header entirely from the formatted output
|
|
169
|
+
+
|
|
170
|
+
+2. Update regex patterns:
|
|
171
|
+
+
|
|
172
|
+
+```javascript
|
|
173
|
+
+// Match any changeset type (Major, Minor, or Patch)
|
|
174
|
+
+const changesPattern =
|
|
175
|
+
+ /### (Major|Minor|Patch) Changes\s*\n\s*-\s+(?:([a-f0-9]+):\s+)?(.+?)$/s;
|
|
176
|
+
+```
|
|
177
|
+
+
|
|
178
|
+
+3. Format output without section headers:
|
|
179
|
+
+
|
|
180
|
+
+```javascript
|
|
181
|
+
+// Remove "### X Changes" header entirely
|
|
182
|
+
+const formattedBody = `${cleanDescription}`;
|
|
183
|
+
+```
|
|
184
|
+
+
|
|
185
|
+
+### Fix for Template Repository
|
|
186
|
+
+
|
|
187
|
+
+Create an issue in the template repository:
|
|
188
|
+
+
|
|
189
|
+
+- **Repository:** link-foundation/js-ai-driven-development-pipeline-template
|
|
190
|
+
+- **Title:** Release formatting script only handles Patch changes, not Minor/Major
|
|
191
|
+
+- **Description:** Document the bug and provide the fix
|
|
192
|
+
+
|
|
193
|
+
+## Expected Outcomes
|
|
194
|
+
+
|
|
195
|
+
+### After Fix
|
|
196
|
+
+
|
|
197
|
+
+Release notes should look like:
|
|
198
|
+
+
|
|
199
|
+
+```
|
|
200
|
+
+Add support for google/gemini-3-pro model alias
|
|
201
|
+
+- Added `google/gemini-3-pro` as an alias to `gemini-3-pro-preview`
|
|
202
|
+
+- Updated README.md with Google Gemini usage examples
|
|
203
|
+
+- Created comprehensive case study in docs/case-studies/issue-53/
|
|
204
|
+
+- Fixes ProviderModelNotFoundError when using google/gemini-3-pro
|
|
205
|
+
+
|
|
206
|
+
+This change allows users to use the commonly expected model name `gemini-3-pro` while maintaining compatibility with Google's official `gemini-3-pro-preview` identifier.
|
|
207
|
+
+
|
|
208
|
+
+**Related Pull Request:** #56
|
|
209
|
+
+
|
|
210
|
+
+---
|
|
211
|
+
+
|
|
212
|
+
+[](https://www.npmjs.com/package/@link-assistant/agent/v/0.1.0)
|
|
213
|
+
+```
|
|
214
|
+
+
|
|
215
|
+
+**Key Changes:**
|
|
216
|
+
+
|
|
217
|
+
+1. ✅ NO "### Minor Changes" header
|
|
218
|
+
+2. ✅ Clean description starting directly with the content
|
|
219
|
+
+3. ✅ PR link detected and shown (#56)
|
|
220
|
+
+4. ✅ NPM badge included
|
|
221
|
+
+
|
|
222
|
+
+## Additional Research
|
|
223
|
+
+
|
|
224
|
+
+### Changesets Documentation
|
|
225
|
+
+
|
|
226
|
+
+According to [@changesets/cli](https://github.com/changesets/changesets) documentation:
|
|
227
|
+
+
|
|
228
|
+
+- Changesets generate CHANGELOG entries with section headers like "### Major Changes", "### Minor Changes", "### Patch Changes"
|
|
229
|
+
+- These are useful for the CHANGELOG.md file to organize changes by type
|
|
230
|
+
+- However, for GitHub Releases, these headers are redundant because:
|
|
231
|
+
+ - The release version already indicates the type (0.1.0 is a minor version)
|
|
232
|
+
+ - Users expect clean, concise release notes without internal categorization
|
|
233
|
+
+
|
|
234
|
+
+### Best Practices for Release Notes
|
|
235
|
+
+
|
|
236
|
+
+Research indicates that clean release notes should:
|
|
237
|
+
+
|
|
238
|
+
+1. Start directly with the content (no categorization headers)
|
|
239
|
+
+2. Include links to related PRs for context
|
|
240
|
+
+3. Include package version badge for quick reference
|
|
241
|
+
+4. Be formatted as clean markdown without internal structure headers
|
|
242
|
+
+
|
|
243
|
+
+## Files Modified
|
|
244
|
+
+
|
|
245
|
+
+1. `scripts/format-release-notes.mjs` - Fix regex patterns and remove section headers
|
|
246
|
+
+2. `docs/case-studies/issue-58/README.md` - This case study document
|
|
247
|
+
+3. `.changeset/fix-release-formatting.md` - Changeset for the fix
|
|
248
|
+
+
|
|
249
|
+
+## Verification Steps
|
|
250
|
+
+
|
|
251
|
+
+1. Run the fixed script against v0.1.0 release
|
|
252
|
+
+2. Verify "### Minor Changes" header is removed
|
|
253
|
+
+3. Verify PR #56 link is detected and added
|
|
254
|
+
+4. Verify NPM badge is added
|
|
255
|
+
+5. Check that formatting is preserved correctly
|
|
256
|
+
diff --git a/docs/case-studies/issue-58/release-v0.1.0-api.json b/docs/case-studies/issue-58/release-v0.1.0-api.json
|
|
257
|
+
new file mode 100644
|
|
258
|
+
index 0000000..5090394
|
|
259
|
+
--- /dev/null
|
|
260
|
+
+++ b/docs/case-studies/issue-58/release-v0.1.0-api.json
|
|
261
|
+
@@ -0,0 +1,42 @@
|
|
262
|
+
+{
|
|
263
|
+
+ "url": "https://api.github.com/repos/link-assistant/agent/releases/270875722",
|
|
264
|
+
+ "assets_url": "https://api.github.com/repos/link-assistant/agent/releases/270875722/assets",
|
|
265
|
+
+ "upload_url": "https://uploads.github.com/repos/link-assistant/agent/releases/270875722/assets{?name,label}",
|
|
266
|
+
+ "html_url": "https://github.com/link-assistant/agent/releases/tag/v0.1.0",
|
|
267
|
+
+ "id": 270875722,
|
|
268
|
+
+ "author": {
|
|
269
|
+
+ "login": "github-actions[bot]",
|
|
270
|
+
+ "id": 41898282,
|
|
271
|
+
+ "node_id": "MDM6Qm90NDE4OTgyODI=",
|
|
272
|
+
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
|
|
273
|
+
+ "gravatar_id": "",
|
|
274
|
+
+ "url": "https://api.github.com/users/github-actions%5Bbot%5D",
|
|
275
|
+
+ "html_url": "https://github.com/apps/github-actions",
|
|
276
|
+
+ "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",
|
|
277
|
+
+ "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
|
|
278
|
+
+ "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
|
|
279
|
+
+ "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
|
|
280
|
+
+ "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
|
|
281
|
+
+ "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",
|
|
282
|
+
+ "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",
|
|
283
|
+
+ "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
|
|
284
|
+
+ "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",
|
|
285
|
+
+ "type": "Bot",
|
|
286
|
+
+ "user_view_type": "public",
|
|
287
|
+
+ "site_admin": false
|
|
288
|
+
+ },
|
|
289
|
+
+ "node_id": "RE_kwDOQYTy3M4QJTxK",
|
|
290
|
+
+ "tag_name": "v0.1.0",
|
|
291
|
+
+ "target_commitish": "main",
|
|
292
|
+
+ "name": "0.1.0",
|
|
293
|
+
+ "draft": false,
|
|
294
|
+
+ "immutable": false,
|
|
295
|
+
+ "prerelease": false,
|
|
296
|
+
+ "created_at": "2025-12-16T20:24:31Z",
|
|
297
|
+
+ "updated_at": "2025-12-16T20:26:20Z",
|
|
298
|
+
+ "published_at": "2025-12-16T20:26:20Z",
|
|
299
|
+
+ "assets": [],
|
|
300
|
+
+ "tarball_url": "https://api.github.com/repos/link-assistant/agent/tarball/v0.1.0",
|
|
301
|
+
+ "zipball_url": "https://api.github.com/repos/link-assistant/agent/zipball/v0.1.0",
|
|
302
|
+
+ "body": "### Minor Changes\n\n- 2bcef5f: Add support for google/gemini-3-pro model alias\n - Added `google/gemini-3-pro` as an alias to `gemini-3-pro-preview`\n - Updated README.md with Google Gemini usage examples\n - Created comprehensive case study in docs/case-studies/issue-53/\n - Fixes ProviderModelNotFoundError when using google/gemini-3-pro\n\n This change allows users to use the commonly expected model name `gemini-3-pro` while maintaining compatibility with Google's official `gemini-3-pro-preview` identifier."
|
|
303
|
+
+}
|
|
304
|
+
diff --git a/docs/case-studies/issue-58/release-v0.1.0.json b/docs/case-studies/issue-58/release-v0.1.0.json
|
|
305
|
+
new file mode 100644
|
|
306
|
+
index 0000000..37be6d8
|
|
307
|
+
--- /dev/null
|
|
308
|
+
+++ b/docs/case-studies/issue-58/release-v0.1.0.json
|
|
309
|
+
@@ -0,0 +1,10 @@
|
|
310
|
+
+{
|
|
311
|
+
+ "author": { "id": "MDM6Qm90NDE4OTgyODI=", "login": "github-actions[bot]" },
|
|
312
|
+
+ "body": "### Minor Changes\n\n- 2bcef5f: Add support for google/gemini-3-pro model alias\n - Added `google/gemini-3-pro` as an alias to `gemini-3-pro-preview`\n - Updated README.md with Google Gemini usage examples\n - Created comprehensive case study in docs/case-studies/issue-53/\n - Fixes ProviderModelNotFoundError when using google/gemini-3-pro\n\n This change allows users to use the commonly expected model name `gemini-3-pro` while maintaining compatibility with Google's official `gemini-3-pro-preview` identifier.",
|
|
313
|
+
+ "createdAt": "2025-12-16T20:24:31Z",
|
|
314
|
+
+ "name": "0.1.0",
|
|
315
|
+
+ "publishedAt": "2025-12-16T20:26:20Z",
|
|
316
|
+
+ "tagName": "v0.1.0",
|
|
317
|
+
+ "targetCommitish": "main",
|
|
318
|
+
+ "url": "https://github.com/link-assistant/agent/releases/tag/v0.1.0"
|
|
319
|
+
+}
|
|
320
|
+
diff --git a/docs/case-studies/issue-58/template-format-release-notes.mjs b/docs/case-studies/issue-58/template-format-release-notes.mjs
|
|
321
|
+
new file mode 100644
|
|
322
|
+
index 0000000..913791a
|
|
323
|
+
--- /dev/null
|
|
324
|
+
+++ b/docs/case-studies/issue-58/template-format-release-notes.mjs
|
|
325
|
+
@@ -0,0 +1,212 @@
|
|
326
|
+
+#!/usr/bin/env node
|
|
327
|
+
+
|
|
328
|
+
+/**
|
|
329
|
+
+ * Script to format GitHub release notes with proper formatting:
|
|
330
|
+
+ * - Fix special characters like \n
|
|
331
|
+
+ * - Add link to PR that contains the release commit (if found)
|
|
332
|
+
+ * - Add shields.io NPM version badge
|
|
333
|
+
+ * - Format nicely with proper markdown
|
|
334
|
+
+ *
|
|
335
|
+
+ * IMPORTANT: Update the PACKAGE_NAME constant below to match your package.json
|
|
336
|
+
+ *
|
|
337
|
+
+ * PR Detection Logic:
|
|
338
|
+
+ * 1. Extract commit hash from changelog entry (if present)
|
|
339
|
+
+ * 2. Fall back to --commit-sha argument (passed from workflow)
|
|
340
|
+
+ * 3. Look up PRs that contain the commit via GitHub API
|
|
341
|
+
+ * 4. If no PR found, simply don't display any PR link (no guessing)
|
|
342
|
+
+ *
|
|
343
|
+
+ * Uses link-foundation libraries:
|
|
344
|
+
+ * - use-m: Dynamic package loading without package.json dependencies
|
|
345
|
+
+ * - command-stream: Modern shell command execution with streaming support
|
|
346
|
+
+ * - lino-arguments: Unified configuration from CLI args, env vars, and .lenv files
|
|
347
|
+
+ *
|
|
348
|
+
+ * Note: Uses --release-version instead of --version to avoid conflict with yargs' built-in --version flag.
|
|
349
|
+
+ */
|
|
350
|
+
+
|
|
351
|
+
+// TODO: Update this to match your package name in package.json
|
|
352
|
+
+const PACKAGE_NAME = 'my-package';
|
|
353
|
+
+
|
|
354
|
+
+// Load use-m dynamically
|
|
355
|
+
+const { use } = eval(
|
|
356
|
+
+ await (await fetch('https://unpkg.com/use-m/use.js')).text()
|
|
357
|
+
+);
|
|
358
|
+
+
|
|
359
|
+
+// Import link-foundation libraries
|
|
360
|
+
+const { $ } = await use('command-stream');
|
|
361
|
+
+const { makeConfig } = await use('lino-arguments');
|
|
362
|
+
+
|
|
363
|
+
+// Parse CLI arguments using lino-arguments
|
|
364
|
+
+// Note: Using --release-version instead of --version to avoid conflict with yargs' built-in --version flag
|
|
365
|
+
+const config = makeConfig({
|
|
366
|
+
+ yargs: ({ yargs, getenv }) =>
|
|
367
|
+
+ yargs
|
|
368
|
+
+ .option('release-version', {
|
|
369
|
+
+ type: 'string',
|
|
370
|
+
+ default: getenv('VERSION', ''),
|
|
371
|
+
+ describe: 'Version number (e.g., v0.8.36)',
|
|
372
|
+
+ })
|
|
373
|
+
+ .option('release-id', {
|
|
374
|
+
+ type: 'string',
|
|
375
|
+
+ default: getenv('RELEASE_ID', ''),
|
|
376
|
+
+ describe: 'GitHub release ID',
|
|
377
|
+
+ })
|
|
378
|
+
+ .option('repository', {
|
|
379
|
+
+ type: 'string',
|
|
380
|
+
+ default: getenv('REPOSITORY', ''),
|
|
381
|
+
+ describe: 'GitHub repository (e.g., owner/repo)',
|
|
382
|
+
+ })
|
|
383
|
+
+ .option('commit-sha', {
|
|
384
|
+
+ type: 'string',
|
|
385
|
+
+ default: getenv('COMMIT_SHA', ''),
|
|
386
|
+
+ describe: 'Commit SHA for PR detection',
|
|
387
|
+
+ }),
|
|
388
|
+
+});
|
|
389
|
+
+
|
|
390
|
+
+const releaseId = config.releaseId;
|
|
391
|
+
+const version = config.releaseVersion;
|
|
392
|
+
+const repository = config.repository;
|
|
393
|
+
+const passedCommitSha = config.commitSha;
|
|
394
|
+
+
|
|
395
|
+
+if (!releaseId || !version || !repository) {
|
|
396
|
+
+ console.error(
|
|
397
|
+
+ 'Usage: format-release-notes.mjs --release-id <releaseId> --release-version <version> --repository <repository> [--commit-sha <sha>]'
|
|
398
|
+
+ );
|
|
399
|
+
+ process.exit(1);
|
|
400
|
+
+}
|
|
401
|
+
+
|
|
402
|
+
+try {
|
|
403
|
+
+ // Get current release body
|
|
404
|
+
+ const result = await $`gh api repos/${repository}/releases/${releaseId}`.run({
|
|
405
|
+
+ capture: true,
|
|
406
|
+
+ });
|
|
407
|
+
+ const releaseData = JSON.parse(result.stdout);
|
|
408
|
+
+
|
|
409
|
+
+ const currentBody = releaseData.body || '';
|
|
410
|
+
+
|
|
411
|
+
+ // Skip if already formatted (has shields.io badge image)
|
|
412
|
+
+ if (currentBody.includes('img.shields.io')) {
|
|
413
|
+
+ console.log('ℹ️ Release notes already formatted');
|
|
414
|
+
+ process.exit(0);
|
|
415
|
+
+ }
|
|
416
|
+
+
|
|
417
|
+
+ // Extract the patch changes section
|
|
418
|
+
+ // This regex handles two formats:
|
|
419
|
+
+ // 1. With commit hash: "- abc1234: Description"
|
|
420
|
+
+ // 2. Without commit hash: "- Description"
|
|
421
|
+
+ const patchChangesMatchWithHash = currentBody.match(
|
|
422
|
+
+ /### Patch Changes\s*\n\s*-\s+([a-f0-9]+):\s+(.+?)$/s
|
|
423
|
+
+ );
|
|
424
|
+
+ const patchChangesMatchNoHash = currentBody.match(
|
|
425
|
+
+ /### Patch Changes\s*\n\s*-\s+(.+?)$/s
|
|
426
|
+
+ );
|
|
427
|
+
+
|
|
428
|
+
+ let commitHash = null;
|
|
429
|
+
+ let rawDescription = null;
|
|
430
|
+
+
|
|
431
|
+
+ if (patchChangesMatchWithHash) {
|
|
432
|
+
+ // Format: - abc1234: Description
|
|
433
|
+
+ [, commitHash, rawDescription] = patchChangesMatchWithHash;
|
|
434
|
+
+ } else if (patchChangesMatchNoHash) {
|
|
435
|
+
+ // Format: - Description (no commit hash)
|
|
436
|
+
+ [, rawDescription] = patchChangesMatchNoHash;
|
|
437
|
+
+ } else {
|
|
438
|
+
+ console.log('⚠️ Could not parse patch changes from release notes');
|
|
439
|
+
+ process.exit(0);
|
|
440
|
+
+ }
|
|
441
|
+
+
|
|
442
|
+
+ // Clean up the description:
|
|
443
|
+
+ // 1. Convert literal \n sequences (escaped newlines from GitHub API) to actual newlines
|
|
444
|
+
+ // 2. Remove leading/trailing quotes (including escaped quotes from command-stream shell escaping)
|
|
445
|
+
+ // 3. Remove any trailing npm package links or markdown that might be there
|
|
446
|
+
+ // 4. Normalize whitespace while preserving line breaks
|
|
447
|
+
+ const cleanDescription = rawDescription
|
|
448
|
+
+ .replace(/\\n/g, '\n') // Convert escaped \n to actual newlines
|
|
449
|
+
+ .replace(/^(\\['"])+/g, '') // Remove leading escaped quotes (e.g., \', \", \'', \'')
|
|
450
|
+
+ .replace(/(['"])+$/g, '') // Remove trailing unescaped quotes (e.g., ', ", '', '')
|
|
451
|
+
+ .replace(/^(['"])+/g, '') // Remove leading unescaped quotes
|
|
452
|
+
+ .replace(/📦.*$/s, '') // Remove any existing npm package info
|
|
453
|
+
+ .replace(/---.*$/s, '') // Remove any existing separators and everything after
|
|
454
|
+
+ .trim()
|
|
455
|
+
+ .split('\n') // Split by lines
|
|
456
|
+
+ .map((line) => line.trim()) // Trim whitespace from each line
|
|
457
|
+
+ .join('\n') // Rejoin with newlines
|
|
458
|
+
+ .replace(/\n{3,}/g, '\n\n'); // Normalize excessive blank lines (3+ becomes 2)
|
|
459
|
+
+
|
|
460
|
+
+ // Find the PR that contains the release commit
|
|
461
|
+
+ // Uses commit hash from changelog or passed commit SHA from workflow
|
|
462
|
+
+ let prNumber = null;
|
|
463
|
+
+
|
|
464
|
+
+ // Determine which commit SHA to use for PR lookup
|
|
465
|
+
+ const commitShaToLookup = commitHash || passedCommitSha;
|
|
466
|
+
+
|
|
467
|
+
+ if (commitShaToLookup) {
|
|
468
|
+
+ const source = commitHash ? 'changelog' : 'workflow';
|
|
469
|
+
+ console.log(
|
|
470
|
+
+ `ℹ️ Looking up PR for commit ${commitShaToLookup} (from ${source})`
|
|
471
|
+
+ );
|
|
472
|
+
+
|
|
473
|
+
+ try {
|
|
474
|
+
+ const prResult =
|
|
475
|
+
+ await $`gh api "repos/${repository}/commits/${commitShaToLookup}/pulls"`.run(
|
|
476
|
+
+ { capture: true }
|
|
477
|
+
+ );
|
|
478
|
+
+ const prsData = JSON.parse(prResult.stdout);
|
|
479
|
+
+
|
|
480
|
+
+ // Find the PR that's not the version bump PR (not "chore: version packages")
|
|
481
|
+
+ const relevantPr = prsData.find(
|
|
482
|
+
+ (pr) => !pr.title.includes('version packages')
|
|
483
|
+
+ );
|
|
484
|
+
+
|
|
485
|
+
+ if (relevantPr) {
|
|
486
|
+
+ prNumber = relevantPr.number;
|
|
487
|
+
+ console.log(`✅ Found PR #${prNumber} containing commit`);
|
|
488
|
+
+ } else if (prsData.length > 0) {
|
|
489
|
+
+ console.log(
|
|
490
|
+
+ '⚠️ Found PRs but all are version bump PRs, not linking any'
|
|
491
|
+
+ );
|
|
492
|
+
+ } else {
|
|
493
|
+
+ console.log(
|
|
494
|
+
+ 'ℹ️ No PR found containing this commit - not adding PR link'
|
|
495
|
+
+ );
|
|
496
|
+
+ }
|
|
497
|
+
+ } catch (error) {
|
|
498
|
+
+ console.log('⚠️ Could not find PR for commit', commitShaToLookup);
|
|
499
|
+
+ console.log(' Error:', error.message);
|
|
500
|
+
+ if (process.env.DEBUG) {
|
|
501
|
+
+ console.error(error);
|
|
502
|
+
+ }
|
|
503
|
+
+ }
|
|
504
|
+
+ } else {
|
|
505
|
+
+ // No commit hash available from any source
|
|
506
|
+
+ console.log('ℹ️ No commit SHA available - not adding PR link');
|
|
507
|
+
+ }
|
|
508
|
+
+
|
|
509
|
+
+ // Build formatted release notes
|
|
510
|
+
+ const versionWithoutV = version.replace(/^v/, '');
|
|
511
|
+
+ const npmBadge = `[](https://www.npmjs.com/package/${PACKAGE_NAME}/v/${versionWithoutV})`;
|
|
512
|
+
+
|
|
513
|
+
+ let formattedBody = `${cleanDescription}`;
|
|
514
|
+
+
|
|
515
|
+
+ // Add PR link if available
|
|
516
|
+
+ if (prNumber) {
|
|
517
|
+
+ formattedBody += `\n\n**Related Pull Request:** #${prNumber}`;
|
|
518
|
+
+ }
|
|
519
|
+
+
|
|
520
|
+
+ formattedBody += `\n\n---\n\n${npmBadge}`;
|
|
521
|
+
+
|
|
522
|
+
+ // Update the release using JSON input to properly handle special characters
|
|
523
|
+
+ const updatePayload = JSON.stringify({ body: formattedBody });
|
|
524
|
+
+ await $`gh api repos/${repository}/releases/${releaseId} -X PATCH --input -`.run(
|
|
525
|
+
+ { stdin: updatePayload }
|
|
526
|
+
+ );
|
|
527
|
+
+
|
|
528
|
+
+ console.log(`✅ Formatted release notes for v${versionWithoutV}`);
|
|
529
|
+
+ if (prNumber) {
|
|
530
|
+
+ console.log(` - Added link to PR #${prNumber}`);
|
|
531
|
+
+ }
|
|
532
|
+
+ console.log(' - Added shields.io npm badge');
|
|
533
|
+
+ console.log(' - Cleaned up formatting');
|
|
534
|
+
+} catch (error) {
|
|
535
|
+
+ console.error('❌ Error formatting release notes:', error.message);
|
|
536
|
+
+ process.exit(1);
|
|
537
|
+
+}
|
|
538
|
+
diff --git a/package-lock.json b/package-lock.json
|
|
539
|
+
index 8ec099f..3c851c6 100644
|
|
540
|
+
--- a/package-lock.json
|
|
541
|
+
+++ b/package-lock.json
|
|
542
|
+
@@ -1,12 +1,12 @@
|
|
543
|
+
{
|
|
544
|
+
"name": "@link-assistant/agent",
|
|
545
|
+
- "version": "0.0.17",
|
|
546
|
+
+ "version": "0.1.0",
|
|
547
|
+
"lockfileVersion": 3,
|
|
548
|
+
"requires": true,
|
|
549
|
+
"packages": {
|
|
550
|
+
"": {
|
|
551
|
+
"name": "@link-assistant/agent",
|
|
552
|
+
- "version": "0.0.17",
|
|
553
|
+
+ "version": "0.1.0",
|
|
554
|
+
"license": "Unlicense",
|
|
555
|
+
"dependencies": {
|
|
556
|
+
"@actions/core": "^1.11.1",
|
|
557
|
+
diff --git a/scripts/format-release-notes.mjs b/scripts/format-release-notes.mjs
|
|
558
|
+
index 76fef1c..da0eec4 100644
|
|
559
|
+
--- a/scripts/format-release-notes.mjs
|
|
560
|
+
+++ b/scripts/format-release-notes.mjs
|
|
561
|
+
@@ -89,28 +89,35 @@ try {
|
|
562
|
+
process.exit(0);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
- // Extract the patch changes section
|
|
566
|
+
- // This regex handles two formats:
|
|
567
|
+
- // 1. With commit hash: "- abc1234: Description"
|
|
568
|
+
- // 2. Without commit hash: "- Description"
|
|
569
|
+
- const patchChangesMatchWithHash = currentBody.match(
|
|
570
|
+
- /### Patch Changes\s*\n\s*-\s+([a-f0-9]+):\s+(.+?)$/s
|
|
571
|
+
- );
|
|
572
|
+
- const patchChangesMatchNoHash = currentBody.match(
|
|
573
|
+
- /### Patch Changes\s*\n\s*-\s+(.+?)$/s
|
|
574
|
+
- );
|
|
575
|
+
+ // Extract changes section (Major, Minor, or Patch)
|
|
576
|
+
+ // This regex handles multiple formats:
|
|
577
|
+
+ // 1. With commit hash: "### [Major|Minor|Patch] Changes\n- abc1234: Description"
|
|
578
|
+
+ // 2. Without commit hash: "### [Major|Minor|Patch] Changes\n- Description"
|
|
579
|
+
+ const changesPattern =
|
|
580
|
+
+ /### (Major|Minor|Patch) Changes\s*\n\s*-\s+(?:([a-f0-9]+):\s+)?(.+?)$/s;
|
|
581
|
+
+ const changesMatch = currentBody.match(changesPattern);
|
|
582
|
+
|
|
583
|
+
let commitHash = null;
|
|
584
|
+
let rawDescription = null;
|
|
585
|
+
-
|
|
586
|
+
- if (patchChangesMatchWithHash) {
|
|
587
|
+
- // Format: - abc1234: Description
|
|
588
|
+
- [, commitHash, rawDescription] = patchChangesMatchWithHash;
|
|
589
|
+
- } else if (patchChangesMatchNoHash) {
|
|
590
|
+
- // Format: - Description (no commit hash)
|
|
591
|
+
- [, rawDescription] = patchChangesMatchNoHash;
|
|
592
|
+
+ let changeType = null;
|
|
593
|
+
+
|
|
594
|
+
+ if (changesMatch) {
|
|
595
|
+
+ // Extract: [full match, changeType, commitHash (optional), description]
|
|
596
|
+
+ [, changeType, commitHash, rawDescription] = changesMatch;
|
|
597
|
+
+ console.log(`ℹ️ Found ${changeType} Changes section`);
|
|
598
|
+
+
|
|
599
|
+
+ // If commitHash is undefined and description contains it, try to extract
|
|
600
|
+
+ if (!commitHash && rawDescription) {
|
|
601
|
+
+ // This handles the case where description itself might be null/undefined
|
|
602
|
+
+ // and we need to safely check for commit hash at the start
|
|
603
|
+
+ const descWithHashMatch = rawDescription.match(/^([a-f0-9]+):\s+(.+)$/s);
|
|
604
|
+
+ if (descWithHashMatch) {
|
|
605
|
+
+ [, commitHash, rawDescription] = descWithHashMatch;
|
|
606
|
+
+ }
|
|
607
|
+
+ }
|
|
608
|
+
} else {
|
|
609
|
+
- console.log('⚠️ Could not parse patch changes from release notes');
|
|
610
|
+
+ console.log('⚠️ Could not parse changes from release notes');
|
|
611
|
+
+ console.log(' Looking for pattern: ### [Major|Minor|Patch] Changes');
|
|
612
|
+
process.exit(0);
|
|
613
|
+
}
|
|
614
|
+
|