trustci 0.1.0 → 0.2.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.
Files changed (2) hide show
  1. package/dist/cli.js +112 -7
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -19,6 +19,7 @@ var options = {
19
19
  project: { type: "string" },
20
20
  env: { type: "string" },
21
21
  file: { type: "string" },
22
+ "circle-token": { type: "string" },
22
23
  "org-id": { type: "string" },
23
24
  "project-id": { type: "string" },
24
25
  "pipeline-definition-id": { type: "string" },
@@ -105,12 +106,26 @@ function parseCliArgs(argv) {
105
106
  if (!vcsOrigin.includes("://")) {
106
107
  throw new ArgError(`--vcs-origin must include a protocol, e.g. https://github.com/org/repo (got "${vcsOrigin}").`);
107
108
  }
109
+ const circleToken = values["circle-token"];
110
+ const orgId = values["org-id"];
111
+ const projectId = values["project-id"];
112
+ const pipelineDefinitionId = values["pipeline-definition-id"];
113
+ if (!circleToken) {
114
+ if (!orgId)
115
+ throw new ArgError("--org-id is required for --provider circleci (or provide --circle-token for auto-resolution).");
116
+ if (!projectId)
117
+ throw new ArgError("--project-id is required for --provider circleci (or provide --circle-token for auto-resolution).");
118
+ if (!pipelineDefinitionId)
119
+ throw new ArgError("--pipeline-definition-id is required for --provider circleci (or provide --circle-token for auto-resolution).");
120
+ }
108
121
  providerOptions = {
109
122
  provider: "circleci",
110
- orgId: require_(values["org-id"], "org-id", "circleci"),
111
- projectId: require_(values["project-id"], "project-id", "circleci"),
112
- pipelineDefinitionId: require_(values["pipeline-definition-id"], "pipeline-definition-id", "circleci"),
123
+ circleToken,
124
+ orgId,
125
+ projectId,
126
+ pipelineDefinitionId,
113
127
  vcsOrigin,
128
+ file: values.file,
114
129
  contextIds: values["context-id"] ?? [],
115
130
  ...common
116
131
  };
@@ -126,6 +141,62 @@ function parseCliArgs(argv) {
126
141
  };
127
142
  }
128
143
 
144
+ // src/circleci.ts
145
+ var BASE_URL = "https://circleci.com/api/v2";
146
+ function vcsTypeFromUrl(url) {
147
+ const { hostname } = new URL(url);
148
+ if (hostname === "github.com" || hostname.endsWith(".github.com"))
149
+ return "github";
150
+ if (hostname === "gitlab.com" || hostname.endsWith(".gitlab.com"))
151
+ return "gitlab";
152
+ if (hostname === "bitbucket.org" || hostname.endsWith(".bitbucket.org"))
153
+ return "bitbucket";
154
+ throw new Error(`Cannot determine VCS type from URL: ${url}`);
155
+ }
156
+ function projectSlugFromVcsOrigin(url) {
157
+ const vcsType = vcsTypeFromUrl(url);
158
+ const { pathname } = new URL(url);
159
+ const parts = pathname.replace(/^\//, "").replace(/\.git$/, "").split("/");
160
+ if (parts.length < 2 || !parts[0] || !parts[1]) {
161
+ throw new Error(`Cannot extract org/repo from URL: ${url}`);
162
+ }
163
+ return `${vcsType}/${parts[0]}/${parts[1]}`;
164
+ }
165
+ async function circleGet(token, path) {
166
+ const response = await fetch(`${BASE_URL}${path}`, {
167
+ headers: { "Circle-Token": token, Accept: "application/json" }
168
+ });
169
+ if (!response.ok) {
170
+ const body = await response.text();
171
+ throw new Error(`CircleCI API error (${response.status}) for ${path}: ${body}`);
172
+ }
173
+ return response.json();
174
+ }
175
+ async function resolveOrgAndProjectId(token, vcsOrigin) {
176
+ const slug = projectSlugFromVcsOrigin(vcsOrigin);
177
+ const project = await circleGet(token, `/project/${slug}`);
178
+ return { orgId: project.organization_id, projectId: project.id };
179
+ }
180
+ async function resolvePipelineDefinitionId(token, projectId, file) {
181
+ const data = await circleGet(token, `/pipeline-definitions?project_id=${encodeURIComponent(projectId)}`);
182
+ if (data.items.length === 0) {
183
+ throw new Error(`No pipeline definitions found for project "${projectId}".`);
184
+ }
185
+ if (file) {
186
+ const match = data.items.find((d) => d.config_file_path === file || d.name === file);
187
+ if (!match) {
188
+ const available2 = data.items.map((d) => d.config_file_path ?? d.name ?? d.id).join(", ");
189
+ throw new Error(`No pipeline definition found matching "${file}". Available: ${available2}`);
190
+ }
191
+ return match.id;
192
+ }
193
+ if (data.items.length === 1) {
194
+ return data.items[0].id;
195
+ }
196
+ const available = data.items.map((d) => d.config_file_path ?? d.name ?? d.id).join(", ");
197
+ throw new Error(`Multiple pipeline definitions found for project "${projectId}". Specify --file to select one: ${available}`);
198
+ }
199
+
129
200
  // src/exec.ts
130
201
  import { spawnSync } from "node:child_process";
131
202
  function run(cmd, args) {
@@ -435,6 +506,12 @@ function discoverPackages(root) {
435
506
  all.push(pkg);
436
507
  }
437
508
  }
509
+ if (source === "none") {
510
+ const pkg = readPkg(path2.resolve(root));
511
+ if (pkg) {
512
+ return { source: "package.json (root)", patterns: [], all: [pkg] };
513
+ }
514
+ }
438
515
  return { source, patterns, all };
439
516
  }
440
517
  function filterPackages(all, only, exclude) {
@@ -461,8 +538,11 @@ Providers:
461
538
  github --repo <owner/repo> --file <workflow> [--env <name>]
462
539
  gitlab --project <group/project> --file <workflow> [--env <name>]
463
540
  (--repo is accepted as an alias for --project)
464
- circleci --org-id <uuid> --project-id <uuid> --pipeline-definition-id <uuid>
465
- --vcs-origin <url> [--context-id <uuid> ...]
541
+ circleci --vcs-origin <url> --circle-token <token> [--file <config>]
542
+ [--org-id <uuid>] [--project-id <uuid>] [--pipeline-definition-id <uuid>]
543
+ [--context-id <uuid> ...]
544
+ UUIDs are auto-resolved via CircleCI API v2 when --circle-token is provided.
545
+ Explicit UUIDs override auto-resolution and work without a token.
466
546
 
467
547
  Permissions (at least one required):
468
548
  --allow-publish allow npm publish
@@ -477,11 +557,14 @@ Options:
477
557
  -v, --version show the trustci version
478
558
 
479
559
  Workspaces are detected from pnpm-workspace.yaml, package.json "workspaces",
480
- or lerna.json. Private packages ("private": true) are always excluded.
560
+ or lerna.json. If no workspace config is found, the root package.json is used
561
+ as a single-package fallback. Private packages ("private": true) are always excluded.
481
562
 
482
563
  Examples:
483
564
  trustci --dry-run --provider github --repo me/repo --file release.yml --allow-publish
484
565
  trustci --provider gitlab --project me/repo --file .gitlab-ci.yml --allow-publish -y
566
+ trustci --provider circleci --vcs-origin https://github.com/me/repo \\
567
+ --circle-token $CIRCLECI_TOKEN --allow-publish
485
568
  trustci --provider circleci --org-id <uuid> --project-id <uuid> \\
486
569
  --pipeline-definition-id <uuid> --vcs-origin https://github.com/me/repo --allow-publish
487
570
  trustci list
@@ -626,7 +709,29 @@ async function main() {
626
709
  return 1;
627
710
  }
628
711
  }
629
- return parsed.kind === "list" ? runList(parsed.pkg, parsed.dryRun) : runTrust(parsed);
712
+ if (parsed.kind === "list")
713
+ return runList(parsed.pkg, parsed.dryRun);
714
+ if (parsed.options.provider === "circleci" && !parsed.dryRun) {
715
+ const opts = parsed.options;
716
+ if (opts.circleToken) {
717
+ try {
718
+ if (!opts.orgId || !opts.projectId) {
719
+ console.error("Resolving org-id and project-id via CircleCI API...");
720
+ const resolved = await resolveOrgAndProjectId(opts.circleToken, opts.vcsOrigin);
721
+ opts.orgId ??= resolved.orgId;
722
+ opts.projectId ??= resolved.projectId;
723
+ }
724
+ if (!opts.pipelineDefinitionId) {
725
+ console.error("Resolving pipeline-definition-id via CircleCI API...");
726
+ opts.pipelineDefinitionId = await resolvePipelineDefinitionId(opts.circleToken, opts.projectId, opts.file);
727
+ }
728
+ } catch (err) {
729
+ console.error(`error: ${err.message}`);
730
+ return 1;
731
+ }
732
+ }
733
+ }
734
+ return runTrust(parsed);
630
735
  }
631
736
  main().then((code) => {
632
737
  process2.exitCode = code;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trustci",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Bulk-register npm Trusted Publishers (npm trust) across all public packages in a monorepo. Supports GitHub, GitLab and CircleCI.",
5
5
  "type": "module",
6
6
  "bin": {