@biffo/cli 0.166.0 → 0.166.2
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/index.js +75 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1629,6 +1629,34 @@ var GitHubAdapter = class {
|
|
|
1629
1629
|
throw err;
|
|
1630
1630
|
}
|
|
1631
1631
|
}
|
|
1632
|
+
/**
|
|
1633
|
+
* How many self-hosted runners this repo can actually see (#803, biffo-runners#2).
|
|
1634
|
+
*
|
|
1635
|
+
* Setting `RUNNER_LABEL` points a repo's jobs at a self-hosted fleet. It does
|
|
1636
|
+
* not grant the fleet's GitHub App access to that repo — and until someone
|
|
1637
|
+
* does, the repo sees **zero** runners and every job queues for ever with no
|
|
1638
|
+
* error at all. Measured on a freshly created plugin repo: 0 runners, while an
|
|
1639
|
+
* established one in the same fleet saw 3.
|
|
1640
|
+
*
|
|
1641
|
+
* Queuing for ever and failing at the billing wall look completely different
|
|
1642
|
+
* in the UI and are the same outcome under branch protection: nothing can
|
|
1643
|
+
* merge. Callers use this to say so at create time rather than leaving it to
|
|
1644
|
+
* be discovered on the first PR.
|
|
1645
|
+
*
|
|
1646
|
+
* Returns `null` when the count cannot be read (permissions, API error) —
|
|
1647
|
+
* distinct from `0`, which is a real and actionable answer.
|
|
1648
|
+
*/
|
|
1649
|
+
async repoRunnerCount(org, repo) {
|
|
1650
|
+
try {
|
|
1651
|
+
const { data } = await this.octokit.actions.listSelfHostedRunnersForRepo({
|
|
1652
|
+
owner: org,
|
|
1653
|
+
repo
|
|
1654
|
+
});
|
|
1655
|
+
return data.total_count;
|
|
1656
|
+
} catch {
|
|
1657
|
+
return null;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1632
1660
|
async setRepoVariable(org, repo, name, value) {
|
|
1633
1661
|
log.info(`Setting variable: ${name}`);
|
|
1634
1662
|
try {
|
|
@@ -4538,6 +4566,7 @@ async function readRemoteCoreVersion(github, org, repo, ref) {
|
|
|
4538
4566
|
}
|
|
4539
4567
|
} catch {
|
|
4540
4568
|
}
|
|
4569
|
+
return null;
|
|
4541
4570
|
}
|
|
4542
4571
|
const inherited = await github.getFileContent(org, repo, CORE_VERSION_FILE, ref);
|
|
4543
4572
|
if (inherited) {
|
|
@@ -6839,6 +6868,9 @@ var pluginCreateCommand = new Command13("create").description("Scaffold a new pl
|
|
|
6839
6868
|
).option(
|
|
6840
6869
|
"--org <org>",
|
|
6841
6870
|
"With --standalone, also create the GitHub repo under this org (or user), push, and protect dev"
|
|
6871
|
+
).option(
|
|
6872
|
+
"--runner-label <label>",
|
|
6873
|
+
"With --org, the RUNNER_LABEL the new repo\u2019s CI should run on (defaults to mirroring this checkout\u2019s)"
|
|
6842
6874
|
).option(
|
|
6843
6875
|
"--skeleton <path>",
|
|
6844
6876
|
"Path to the plugin skeleton (defaults to _skeletons/plugin-template)"
|
|
@@ -6852,6 +6884,7 @@ var pluginCreateCommand = new Command13("create").description("Scaffold a new pl
|
|
|
6852
6884
|
firstParty: options.firstParty ?? false,
|
|
6853
6885
|
standalone: options.standalone ?? false,
|
|
6854
6886
|
...options.org ? { org: options.org } : {},
|
|
6887
|
+
...options.runnerLabel ? { runnerLabel: options.runnerLabel } : {},
|
|
6855
6888
|
...options.skeleton ? { skeletonRoot: resolve11(options.skeleton) } : {},
|
|
6856
6889
|
dryRun: options.dryRun ?? false,
|
|
6857
6890
|
commit: options.commit !== false,
|
|
@@ -6980,18 +7013,19 @@ async function runStandaloneCreate(names, options, deps) {
|
|
|
6980
7013
|
"--org needs a commit to push. Drop --no-commit, or create the repo yourself using the steps printed by a --no-commit run."
|
|
6981
7014
|
);
|
|
6982
7015
|
}
|
|
6983
|
-
await createAndPushStandaloneRepo(options.org, names, destDir, deps);
|
|
7016
|
+
await createAndPushStandaloneRepo(options.org, names, destDir, options, deps);
|
|
6984
7017
|
return;
|
|
6985
7018
|
}
|
|
6986
7019
|
printStandaloneNextSteps(names, minorOf(manifest.version));
|
|
6987
7020
|
}
|
|
6988
|
-
async function createAndPushStandaloneRepo(org, names, destDir, deps) {
|
|
7021
|
+
async function createAndPushStandaloneRepo(org, names, destDir, options, deps) {
|
|
6989
7022
|
if (deps.makeGitHub === void 0 || deps.resolveToken === void 0) {
|
|
6990
7023
|
throw new Error("No GitHub adapter available \u2014 cannot create a repository.");
|
|
6991
7024
|
}
|
|
6992
7025
|
const token = await deps.resolveToken();
|
|
6993
7026
|
const github = deps.makeGitHub(token);
|
|
6994
7027
|
const cloneUrl = await github.createEmptyRepo(org, names.dist, `${names.slug} \u2014 a Biffo plugin`);
|
|
7028
|
+
await propagateRunnerLabel(org, names.dist, options, deps, github);
|
|
6995
7029
|
await deps.git.addRemote(destDir, "origin", cloneUrl);
|
|
6996
7030
|
await deps.git.push(destDir, "dev", { token });
|
|
6997
7031
|
log.success(`Pushed dev to ${org}/${names.dist}`);
|
|
@@ -7007,6 +7041,45 @@ async function createAndPushStandaloneRepo(org, names, destDir, deps) {
|
|
|
7007
7041
|
}
|
|
7008
7042
|
printStandaloneRemoteNextSteps(names, org);
|
|
7009
7043
|
}
|
|
7044
|
+
async function propagateRunnerLabel(org, repo, options, deps, github) {
|
|
7045
|
+
try {
|
|
7046
|
+
let label = options.runnerLabel?.trim();
|
|
7047
|
+
if (!label) {
|
|
7048
|
+
const source = await currentRepoSlug(options.cwd, deps);
|
|
7049
|
+
if (source) {
|
|
7050
|
+
label = (await github.getRepoVariable(source.org, source.repo, "RUNNER_LABEL"))?.trim();
|
|
7051
|
+
}
|
|
7052
|
+
}
|
|
7053
|
+
if (!label) {
|
|
7054
|
+
log.warn(
|
|
7055
|
+
`No RUNNER_LABEL set on ${org}/${repo} \u2014 its CI will use GitHub-hosted runners. If this account routes CI to a self-hosted fleet, every job will fail before it starts, and the branch protection just configured will block every PR on checks that never report. Fix with: gh variable set RUNNER_LABEL --repo ${org}/${repo}`
|
|
7056
|
+
);
|
|
7057
|
+
return;
|
|
7058
|
+
}
|
|
7059
|
+
await github.setRepoVariable(org, repo, "RUNNER_LABEL", label);
|
|
7060
|
+
log.success(`RUNNER_LABEL=${label} set on ${org}/${repo}`);
|
|
7061
|
+
const runners = await github.repoRunnerCount(org, repo);
|
|
7062
|
+
if (runners === 0) {
|
|
7063
|
+
log.warn(
|
|
7064
|
+
`${org}/${repo} points at the '${label}' runner fleet but can see 0 runners. Jobs will queue indefinitely with no error until the fleet's GitHub App is granted access to this repo (biffo-runners#2) \u2014 and the branch protection just applied will block every PR until then.`
|
|
7065
|
+
);
|
|
7066
|
+
}
|
|
7067
|
+
} catch (err) {
|
|
7068
|
+
log.warn(
|
|
7069
|
+
`Could not set RUNNER_LABEL on ${org}/${repo}: ${err.message}. Set it manually if this account uses self-hosted runners.`
|
|
7070
|
+
);
|
|
7071
|
+
}
|
|
7072
|
+
}
|
|
7073
|
+
async function currentRepoSlug(cwd, deps) {
|
|
7074
|
+
try {
|
|
7075
|
+
const url = await deps.git.getRemoteUrl(cwd, "origin");
|
|
7076
|
+
const match = /[:/]([^/:]+)\/([^/]+?)(?:\.git)?$/.exec(url.trim());
|
|
7077
|
+
if (match?.[1] === void 0 || match[2] === void 0) return null;
|
|
7078
|
+
return { org: match[1], repo: match[2] };
|
|
7079
|
+
} catch {
|
|
7080
|
+
return null;
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7010
7083
|
function printStandaloneRemoteNextSteps(names, org) {
|
|
7011
7084
|
console.log(chalk13.bold("\n Standalone plugin repo created!\n"));
|
|
7012
7085
|
console.log(` https://github.com/${org}/${names.dist} (dev, protected)
|