@pubm/plugin-brew 0.4.7 → 0.4.8
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/brew-core.d.ts +1 -1
- package/dist/brew-tap.d.ts +1 -1
- package/dist/index.js +177 -13
- package/package.json +1 -1
package/dist/brew-core.d.ts
CHANGED
package/dist/brew-tap.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
5
5
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { dirname, join, resolve } from "node:path";
|
|
8
|
+
import { resolvePhases } from "@pubm/core";
|
|
8
9
|
|
|
9
10
|
// src/formula.ts
|
|
10
11
|
function toClassName(name) {
|
|
@@ -204,8 +205,64 @@ function brewCore(options) {
|
|
|
204
205
|
]
|
|
205
206
|
}
|
|
206
207
|
],
|
|
208
|
+
credentials: (ctx) => {
|
|
209
|
+
if (ctx.options.mode !== "ci")
|
|
210
|
+
return [];
|
|
211
|
+
return [
|
|
212
|
+
{
|
|
213
|
+
key: "brew-github-token",
|
|
214
|
+
env: "PUBM_BREW_GITHUB_TOKEN",
|
|
215
|
+
label: "GitHub PAT for Homebrew (homebrew-core)",
|
|
216
|
+
tokenUrl: "https://github.com/settings/tokens/new?scopes=repo,workflow",
|
|
217
|
+
tokenUrlLabel: "github.com",
|
|
218
|
+
ghSecretName: "PUBM_BREW_GITHUB_TOKEN",
|
|
219
|
+
required: true
|
|
220
|
+
}
|
|
221
|
+
];
|
|
222
|
+
},
|
|
223
|
+
checks: (ctx) => {
|
|
224
|
+
const phases = resolvePhases(ctx.options);
|
|
225
|
+
if (!phases.includes("publish") && ctx.options.mode !== "ci")
|
|
226
|
+
return [];
|
|
227
|
+
if (ctx.options.mode === "ci") {
|
|
228
|
+
return [
|
|
229
|
+
{
|
|
230
|
+
title: "Checking Homebrew core token availability",
|
|
231
|
+
phase: "conditions",
|
|
232
|
+
task: async (ctx2, task) => {
|
|
233
|
+
const token = ctx2.runtime.pluginTokens?.["brew-github-token"];
|
|
234
|
+
if (!token) {
|
|
235
|
+
throw new Error("PUBM_BREW_GITHUB_TOKEN is required for homebrew-core publishing.");
|
|
236
|
+
}
|
|
237
|
+
task.output = "Homebrew core token verified";
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
];
|
|
241
|
+
}
|
|
242
|
+
return [
|
|
243
|
+
{
|
|
244
|
+
title: "Checking GitHub CLI access for homebrew-core",
|
|
245
|
+
phase: "conditions",
|
|
246
|
+
task: async (_ctx, task) => {
|
|
247
|
+
const { execFileSync } = await import("node:child_process");
|
|
248
|
+
try {
|
|
249
|
+
execFileSync("gh", ["auth", "status"], { stdio: "pipe" });
|
|
250
|
+
task.output = "GitHub CLI authenticated";
|
|
251
|
+
} catch {
|
|
252
|
+
throw new Error("GitHub CLI is not authenticated. Run `gh auth login` first.");
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
execFileSync("gh", ["repo", "view", "homebrew/homebrew-core", "--json", "name"], { stdio: "pipe" });
|
|
256
|
+
task.output = "Access to homebrew/homebrew-core verified";
|
|
257
|
+
} catch {
|
|
258
|
+
throw new Error("Cannot access homebrew/homebrew-core. Check your GitHub permissions.");
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
];
|
|
263
|
+
},
|
|
207
264
|
hooks: {
|
|
208
|
-
afterRelease: async (
|
|
265
|
+
afterRelease: async (ctx, releaseCtx) => {
|
|
209
266
|
if (options.packageName && releaseCtx.displayLabel !== options.packageName) {
|
|
210
267
|
return;
|
|
211
268
|
}
|
|
@@ -215,16 +272,26 @@ function brewCore(options) {
|
|
|
215
272
|
const pkg = existsSync(pkgPath) ? JSON.parse(readFileSync(pkgPath, "utf-8")) : {};
|
|
216
273
|
const name = pkg.name?.replace(/^@[^/]+\//, "") ?? "my-tool";
|
|
217
274
|
const formulaAssets = releaseAssetsToFormulaAssets(releaseCtx.assets, options.assetPlatforms);
|
|
275
|
+
const token = ctx.runtime.pluginTokens?.["brew-github-token"];
|
|
276
|
+
const ghEnv = token ? { env: { ...process.env, GH_TOKEN: token } } : {};
|
|
218
277
|
try {
|
|
219
278
|
execSync2("gh repo fork homebrew/homebrew-core --clone=false", {
|
|
220
|
-
stdio: "pipe"
|
|
279
|
+
stdio: "pipe",
|
|
280
|
+
...ghEnv
|
|
221
281
|
});
|
|
222
282
|
} catch {}
|
|
223
283
|
const username = execSync2("gh api user --jq .login", {
|
|
224
|
-
encoding: "utf-8"
|
|
284
|
+
encoding: "utf-8",
|
|
285
|
+
...ghEnv
|
|
225
286
|
}).trim();
|
|
226
287
|
const tmpDir = join(tmpdir(), `pubm-brew-core-${Date.now()}`);
|
|
227
|
-
|
|
288
|
+
let cloneUrl = `https://github.com/${username}/homebrew-core.git`;
|
|
289
|
+
if (token) {
|
|
290
|
+
cloneUrl = `https://x-access-token:${token}@github.com/${username}/homebrew-core.git`;
|
|
291
|
+
}
|
|
292
|
+
execSync2(`git clone --depth 1 ${cloneUrl} ${tmpDir}`, {
|
|
293
|
+
stdio: "inherit"
|
|
294
|
+
});
|
|
228
295
|
ensureGitIdentity(tmpDir);
|
|
229
296
|
const formulaPath = join(tmpDir, "Formula", `${name}.rb`);
|
|
230
297
|
let content;
|
|
@@ -251,10 +318,21 @@ function brewCore(options) {
|
|
|
251
318
|
`git commit -m "${name} ${releaseCtx.version}"`,
|
|
252
319
|
`git push origin ${branchName}`
|
|
253
320
|
].join(" && "), { stdio: "inherit" });
|
|
254
|
-
execSync2([
|
|
321
|
+
const prUrl = execSync2([
|
|
255
322
|
`cd ${tmpDir}`,
|
|
256
323
|
`gh pr create --repo homebrew/homebrew-core --title "${name} ${releaseCtx.version}" --body "Update ${name} formula to version ${releaseCtx.version}"`
|
|
257
|
-
].join(" && "), {
|
|
324
|
+
].join(" && "), { encoding: "utf-8", ...ghEnv }).trim();
|
|
325
|
+
const prNumber = prUrl.match(/\/pull\/(\d+)/)?.[1];
|
|
326
|
+
if (prNumber) {
|
|
327
|
+
ctx.runtime.rollback.add({
|
|
328
|
+
label: `Close homebrew-core PR #${prNumber}`,
|
|
329
|
+
fn: async () => {
|
|
330
|
+
const { execSync: execSyncRb } = await import("node:child_process");
|
|
331
|
+
execSyncRb(`gh pr close ${prNumber} --repo homebrew/homebrew-core --comment "Closed by pubm rollback"`, { stdio: "inherit", ...ghEnv });
|
|
332
|
+
},
|
|
333
|
+
confirm: true
|
|
334
|
+
});
|
|
335
|
+
}
|
|
258
336
|
console.log(`PR created to homebrew/homebrew-core for ${name} ${releaseCtx.version}`);
|
|
259
337
|
}
|
|
260
338
|
}
|
|
@@ -263,6 +341,7 @@ function brewCore(options) {
|
|
|
263
341
|
// src/brew-tap.ts
|
|
264
342
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
265
343
|
import { dirname as dirname2, resolve as resolve2 } from "node:path";
|
|
344
|
+
import { resolvePhases as resolvePhases2 } from "@pubm/core";
|
|
266
345
|
function brewTap(options) {
|
|
267
346
|
return {
|
|
268
347
|
name: "@pubm/plugin-brew-tap",
|
|
@@ -299,8 +378,72 @@ function brewTap(options) {
|
|
|
299
378
|
]
|
|
300
379
|
}
|
|
301
380
|
],
|
|
381
|
+
credentials: (ctx) => {
|
|
382
|
+
if (!options.repo || ctx.options.mode !== "ci")
|
|
383
|
+
return [];
|
|
384
|
+
return [
|
|
385
|
+
{
|
|
386
|
+
key: "brew-github-token",
|
|
387
|
+
env: "PUBM_BREW_GITHUB_TOKEN",
|
|
388
|
+
label: "GitHub PAT for Homebrew tap",
|
|
389
|
+
tokenUrl: "https://github.com/settings/tokens/new?scopes=repo",
|
|
390
|
+
tokenUrlLabel: "github.com",
|
|
391
|
+
ghSecretName: "PUBM_BREW_GITHUB_TOKEN",
|
|
392
|
+
required: true
|
|
393
|
+
}
|
|
394
|
+
];
|
|
395
|
+
},
|
|
396
|
+
checks: (ctx) => {
|
|
397
|
+
const phases = resolvePhases2(ctx.options);
|
|
398
|
+
if (!phases.includes("publish") && ctx.options.mode !== "ci")
|
|
399
|
+
return [];
|
|
400
|
+
if (ctx.options.mode === "ci") {
|
|
401
|
+
if (!options.repo)
|
|
402
|
+
return [];
|
|
403
|
+
return [
|
|
404
|
+
{
|
|
405
|
+
title: "Checking Homebrew tap token availability",
|
|
406
|
+
phase: "conditions",
|
|
407
|
+
task: async (ctx2, task) => {
|
|
408
|
+
const token = ctx2.runtime.pluginTokens?.["brew-github-token"];
|
|
409
|
+
if (!token) {
|
|
410
|
+
throw new Error("PUBM_BREW_GITHUB_TOKEN is required for Homebrew tap publishing.");
|
|
411
|
+
}
|
|
412
|
+
task.output = "Homebrew tap token verified";
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
];
|
|
416
|
+
}
|
|
417
|
+
if (!options.repo)
|
|
418
|
+
return [];
|
|
419
|
+
const targetRepo = options.repo;
|
|
420
|
+
return [
|
|
421
|
+
{
|
|
422
|
+
title: "Checking git/gh access for Homebrew tap",
|
|
423
|
+
phase: "conditions",
|
|
424
|
+
task: async (_ctx, task) => {
|
|
425
|
+
const { execFileSync } = await import("node:child_process");
|
|
426
|
+
try {
|
|
427
|
+
execFileSync("gh", ["auth", "status"], { stdio: "pipe" });
|
|
428
|
+
task.output = "GitHub CLI authenticated";
|
|
429
|
+
} catch {
|
|
430
|
+
throw new Error("GitHub CLI is not authenticated. Run `gh auth login` first.");
|
|
431
|
+
}
|
|
432
|
+
const repoName = /^[^/]+\/[^/]+$/.test(targetRepo) ? targetRepo : targetRepo.match(/github\.com[/:]([^/]+\/[^/.]+)/)?.[1];
|
|
433
|
+
if (repoName) {
|
|
434
|
+
try {
|
|
435
|
+
execFileSync("gh", ["repo", "view", repoName, "--json", "name"], { stdio: "pipe" });
|
|
436
|
+
task.output = `Access to ${repoName} verified`;
|
|
437
|
+
} catch {
|
|
438
|
+
throw new Error(`Cannot access tap repository '${targetRepo}'. Check your GitHub permissions.`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
];
|
|
444
|
+
},
|
|
302
445
|
hooks: {
|
|
303
|
-
afterRelease: async (
|
|
446
|
+
afterRelease: async (ctx, releaseCtx) => {
|
|
304
447
|
if (options.packageName && releaseCtx.displayLabel !== options.packageName) {
|
|
305
448
|
return;
|
|
306
449
|
}
|
|
@@ -338,7 +481,17 @@ function brewTap(options) {
|
|
|
338
481
|
const branch = `pubm/brew-formula-v${releaseCtx.version}`;
|
|
339
482
|
execSync2(`git checkout -b ${branch}`, { stdio: "inherit" });
|
|
340
483
|
execSync2(`git push origin ${branch}`, { stdio: "inherit" });
|
|
341
|
-
execSync2(`gh pr create --title "chore(brew): update formula to ${releaseCtx.version}" --body "Automated formula update by pubm"`, {
|
|
484
|
+
const prUrl = execSync2(`gh pr create --title "chore(brew): update formula to ${releaseCtx.version}" --body "Automated formula update by pubm"`, { encoding: "utf-8" }).trim();
|
|
485
|
+
const prNumber = prUrl.match(/\/pull\/(\d+)/)?.[1];
|
|
486
|
+
if (prNumber) {
|
|
487
|
+
ctx.runtime.rollback.add({
|
|
488
|
+
label: `Close Homebrew tap PR #${prNumber}`,
|
|
489
|
+
fn: async () => {
|
|
490
|
+
execSync2(`gh pr close ${prNumber} --comment "Closed by pubm rollback"`, { stdio: "inherit" });
|
|
491
|
+
},
|
|
492
|
+
confirm: true
|
|
493
|
+
});
|
|
494
|
+
}
|
|
342
495
|
console.log(`Created PR on branch ${branch}`);
|
|
343
496
|
}
|
|
344
497
|
return;
|
|
@@ -347,7 +500,6 @@ function brewTap(options) {
|
|
|
347
500
|
const { tmpdir: tmpdir2 } = await import("node:os");
|
|
348
501
|
const { basename, join: join2 } = await import("node:path");
|
|
349
502
|
const { execSync: execSync2 } = await import("node:child_process");
|
|
350
|
-
const { resolveGitHubToken } = await import("@pubm/core");
|
|
351
503
|
const tmpDir = join2(tmpdir2(), `pubm-brew-tap-${Date.now()}`);
|
|
352
504
|
const formulaFile = basename(formulaPath);
|
|
353
505
|
const isShorthand = /^[^/]+\/[^/]+$/.test(options.repo);
|
|
@@ -355,10 +507,11 @@ function brewTap(options) {
|
|
|
355
507
|
const ownerRepoMatch = repoUrl.match(/github\.com[/:]([^/]+\/[^/.]+?)(?:\.git)?$/);
|
|
356
508
|
const ownerRepo = ownerRepoMatch?.[1] ?? options.repo;
|
|
357
509
|
let cloneUrl = repoUrl;
|
|
358
|
-
const
|
|
359
|
-
if (
|
|
360
|
-
cloneUrl = repoUrl.replace("https://github.com/", `https://x-access-token:${
|
|
510
|
+
const token = ctx.runtime.pluginTokens?.["brew-github-token"];
|
|
511
|
+
if (token && repoUrl.startsWith("https://github.com/")) {
|
|
512
|
+
cloneUrl = repoUrl.replace("https://github.com/", `https://x-access-token:${token}@github.com/`);
|
|
361
513
|
}
|
|
514
|
+
const ghEnv = token ? { env: { ...process.env, GH_TOKEN: token } } : {};
|
|
362
515
|
execSync2(`git clone --depth 1 ${cloneUrl} ${tmpDir}`, {
|
|
363
516
|
stdio: "inherit"
|
|
364
517
|
});
|
|
@@ -381,7 +534,18 @@ function brewTap(options) {
|
|
|
381
534
|
execSync2(`cd ${tmpDir} && git push origin ${branch}`, {
|
|
382
535
|
stdio: "inherit"
|
|
383
536
|
});
|
|
384
|
-
execSync2(`gh pr create --repo ${ownerRepo} --title "chore(brew): update formula to ${releaseCtx.version}" --body "Automated formula update by pubm"`, {
|
|
537
|
+
const prUrl = execSync2(`gh pr create --repo ${ownerRepo} --title "chore(brew): update formula to ${releaseCtx.version}" --body "Automated formula update by pubm"`, { encoding: "utf-8", ...ghEnv }).trim();
|
|
538
|
+
const prNumber = prUrl.match(/\/pull\/(\d+)/)?.[1];
|
|
539
|
+
if (prNumber) {
|
|
540
|
+
const repoFlag = ownerRepo;
|
|
541
|
+
ctx.runtime.rollback.add({
|
|
542
|
+
label: `Close Homebrew tap PR #${prNumber} (${repoFlag})`,
|
|
543
|
+
fn: async () => {
|
|
544
|
+
execSync2(`gh pr close ${prNumber} --repo ${repoFlag} --comment "Closed by pubm rollback"`, { stdio: "inherit", ...ghEnv });
|
|
545
|
+
},
|
|
546
|
+
confirm: true
|
|
547
|
+
});
|
|
548
|
+
}
|
|
385
549
|
console.log(`Created PR on branch ${branch}`);
|
|
386
550
|
}
|
|
387
551
|
}
|