0
# Utilities
1
2
Helper functions for URL parsing, templating, error handling, and GitHub-specific operations. These utilities support the core plugin functionality with specialized operations for GitHub integration.
3
4
## Capabilities
5
6
### GitHub URL Parsing
7
8
Parses various GitHub repository URL formats to extract owner and repository names.
9
10
```javascript { .api }
11
/**
12
* Parses GitHub repository URLs to extract owner and repo names
13
* @param repositoryUrl - Git repository URL in various formats
14
* @returns Object containing owner and repo, or empty object if parsing fails
15
*/
16
function parseGitHubUrl(repositoryUrl: string): { owner?: string; repo?: string };
17
```
18
19
**Supported URL Formats:**
20
- HTTPS: `https://github.com/owner/repo.git`
21
- SSH: `git@github.com:owner/repo.git`
22
- GitHub Enterprise: `https://github.company.com/owner/repo.git`
23
- No protocol: `github.com/owner/repo`
24
- With authentication: `https://user:token@github.com/owner/repo.git`
25
26
**Usage Examples:**
27
28
```javascript
29
import parseGitHubUrl from "@semantic-release/github/lib/parse-github-url.js";
30
31
// Standard GitHub URLs
32
parseGitHubUrl("https://github.com/semantic-release/github.git");
33
// Returns: { owner: "semantic-release", repo: "github" }
34
35
parseGitHubUrl("git@github.com:semantic-release/github.git");
36
// Returns: { owner: "semantic-release", repo: "github" }
37
38
// GitHub Enterprise
39
parseGitHubUrl("https://github.company.com/team/project.git");
40
// Returns: { owner: "team", repo: "project" }
41
42
// With authentication
43
parseGitHubUrl("https://user:token@github.com/owner/repo.git");
44
// Returns: { owner: "owner", repo: "repo" }
45
46
// Invalid URLs
47
parseGitHubUrl("not-a-git-url");
48
// Returns: {}
49
50
parseGitHubUrl("https://gitlab.com/owner/repo.git");
51
// Returns: {} (not a GitHub URL)
52
```
53
54
### Comment Generation
55
56
Template-based comment generation for success and failure scenarios.
57
58
```javascript { .api }
59
/**
60
* Generates success comment content for resolved issues and PRs
61
* @param issue - GitHub issue or PR object
62
* @param releaseInfos - Array of release information objects with URL and name
63
* @param nextRelease - Next release information with version
64
* @returns Rendered comment content as string
65
*/
66
function getSuccessComment(issue: Issue, releaseInfos: ReleaseInfo[], nextRelease: NextRelease): string;
67
68
/**
69
* Generates failure comment content for release failures
70
* @param branch - Branch information object with name
71
* @param errors - Array of semantic-release errors that caused the failure
72
* @returns Rendered comment content as string
73
*/
74
function getFailComment(branch: Branch, errors: SemanticReleaseError[]): string;
75
```
76
77
**Template Variables Available:**
78
- `nextRelease`: Version, tag, name, notes, channel
79
- `branch`: Branch name and channel information
80
- `lastRelease`: Previous release information
81
- `commits`: Array of commits in the release
82
- `releases`: Array of published releases
83
- `errors`: Array of errors (in failure comments)
84
85
**Usage Examples:**
86
87
```javascript
88
import getSuccessComment from "@semantic-release/github/lib/get-success-comment.js";
89
import getFailComment from "@semantic-release/github/lib/get-fail-comment.js";
90
91
// Success comment generation
92
const successTemplate = `
93
🎉 This issue has been resolved in version ${nextRelease.version}
94
95
**Release Information:**
96
- **Version:** ${nextRelease.version}
97
- **Tag:** ${nextRelease.gitTag}
98
- **Release Notes:** [View on GitHub](${releases[0].url})
99
100
The fix is now available for installation.
101
`;
102
103
const successComment = getSuccessComment(successTemplate, {
104
nextRelease: {
105
version: "1.2.0",
106
gitTag: "v1.2.0",
107
name: "1.2.0",
108
notes: "Bug fixes and improvements"
109
},
110
releases: [{ url: "https://github.com/owner/repo/releases/tag/v1.2.0" }]
111
});
112
113
// Failure comment generation
114
const failTemplate = `
115
❌ The automated release failed on branch \`${branch.name}\`.
116
117
**Error Details:**
118
${errors.map(error => \`- \${error.message}\`).join('\\n')}
119
120
**Troubleshooting:**
121
1. Check the [build logs](${env.BUILD_URL || 'CI system'})
122
2. Verify GitHub token permissions
123
3. Review the configuration for errors
124
125
This issue will be automatically updated when the release is retried.
126
`;
127
128
const failComment = getFailComment(failTemplate, {
129
branch: { name: "main" },
130
errors: [
131
new Error("GitHub token expired"),
132
new Error("Network timeout during asset upload")
133
],
134
env: { BUILD_URL: "https://ci.example.com/build/123" }
135
});
136
```
137
138
### Release Link Generation
139
140
Generates formatted markdown links for releases across multiple channels.
141
142
```javascript { .api }
143
/**
144
* Generates release link markdown from release information
145
* @param releases - Array of release objects with URLs and metadata
146
* @returns Formatted markdown string with release links
147
*/
148
function getReleaseLinks(releases: Release[]): string;
149
150
interface Release {
151
url: string;
152
name?: string;
153
channel?: string;
154
}
155
```
156
157
**Usage Examples:**
158
159
```javascript
160
import getReleaseLinks from "@semantic-release/github/lib/get-release-links.js";
161
162
// Single release
163
const singleRelease = getReleaseLinks([
164
{ url: "https://github.com/owner/repo/releases/tag/v1.0.0", name: "1.0.0" }
165
]);
166
// Returns: "- [1.0.0](https://github.com/owner/repo/releases/tag/v1.0.0)"
167
168
// Multiple releases with channels
169
const multipleReleases = getReleaseLinks([
170
{
171
url: "https://github.com/owner/repo/releases/tag/v1.0.0",
172
name: "1.0.0",
173
channel: "stable"
174
},
175
{
176
url: "https://github.com/owner/repo/releases/tag/v1.1.0-beta.1",
177
name: "1.1.0-beta.1",
178
channel: "beta"
179
}
180
]);
181
// Returns: "- [1.0.0](https://github.com/owner/repo/releases/tag/v1.0.0) (stable)\n- [1.1.0-beta.1](https://github.com/owner/repo/releases/tag/v1.1.0-beta.1) (beta)"
182
```
183
184
### Issue Discovery
185
186
Finds semantic-release related issues in the repository for management and updates.
187
188
```javascript { .api }
189
/**
190
* Finds semantic-release related issues in the repository
191
* @param octokit - Configured Octokit instance
192
* @param logger - Logger instance for debug output
193
* @param labels - Array of label names to filter by (optional)
194
* @param owner - Repository owner
195
* @param repo - Repository name
196
* @returns Promise resolving to array of matching issues
197
*/
198
async function findSRIssues(
199
octokit: Octokit,
200
logger: Logger,
201
labels: string[] | undefined,
202
owner: string,
203
repo: string
204
): Promise<Issue[]>;
205
206
interface Issue {
207
id: number;
208
number: number;
209
title: string;
210
body: string;
211
state: "open" | "closed";
212
labels: string[];
213
assignees: string[];
214
html_url: string;
215
}
216
```
217
218
**Issue Detection Logic:**
219
- Searches for issues containing the semantic-release identifier comment
220
- Filters by semantic-release labels
221
- Identifies both open and closed failure issues
222
- Returns issues that may need updates or closure
223
224
**Usage Examples:**
225
226
```javascript
227
import findSRIssues from "@semantic-release/github/lib/find-sr-issues.js";
228
import { SemanticReleaseOctokit } from "@semantic-release/github/lib/octokit.js";
229
230
const octokit = new SemanticReleaseOctokit({ auth: process.env.GITHUB_TOKEN });
231
232
// Find existing semantic-release issues
233
const issues = await findSRIssues(
234
octokit,
235
console, // logger
236
["semantic-release"], // labels
237
"semantic-release", // owner
238
"github" // repo
239
);
240
241
console.log(`Found ${issues.length} semantic-release issues`);
242
243
// Process issues
244
for (const issue of issues) {
245
if (issue.state === "open") {
246
console.log(`Open failure issue: ${issue.title} (#${issue.number})`);
247
} else {
248
console.log(`Resolved issue: ${issue.title} (#${issue.number})`);
249
}
250
}
251
```
252
253
### Error Handling
254
255
Creates standardized semantic-release error objects with detailed messages and documentation links.
256
257
```javascript { .api }
258
/**
259
* Creates semantic-release error objects with standardized format
260
* @param code - Error code identifying the specific error type
261
* @param context - Additional context data for error message templating
262
* @returns Formatted error object with message and details
263
*/
264
function getError(code: string, context?: any): SemanticReleaseError;
265
266
interface SemanticReleaseError extends Error {
267
name: string;
268
message: string;
269
details: string;
270
code: string;
271
}
272
```
273
274
**Available Error Codes:**
275
- `EINVALIDASSETS` - Invalid assets configuration
276
- `EINVALIDSUCCESSCOMMENT` - Invalid success comment format
277
- `EINVALIDFAILTITLE` - Invalid fail title format
278
- `EINVALIDFAILCOMMENT` - Invalid fail comment format
279
- `EINVALIDLABELS` - Invalid labels configuration
280
- `EINVALIDASSIGNEES` - Invalid assignees configuration
281
- `EINVALIDRELEASEDLABELS` - Invalid released labels configuration
282
- `EINVALIDADDRELEASES` - Invalid addReleases configuration
283
- `EINVALIDDRAFTRELEASE` - Invalid draftRelease configuration
284
- `EINVALIDPROXY` - Invalid proxy configuration
285
- `EINVALIDGITHUBURL` - Invalid GitHub repository URL
286
- `EMISMATCHGITHUBURL` - Repository URL mismatch
287
- `EMISSINGREPO` - Repository not found
288
- `EGHNOPERMISSION` - Insufficient GitHub permissions
289
- `EINVALIDGHTOKEN` - Invalid GitHub token
290
- `ENOGHTOKEN` - Missing GitHub token
291
- `EINVALIDRELEASEBODYTEMPLATE` - Invalid release body template
292
- `EINVALIDRELEASENAMETEMPLATE` - Invalid release name template
293
- `EINVALIDDISCUSSIONCATEGORYNAME` - Invalid discussion category
294
295
**Usage Examples:**
296
297
```javascript
298
import getError from "@semantic-release/github/lib/get-error.js";
299
300
// Configuration validation errors
301
const assetsError = getError("EINVALIDASSETS", {
302
assets: "invalid-string-should-be-array"
303
});
304
console.log(assetsError.message); // "Invalid `assets` option."
305
console.log(assetsError.details); // Detailed explanation with documentation links
306
307
// Authentication errors
308
const tokenError = getError("ENOGHTOKEN", {
309
owner: "semantic-release",
310
repo: "github"
311
});
312
console.log(tokenError.code); // "ENOGHTOKEN"
313
console.log(tokenError.message); // "No GitHub token specified."
314
315
// Repository access errors
316
const permissionError = getError("EGHNOPERMISSION", {
317
owner: "private-org",
318
repo: "secret-repo"
319
});
320
console.log(permissionError.details); // Instructions for fixing permissions
321
```
322
323
### Prerelease Detection
324
325
Determines whether a branch or release should be marked as a prerelease.
326
327
```javascript { .api }
328
/**
329
* Determines if a release should be marked as prerelease based on branch configuration
330
* @param branchConfig - Branch configuration object with type and prerelease settings
331
* @returns True if the release should be marked as prerelease
332
*/
333
function isPrerelease(branchConfig: BranchConfig): boolean;
334
335
interface BranchConfig {
336
type: "prerelease" | "release";
337
main?: boolean;
338
prerelease?: boolean | string;
339
}
340
```
341
342
**Prerelease Logic:**
343
- Returns `true` if `branch.prerelease` is explicitly set to `true` or a string
344
- Returns `false` if `branch.prerelease` is explicitly set to `false`
345
- Returns `false` for main/stable branches (typically "main", "master")
346
- Returns `true` for feature branches and channels like "beta", "alpha", "next"
347
348
**Usage Examples:**
349
350
```javascript
351
import isPrerelease from "@semantic-release/github/lib/is-prerelease.js";
352
353
// Stable branches
354
isPrerelease({ name: "main" });
355
// Returns: false
356
357
isPrerelease({ name: "master" });
358
// Returns: false
359
360
// Prerelease branches
361
isPrerelease({ name: "beta", prerelease: "beta" });
362
// Returns: true
363
364
isPrerelease({ name: "develop", prerelease: true });
365
// Returns: true
366
367
// Explicit configuration
368
isPrerelease({ name: "release", prerelease: false });
369
// Returns: false (explicitly disabled)
370
```
371
372
### Template Processing
373
374
Internal template processing utilities used throughout the plugin.
375
376
```javascript { .api }
377
/**
378
* Internal utilities for template processing (from lodash-es)
379
* Used throughout the plugin for dynamic content generation
380
*/
381
382
// Template compilation and execution
383
function template(templateString: string): (context: any) => string;
384
385
// Array and object utilities
386
function castArray<T>(value: T | T[]): T[];
387
function defaultTo<T>(value: T | null | undefined, defaultValue: T): T;
388
function isNil(value: any): value is null | undefined;
389
function merge<T>(target: T, ...sources: Partial<T>[]): T;
390
391
// String and validation utilities
392
function isString(value: any): value is string;
393
function isPlainObject(value: any): value is Record<string, any>;
394
function isArray(value: any): value is any[];
395
function isBoolean(value: any): value is boolean;
396
function isNumber(value: any): value is number;
397
```
398
399
**Template Processing Examples:**
400
401
```javascript
402
import { template } from "lodash-es";
403
404
// Create reusable templates
405
const releaseTemplate = template("Released version ${version} on ${date}");
406
const commentTemplate = template(`
407
## Release ${nextRelease.version}
408
409
This ${nextRelease.channel ? 'prerelease' : 'stable release'} includes:
410
${nextRelease.notes}
411
`);
412
413
// Execute templates with context
414
const releaseMessage = releaseTemplate({
415
version: "1.0.0",
416
date: new Date().toISOString()
417
});
418
419
const comment = commentTemplate({
420
nextRelease: {
421
version: "1.1.0-beta.1",
422
channel: "beta",
423
notes: "- Bug fixes\n- New features"
424
}
425
});
426
```
427
428
### Constants and Identifiers
429
430
Shared constants used throughout the plugin for consistent identification and labeling.
431
432
```javascript { .api }
433
// Issue identification marker
434
const ISSUE_ID = "<!-- semantic-release:github -->";
435
436
// Release type identifier
437
const RELEASE_NAME = "GitHub release";
438
439
// Default failure issue label
440
const RELEASE_FAIL_LABEL = "semantic-release";
441
```
442
443
**Usage in Generated Content:**
444
445
```javascript
446
// Issues created by the plugin include the identifier
447
const issueBody = `
448
${ISSUE_ID}
449
450
## Release Failure
451
452
The automated release process failed...
453
`;
454
455
// Release results include the consistent name
456
const releaseResult = {
457
url: "https://github.com/owner/repo/releases/tag/v1.0.0",
458
name: RELEASE_NAME, // "GitHub release"
459
id: 12345
460
};
461
462
// Default labels applied to failure issues
463
const defaultLabels = [RELEASE_FAIL_LABEL]; // ["semantic-release"]
464
```