gitverse-release 2.0.2 → 3.1.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/dist/cli.js +1307 -4
- package/dist/cli.js.map +30 -3
- package/dist/index.js +35 -20
- package/dist/index.js.map +6 -6
- package/dist/types.d.ts +4 -0
- package/dist/utils/changelog.d.ts +2 -2
- package/dist/utils/git.d.ts +7 -0
- package/package.json +5 -2
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,1310 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
+
for (let key of __getOwnPropNames(mod))
|
|
12
|
+
if (!__hasOwnProp.call(to, key))
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: () => mod[key],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
import { resolve as resolve2 } from "node:path";
|
|
23
|
+
|
|
24
|
+
// src/config.ts
|
|
25
|
+
import { readFile } from "node:fs/promises";
|
|
26
|
+
import { resolve } from "node:path";
|
|
27
|
+
var DEFAULT_CONFIG = {
|
|
28
|
+
changelog: {
|
|
29
|
+
showAuthor: true,
|
|
30
|
+
showHash: true,
|
|
31
|
+
types: {
|
|
32
|
+
build: "\uD83C\uDFD7️ Build System",
|
|
33
|
+
chore: "\uD83D\uDD27 Chores",
|
|
34
|
+
ci: "\uD83D\uDC77 CI/CD",
|
|
35
|
+
docs: "\uD83D\uDCDD Documentation",
|
|
36
|
+
feat: "✨ Features",
|
|
37
|
+
fix: "\uD83D\uDC1B Bug Fixes",
|
|
38
|
+
perf: "⚡ Performance",
|
|
39
|
+
refactor: "♻️ Refactoring",
|
|
40
|
+
revert: "⏪ Reverts",
|
|
41
|
+
style: "\uD83D\uDC84 Styling",
|
|
42
|
+
test: "✅ Tests"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
git: {
|
|
46
|
+
commitChanges: true,
|
|
47
|
+
commitMessage: "chore(release): {{package}} v{{version}} [skip ci]",
|
|
48
|
+
push: true,
|
|
49
|
+
tagMessage: "Release {{package}} v{{version}}"
|
|
50
|
+
},
|
|
51
|
+
monorepo: {
|
|
52
|
+
enabled: false,
|
|
53
|
+
packages: []
|
|
54
|
+
},
|
|
55
|
+
versioning: {
|
|
56
|
+
allowPrerelease: false,
|
|
57
|
+
prereleasePrefix: "beta",
|
|
58
|
+
tagPrefix: "v"
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
async function loadConfig(configPath) {
|
|
62
|
+
const path = configPath || ".gitversereleaserc.json";
|
|
63
|
+
const fullPath = resolve(process.cwd(), path);
|
|
64
|
+
try {
|
|
65
|
+
const content = await readFile(fullPath, "utf-8");
|
|
66
|
+
const userConfig = JSON.parse(content);
|
|
67
|
+
return mergeConfig(DEFAULT_CONFIG, userConfig);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
70
|
+
return DEFAULT_CONFIG;
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Failed to load config from ${fullPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function mergeConfig(defaults, user) {
|
|
76
|
+
return {
|
|
77
|
+
changelog: {
|
|
78
|
+
...defaults.changelog,
|
|
79
|
+
...user.changelog,
|
|
80
|
+
types: {
|
|
81
|
+
...defaults.changelog.types,
|
|
82
|
+
...user.changelog?.types
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
git: {
|
|
86
|
+
...defaults.git,
|
|
87
|
+
...user.git
|
|
88
|
+
},
|
|
89
|
+
monorepo: {
|
|
90
|
+
...defaults.monorepo,
|
|
91
|
+
...user.monorepo
|
|
92
|
+
},
|
|
93
|
+
versioning: {
|
|
94
|
+
...defaults.versioning,
|
|
95
|
+
...user.versioning
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function validateConfig(config) {
|
|
100
|
+
if (config.monorepo.enabled && config.monorepo.packages.length === 0) {
|
|
101
|
+
throw new Error("Monorepo mode is enabled but no packages are configured");
|
|
102
|
+
}
|
|
103
|
+
for (const pkg of config.monorepo.packages) {
|
|
104
|
+
if (!(pkg.name && pkg.path && pkg.packageName && pkg.tagPrefix)) {
|
|
105
|
+
throw new Error(`Invalid package configuration for ${pkg.name || "unknown"}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ../sdk/dist/api/organizations.js
|
|
111
|
+
class j {
|
|
112
|
+
client;
|
|
113
|
+
constructor(b) {
|
|
114
|
+
this.client = b;
|
|
115
|
+
}
|
|
116
|
+
async checkMembership(b, h) {
|
|
117
|
+
try {
|
|
118
|
+
return await this.client.get(`/orgs/${b}/members/${h}`), true;
|
|
119
|
+
} catch (d) {
|
|
120
|
+
if (d instanceof Error && d.message.includes("404"))
|
|
121
|
+
return false;
|
|
122
|
+
throw d;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ../sdk/dist/api/commits.js
|
|
128
|
+
class g {
|
|
129
|
+
client;
|
|
130
|
+
constructor(b) {
|
|
131
|
+
this.client = b;
|
|
132
|
+
}
|
|
133
|
+
list(b, d) {
|
|
134
|
+
return this.client.get(`/repos/${b}/${d}/commits`);
|
|
135
|
+
}
|
|
136
|
+
get(b, d, f) {
|
|
137
|
+
return this.client.get(`/repos/${b}/${d}/commits/${f}`);
|
|
138
|
+
}
|
|
139
|
+
create(b, d, f) {
|
|
140
|
+
return this.client.post(`/repos/${b}/${d}/git/commits`, f);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ../sdk/dist/api/actions.js
|
|
145
|
+
class v {
|
|
146
|
+
client;
|
|
147
|
+
constructor(b) {
|
|
148
|
+
this.client = b;
|
|
149
|
+
}
|
|
150
|
+
listOrgRunners(b) {
|
|
151
|
+
return this.client.get(`/orgs/${b}/actions/runners`);
|
|
152
|
+
}
|
|
153
|
+
createOrgRegistrationToken(b) {
|
|
154
|
+
return this.client.post(`/orgs/${b}/actions/runners/registration-token`, {});
|
|
155
|
+
}
|
|
156
|
+
getOrgRunner(b, h) {
|
|
157
|
+
return this.client.get(`/orgs/${b}/actions/runners/${h}`);
|
|
158
|
+
}
|
|
159
|
+
deleteOrgRunner(b, h) {
|
|
160
|
+
return this.client.delete(`/orgs/${b}/actions/runners/${h}`);
|
|
161
|
+
}
|
|
162
|
+
listRepoRunners(b, h) {
|
|
163
|
+
return this.client.get(`/repos/${b}/${h}/actions/runners`);
|
|
164
|
+
}
|
|
165
|
+
createRepoRegistrationToken(b, h) {
|
|
166
|
+
return this.client.post(`/repos/${b}/${h}/actions/runners/registration-token`, {});
|
|
167
|
+
}
|
|
168
|
+
getRepoRunner(b, h, j2) {
|
|
169
|
+
return this.client.get(`/repos/${b}/${h}/actions/runners/${j2}`);
|
|
170
|
+
}
|
|
171
|
+
deleteRepoRunner(b, h, j2) {
|
|
172
|
+
return this.client.delete(`/repos/${b}/${h}/actions/runners/${j2}`);
|
|
173
|
+
}
|
|
174
|
+
listOrgSecrets(b) {
|
|
175
|
+
return this.client.get(`/orgs/${b}/actions/secrets`);
|
|
176
|
+
}
|
|
177
|
+
getOrgSecret(b, h) {
|
|
178
|
+
return this.client.get(`/orgs/${b}/actions/secrets/${h}`);
|
|
179
|
+
}
|
|
180
|
+
createOrUpdateOrgSecret(b, h, j2) {
|
|
181
|
+
return this.client.put(`/orgs/${b}/actions/secrets/${h}`, j2);
|
|
182
|
+
}
|
|
183
|
+
deleteOrgSecret(b, h) {
|
|
184
|
+
return this.client.delete(`/orgs/${b}/actions/secrets/${h}`);
|
|
185
|
+
}
|
|
186
|
+
listRepoSecrets(b, h) {
|
|
187
|
+
return this.client.get(`/repos/${b}/${h}/actions/secrets`);
|
|
188
|
+
}
|
|
189
|
+
getRepoSecret(b, h, j2) {
|
|
190
|
+
return this.client.get(`/repos/${b}/${h}/actions/secrets/${j2}`);
|
|
191
|
+
}
|
|
192
|
+
createOrUpdateRepoSecret(b, h, j2, q) {
|
|
193
|
+
return this.client.put(`/repos/${b}/${h}/actions/secrets/${j2}`, q);
|
|
194
|
+
}
|
|
195
|
+
deleteRepoSecret(b, h, j2) {
|
|
196
|
+
return this.client.delete(`/repos/${b}/${h}/actions/secrets/${j2}`);
|
|
197
|
+
}
|
|
198
|
+
listOrgVariables(b) {
|
|
199
|
+
return this.client.get(`/orgs/${b}/actions/variables`);
|
|
200
|
+
}
|
|
201
|
+
createOrgVariable(b, h) {
|
|
202
|
+
return this.client.post(`/orgs/${b}/actions/variables`, h);
|
|
203
|
+
}
|
|
204
|
+
getOrgVariable(b, h) {
|
|
205
|
+
return this.client.get(`/orgs/${b}/actions/variables/${h}`);
|
|
206
|
+
}
|
|
207
|
+
deleteOrgVariable(b, h) {
|
|
208
|
+
return this.client.delete(`/orgs/${b}/actions/variables/${h}`);
|
|
209
|
+
}
|
|
210
|
+
updateOrgVariable(b, h, j2) {
|
|
211
|
+
return this.client.patch(`/orgs/${b}/actions/variables/${h}`, j2);
|
|
212
|
+
}
|
|
213
|
+
listRepoVariables(b, h) {
|
|
214
|
+
return this.client.get(`/repos/${b}/${h}/actions/variables`);
|
|
215
|
+
}
|
|
216
|
+
createRepoVariable(b, h, j2) {
|
|
217
|
+
return this.client.post(`/repos/${b}/${h}/actions/variables`, j2);
|
|
218
|
+
}
|
|
219
|
+
getRepoVariable(b, h, j2) {
|
|
220
|
+
return this.client.get(`/repos/${b}/${h}/actions/variables/${j2}`);
|
|
221
|
+
}
|
|
222
|
+
deleteRepoVariable(b, h, j2) {
|
|
223
|
+
return this.client.delete(`/repos/${b}/${h}/actions/variables/${j2}`);
|
|
224
|
+
}
|
|
225
|
+
updateRepoVariable(b, h, j2, q) {
|
|
226
|
+
return this.client.patch(`/repos/${b}/${h}/actions/variables/${j2}`, q);
|
|
227
|
+
}
|
|
228
|
+
listArtifacts(b, h) {
|
|
229
|
+
return this.client.get(`/repos/${b}/${h}/actions/artifacts`);
|
|
230
|
+
}
|
|
231
|
+
getArtifact(b, h, j2) {
|
|
232
|
+
return this.client.get(`/repos/${b}/${h}/actions/artifacts/${j2}`);
|
|
233
|
+
}
|
|
234
|
+
deleteArtifact(b, h, j2) {
|
|
235
|
+
return this.client.delete(`/repos/${b}/${h}/actions/artifacts/${j2}`);
|
|
236
|
+
}
|
|
237
|
+
downloadArtifact(b, h, j2) {
|
|
238
|
+
return this.client.get(`/repos/${b}/${h}/actions/artifacts/${j2}/zip`);
|
|
239
|
+
}
|
|
240
|
+
downloadArtifactRaw(b, h, j2) {
|
|
241
|
+
return this.client.get(`/repos/${b}/${h}/actions/artifacts/${j2}/zip/raw`);
|
|
242
|
+
}
|
|
243
|
+
getWorkflowDispatchInputs(b, h, j2) {
|
|
244
|
+
return this.client.get(`/repos/${b}/${h}/actions/workflows/${j2}/dispatches`);
|
|
245
|
+
}
|
|
246
|
+
dispatchWorkflow(b, h, j2, q) {
|
|
247
|
+
return this.client.post(`/repos/${b}/${h}/actions/workflows/${j2}/dispatches`, q);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ../sdk/dist/errors.js
|
|
252
|
+
class j2 extends Error {
|
|
253
|
+
status;
|
|
254
|
+
metadata;
|
|
255
|
+
constructor(b, f, h) {
|
|
256
|
+
super(f);
|
|
257
|
+
this.name = "GitVerseApiError", this.status = b, this.metadata = h, Object.setPrototypeOf(this, j2.prototype);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
class k extends j2 {
|
|
262
|
+
rateLimit;
|
|
263
|
+
constructor(b, f, h) {
|
|
264
|
+
super(429, b, h);
|
|
265
|
+
this.name = "RateLimitError", this.rateLimit = f, Object.setPrototypeOf(this, k.prototype);
|
|
266
|
+
}
|
|
267
|
+
getRetryAfterSeconds() {
|
|
268
|
+
return this.rateLimit.retryAfter;
|
|
269
|
+
}
|
|
270
|
+
getResetDate() {
|
|
271
|
+
return new Date(this.rateLimit.reset * 1000);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
class q {
|
|
276
|
+
currentVersion;
|
|
277
|
+
latestVersion;
|
|
278
|
+
decommissioning;
|
|
279
|
+
constructor(b, f, h) {
|
|
280
|
+
this.currentVersion = b, this.latestVersion = f, this.decommissioning = h;
|
|
281
|
+
}
|
|
282
|
+
getMessage() {
|
|
283
|
+
let b = `Используется устаревшая версия API: ${this.currentVersion}. Последняя версия: ${this.latestVersion}.`;
|
|
284
|
+
if (this.decommissioning)
|
|
285
|
+
b += ` Версия будет выведена из эксплуатации: ${this.decommissioning}.`;
|
|
286
|
+
return b;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ../sdk/dist/api/stars.js
|
|
291
|
+
class j3 {
|
|
292
|
+
client;
|
|
293
|
+
constructor(b) {
|
|
294
|
+
this.client = b;
|
|
295
|
+
}
|
|
296
|
+
list() {
|
|
297
|
+
return this.client.get("/user/starred");
|
|
298
|
+
}
|
|
299
|
+
async add(b, c) {
|
|
300
|
+
await this.client.put(`/user/starred/${b}/${c}`);
|
|
301
|
+
}
|
|
302
|
+
async check(b, c) {
|
|
303
|
+
try {
|
|
304
|
+
return await this.client.get(`/user/starred/${b}/${c}`), true;
|
|
305
|
+
} catch (f) {
|
|
306
|
+
if (f instanceof j2 && f.status === 404)
|
|
307
|
+
return false;
|
|
308
|
+
throw f;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async remove(b, c) {
|
|
312
|
+
await this.client.delete(`/user/starred/${b}/${c}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ../sdk/dist/api/issues.js
|
|
317
|
+
class A {
|
|
318
|
+
client;
|
|
319
|
+
constructor(c) {
|
|
320
|
+
this.client = c;
|
|
321
|
+
}
|
|
322
|
+
list(c, h, f) {
|
|
323
|
+
let j4 = new URLSearchParams;
|
|
324
|
+
if (f)
|
|
325
|
+
j4.append("state", f);
|
|
326
|
+
let k2 = j4.toString(), z = `/repos/${c}/${h}/issues${k2 ? `?${k2}` : ""}`;
|
|
327
|
+
return this.client.get(z);
|
|
328
|
+
}
|
|
329
|
+
get(c, h, f) {
|
|
330
|
+
return this.client.get(`/repos/${c}/${h}/issues/${f}`);
|
|
331
|
+
}
|
|
332
|
+
getComment(c, h, f) {
|
|
333
|
+
return this.client.get(`/repos/${c}/${h}/issues/comments/${f}`);
|
|
334
|
+
}
|
|
335
|
+
getComments(c, h, f) {
|
|
336
|
+
return this.client.get(`/repos/${c}/${h}/issues/${f}/comments`);
|
|
337
|
+
}
|
|
338
|
+
getLabels(c, h, f) {
|
|
339
|
+
return this.client.get(`/repos/${c}/${h}/issues/${f}/labels`);
|
|
340
|
+
}
|
|
341
|
+
getTimeline(c, h, f) {
|
|
342
|
+
return this.client.get(`/repos/${c}/${h}/issues/${f}/timeline`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ../sdk/dist/api/branches.js
|
|
347
|
+
class f {
|
|
348
|
+
client;
|
|
349
|
+
constructor(b) {
|
|
350
|
+
this.client = b;
|
|
351
|
+
}
|
|
352
|
+
list(b, d) {
|
|
353
|
+
return this.client.get(`/repos/${b}/${d}/branches`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ../sdk/dist/utils.js
|
|
358
|
+
var z = /^([a-z][a-z0-9+.-]*:\/\/[^/]+)\/([a-z][a-z0-9+.-]*:\/\/.+)$/i;
|
|
359
|
+
function E(j4) {
|
|
360
|
+
if (!j4)
|
|
361
|
+
return j4;
|
|
362
|
+
let k2 = j4.match(z);
|
|
363
|
+
if (k2?.[1] && k2?.[2]) {
|
|
364
|
+
let q2 = k2[1], v2 = k2[2];
|
|
365
|
+
if (v2.startsWith(q2))
|
|
366
|
+
return v2;
|
|
367
|
+
}
|
|
368
|
+
return j4;
|
|
369
|
+
}
|
|
370
|
+
function J(j4) {
|
|
371
|
+
let k2 = ["clone_url", "html_url", "url", "git_url", "mirror_url"], q2 = { ...j4 };
|
|
372
|
+
for (let v2 of k2)
|
|
373
|
+
if (typeof q2[v2] === "string")
|
|
374
|
+
q2[v2] = E(q2[v2]);
|
|
375
|
+
return q2;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ../sdk/dist/api/repositories.js
|
|
379
|
+
class z2 {
|
|
380
|
+
client;
|
|
381
|
+
constructor(g2) {
|
|
382
|
+
this.client = g2;
|
|
383
|
+
}
|
|
384
|
+
async get(g2, j4) {
|
|
385
|
+
let k2 = await this.client.get(`/repos/${g2}/${j4}`);
|
|
386
|
+
return J(k2);
|
|
387
|
+
}
|
|
388
|
+
delete(g2, j4) {
|
|
389
|
+
return this.client.delete(`/repos/${g2}/${j4}`);
|
|
390
|
+
}
|
|
391
|
+
async update(g2, j4, k2) {
|
|
392
|
+
let v2 = await this.client.patch(`/repos/${g2}/${j4}`, k2);
|
|
393
|
+
return J(v2);
|
|
394
|
+
}
|
|
395
|
+
compare(g2, j4, k2) {
|
|
396
|
+
return this.client.get(`/repos/${g2}/${j4}/compare/${k2}`);
|
|
397
|
+
}
|
|
398
|
+
getLanguages(g2, j4) {
|
|
399
|
+
return this.client.get(`/repos/${g2}/${j4}/languages`);
|
|
400
|
+
}
|
|
401
|
+
async listForAuthenticatedUser() {
|
|
402
|
+
return (await this.client.get("/user/repos")).map((j4) => J(j4));
|
|
403
|
+
}
|
|
404
|
+
async create(g2) {
|
|
405
|
+
let j4 = await this.client.post("/user/repos", g2);
|
|
406
|
+
return J(j4);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ../sdk/dist/api/collaborators.js
|
|
411
|
+
class h {
|
|
412
|
+
client;
|
|
413
|
+
constructor(d) {
|
|
414
|
+
this.client = d;
|
|
415
|
+
}
|
|
416
|
+
list(d, f2) {
|
|
417
|
+
return this.client.get(`/repos/${d}/${f2}/collaborators`);
|
|
418
|
+
}
|
|
419
|
+
add(d, f2, g2) {
|
|
420
|
+
return this.client.put(`/repos/${d}/${f2}/collaborators/${g2}`, {});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// ../sdk/dist/api/contents.js
|
|
425
|
+
class j4 {
|
|
426
|
+
client;
|
|
427
|
+
constructor(b) {
|
|
428
|
+
this.client = b;
|
|
429
|
+
}
|
|
430
|
+
get(b, d, f2) {
|
|
431
|
+
return this.client.get(`/repos/${b}/${d}/contents/${f2}`);
|
|
432
|
+
}
|
|
433
|
+
createFile(b, d, f2, g2) {
|
|
434
|
+
return this.client.put(`/repos/${b}/${d}/contents/${f2}`, g2);
|
|
435
|
+
}
|
|
436
|
+
updateFile(b, d, f2, g2) {
|
|
437
|
+
return this.client.put(`/repos/${b}/${d}/contents/${f2}`, g2);
|
|
438
|
+
}
|
|
439
|
+
deleteFile(b, d, f2, g2) {
|
|
440
|
+
return this.client.delete(`/repos/${b}/${d}/contents/${f2}`, g2);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// ../sdk/dist/api/teams.js
|
|
445
|
+
class j5 {
|
|
446
|
+
client;
|
|
447
|
+
constructor(b) {
|
|
448
|
+
this.client = b;
|
|
449
|
+
}
|
|
450
|
+
list(b) {
|
|
451
|
+
return this.client.get(`/orgs/${b}/teams`);
|
|
452
|
+
}
|
|
453
|
+
getInvitations(b, d) {
|
|
454
|
+
return this.client.get(`/orgs/${b}/teams/${d}/invitations`);
|
|
455
|
+
}
|
|
456
|
+
getMembers(b, d) {
|
|
457
|
+
return this.client.get(`/orgs/${b}/teams/${d}/members`);
|
|
458
|
+
}
|
|
459
|
+
addRepository(b, d, f2, h2) {
|
|
460
|
+
return this.client.put(`/orgs/${b}/teams/${d}/repos/${f2}/${h2}`, {});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// ../sdk/dist/api/git.js
|
|
465
|
+
class g2 {
|
|
466
|
+
client;
|
|
467
|
+
constructor(b) {
|
|
468
|
+
this.client = b;
|
|
469
|
+
}
|
|
470
|
+
createRef(b, d, f2) {
|
|
471
|
+
return this.client.post(`/repos/${b}/${d}/git/refs`, f2);
|
|
472
|
+
}
|
|
473
|
+
createTree(b, d, f2) {
|
|
474
|
+
return this.client.post(`/repos/${b}/${d}/git/trees`, f2);
|
|
475
|
+
}
|
|
476
|
+
getTree(b, d, f2) {
|
|
477
|
+
return this.client.get(`/repos/${b}/${d}/git/trees/${f2}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// ../sdk/dist/api/releases.js
|
|
482
|
+
class k2 {
|
|
483
|
+
client;
|
|
484
|
+
constructor(b) {
|
|
485
|
+
this.client = b;
|
|
486
|
+
}
|
|
487
|
+
list(b, f2) {
|
|
488
|
+
return this.client.get(`/repos/${b}/${f2}/releases`);
|
|
489
|
+
}
|
|
490
|
+
create(b, f2, h2) {
|
|
491
|
+
return this.client.post(`/repos/${b}/${f2}/releases`, h2);
|
|
492
|
+
}
|
|
493
|
+
getByTag(b, f2, h2) {
|
|
494
|
+
return this.client.get(`/repos/${b}/${f2}/releases/tags/${h2}`);
|
|
495
|
+
}
|
|
496
|
+
deleteByTag(b, f2, h2) {
|
|
497
|
+
return this.client.delete(`/repos/${b}/${f2}/releases/tags/${h2}`);
|
|
498
|
+
}
|
|
499
|
+
get(b, f2, h2) {
|
|
500
|
+
return this.client.get(`/repos/${b}/${f2}/releases/${h2}`);
|
|
501
|
+
}
|
|
502
|
+
delete(b, f2, h2) {
|
|
503
|
+
return this.client.delete(`/repos/${b}/${f2}/releases/${h2}`);
|
|
504
|
+
}
|
|
505
|
+
update(b, f2, h2, j6) {
|
|
506
|
+
return this.client.patch(`/repos/${b}/${f2}/releases/${h2}`, j6);
|
|
507
|
+
}
|
|
508
|
+
getAssets(b, f2, h2) {
|
|
509
|
+
return this.client.get(`/repos/${b}/${f2}/releases/${h2}/assets`);
|
|
510
|
+
}
|
|
511
|
+
uploadAsset(b, f2, h2, j6) {
|
|
512
|
+
return this.client.post(`/repos/${b}/${f2}/releases/${h2}/assets`, j6);
|
|
513
|
+
}
|
|
514
|
+
deleteAsset(b, f2, h2, j6) {
|
|
515
|
+
return this.client.delete(`/repos/${b}/${f2}/releases/${h2}/assets/${j6}`);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// ../sdk/dist/api/pulls.js
|
|
520
|
+
class v2 {
|
|
521
|
+
client;
|
|
522
|
+
constructor(d) {
|
|
523
|
+
this.client = d;
|
|
524
|
+
}
|
|
525
|
+
create(d, g3, f2) {
|
|
526
|
+
return this.client.post(`/repos/${d}/${g3}/pulls`, f2);
|
|
527
|
+
}
|
|
528
|
+
get(d, g3, f2) {
|
|
529
|
+
return this.client.get(`/repos/${d}/${g3}/pulls/${f2}`);
|
|
530
|
+
}
|
|
531
|
+
list(d, g3, f2) {
|
|
532
|
+
let k3 = new URL(`/repos/${d}/${g3}/pulls`, "http://localhost");
|
|
533
|
+
if (f2)
|
|
534
|
+
k3.searchParams.set("state", f2);
|
|
535
|
+
return this.client.get(k3.href.replace("http://localhost", ""));
|
|
536
|
+
}
|
|
537
|
+
update(d, g3, f2, j6) {
|
|
538
|
+
return this.client.patch(`/repos/${d}/${g3}/pulls/${f2}`, j6);
|
|
539
|
+
}
|
|
540
|
+
getFiles(d, g3, f2) {
|
|
541
|
+
return this.client.get(`/repos/${d}/${g3}/pulls/${f2}/files`);
|
|
542
|
+
}
|
|
543
|
+
updateBranch(d, g3, f2) {
|
|
544
|
+
return this.client.put(`/repos/${d}/${g3}/pulls/${f2}/update-branch`, {});
|
|
545
|
+
}
|
|
546
|
+
getCommits(d, g3, f2) {
|
|
547
|
+
return this.client.get(`/repos/${d}/${g3}/pulls/${f2}/commits`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// ../sdk/dist/api/forks.js
|
|
552
|
+
class k3 {
|
|
553
|
+
client;
|
|
554
|
+
constructor(b) {
|
|
555
|
+
this.client = b;
|
|
556
|
+
}
|
|
557
|
+
async create(b, g3, h2) {
|
|
558
|
+
let j6 = await this.client.post(`/repos/${b}/${g3}/forks`, h2);
|
|
559
|
+
return J(j6);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// ../sdk/dist/client.js
|
|
564
|
+
var F = { DELETE: "DELETE", GET: "GET", PATCH: "PATCH", POST: "POST", PUT: "PUT" };
|
|
565
|
+
|
|
566
|
+
class Y {
|
|
567
|
+
baseUrl;
|
|
568
|
+
token;
|
|
569
|
+
apiVersion;
|
|
570
|
+
onApiVersionWarning;
|
|
571
|
+
constructor(j6 = {}) {
|
|
572
|
+
this.baseUrl = j6.baseUrl || "https://api.gitverse.ru", this.token = j6.token, this.apiVersion = j6.apiVersion || "1";
|
|
573
|
+
}
|
|
574
|
+
setToken(j6) {
|
|
575
|
+
this.token = j6;
|
|
576
|
+
}
|
|
577
|
+
extractRateLimitInfo(j6) {
|
|
578
|
+
let q2 = j6.get("GitVerse-RateLimit-Limit"), x = j6.get("GitVerse-RateLimit-Remaining"), z3 = j6.get("GitVerse-RateLimit-Retry-After"), B = j6.get("Gitverse-Ratelimit-Reset");
|
|
579
|
+
if (!(q2 && x && z3 && B))
|
|
580
|
+
return;
|
|
581
|
+
return { limit: Number.parseInt(q2, 10), remaining: Number.parseInt(x, 10), reset: Number.parseInt(B, 10), retryAfter: Number.parseInt(z3, 10) };
|
|
582
|
+
}
|
|
583
|
+
extractApiVersionInfo(j6) {
|
|
584
|
+
let q2 = j6.get("Gitverse-Api-Version"), x = j6.get("Gitverse-Api-Latest-Version"), z3 = j6.get("Gitverse-Api-Deprecation") === "true", B = j6.get("Gitverse-Api-Decommissioning");
|
|
585
|
+
if (!(q2 && x))
|
|
586
|
+
return;
|
|
587
|
+
return { decommissioning: B || undefined, deprecated: z3, latestVersion: x, version: q2 };
|
|
588
|
+
}
|
|
589
|
+
extractMetadata(j6) {
|
|
590
|
+
let q2 = this.extractRateLimitInfo(j6), x = this.extractApiVersionInfo(j6);
|
|
591
|
+
if (x?.deprecated && this.onApiVersionWarning) {
|
|
592
|
+
let z3 = new q(x.version, x.latestVersion, x.decommissioning);
|
|
593
|
+
this.onApiVersionWarning(z3);
|
|
594
|
+
}
|
|
595
|
+
return { apiVersion: x, rateLimit: q2 };
|
|
596
|
+
}
|
|
597
|
+
async request(j6, q2, x) {
|
|
598
|
+
let z3 = j6.startsWith("/") ? j6.slice(1) : j6, B = `${this.baseUrl}/${z3}`, J2 = new Headers;
|
|
599
|
+
if (J2.set("Content-Type", "application/json"), J2.set("Accept", `application/vnd.gitverse.object+json; version=${this.apiVersion}`), this.token)
|
|
600
|
+
J2.set("Authorization", `Bearer ${this.token}`);
|
|
601
|
+
let X = { body: x ? JSON.stringify(x) : undefined, headers: J2, method: q2 }, D = await fetch(B, X), K = this.extractMetadata(D.headers), N;
|
|
602
|
+
try {
|
|
603
|
+
N = await D.json();
|
|
604
|
+
} catch {
|
|
605
|
+
N = undefined;
|
|
606
|
+
}
|
|
607
|
+
if (!D.ok) {
|
|
608
|
+
let O = N?.message || D.statusText;
|
|
609
|
+
if (D.status === 429 && K.rateLimit)
|
|
610
|
+
throw new k(O || "Превышен лимит запросов. Попробуйте позже.", K.rateLimit, K);
|
|
611
|
+
throw new j2(D.status, O, K);
|
|
612
|
+
}
|
|
613
|
+
return N;
|
|
614
|
+
}
|
|
615
|
+
get(j6) {
|
|
616
|
+
return this.request(j6, F.GET);
|
|
617
|
+
}
|
|
618
|
+
post(j6, q2) {
|
|
619
|
+
return this.request(j6, F.POST, q2);
|
|
620
|
+
}
|
|
621
|
+
put(j6, q2) {
|
|
622
|
+
return this.request(j6, F.PUT, q2);
|
|
623
|
+
}
|
|
624
|
+
delete(j6, q2) {
|
|
625
|
+
return this.request(j6, F.DELETE, q2);
|
|
626
|
+
}
|
|
627
|
+
patch(j6, q2) {
|
|
628
|
+
return this.request(j6, F.PATCH, q2);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// ../sdk/dist/api/users.js
|
|
633
|
+
class d {
|
|
634
|
+
client;
|
|
635
|
+
constructor(b) {
|
|
636
|
+
this.client = b;
|
|
637
|
+
}
|
|
638
|
+
getCurrent() {
|
|
639
|
+
return this.client.get("/user");
|
|
640
|
+
}
|
|
641
|
+
getByUsername(b) {
|
|
642
|
+
return this.client.get(`/users/${b}`);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// ../sdk/dist/api/emails.js
|
|
647
|
+
class c {
|
|
648
|
+
client;
|
|
649
|
+
constructor(b) {
|
|
650
|
+
this.client = b;
|
|
651
|
+
}
|
|
652
|
+
list() {
|
|
653
|
+
return this.client.get("/user/emails");
|
|
654
|
+
}
|
|
655
|
+
add(b) {
|
|
656
|
+
return this.client.post("/user/emails", b);
|
|
657
|
+
}
|
|
658
|
+
remove(b) {
|
|
659
|
+
return this.client.delete("/user/emails", b);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// ../sdk/dist/index.js
|
|
664
|
+
class P {
|
|
665
|
+
client;
|
|
666
|
+
users;
|
|
667
|
+
repos;
|
|
668
|
+
contents;
|
|
669
|
+
pulls;
|
|
670
|
+
forks;
|
|
671
|
+
emails;
|
|
672
|
+
issues;
|
|
673
|
+
stars;
|
|
674
|
+
branches;
|
|
675
|
+
commits;
|
|
676
|
+
collaborators;
|
|
677
|
+
organizations;
|
|
678
|
+
teams;
|
|
679
|
+
releases;
|
|
680
|
+
git;
|
|
681
|
+
actions;
|
|
682
|
+
constructor(d2 = {}) {
|
|
683
|
+
this.client = new Y(d2), this.users = new d(this.client), this.repos = new z2(this.client), this.contents = new j4(this.client), this.pulls = new v2(this.client), this.forks = new k3(this.client), this.emails = new c(this.client), this.issues = new A(this.client), this.stars = new j3(this.client), this.branches = new f(this.client), this.commits = new g(this.client), this.collaborators = new h(this.client), this.organizations = new j(this.client), this.teams = new j5(this.client), this.releases = new k2(this.client), this.git = new g2(this.client), this.actions = new v(this.client);
|
|
684
|
+
}
|
|
685
|
+
setToken(d2) {
|
|
686
|
+
return this.client.setToken(d2), this;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// src/gitverse.ts
|
|
691
|
+
class GitVerseReleaseClient {
|
|
692
|
+
client;
|
|
693
|
+
repoInfo;
|
|
694
|
+
constructor(token, repoInfo) {
|
|
695
|
+
this.client = new P({ token });
|
|
696
|
+
this.repoInfo = repoInfo;
|
|
697
|
+
}
|
|
698
|
+
async createRelease(tag, name, body, options = {}) {
|
|
699
|
+
const { owner, repo } = this.repoInfo;
|
|
700
|
+
try {
|
|
701
|
+
await this.client.releases.create(owner, repo, {
|
|
702
|
+
body,
|
|
703
|
+
draft: options.draft,
|
|
704
|
+
name,
|
|
705
|
+
prerelease: options.prerelease,
|
|
706
|
+
tag_name: tag
|
|
707
|
+
});
|
|
708
|
+
return `${this.repoInfo.url}/releases/tag/${tag}`;
|
|
709
|
+
} catch (error) {
|
|
710
|
+
throw new Error(`Failed to create GitVerse release: ${error instanceof Error ? error.message : String(error)}`);
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
async releaseExists(tag) {
|
|
714
|
+
const { owner, repo } = this.repoInfo;
|
|
715
|
+
try {
|
|
716
|
+
await this.client.releases.getByTag(owner, repo, tag);
|
|
717
|
+
return true;
|
|
718
|
+
} catch {
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
async getRelease(tag) {
|
|
723
|
+
const { owner, repo } = this.repoInfo;
|
|
724
|
+
return await this.client.releases.getByTag(owner, repo, tag);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
function createGitVerseClient(repoInfo) {
|
|
728
|
+
const token = process.env.GITVERSE_TOKEN;
|
|
729
|
+
if (!token) {
|
|
730
|
+
throw new Error("GITVERSE_TOKEN environment variable is required for creating releases");
|
|
731
|
+
}
|
|
732
|
+
return new GitVerseReleaseClient(token, repoInfo);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// src/utils/changelog.ts
|
|
736
|
+
import { readFile as readFile2, writeFile } from "node:fs/promises";
|
|
737
|
+
|
|
738
|
+
// src/utils/parser.ts
|
|
739
|
+
var COMMIT_REGEX = /^(?<type>\w+)(?:\((?<scope>[^)]+)\))?(?<breaking>!)?: (?<subject>.+)$/;
|
|
740
|
+
function parseCommit(rawCommit) {
|
|
741
|
+
const lines = rawCommit.split(`
|
|
742
|
+
`);
|
|
743
|
+
if (lines.length < 5) {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
const [hash, shortHash, author, email, dateStr, ...messageLines] = lines;
|
|
747
|
+
if (!(hash && shortHash && author && email && dateStr)) {
|
|
748
|
+
return null;
|
|
749
|
+
}
|
|
750
|
+
const message = messageLines.join(`
|
|
751
|
+
`).trim();
|
|
752
|
+
const messageParts = message.split(`
|
|
753
|
+
`);
|
|
754
|
+
const firstLine = messageParts[0];
|
|
755
|
+
const bodyLines = messageParts.slice(1);
|
|
756
|
+
if (!firstLine) {
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
759
|
+
const match = firstLine.match(COMMIT_REGEX);
|
|
760
|
+
if (!match?.groups) {
|
|
761
|
+
return null;
|
|
762
|
+
}
|
|
763
|
+
const { type, scope, breaking, subject } = match.groups;
|
|
764
|
+
if (!(type && subject)) {
|
|
765
|
+
return null;
|
|
766
|
+
}
|
|
767
|
+
const body = bodyLines.join(`
|
|
768
|
+
`).trim();
|
|
769
|
+
const hasBreakingInBody = body.includes("BREAKING CHANGE:") || body.includes("BREAKING-CHANGE:");
|
|
770
|
+
return {
|
|
771
|
+
author,
|
|
772
|
+
body: body || undefined,
|
|
773
|
+
breaking: !!breaking || hasBreakingInBody,
|
|
774
|
+
date: new Date(dateStr),
|
|
775
|
+
email,
|
|
776
|
+
footer: undefined,
|
|
777
|
+
hash,
|
|
778
|
+
raw: message,
|
|
779
|
+
scope: scope || undefined,
|
|
780
|
+
shortHash,
|
|
781
|
+
subject,
|
|
782
|
+
type
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
function parseCommits(rawCommits) {
|
|
786
|
+
return rawCommits.map((raw) => parseCommit(raw)).filter((commit) => commit !== null);
|
|
787
|
+
}
|
|
788
|
+
function groupCommitsByType(commits) {
|
|
789
|
+
const groups = {};
|
|
790
|
+
for (const commit of commits) {
|
|
791
|
+
if (!groups[commit.type]) {
|
|
792
|
+
groups[commit.type] = [];
|
|
793
|
+
}
|
|
794
|
+
groups[commit.type]?.push(commit);
|
|
795
|
+
}
|
|
796
|
+
return groups;
|
|
797
|
+
}
|
|
798
|
+
function hasBreakingChanges(commits) {
|
|
799
|
+
return commits.some((commit) => commit.breaking);
|
|
800
|
+
}
|
|
801
|
+
function hasFeatures(commits) {
|
|
802
|
+
return commits.some((commit) => commit.type === "feat");
|
|
803
|
+
}
|
|
804
|
+
function hasFixes(commits) {
|
|
805
|
+
return commits.some((commit) => commit.type === "fix");
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// src/utils/changelog.ts
|
|
809
|
+
function generateChangelog(options, config) {
|
|
810
|
+
const { version, commits, date = new Date, repoUrl } = options;
|
|
811
|
+
const sections = [];
|
|
812
|
+
const dateStr = date.toISOString().split("T")[0];
|
|
813
|
+
sections.push(`## [${version}] - ${dateStr}`);
|
|
814
|
+
sections.push("");
|
|
815
|
+
const grouped = groupCommitsByType(commits);
|
|
816
|
+
const typeOrder = ["feat", "fix", "perf", "refactor", "docs", "test", "build", "ci", "chore", "style", "revert"];
|
|
817
|
+
const breakingCommits = commits.filter((c2) => c2.breaking);
|
|
818
|
+
if (breakingCommits.length > 0) {
|
|
819
|
+
sections.push("### ⚠️ BREAKING CHANGES");
|
|
820
|
+
sections.push("");
|
|
821
|
+
for (const commit of breakingCommits) {
|
|
822
|
+
sections.push(formatCommit(commit, config, repoUrl));
|
|
823
|
+
}
|
|
824
|
+
sections.push("");
|
|
825
|
+
}
|
|
826
|
+
for (const type of typeOrder) {
|
|
827
|
+
const typeCommits = grouped[type]?.filter((c2) => !c2.breaking);
|
|
828
|
+
if (!typeCommits || typeCommits.length === 0) {
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
const title = config.types[type] || type.toUpperCase();
|
|
832
|
+
sections.push(`### ${title}`);
|
|
833
|
+
sections.push("");
|
|
834
|
+
for (const commit of typeCommits) {
|
|
835
|
+
sections.push(formatCommit(commit, config, repoUrl));
|
|
836
|
+
}
|
|
837
|
+
sections.push("");
|
|
838
|
+
}
|
|
839
|
+
return sections.join(`
|
|
840
|
+
`);
|
|
841
|
+
}
|
|
842
|
+
function formatCommit(commit, config, repoUrl) {
|
|
843
|
+
const parts = [];
|
|
844
|
+
let message = commit.subject;
|
|
845
|
+
if (commit.scope) {
|
|
846
|
+
message = `**${commit.scope}:** ${message}`;
|
|
847
|
+
}
|
|
848
|
+
parts.push(`- ${message}`);
|
|
849
|
+
if (config.showHash && repoUrl) {
|
|
850
|
+
parts.push(`([${commit.shortHash}](${repoUrl}/commit/${commit.hash}))`);
|
|
851
|
+
} else if (config.showHash) {
|
|
852
|
+
parts.push(`(${commit.shortHash})`);
|
|
853
|
+
}
|
|
854
|
+
if (config.showAuthor) {
|
|
855
|
+
parts.push(`by @${commit.author}`);
|
|
856
|
+
}
|
|
857
|
+
return parts.join(" ");
|
|
858
|
+
}
|
|
859
|
+
async function updateChangelogFile(changelogPath, newEntry) {
|
|
860
|
+
let existingContent = "";
|
|
861
|
+
try {
|
|
862
|
+
existingContent = await readFile2(changelogPath, "utf-8");
|
|
863
|
+
} catch (error) {
|
|
864
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
865
|
+
existingContent = `# Changelog
|
|
866
|
+
|
|
867
|
+
All notable changes to this project will be documented in this file.
|
|
868
|
+
|
|
869
|
+
`;
|
|
870
|
+
} else {
|
|
871
|
+
throw error;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
const lines = existingContent.split(`
|
|
875
|
+
`);
|
|
876
|
+
let insertIndex = 0;
|
|
877
|
+
for (let i = 0;i < lines.length; i++) {
|
|
878
|
+
const currentLine = lines[i];
|
|
879
|
+
const prevLine = lines[i - 1];
|
|
880
|
+
if (currentLine?.startsWith("## ")) {
|
|
881
|
+
insertIndex = i;
|
|
882
|
+
break;
|
|
883
|
+
}
|
|
884
|
+
if (i > 0 && currentLine?.trim() === "" && prevLine?.trim() !== "") {
|
|
885
|
+
insertIndex = i + 1;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (insertIndex === 0) {
|
|
889
|
+
insertIndex = lines.length;
|
|
890
|
+
}
|
|
891
|
+
lines.splice(insertIndex, 0, newEntry);
|
|
892
|
+
await writeFile(changelogPath, lines.join(`
|
|
893
|
+
`));
|
|
894
|
+
}
|
|
895
|
+
function generateReleaseNotes(commits, config, repoUrl) {
|
|
896
|
+
const sections = [];
|
|
897
|
+
const breakingCommits = commits.filter((c2) => c2.breaking);
|
|
898
|
+
if (breakingCommits.length > 0) {
|
|
899
|
+
sections.push("⚠️ BREAKING CHANGES");
|
|
900
|
+
sections.push("");
|
|
901
|
+
for (const commit of breakingCommits) {
|
|
902
|
+
sections.push(formatCommit(commit, config, repoUrl));
|
|
903
|
+
}
|
|
904
|
+
sections.push("");
|
|
905
|
+
}
|
|
906
|
+
const grouped = groupCommitsByType(commits.filter((c2) => !c2.breaking));
|
|
907
|
+
const typeOrder = ["feat", "fix", "perf", "refactor", "docs", "test", "build", "ci", "chore", "style", "revert"];
|
|
908
|
+
for (const type of typeOrder) {
|
|
909
|
+
const typeCommits = grouped[type];
|
|
910
|
+
if (!typeCommits || typeCommits.length === 0) {
|
|
911
|
+
continue;
|
|
912
|
+
}
|
|
913
|
+
const title = config.types[type] || type.toUpperCase();
|
|
914
|
+
sections.push(title);
|
|
915
|
+
sections.push("");
|
|
916
|
+
for (const commit of typeCommits) {
|
|
917
|
+
sections.push(formatCommit(commit, config, repoUrl));
|
|
918
|
+
}
|
|
919
|
+
sections.push("");
|
|
920
|
+
}
|
|
921
|
+
return sections.join(`
|
|
922
|
+
`).trim();
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// src/utils/git.ts
|
|
926
|
+
import { exec } from "node:child_process";
|
|
927
|
+
import { promisify } from "node:util";
|
|
928
|
+
var execAsync = promisify(exec);
|
|
929
|
+
var GITVERSE_URL_REGEX_1 = /gitverse\.ru[:/]([^/]+)\/([^/.]+)(\.git)?$/;
|
|
930
|
+
var GITVERSE_URL_REGEX_2 = /gitverse\.ru\/([^/]+)\/([^/.]+)(\.git)?$/;
|
|
931
|
+
async function git(command) {
|
|
932
|
+
const { stdout } = await execAsync(`git ${command}`);
|
|
933
|
+
return stdout.trim();
|
|
934
|
+
}
|
|
935
|
+
async function getRepoInfo() {
|
|
936
|
+
if (process.env.GITVERSE_ACTIONS === "true" && process.env.GITHUB_REPOSITORY) {
|
|
937
|
+
const fullName = process.env.GITHUB_REPOSITORY;
|
|
938
|
+
const parts = fullName.split("/");
|
|
939
|
+
if (parts.length === 2 && parts[0] && parts[1]) {
|
|
940
|
+
const owner2 = parts[0];
|
|
941
|
+
const repo2 = parts[1];
|
|
942
|
+
const branch2 = process.env.GITHUB_REF_NAME || "main";
|
|
943
|
+
return {
|
|
944
|
+
branch: branch2,
|
|
945
|
+
fullName,
|
|
946
|
+
owner: owner2,
|
|
947
|
+
repo: repo2,
|
|
948
|
+
url: `https://gitverse.ru/${owner2}/${repo2}`
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
const url = await git("remote get-url origin");
|
|
953
|
+
const match = url.match(GITVERSE_URL_REGEX_1) || url.match(GITVERSE_URL_REGEX_2);
|
|
954
|
+
if (!(match?.[1] && match[2])) {
|
|
955
|
+
throw new Error(`Unable to parse GitVerse repository from URL: ${url}`);
|
|
956
|
+
}
|
|
957
|
+
const owner = match[1];
|
|
958
|
+
const repo = match[2];
|
|
959
|
+
const branch = await git("branch --show-current");
|
|
960
|
+
return {
|
|
961
|
+
branch,
|
|
962
|
+
fullName: `${owner}/${repo}`,
|
|
963
|
+
owner,
|
|
964
|
+
repo,
|
|
965
|
+
url: `https://gitverse.ru/${owner}/${repo}`
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
async function getLatestTag(prefix) {
|
|
969
|
+
try {
|
|
970
|
+
const tags = await git(`tag --sort=-v:refname --list "${prefix}*"`);
|
|
971
|
+
const tagList = tags.split(`
|
|
972
|
+
`).filter((tag) => tag.length > 0);
|
|
973
|
+
return tagList.length > 0 ? tagList[0] ?? null : null;
|
|
974
|
+
} catch {
|
|
975
|
+
return null;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
async function getCommitsSinceTag(tagPrefix, path) {
|
|
979
|
+
const latestTag = await getLatestTag(tagPrefix);
|
|
980
|
+
let range;
|
|
981
|
+
if (latestTag) {
|
|
982
|
+
range = `${latestTag}..HEAD`;
|
|
983
|
+
} else {
|
|
984
|
+
range = "HEAD";
|
|
985
|
+
}
|
|
986
|
+
const format = "%H%n%h%n%an%n%ae%n%ai%n%B%n==END==";
|
|
987
|
+
const pathFilter = path ? `-- ${path}` : "";
|
|
988
|
+
const log = await git(`log ${range} --format="${format}" ${pathFilter}`);
|
|
989
|
+
const commits = log.split(`
|
|
990
|
+
==END==`).map((commit) => commit.trim()).filter((commit) => commit.length > 0 && commit !== "==END==");
|
|
991
|
+
return commits;
|
|
992
|
+
}
|
|
993
|
+
async function getCurrentVersion(packagePath) {
|
|
994
|
+
const { readFile: readFile3 } = await import("node:fs/promises");
|
|
995
|
+
const { resolve: resolve2 } = await import("node:path");
|
|
996
|
+
const pkgJsonPath = resolve2(packagePath, "package.json");
|
|
997
|
+
const content = await readFile3(pkgJsonPath, "utf-8");
|
|
998
|
+
const pkgJson = JSON.parse(content);
|
|
999
|
+
if (!pkgJson.version) {
|
|
1000
|
+
throw new Error(`No version found in ${pkgJsonPath}`);
|
|
1001
|
+
}
|
|
1002
|
+
return pkgJson.version;
|
|
1003
|
+
}
|
|
1004
|
+
async function getPackageInfo(packagePath) {
|
|
1005
|
+
const { readFile: readFile3 } = await import("node:fs/promises");
|
|
1006
|
+
const { resolve: resolve2 } = await import("node:path");
|
|
1007
|
+
const pkgJsonPath = resolve2(packagePath, "package.json");
|
|
1008
|
+
const content = await readFile3(pkgJsonPath, "utf-8");
|
|
1009
|
+
const pkgJson = JSON.parse(content);
|
|
1010
|
+
if (!pkgJson.name) {
|
|
1011
|
+
throw new Error(`No name found in ${pkgJsonPath}`);
|
|
1012
|
+
}
|
|
1013
|
+
if (!pkgJson.version) {
|
|
1014
|
+
throw new Error(`No version found in ${pkgJsonPath}`);
|
|
1015
|
+
}
|
|
1016
|
+
return {
|
|
1017
|
+
name: pkgJson.name,
|
|
1018
|
+
version: pkgJson.version
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
async function updatePackageVersion(packagePath, newVersion) {
|
|
1022
|
+
const { readFile: readFile3, writeFile: writeFile2 } = await import("node:fs/promises");
|
|
1023
|
+
const { resolve: resolve2 } = await import("node:path");
|
|
1024
|
+
const pkgJsonPath = resolve2(packagePath, "package.json");
|
|
1025
|
+
const content = await readFile3(pkgJsonPath, "utf-8");
|
|
1026
|
+
const pkgJson = JSON.parse(content);
|
|
1027
|
+
pkgJson.version = newVersion;
|
|
1028
|
+
await writeFile2(pkgJsonPath, `${JSON.stringify(pkgJson, null, 2)}
|
|
1029
|
+
`);
|
|
1030
|
+
}
|
|
1031
|
+
async function createCommit(message, files) {
|
|
1032
|
+
for (const file of files) {
|
|
1033
|
+
await git(`add "${file}"`);
|
|
1034
|
+
}
|
|
1035
|
+
await git(`commit -m "${message}"`);
|
|
1036
|
+
}
|
|
1037
|
+
async function createTag(tag, message) {
|
|
1038
|
+
await git(`tag -a "${tag}" -m "${message}"`);
|
|
1039
|
+
}
|
|
1040
|
+
async function pushChanges(tag) {
|
|
1041
|
+
await git("push");
|
|
1042
|
+
if (tag) {
|
|
1043
|
+
await git(`push origin "${tag}"`);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
async function isWorkingTreeClean() {
|
|
1047
|
+
try {
|
|
1048
|
+
const status = await git("status --porcelain");
|
|
1049
|
+
return status.length === 0;
|
|
1050
|
+
} catch {
|
|
1051
|
+
return false;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
async function tagExists(tag) {
|
|
1055
|
+
try {
|
|
1056
|
+
await git(`rev-parse "${tag}"`);
|
|
1057
|
+
return true;
|
|
1058
|
+
} catch {
|
|
1059
|
+
return false;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
// src/utils/version.ts
|
|
1064
|
+
var VERSION_REGEX = /^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/;
|
|
1065
|
+
var PRERELEASE_INCREMENT_REGEX = /^(.+)\.(\d+)$/;
|
|
1066
|
+
function parseVersion(version) {
|
|
1067
|
+
const v3 = version.startsWith("v") ? version.slice(1) : version;
|
|
1068
|
+
const match = v3.match(VERSION_REGEX);
|
|
1069
|
+
if (!(match?.[1] && match[2] && match[3])) {
|
|
1070
|
+
throw new Error(`Invalid version format: ${version}`);
|
|
1071
|
+
}
|
|
1072
|
+
return {
|
|
1073
|
+
major: Number.parseInt(match[1], 10),
|
|
1074
|
+
minor: Number.parseInt(match[2], 10),
|
|
1075
|
+
patch: Number.parseInt(match[3], 10),
|
|
1076
|
+
prerelease: match[4]
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
function formatVersion(ver) {
|
|
1080
|
+
let result = `${ver.major}.${ver.minor}.${ver.patch}`;
|
|
1081
|
+
if (ver.prerelease) {
|
|
1082
|
+
result += `-${ver.prerelease}`;
|
|
1083
|
+
}
|
|
1084
|
+
return result;
|
|
1085
|
+
}
|
|
1086
|
+
function determineBumpType(commits) {
|
|
1087
|
+
if (commits.length === 0) {
|
|
1088
|
+
return null;
|
|
1089
|
+
}
|
|
1090
|
+
if (hasBreakingChanges(commits)) {
|
|
1091
|
+
return "major";
|
|
1092
|
+
}
|
|
1093
|
+
if (hasFeatures(commits)) {
|
|
1094
|
+
return "minor";
|
|
1095
|
+
}
|
|
1096
|
+
if (hasFixes(commits)) {
|
|
1097
|
+
return "patch";
|
|
1098
|
+
}
|
|
1099
|
+
return "patch";
|
|
1100
|
+
}
|
|
1101
|
+
function bumpVersion(currentVersion, bumpType, prereleasePrefix) {
|
|
1102
|
+
const ver = parseVersion(currentVersion);
|
|
1103
|
+
switch (bumpType) {
|
|
1104
|
+
case "major":
|
|
1105
|
+
ver.major += 1;
|
|
1106
|
+
ver.minor = 0;
|
|
1107
|
+
ver.patch = 0;
|
|
1108
|
+
ver.prerelease = undefined;
|
|
1109
|
+
break;
|
|
1110
|
+
case "minor":
|
|
1111
|
+
ver.minor += 1;
|
|
1112
|
+
ver.patch = 0;
|
|
1113
|
+
ver.prerelease = undefined;
|
|
1114
|
+
break;
|
|
1115
|
+
case "patch":
|
|
1116
|
+
ver.patch += 1;
|
|
1117
|
+
ver.prerelease = undefined;
|
|
1118
|
+
break;
|
|
1119
|
+
case "prerelease":
|
|
1120
|
+
if (ver.prerelease) {
|
|
1121
|
+
const match = ver.prerelease.match(PRERELEASE_INCREMENT_REGEX);
|
|
1122
|
+
if (match?.[1] && match[2]) {
|
|
1123
|
+
const prefix = match[1];
|
|
1124
|
+
const num = Number.parseInt(match[2], 10);
|
|
1125
|
+
ver.prerelease = `${prefix}.${num + 1}`;
|
|
1126
|
+
} else {
|
|
1127
|
+
ver.prerelease = `${ver.prerelease}.1`;
|
|
1128
|
+
}
|
|
1129
|
+
} else {
|
|
1130
|
+
ver.patch += 1;
|
|
1131
|
+
ver.prerelease = `${prereleasePrefix || "beta"}.0`;
|
|
1132
|
+
}
|
|
1133
|
+
break;
|
|
1134
|
+
}
|
|
1135
|
+
return formatVersion(ver);
|
|
1136
|
+
}
|
|
1137
|
+
function calculateVersionBump(currentVersion, commits, forceVersion, prerelease) {
|
|
1138
|
+
const bumpType = prerelease ? "prerelease" : determineBumpType(commits) || "patch";
|
|
1139
|
+
const newVersion = forceVersion || bumpVersion(currentVersion, bumpType, prerelease);
|
|
1140
|
+
return {
|
|
1141
|
+
bumpType,
|
|
1142
|
+
commits,
|
|
1143
|
+
currentVersion,
|
|
1144
|
+
hasBreaking: hasBreakingChanges(commits),
|
|
1145
|
+
hasFeatures: hasFeatures(commits),
|
|
1146
|
+
hasFixes: hasFixes(commits),
|
|
1147
|
+
newVersion
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
// src/index.ts
|
|
1152
|
+
function printDryRunInfo(pkg, currentVersion, versionBump, tag, commits, changelogEntry) {
|
|
1153
|
+
console.log(`
|
|
1154
|
+
\uD83D\uDD0D DRY RUN MODE - No changes will be made
|
|
1155
|
+
`);
|
|
1156
|
+
console.log(`\uD83D\uDCE6 Package: ${pkg.packageName}`);
|
|
1157
|
+
console.log(`\uD83D\uDCC8 Version: ${currentVersion} → ${versionBump.newVersion}`);
|
|
1158
|
+
console.log(`\uD83C\uDFF7️ Tag: ${tag}`);
|
|
1159
|
+
console.log(`\uD83D\uDCAC Commits: ${commits.length}`);
|
|
1160
|
+
console.log(`
|
|
1161
|
+
\uD83D\uDCDD CHANGELOG:
|
|
1162
|
+
`);
|
|
1163
|
+
console.log(changelogEntry);
|
|
1164
|
+
}
|
|
1165
|
+
function printSuccessInfo(pkg, currentVersion, newVersion, tag, releaseUrl) {
|
|
1166
|
+
console.log(`
|
|
1167
|
+
✅ Release created successfully!
|
|
1168
|
+
`);
|
|
1169
|
+
console.log(`\uD83D\uDCE6 Package: ${pkg.packageName}`);
|
|
1170
|
+
console.log(`\uD83D\uDCC8 Version: ${currentVersion} → ${newVersion}`);
|
|
1171
|
+
console.log(`\uD83C\uDFF7️ Tag: ${tag}`);
|
|
1172
|
+
if (releaseUrl) {
|
|
1173
|
+
console.log(`\uD83C\uDF10 Release: ${releaseUrl}`);
|
|
1174
|
+
}
|
|
1175
|
+
console.log("");
|
|
1176
|
+
}
|
|
1177
|
+
async function updatePackageFiles(pkg, newVersion, changelogEntry) {
|
|
1178
|
+
await updatePackageVersion(pkg.path, newVersion);
|
|
1179
|
+
const changelogPath = resolve2(pkg.path, pkg.changelog);
|
|
1180
|
+
await updateChangelogFile(changelogPath, changelogEntry);
|
|
1181
|
+
return changelogPath;
|
|
1182
|
+
}
|
|
1183
|
+
async function collectCommits(pkg, options, warnings) {
|
|
1184
|
+
const rawCommits = await getCommitsSinceTag(pkg.tagPrefix, pkg.path);
|
|
1185
|
+
if (rawCommits.length === 0 && !options.version) {
|
|
1186
|
+
throw new Error(`No commits found since last release for ${pkg.packageName}`);
|
|
1187
|
+
}
|
|
1188
|
+
const commits = parseCommits(rawCommits);
|
|
1189
|
+
if (commits.length === 0 && !options.version) {
|
|
1190
|
+
warnings.push("No conventional commits found, but will proceed with patch bump");
|
|
1191
|
+
}
|
|
1192
|
+
return commits;
|
|
1193
|
+
}
|
|
1194
|
+
function resolvePrereleaseTag(options, config) {
|
|
1195
|
+
if (typeof options.prerelease === "string") {
|
|
1196
|
+
return options.prerelease;
|
|
1197
|
+
}
|
|
1198
|
+
if (options.prerelease) {
|
|
1199
|
+
return config.versioning.prereleasePrefix;
|
|
1200
|
+
}
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
async function createGitVerseRelease(options, repoInfo, commits, config, pkg, versionBump, tag, warnings) {
|
|
1204
|
+
if (options.noRelease) {
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
try {
|
|
1208
|
+
const gitverseClient = createGitVerseClient(repoInfo);
|
|
1209
|
+
const releaseNotes = generateReleaseNotes(commits, config.changelog, repoInfo.url);
|
|
1210
|
+
return await gitverseClient.createRelease(tag, `${pkg.packageName} v${versionBump.newVersion}`, releaseNotes, {
|
|
1211
|
+
prerelease: !!options.prerelease
|
|
1212
|
+
});
|
|
1213
|
+
} catch (error) {
|
|
1214
|
+
warnings.push(`Failed to create GitVerse release: ${error instanceof Error ? error.message : String(error)}`);
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
async function performGitOperations(config, options, pkg, newVersion, tag, changelogPath) {
|
|
1219
|
+
if (config.git.commitChanges && !options.noCommit) {
|
|
1220
|
+
const commitMessage = config.git.commitMessage.replace("{{package}}", pkg.name).replace("{{version}}", newVersion);
|
|
1221
|
+
await createCommit(commitMessage, [resolve2(pkg.path, "package.json"), changelogPath]);
|
|
1222
|
+
}
|
|
1223
|
+
if (!options.noTag) {
|
|
1224
|
+
const tagMessage = config.git.tagMessage.replace("{{package}}", pkg.name).replace("{{version}}", newVersion);
|
|
1225
|
+
await createTag(tag, tagMessage);
|
|
1226
|
+
}
|
|
1227
|
+
if (config.git.push && !options.noPush) {
|
|
1228
|
+
await pushChanges(options.noTag ? undefined : tag);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
async function release(packageName, options = {}) {
|
|
1232
|
+
const result = {
|
|
1233
|
+
errors: [],
|
|
1234
|
+
newVersion: "",
|
|
1235
|
+
oldVersion: "",
|
|
1236
|
+
packageName: packageName || "unknown",
|
|
1237
|
+
success: false,
|
|
1238
|
+
warnings: []
|
|
1239
|
+
};
|
|
1240
|
+
try {
|
|
1241
|
+
const config = await loadConfig(options.config);
|
|
1242
|
+
validateConfig(config);
|
|
1243
|
+
const repoInfo = await getRepoInfo();
|
|
1244
|
+
const pkg = await resolvePackage(config, packageName);
|
|
1245
|
+
result.packageName = pkg.packageName;
|
|
1246
|
+
if (!(options.dryRun || await isWorkingTreeClean())) {
|
|
1247
|
+
throw new Error("Working tree is not clean. Please commit or stash your changes.");
|
|
1248
|
+
}
|
|
1249
|
+
const currentVersion = await getCurrentVersion(pkg.path);
|
|
1250
|
+
result.oldVersion = currentVersion;
|
|
1251
|
+
const commits = await collectCommits(pkg, options, result.warnings);
|
|
1252
|
+
const prereleaseTag = resolvePrereleaseTag(options, config);
|
|
1253
|
+
const versionBump = calculateVersionBump(currentVersion, commits, options.version, prereleaseTag);
|
|
1254
|
+
result.newVersion = versionBump.newVersion;
|
|
1255
|
+
const tag = `${pkg.tagPrefix}${versionBump.newVersion}`;
|
|
1256
|
+
result.tag = tag;
|
|
1257
|
+
if (await tagExists(tag)) {
|
|
1258
|
+
throw new Error(`Tag ${tag} already exists`);
|
|
1259
|
+
}
|
|
1260
|
+
const changelogEntry = generateChangelog({
|
|
1261
|
+
commits,
|
|
1262
|
+
date: new Date,
|
|
1263
|
+
repoUrl: repoInfo.url,
|
|
1264
|
+
version: versionBump.newVersion
|
|
1265
|
+
}, config.changelog);
|
|
1266
|
+
if (options.dryRun) {
|
|
1267
|
+
printDryRunInfo(pkg, currentVersion, versionBump, tag, commits, changelogEntry);
|
|
1268
|
+
result.success = true;
|
|
1269
|
+
return result;
|
|
1270
|
+
}
|
|
1271
|
+
const changelogPath = await updatePackageFiles(pkg, versionBump.newVersion, changelogEntry);
|
|
1272
|
+
await performGitOperations(config, options, pkg, versionBump.newVersion, tag, changelogPath);
|
|
1273
|
+
result.releaseUrl = await createGitVerseRelease(options, repoInfo, commits, config, pkg, versionBump, tag, result.warnings);
|
|
1274
|
+
result.success = true;
|
|
1275
|
+
printSuccessInfo(pkg, currentVersion, versionBump.newVersion, tag, result.releaseUrl);
|
|
1276
|
+
return result;
|
|
1277
|
+
} catch (error) {
|
|
1278
|
+
result.success = false;
|
|
1279
|
+
result.errors.push(error instanceof Error ? error.message : String(error));
|
|
1280
|
+
console.error(`
|
|
1281
|
+
❌ Release failed:
|
|
1282
|
+
`);
|
|
1283
|
+
console.error(error);
|
|
1284
|
+
console.error("");
|
|
1285
|
+
return result;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
async function resolvePackage(config, packageName) {
|
|
1289
|
+
if (!config.monorepo.enabled) {
|
|
1290
|
+
const pkgInfo = await getPackageInfo(".");
|
|
1291
|
+
return {
|
|
1292
|
+
changelog: "CHANGELOG.md",
|
|
1293
|
+
name: "main",
|
|
1294
|
+
packageName: pkgInfo.name,
|
|
1295
|
+
path: ".",
|
|
1296
|
+
tagPrefix: config.versioning.tagPrefix
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
if (!packageName) {
|
|
1300
|
+
throw new Error("Package name is required in monorepo mode. Use --package <name>");
|
|
1301
|
+
}
|
|
1302
|
+
const pkg = config.monorepo.packages.find((p) => p.name === packageName);
|
|
1303
|
+
if (!pkg) {
|
|
1304
|
+
throw new Error(`Package "${packageName}" not found in config. Available packages: ${config.monorepo.packages.map((p) => p.name).join(", ")}`);
|
|
1305
|
+
}
|
|
1306
|
+
return pkg;
|
|
1307
|
+
}
|
|
5
1308
|
|
|
6
1309
|
// src/cli.ts
|
|
7
1310
|
import { parseArgs } from "node:util";
|
|
@@ -115,4 +1418,4 @@ async function main() {
|
|
|
115
1418
|
}
|
|
116
1419
|
main();
|
|
117
1420
|
|
|
118
|
-
//# debugId=
|
|
1421
|
+
//# debugId=6005E5D83DA9623E64756E2164756E21
|