or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-management.mdconfiguration.mdgithub-integration.mdindex.mdplugin-lifecycle.mdutilities.md

utilities.mddocs/

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

```