@teambit/ci 1.0.632 → 1.0.633

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.
@@ -1,13 +1,38 @@
1
1
  import type { GitHostProvider, PrInfo } from './git-host-provider';
2
2
  /**
3
- * The `owner/repo` out of a github.com remote URL, anchored to the URL authority. `:digits` is a port
3
+ * The host of the GitHub instance this run belongs to: the one `GITHUB_SERVER_URL` names (Actions sets
4
+ * it on every runner — `https://github.com`, or the GitHub Enterprise Server URL), else github.com.
5
+ */
6
+ export declare function gitHubServerHost(): string;
7
+ /** A resolved REST API base, or why the environment's API cannot be trusted with the repository's token. */
8
+ export type GitHubApiUrl = {
9
+ url: string;
10
+ } | {
11
+ error: string;
12
+ };
13
+ /**
14
+ * The REST API base for a repository on `host` (the `GITHUB_SERVER_URL` instance's host when omitted).
15
+ * Every request to it carries that instance's token, so:
16
+ * - github.com (and any host that is not the enterprise one) is always `https://api.github.com`.
17
+ * - the enterprise host takes `GITHUB_API_URL` only when it lives on that host or on `api.<host>`
18
+ * (GHE.com data residency: `https://<sub>.ghe.com` serves its API at `https://api.<sub>.ghe.com`);
19
+ * unset, it is the GHES convention `<GITHUB_SERVER_URL origin>/api/v3`. An https server's API must be
20
+ * https too, so the token never travels in plaintext. Any other API is refused — never replaced by
21
+ * api.github.com, which must not receive an enterprise token.
22
+ */
23
+ export declare function gitHubApiUrl(host?: string): GitHubApiUrl;
24
+ /** The host a git remote URL points at, lower-cased, or undefined when the URL has no authority. */
25
+ export declare function remoteHost(remoteUrl: string): string | undefined;
26
+ /**
27
+ * The `owner/repo` out of a GitHub remote URL, anchored to the URL authority. `:digits` is a port
4
28
  * only under a scheme; in the scp-like form (`git@github.com:12345/repo`) the colon starts the PATH
5
29
  * and an all-digits owner is a legal GitHub username.
6
30
  */
7
31
  export declare function parseGitHubRepo(remoteUrl: string): string | undefined;
8
32
  /**
9
- * Does this remote point at GitHub? A host test only — an unparseable github.com remote is still
10
- * GitHub's to claim. Host equality, not substring: `github.com` can be a path segment on another host.
33
+ * Does this remote point at GitHub — github.com, or the GitHub Enterprise Server host `GITHUB_SERVER_URL`
34
+ * names? A host test only — an unparseable GitHub remote is still GitHub's to claim. Host equality, not
35
+ * substring: `github.com` can be a path segment on another host.
11
36
  */
12
37
  export declare function isGitHubRemote(remoteUrl: string): boolean;
13
38
  /** Warning sink; a plain callback rather than a `Logger` so this module needs no logger aspect. */
@@ -17,10 +42,16 @@ export declare class GitHubClient implements GitHostProvider {
17
42
  private token;
18
43
  /** `owner/repo`. Readable so callers (and tests) can see *which* repository a resolved client speaks to. */
19
44
  readonly repo: string;
45
+ /**
46
+ * The REST API base, e.g. `https://api.github.com` (the default) or a GitHub Enterprise Server's
47
+ * `https://<host>/api/v3`; `fromEnv` resolves it for the remote's host.
48
+ */
49
+ readonly apiUrl: string;
20
50
  private fetchImpl;
21
51
  constructor(opts: {
22
52
  token: string;
23
53
  repo: string;
54
+ apiUrl?: string;
24
55
  fetchImpl?: typeof fetch;
25
56
  });
26
57
  /**
@@ -72,15 +103,19 @@ export declare class GitHubClient implements GitHostProvider {
72
103
  }
73
104
  /**
74
105
  * The registrable GitHub provider: resolves its `GitHubClient` from the environment lazily, since
75
- * registration happens at aspect load, before credentials are known. A resolved client is memoized;
76
- * an unresolved one is retried so a later call that does carry the remote URL can still succeed.
106
+ * registration happens at aspect load, before credentials are known. A resolved client is memoized per
107
+ * remote; an unresolved one is retried so a later call that does carry the remote URL can still succeed.
77
108
  */
78
109
  export declare class GitHubHostProvider implements GitHostProvider {
79
110
  private onWarning;
80
111
  readonly name = "github";
81
112
  private client;
113
+ /** The remote `client` was resolved for. */
114
+ private clientRemote;
82
115
  /** The last `origin` URL seen, so a PR method can still recover `owner/repo` from it. */
83
116
  private remoteHint;
117
+ /** Warnings already emitted: an unresolved client is retried on every call, its warning is not. */
118
+ private warned;
84
119
  constructor(onWarning?: WarnFn);
85
120
  matchesRemote(remoteUrl: string): boolean;
86
121
  /**
@@ -103,5 +138,6 @@ export declare class GitHubHostProvider implements GitHostProvider {
103
138
  createIfAbsent?: boolean;
104
139
  }): Promise<void>;
105
140
  private resolveClient;
141
+ private warnOnce;
106
142
  private requireClient;
107
143
  }
@@ -4,49 +4,133 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.GitHubHostProvider = exports.GitHubClient = void 0;
7
+ exports.gitHubApiUrl = gitHubApiUrl;
8
+ exports.gitHubServerHost = gitHubServerHost;
7
9
  exports.isGitHubRemote = isGitHubRemote;
8
10
  exports.parseGitHubRepo = parseGitHubRepo;
11
+ exports.remoteHost = remoteHost;
9
12
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
10
13
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
11
14
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
15
+ const GITHUB_DOT_COM = 'github.com';
16
+ const GITHUB_DOT_COM_API = 'https://api.github.com';
17
+ const WEB_PROTOCOLS = ['http:', 'https:'];
18
+
19
+ /** The GitHub instance `GITHUB_SERVER_URL` names, or undefined when it is unset or malformed. */
20
+ function gitHubServerUrl() {
21
+ try {
22
+ if (process.env.GITHUB_SERVER_URL) return new URL(process.env.GITHUB_SERVER_URL);
23
+ } catch {
24
+ // a malformed value names no instance
25
+ }
26
+ return undefined;
27
+ }
28
+
29
+ /**
30
+ * The host of the GitHub instance this run belongs to: the one `GITHUB_SERVER_URL` names (Actions sets
31
+ * it on every runner — `https://github.com`, or the GitHub Enterprise Server URL), else github.com.
32
+ */
33
+ function gitHubServerHost() {
34
+ return gitHubServerUrl()?.hostname.toLowerCase() || GITHUB_DOT_COM;
35
+ }
36
+
37
+ /** The hosts whose remotes are GitHub's: github.com, plus a GitHub Enterprise Server host. */
38
+ function gitHubHosts() {
39
+ const serverHost = gitHubServerHost();
40
+ return serverHost === GITHUB_DOT_COM ? [GITHUB_DOT_COM] : [GITHUB_DOT_COM, serverHost];
41
+ }
42
+
43
+ /** A resolved REST API base, or why the environment's API cannot be trusted with the repository's token. */
44
+
45
+ /**
46
+ * The REST API base for a repository on `host` (the `GITHUB_SERVER_URL` instance's host when omitted).
47
+ * Every request to it carries that instance's token, so:
48
+ * - github.com (and any host that is not the enterprise one) is always `https://api.github.com`.
49
+ * - the enterprise host takes `GITHUB_API_URL` only when it lives on that host or on `api.<host>`
50
+ * (GHE.com data residency: `https://<sub>.ghe.com` serves its API at `https://api.<sub>.ghe.com`);
51
+ * unset, it is the GHES convention `<GITHUB_SERVER_URL origin>/api/v3`. An https server's API must be
52
+ * https too, so the token never travels in plaintext. Any other API is refused — never replaced by
53
+ * api.github.com, which must not receive an enterprise token.
54
+ */
55
+ function gitHubApiUrl(host) {
56
+ const serverUrl = gitHubServerUrl();
57
+ const serverHost = gitHubServerHost();
58
+ if (!serverUrl || serverHost === GITHUB_DOT_COM || host && host.toLowerCase() !== serverHost) {
59
+ return {
60
+ url: GITHUB_DOT_COM_API
61
+ };
62
+ }
63
+ const refuse = reason => ({
64
+ error: `${reason} — refusing to send the token of the GITHUB_SERVER_URL instance "${process.env.GITHUB_SERVER_URL}" to it`
65
+ });
66
+ if (!WEB_PROTOCOLS.includes(serverUrl.protocol)) return refuse(`GITHUB_SERVER_URL is not an http(s) URL`);
67
+ const apiUrl = process.env.GITHUB_API_URL;
68
+ if (!apiUrl) return {
69
+ url: `${serverUrl.origin}/api/v3`
70
+ };
71
+ let api;
72
+ try {
73
+ api = new URL(apiUrl);
74
+ } catch {
75
+ // a malformed value is refused below like any other foreign API
76
+ }
77
+ if (!api || ![serverHost, `api.${serverHost}`].includes(api.hostname.toLowerCase())) {
78
+ return refuse(`GITHUB_API_URL "${apiUrl}" is not on ${serverHost} or api.${serverHost}`);
79
+ }
80
+ // the token travels at least as securely as the server is reached: never in plaintext from an https server
81
+ const protocols = serverUrl.protocol === 'https:' ? ['https:'] : WEB_PROTOCOLS;
82
+ if (!protocols.includes(api.protocol)) {
83
+ return refuse(`GITHUB_API_URL "${apiUrl}" is not ${protocols.map(p => p.slice(0, -1)).join(' or ')}`);
84
+ }
85
+ // the base is a path prefix: `/repos/...` appended after a query or fragment would never reach the API
86
+ if (api.search || api.hash) return refuse(`GITHUB_API_URL "${apiUrl}" carries a query or fragment`);
87
+ return {
88
+ url: apiUrl.replace(/\/+$/, '')
89
+ };
90
+ }
91
+
92
+ /** The host a git remote URL points at, lower-cased, or undefined when the URL has no authority. */
93
+ function remoteHost(remoteUrl) {
94
+ return remoteUrl.trim().match(/^(?:[a-z+]+:\/\/)?(?:[^@/]+@)?([^:/]+)/i)?.[1]?.toLowerCase();
95
+ }
96
+
12
97
  /**
13
- * The `owner/repo` out of a github.com remote URL, anchored to the URL authority. `:digits` is a port
98
+ * The `owner/repo` out of a GitHub remote URL, anchored to the URL authority. `:digits` is a port
14
99
  * only under a scheme; in the scp-like form (`git@github.com:12345/repo`) the colon starts the PATH
15
100
  * and an all-digits owner is a legal GitHub username.
16
101
  */
17
102
  function parseGitHubRepo(remoteUrl) {
18
103
  const url = remoteUrl.trim();
104
+ const host = remoteHost(url);
105
+ if (!host || !gitHubHosts().includes(host)) return undefined;
106
+ const hostPattern = host.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
19
107
  const hasScheme = /^[a-z+]+:\/\//i.test(url);
20
- const match = hasScheme ? url.match(/(?:\/\/|@)github\.com(?::\d+)?\/([^/]+\/[^/]+?)(?:\.git)?$/i) : url.match(/(?:^|@)github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/i);
108
+ const match = hasScheme ? url.match(new RegExp(`(?:\\/\\/|@)${hostPattern}(?::\\d+)?\\/([^/]+\\/[^/]+?)(?:\\.git)?$`, 'i')) : url.match(new RegExp(`(?:^|@)${hostPattern}[:/]([^/]+\\/[^/]+?)(?:\\.git)?$`, 'i'));
21
109
  return match?.[1];
22
110
  }
23
111
 
24
- /** The host a git remote URL points at, lower-cased, or undefined when the URL has no authority. */
25
- function remoteHost(remoteUrl) {
26
- return remoteUrl.trim().match(/^(?:[a-z+]+:\/\/)?(?:[^@/]+@)?([^:/]+)/i)?.[1]?.toLowerCase();
27
- }
28
-
29
112
  /**
30
- * Does this remote point at GitHub? A host test only — an unparseable github.com remote is still
31
- * GitHub's to claim. Host equality, not substring: `github.com` can be a path segment on another host.
113
+ * Does this remote point at GitHub — github.com, or the GitHub Enterprise Server host `GITHUB_SERVER_URL`
114
+ * names? A host test only — an unparseable GitHub remote is still GitHub's to claim. Host equality, not
115
+ * substring: `github.com` can be a path segment on another host.
32
116
  */
33
117
  function isGitHubRemote(remoteUrl) {
34
- return remoteHost(remoteUrl) === 'github.com';
118
+ const host = remoteHost(remoteUrl);
119
+ return Boolean(host && gitHubHosts().includes(host));
35
120
  }
36
- const API = 'https://api.github.com';
37
121
 
38
122
  /**
39
123
  * The `rel="next"` URL out of a GitHub `Link` response header, or undefined on the last page. The
40
124
  * header is response data, and `requestRaw` attaches the bearer token to whatever URL it is handed —
41
125
  * so a next link whose origin is not the API's reads as "last page", never as a request target.
42
126
  */
43
- function nextPageUrl(linkHeader) {
127
+ function nextPageUrl(linkHeader, apiUrl) {
44
128
  if (!linkHeader) return undefined;
45
129
  const next = linkHeader.split(',').find(part => part.includes('rel="next"'));
46
130
  const url = next?.match(/<([^>]+)>/)?.[1];
47
131
  if (!url) return undefined;
48
132
  try {
49
- return new URL(url).origin === API ? url : undefined;
133
+ return new URL(url).origin === new URL(apiUrl).origin ? url : undefined;
50
134
  } catch {
51
135
  return undefined;
52
136
  }
@@ -61,9 +145,15 @@ class GitHubClient {
61
145
  _defineProperty(this, "token", void 0);
62
146
  /** `owner/repo`. Readable so callers (and tests) can see *which* repository a resolved client speaks to. */
63
147
  _defineProperty(this, "repo", void 0);
148
+ /**
149
+ * The REST API base, e.g. `https://api.github.com` (the default) or a GitHub Enterprise Server's
150
+ * `https://<host>/api/v3`; `fromEnv` resolves it for the remote's host.
151
+ */
152
+ _defineProperty(this, "apiUrl", void 0);
64
153
  _defineProperty(this, "fetchImpl", void 0);
65
154
  this.token = opts.token;
66
155
  this.repo = opts.repo;
156
+ this.apiUrl = opts.apiUrl ?? GITHUB_DOT_COM_API;
67
157
  this.fetchImpl = opts.fetchImpl ?? fetch;
68
158
  }
69
159
 
@@ -86,9 +176,16 @@ class GitHubClient {
86
176
  if (repoFromRemote && repoFromEnv && repoFromRemote.toLowerCase() !== repoFromEnv.toLowerCase()) {
87
177
  warn(`bit ci sync: GITHUB_REPOSITORY is "${repoFromEnv}" but the "origin" remote points at ` + `"${repoFromRemote}" — using "${repoFromRemote}", the repository this run pushes its branches to.`);
88
178
  }
179
+ // Without a remote, the GITHUB_REPOSITORY repository lives on the GITHUB_SERVER_URL instance.
180
+ const api = gitHubApiUrl(gitRemoteUrl ? remoteHost(gitRemoteUrl) : undefined);
181
+ if ('error' in api) {
182
+ warn(`bit ci sync: ${api.error}. The GitHub provider is not configured.`);
183
+ return undefined;
184
+ }
89
185
  return new GitHubClient({
90
186
  token,
91
- repo
187
+ repo,
188
+ apiUrl: api.url
92
189
  });
93
190
  }
94
191
  matchesRemote(remoteUrl) {
@@ -102,7 +199,7 @@ class GitHubClient {
102
199
 
103
200
  /** `pathOrUrl` may be a path relative to this repo, or an absolute URL (a `Link` header's next page). */
104
201
  async requestRaw(method, pathOrUrl, body) {
105
- const url = /^https?:\/\//i.test(pathOrUrl) ? pathOrUrl : `${API}/repos/${this.repo}${pathOrUrl}`;
202
+ const url = /^https?:\/\//i.test(pathOrUrl) ? pathOrUrl : `${this.apiUrl}/repos/${this.repo}${pathOrUrl}`;
106
203
  const res = await this.fetchImpl(url, {
107
204
  method,
108
205
  headers: {
@@ -176,7 +273,7 @@ class GitHubClient {
176
273
  if (match) return {
177
274
  id: match.id
178
275
  };
179
- next = nextPageUrl(res.headers.get('link'));
276
+ next = nextPageUrl(res.headers.get('link'), this.apiUrl);
180
277
  }
181
278
  return next ? 'unknown' : 'absent';
182
279
  }
@@ -211,8 +308,8 @@ class GitHubClient {
211
308
 
212
309
  /**
213
310
  * The registrable GitHub provider: resolves its `GitHubClient` from the environment lazily, since
214
- * registration happens at aspect load, before credentials are known. A resolved client is memoized;
215
- * an unresolved one is retried so a later call that does carry the remote URL can still succeed.
311
+ * registration happens at aspect load, before credentials are known. A resolved client is memoized per
312
+ * remote; an unresolved one is retried so a later call that does carry the remote URL can still succeed.
216
313
  */
217
314
  exports.GitHubClient = GitHubClient;
218
315
  class GitHubHostProvider {
@@ -220,8 +317,17 @@ class GitHubHostProvider {
220
317
  this.onWarning = onWarning;
221
318
  _defineProperty(this, "name", 'github');
222
319
  _defineProperty(this, "client", void 0);
320
+ /** The remote `client` was resolved for. */
321
+ _defineProperty(this, "clientRemote", void 0);
223
322
  /** The last `origin` URL seen, so a PR method can still recover `owner/repo` from it. */
224
323
  _defineProperty(this, "remoteHint", void 0);
324
+ /** Warnings already emitted: an unresolved client is retried on every call, its warning is not. */
325
+ _defineProperty(this, "warned", new Set());
326
+ _defineProperty(this, "warnOnce", message => {
327
+ if (this.warned.has(message)) return;
328
+ this.warned.add(message);
329
+ this.onWarning(message);
330
+ });
225
331
  }
226
332
  matchesRemote(remoteUrl) {
227
333
  const matches = isGitHubRemote(remoteUrl);
@@ -260,13 +366,18 @@ class GitHubHostProvider {
260
366
  return this.requireClient().upsertComment(prNumber, marker, body, options);
261
367
  }
262
368
  resolveClient(remoteUrl) {
263
- if (!this.client) this.client = GitHubClient.fromEnv(remoteUrl ?? this.remoteHint, this.onWarning);
369
+ const remote = remoteUrl ?? this.remoteHint;
370
+ // The client pins the remote's repository and API, so another remote needs its own client.
371
+ if (!this.client || this.clientRemote !== remote) {
372
+ this.client = GitHubClient.fromEnv(remote, this.warnOnce);
373
+ this.clientRemote = remote;
374
+ }
264
375
  return this.client;
265
376
  }
266
377
  requireClient() {
267
378
  const client = this.resolveClient();
268
379
  if (!client) {
269
- throw new Error(`the github host provider is not configured: set BIT_GITHUB_TOKEN (or GITHUB_TOKEN), and either ` + `GITHUB_REPOSITORY or a github.com "origin" remote`);
380
+ throw new Error(`the github host provider is not configured: set BIT_GITHUB_TOKEN (or GITHUB_TOKEN), and either ` + `GITHUB_REPOSITORY or a GitHub "origin" remote (github.com, or the GITHUB_SERVER_URL host)`);
270
381
  }
271
382
  return client;
272
383
  }
@@ -1 +1 @@
1
- {"version":3,"names":["parseGitHubRepo","remoteUrl","url","trim","hasScheme","test","match","remoteHost","toLowerCase","isGitHubRemote","API","nextPageUrl","linkHeader","undefined","next","split","find","part","includes","URL","origin","noopWarn","GitHubClient","constructor","opts","_defineProperty","token","repo","fetchImpl","fetch","fromEnv","gitRemoteUrl","warn","process","env","BIT_GITHUB_TOKEN","GITHUB_TOKEN","repoFromRemote","repoFromEnv","GITHUB_REPOSITORY","matchesRemote","isConfigured","Boolean","requestRaw","method","pathOrUrl","body","res","headers","authorization","accept","JSON","stringify","ok","text","catch","Error","status","request","path","json","toPrInfo","raw","number","state","labels","map","l","name","headRef","head","ref","htmlUrl","html_url","findPrByBranch","branch","owner","list","encodeURIComponent","length","createPr","closePr","prNumber","comment","addLabel","label","findMarkedComment","marker","page","c","id","get","upsertComment","options","existing","createIfAbsent","exports","GitHubHostProvider","onWarning","matches","remoteHint","resolveClient","requireClient","client"],"sources":["github-client.ts"],"sourcesContent":["import type { GitHostProvider, PrInfo } from './git-host-provider';\n\n/**\n * The `owner/repo` out of a github.com remote URL, anchored to the URL authority. `:digits` is a port\n * only under a scheme; in the scp-like form (`git@github.com:12345/repo`) the colon starts the PATH\n * and an all-digits owner is a legal GitHub username.\n */\nexport function parseGitHubRepo(remoteUrl: string): string | undefined {\n const url = remoteUrl.trim();\n const hasScheme = /^[a-z+]+:\\/\\//i.test(url);\n const match = hasScheme\n ? url.match(/(?:\\/\\/|@)github\\.com(?::\\d+)?\\/([^/]+\\/[^/]+?)(?:\\.git)?$/i)\n : url.match(/(?:^|@)github\\.com[:/]([^/]+\\/[^/]+?)(?:\\.git)?$/i);\n return match?.[1];\n}\n\n/** The host a git remote URL points at, lower-cased, or undefined when the URL has no authority. */\nfunction remoteHost(remoteUrl: string): string | undefined {\n return remoteUrl\n .trim()\n .match(/^(?:[a-z+]+:\\/\\/)?(?:[^@/]+@)?([^:/]+)/i)?.[1]\n ?.toLowerCase();\n}\n\n/**\n * Does this remote point at GitHub? A host test only — an unparseable github.com remote is still\n * GitHub's to claim. Host equality, not substring: `github.com` can be a path segment on another host.\n */\nexport function isGitHubRemote(remoteUrl: string): boolean {\n return remoteHost(remoteUrl) === 'github.com';\n}\n\nconst API = 'https://api.github.com';\n\n/**\n * The `rel=\"next\"` URL out of a GitHub `Link` response header, or undefined on the last page. The\n * header is response data, and `requestRaw` attaches the bearer token to whatever URL it is handed —\n * so a next link whose origin is not the API's reads as \"last page\", never as a request target.\n */\nfunction nextPageUrl(linkHeader: string | null): string | undefined {\n if (!linkHeader) return undefined;\n const next = linkHeader.split(',').find((part) => part.includes('rel=\"next\"'));\n const url = next?.match(/<([^>]+)>/)?.[1];\n if (!url) return undefined;\n try {\n return new URL(url).origin === API ? url : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Warning sink; a plain callback rather than a `Logger` so this module needs no logger aspect. */\nexport type WarnFn = (message: string) => void;\n\nconst noopWarn: WarnFn = () => {};\n\nexport class GitHubClient implements GitHostProvider {\n readonly name = 'github';\n\n private token: string;\n /** `owner/repo`. Readable so callers (and tests) can see *which* repository a resolved client speaks to. */\n readonly repo: string;\n private fetchImpl: typeof fetch;\n\n constructor(opts: { token: string; repo: string; fetchImpl?: typeof fetch }) {\n this.token = opts.token;\n this.repo = opts.repo;\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n /**\n * The client this environment describes, or undefined when it describes none. `origin` outranks\n * `GITHUB_REPOSITORY`: every PR operation names a branch that only exists on `origin`, so if the two\n * disagree the origin-parsed repository wins and the mismatch is warned about once.\n */\n static fromEnv(gitRemoteUrl?: string, warn: WarnFn = noopWarn): GitHubClient | undefined {\n // BIT_GITHUB_TOKEN is the override; GITHUB_TOKEN is the ambient default Actions injects everywhere.\n const token = process.env.BIT_GITHUB_TOKEN || process.env.GITHUB_TOKEN;\n // A remote that is demonstrably not GitHub's is a hard no, whatever the environment says —\n // GITHUB_REPOSITORY is set on every Actions job, including ones whose origin is another host.\n if (gitRemoteUrl && !isGitHubRemote(gitRemoteUrl)) return undefined;\n const repoFromRemote = gitRemoteUrl ? parseGitHubRepo(gitRemoteUrl) : undefined;\n const repoFromEnv = process.env.GITHUB_REPOSITORY;\n const repo = repoFromRemote || repoFromEnv;\n if (!token || !repo) return undefined;\n // GitHub owner/repo names are case-insensitive.\n if (repoFromRemote && repoFromEnv && repoFromRemote.toLowerCase() !== repoFromEnv.toLowerCase()) {\n warn(\n `bit ci sync: GITHUB_REPOSITORY is \"${repoFromEnv}\" but the \"origin\" remote points at ` +\n `\"${repoFromRemote}\" — using \"${repoFromRemote}\", the repository this run pushes its branches to.`\n );\n }\n return new GitHubClient({ token, repo });\n }\n\n matchesRemote(remoteUrl: string): boolean {\n return isGitHubRemote(remoteUrl);\n }\n\n /** A constructed client always has both halves — it cannot be built without them. */\n isConfigured(): boolean {\n return Boolean(this.token && this.repo);\n }\n\n /** `pathOrUrl` may be a path relative to this repo, or an absolute URL (a `Link` header's next page). */\n private async requestRaw(method: string, pathOrUrl: string, body?: unknown): Promise<Response> {\n const url = /^https?:\\/\\//i.test(pathOrUrl) ? pathOrUrl : `${API}/repos/${this.repo}${pathOrUrl}`;\n const res = await this.fetchImpl(url, {\n method,\n headers: {\n authorization: `Bearer ${this.token}`,\n accept: 'application/vnd.github+json',\n 'content-type': 'application/json',\n 'x-github-api-version': '2022-11-28',\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`GitHub API ${method} ${pathOrUrl} failed: ${res.status} ${text}`);\n }\n return res;\n }\n\n private async request(method: string, path: string, body?: unknown): Promise<any> {\n const res = await this.requestRaw(method, path, body);\n return res.status === 204 ? undefined : res.json();\n }\n\n private toPrInfo(raw: any): PrInfo {\n return {\n number: raw.number,\n state: raw.state,\n labels: (raw.labels ?? []).map((l: any) => (typeof l === 'string' ? l : l.name)),\n headRef: raw.head?.ref,\n htmlUrl: raw.html_url,\n };\n }\n\n async findPrByBranch(branch: string): Promise<PrInfo | undefined> {\n const owner = this.repo.split('/')[0];\n const list = await this.request('GET', `/pulls?state=open&head=${encodeURIComponent(`${owner}:${branch}`)}`);\n return list.length ? this.toPrInfo(list[0]) : undefined;\n }\n\n async createPr(opts: { head: string; base: string; title: string; body: string }): Promise<PrInfo> {\n return this.toPrInfo(await this.request('POST', '/pulls', opts));\n }\n\n async closePr(prNumber: number, comment?: string): Promise<void> {\n if (comment) await this.comment(prNumber, comment);\n await this.request('PATCH', `/pulls/${prNumber}`, { state: 'closed' });\n }\n\n async comment(prNumber: number, body: string): Promise<void> {\n await this.request('POST', `/issues/${prNumber}/comments`, { body });\n }\n\n async addLabel(prNumber: number, label: string): Promise<void> {\n await this.request('POST', `/issues/${prNumber}/labels`, { labels: [label] });\n }\n\n /**\n * The marker-bearing comment on the PR, `'absent'` when every page was searched, or `'unknown'`\n * when the defensive page cap cut the search short. GitHub defaults `per_page` to 30 and orders\n * ascending, and the maintained comment is posted once, early in a PR's life — so it lives in the\n * first pages and the search returns as soon as it is seen. `'unknown'` is distinct from `'absent'`\n * because running out of budget must not read as \"not there\": the caller would post a duplicate\n * report on every later push.\n */\n private async findMarkedComment(prNumber: number, marker: string): Promise<{ id: number } | 'absent' | 'unknown'> {\n let next: string | undefined = `/issues/${prNumber}/comments?per_page=100`;\n // Defensive cap: 20 pages (2,000 comments) is far past any real PR; without it a malformed or\n // adversarial `Link` header could loop this call forever.\n for (let page = 0; next && page < 20; page += 1) {\n const res: Response = await this.requestRaw('GET', next);\n const body = (await res.json()) as any[];\n const match = body.find((c: any) => (c.body ?? '').includes(marker));\n if (match) return { id: match.id };\n next = nextPageUrl(res.headers.get('link'));\n }\n return next ? 'unknown' : 'absent';\n }\n\n /**\n * Find the comment carrying `marker` (an HTML comment embedded in the body) and replace its body,\n * or post `body` as a new comment when none exists and `options.createIfAbsent` is not false.\n * GitHub's comment PATCH endpoint is `/issues/comments/{id}`, not `/issues/{pr}/comments/{id}` —\n * a comment id is unique per repository, not scoped under the issue/PR that carries it.\n *\n * Named to match `GitHostProvider.upsertComment` exactly (not e.g. `upsertIssueComment`): a\n * `GitHubClient` registered directly as a provider must satisfy the interface's optional method\n * under its real name, or callers that feature-test via `gitHost.upsertComment` would silently\n * treat a fully-capable client as unsupported.\n */\n async upsertComment(\n prNumber: number,\n marker: string,\n body: string,\n options: { createIfAbsent?: boolean } = {}\n ): Promise<void> {\n const existing = await this.findMarkedComment(prNumber, marker);\n if (existing === 'unknown') {\n // Surfaces through the caller's warn-and-skip path; posting blind would duplicate the report.\n throw new Error(\n `PR #${prNumber} has too many comments to establish whether the \"${marker}\" comment already exists`\n );\n }\n if (existing !== 'absent') {\n await this.request('PATCH', `/issues/comments/${existing.id}`, { body });\n return;\n }\n if (options.createIfAbsent === false) return;\n await this.comment(prNumber, body);\n }\n}\n\n/**\n * The registrable GitHub provider: resolves its `GitHubClient` from the environment lazily, since\n * registration happens at aspect load, before credentials are known. A resolved client is memoized;\n * an unresolved one is retried so a later call that does carry the remote URL can still succeed.\n */\nexport class GitHubHostProvider implements GitHostProvider {\n readonly name = 'github';\n\n private client: GitHubClient | undefined;\n\n /** The last `origin` URL seen, so a PR method can still recover `owner/repo` from it. */\n private remoteHint: string | undefined;\n\n constructor(private onWarning: WarnFn = noopWarn) {}\n\n matchesRemote(remoteUrl: string): boolean {\n const matches = isGitHubRemote(remoteUrl);\n // Only remember a remote that is ours — a foreign hint could later pair with GITHUB_REPOSITORY\n // into a client for the wrong repository.\n if (matches) this.remoteHint = remoteUrl;\n return matches;\n }\n\n /**\n * A known non-GitHub remote can never count as configured, however complete the environment looks:\n * on Actions the env is always set, so answering \"configured\" for a remote this provider declined to\n * claim would make it the sole-configured fallback and aim PRs at the wrong host's repository.\n */\n isConfigured(remoteUrl?: string): boolean {\n if (remoteUrl && !isGitHubRemote(remoteUrl)) return false;\n if (remoteUrl) this.remoteHint = remoteUrl;\n return Boolean(this.resolveClient(remoteUrl));\n }\n\n async findPrByBranch(branch: string): Promise<PrInfo | undefined> {\n return this.requireClient().findPrByBranch(branch);\n }\n\n async createPr(opts: { head: string; base: string; title: string; body: string }): Promise<PrInfo> {\n return this.requireClient().createPr(opts);\n }\n\n async closePr(prNumber: number, comment?: string): Promise<void> {\n return this.requireClient().closePr(prNumber, comment);\n }\n\n async comment(prNumber: number, body: string): Promise<void> {\n return this.requireClient().comment(prNumber, body);\n }\n\n async addLabel(prNumber: number, label: string): Promise<void> {\n return this.requireClient().addLabel(prNumber, label);\n }\n\n async upsertComment(\n prNumber: number,\n marker: string,\n body: string,\n options?: { createIfAbsent?: boolean }\n ): Promise<void> {\n return this.requireClient().upsertComment(prNumber, marker, body, options);\n }\n\n private resolveClient(remoteUrl?: string): GitHubClient | undefined {\n if (!this.client) this.client = GitHubClient.fromEnv(remoteUrl ?? this.remoteHint, this.onWarning);\n return this.client;\n }\n\n private requireClient(): GitHubClient {\n const client = this.resolveClient();\n if (!client) {\n throw new Error(\n `the github host provider is not configured: set BIT_GITHUB_TOKEN (or GITHUB_TOKEN), and either ` +\n `GITHUB_REPOSITORY or a github.com \"origin\" remote`\n );\n }\n return client;\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["GITHUB_DOT_COM","GITHUB_DOT_COM_API","WEB_PROTOCOLS","gitHubServerUrl","process","env","GITHUB_SERVER_URL","URL","undefined","gitHubServerHost","hostname","toLowerCase","gitHubHosts","serverHost","gitHubApiUrl","host","serverUrl","url","refuse","reason","error","includes","protocol","apiUrl","GITHUB_API_URL","origin","api","protocols","map","p","slice","join","search","hash","replace","remoteHost","remoteUrl","trim","match","parseGitHubRepo","hostPattern","hasScheme","test","RegExp","isGitHubRemote","Boolean","nextPageUrl","linkHeader","next","split","find","part","noopWarn","GitHubClient","constructor","opts","_defineProperty","token","repo","fetchImpl","fetch","fromEnv","gitRemoteUrl","warn","BIT_GITHUB_TOKEN","GITHUB_TOKEN","repoFromRemote","repoFromEnv","GITHUB_REPOSITORY","matchesRemote","isConfigured","requestRaw","method","pathOrUrl","body","res","headers","authorization","accept","JSON","stringify","ok","text","catch","Error","status","request","path","json","toPrInfo","raw","number","state","labels","l","name","headRef","head","ref","htmlUrl","html_url","findPrByBranch","branch","owner","list","encodeURIComponent","length","createPr","closePr","prNumber","comment","addLabel","label","findMarkedComment","marker","page","c","id","get","upsertComment","options","existing","createIfAbsent","exports","GitHubHostProvider","onWarning","Set","message","warned","has","add","matches","remoteHint","resolveClient","requireClient","remote","client","clientRemote","warnOnce"],"sources":["github-client.ts"],"sourcesContent":["import type { GitHostProvider, PrInfo } from './git-host-provider';\n\nconst GITHUB_DOT_COM = 'github.com';\nconst GITHUB_DOT_COM_API = 'https://api.github.com';\nconst WEB_PROTOCOLS = ['http:', 'https:'];\n\n/** The GitHub instance `GITHUB_SERVER_URL` names, or undefined when it is unset or malformed. */\nfunction gitHubServerUrl(): URL | undefined {\n try {\n if (process.env.GITHUB_SERVER_URL) return new URL(process.env.GITHUB_SERVER_URL);\n } catch {\n // a malformed value names no instance\n }\n return undefined;\n}\n\n/**\n * The host of the GitHub instance this run belongs to: the one `GITHUB_SERVER_URL` names (Actions sets\n * it on every runner — `https://github.com`, or the GitHub Enterprise Server URL), else github.com.\n */\nexport function gitHubServerHost(): string {\n return gitHubServerUrl()?.hostname.toLowerCase() || GITHUB_DOT_COM;\n}\n\n/** The hosts whose remotes are GitHub's: github.com, plus a GitHub Enterprise Server host. */\nfunction gitHubHosts(): string[] {\n const serverHost = gitHubServerHost();\n return serverHost === GITHUB_DOT_COM ? [GITHUB_DOT_COM] : [GITHUB_DOT_COM, serverHost];\n}\n\n/** A resolved REST API base, or why the environment's API cannot be trusted with the repository's token. */\nexport type GitHubApiUrl = { url: string } | { error: string };\n\n/**\n * The REST API base for a repository on `host` (the `GITHUB_SERVER_URL` instance's host when omitted).\n * Every request to it carries that instance's token, so:\n * - github.com (and any host that is not the enterprise one) is always `https://api.github.com`.\n * - the enterprise host takes `GITHUB_API_URL` only when it lives on that host or on `api.<host>`\n * (GHE.com data residency: `https://<sub>.ghe.com` serves its API at `https://api.<sub>.ghe.com`);\n * unset, it is the GHES convention `<GITHUB_SERVER_URL origin>/api/v3`. An https server's API must be\n * https too, so the token never travels in plaintext. Any other API is refused — never replaced by\n * api.github.com, which must not receive an enterprise token.\n */\nexport function gitHubApiUrl(host?: string): GitHubApiUrl {\n const serverUrl = gitHubServerUrl();\n const serverHost = gitHubServerHost();\n if (!serverUrl || serverHost === GITHUB_DOT_COM || (host && host.toLowerCase() !== serverHost)) {\n return { url: GITHUB_DOT_COM_API };\n }\n const refuse = (reason: string): GitHubApiUrl => ({\n error: `${reason} — refusing to send the token of the GITHUB_SERVER_URL instance \"${process.env.GITHUB_SERVER_URL}\" to it`,\n });\n if (!WEB_PROTOCOLS.includes(serverUrl.protocol)) return refuse(`GITHUB_SERVER_URL is not an http(s) URL`);\n const apiUrl = process.env.GITHUB_API_URL;\n if (!apiUrl) return { url: `${serverUrl.origin}/api/v3` };\n let api: URL | undefined;\n try {\n api = new URL(apiUrl);\n } catch {\n // a malformed value is refused below like any other foreign API\n }\n if (!api || ![serverHost, `api.${serverHost}`].includes(api.hostname.toLowerCase())) {\n return refuse(`GITHUB_API_URL \"${apiUrl}\" is not on ${serverHost} or api.${serverHost}`);\n }\n // the token travels at least as securely as the server is reached: never in plaintext from an https server\n const protocols = serverUrl.protocol === 'https:' ? ['https:'] : WEB_PROTOCOLS;\n if (!protocols.includes(api.protocol)) {\n return refuse(`GITHUB_API_URL \"${apiUrl}\" is not ${protocols.map((p) => p.slice(0, -1)).join(' or ')}`);\n }\n // the base is a path prefix: `/repos/...` appended after a query or fragment would never reach the API\n if (api.search || api.hash) return refuse(`GITHUB_API_URL \"${apiUrl}\" carries a query or fragment`);\n return { url: apiUrl.replace(/\\/+$/, '') };\n}\n\n/** The host a git remote URL points at, lower-cased, or undefined when the URL has no authority. */\nexport function remoteHost(remoteUrl: string): string | undefined {\n return remoteUrl\n .trim()\n .match(/^(?:[a-z+]+:\\/\\/)?(?:[^@/]+@)?([^:/]+)/i)?.[1]\n ?.toLowerCase();\n}\n\n/**\n * The `owner/repo` out of a GitHub remote URL, anchored to the URL authority. `:digits` is a port\n * only under a scheme; in the scp-like form (`git@github.com:12345/repo`) the colon starts the PATH\n * and an all-digits owner is a legal GitHub username.\n */\nexport function parseGitHubRepo(remoteUrl: string): string | undefined {\n const url = remoteUrl.trim();\n const host = remoteHost(url);\n if (!host || !gitHubHosts().includes(host)) return undefined;\n const hostPattern = host.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const hasScheme = /^[a-z+]+:\\/\\//i.test(url);\n const match = hasScheme\n ? url.match(new RegExp(`(?:\\\\/\\\\/|@)${hostPattern}(?::\\\\d+)?\\\\/([^/]+\\\\/[^/]+?)(?:\\\\.git)?$`, 'i'))\n : url.match(new RegExp(`(?:^|@)${hostPattern}[:/]([^/]+\\\\/[^/]+?)(?:\\\\.git)?$`, 'i'));\n return match?.[1];\n}\n\n/**\n * Does this remote point at GitHub — github.com, or the GitHub Enterprise Server host `GITHUB_SERVER_URL`\n * names? A host test only — an unparseable GitHub remote is still GitHub's to claim. Host equality, not\n * substring: `github.com` can be a path segment on another host.\n */\nexport function isGitHubRemote(remoteUrl: string): boolean {\n const host = remoteHost(remoteUrl);\n return Boolean(host && gitHubHosts().includes(host));\n}\n\n/**\n * The `rel=\"next\"` URL out of a GitHub `Link` response header, or undefined on the last page. The\n * header is response data, and `requestRaw` attaches the bearer token to whatever URL it is handed —\n * so a next link whose origin is not the API's reads as \"last page\", never as a request target.\n */\nfunction nextPageUrl(linkHeader: string | null, apiUrl: string): string | undefined {\n if (!linkHeader) return undefined;\n const next = linkHeader.split(',').find((part) => part.includes('rel=\"next\"'));\n const url = next?.match(/<([^>]+)>/)?.[1];\n if (!url) return undefined;\n try {\n return new URL(url).origin === new URL(apiUrl).origin ? url : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Warning sink; a plain callback rather than a `Logger` so this module needs no logger aspect. */\nexport type WarnFn = (message: string) => void;\n\nconst noopWarn: WarnFn = () => {};\n\nexport class GitHubClient implements GitHostProvider {\n readonly name = 'github';\n\n private token: string;\n /** `owner/repo`. Readable so callers (and tests) can see *which* repository a resolved client speaks to. */\n readonly repo: string;\n /**\n * The REST API base, e.g. `https://api.github.com` (the default) or a GitHub Enterprise Server's\n * `https://<host>/api/v3`; `fromEnv` resolves it for the remote's host.\n */\n readonly apiUrl: string;\n private fetchImpl: typeof fetch;\n\n constructor(opts: { token: string; repo: string; apiUrl?: string; fetchImpl?: typeof fetch }) {\n this.token = opts.token;\n this.repo = opts.repo;\n this.apiUrl = opts.apiUrl ?? GITHUB_DOT_COM_API;\n this.fetchImpl = opts.fetchImpl ?? fetch;\n }\n\n /**\n * The client this environment describes, or undefined when it describes none. `origin` outranks\n * `GITHUB_REPOSITORY`: every PR operation names a branch that only exists on `origin`, so if the two\n * disagree the origin-parsed repository wins and the mismatch is warned about once.\n */\n static fromEnv(gitRemoteUrl?: string, warn: WarnFn = noopWarn): GitHubClient | undefined {\n // BIT_GITHUB_TOKEN is the override; GITHUB_TOKEN is the ambient default Actions injects everywhere.\n const token = process.env.BIT_GITHUB_TOKEN || process.env.GITHUB_TOKEN;\n // A remote that is demonstrably not GitHub's is a hard no, whatever the environment says —\n // GITHUB_REPOSITORY is set on every Actions job, including ones whose origin is another host.\n if (gitRemoteUrl && !isGitHubRemote(gitRemoteUrl)) return undefined;\n const repoFromRemote = gitRemoteUrl ? parseGitHubRepo(gitRemoteUrl) : undefined;\n const repoFromEnv = process.env.GITHUB_REPOSITORY;\n const repo = repoFromRemote || repoFromEnv;\n if (!token || !repo) return undefined;\n // GitHub owner/repo names are case-insensitive.\n if (repoFromRemote && repoFromEnv && repoFromRemote.toLowerCase() !== repoFromEnv.toLowerCase()) {\n warn(\n `bit ci sync: GITHUB_REPOSITORY is \"${repoFromEnv}\" but the \"origin\" remote points at ` +\n `\"${repoFromRemote}\" — using \"${repoFromRemote}\", the repository this run pushes its branches to.`\n );\n }\n // Without a remote, the GITHUB_REPOSITORY repository lives on the GITHUB_SERVER_URL instance.\n const api = gitHubApiUrl(gitRemoteUrl ? remoteHost(gitRemoteUrl) : undefined);\n if ('error' in api) {\n warn(`bit ci sync: ${api.error}. The GitHub provider is not configured.`);\n return undefined;\n }\n return new GitHubClient({ token, repo, apiUrl: api.url });\n }\n\n matchesRemote(remoteUrl: string): boolean {\n return isGitHubRemote(remoteUrl);\n }\n\n /** A constructed client always has both halves — it cannot be built without them. */\n isConfigured(): boolean {\n return Boolean(this.token && this.repo);\n }\n\n /** `pathOrUrl` may be a path relative to this repo, or an absolute URL (a `Link` header's next page). */\n private async requestRaw(method: string, pathOrUrl: string, body?: unknown): Promise<Response> {\n const url = /^https?:\\/\\//i.test(pathOrUrl) ? pathOrUrl : `${this.apiUrl}/repos/${this.repo}${pathOrUrl}`;\n const res = await this.fetchImpl(url, {\n method,\n headers: {\n authorization: `Bearer ${this.token}`,\n accept: 'application/vnd.github+json',\n 'content-type': 'application/json',\n 'x-github-api-version': '2022-11-28',\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`GitHub API ${method} ${pathOrUrl} failed: ${res.status} ${text}`);\n }\n return res;\n }\n\n private async request(method: string, path: string, body?: unknown): Promise<any> {\n const res = await this.requestRaw(method, path, body);\n return res.status === 204 ? undefined : res.json();\n }\n\n private toPrInfo(raw: any): PrInfo {\n return {\n number: raw.number,\n state: raw.state,\n labels: (raw.labels ?? []).map((l: any) => (typeof l === 'string' ? l : l.name)),\n headRef: raw.head?.ref,\n htmlUrl: raw.html_url,\n };\n }\n\n async findPrByBranch(branch: string): Promise<PrInfo | undefined> {\n const owner = this.repo.split('/')[0];\n const list = await this.request('GET', `/pulls?state=open&head=${encodeURIComponent(`${owner}:${branch}`)}`);\n return list.length ? this.toPrInfo(list[0]) : undefined;\n }\n\n async createPr(opts: { head: string; base: string; title: string; body: string }): Promise<PrInfo> {\n return this.toPrInfo(await this.request('POST', '/pulls', opts));\n }\n\n async closePr(prNumber: number, comment?: string): Promise<void> {\n if (comment) await this.comment(prNumber, comment);\n await this.request('PATCH', `/pulls/${prNumber}`, { state: 'closed' });\n }\n\n async comment(prNumber: number, body: string): Promise<void> {\n await this.request('POST', `/issues/${prNumber}/comments`, { body });\n }\n\n async addLabel(prNumber: number, label: string): Promise<void> {\n await this.request('POST', `/issues/${prNumber}/labels`, { labels: [label] });\n }\n\n /**\n * The marker-bearing comment on the PR, `'absent'` when every page was searched, or `'unknown'`\n * when the defensive page cap cut the search short. GitHub defaults `per_page` to 30 and orders\n * ascending, and the maintained comment is posted once, early in a PR's life — so it lives in the\n * first pages and the search returns as soon as it is seen. `'unknown'` is distinct from `'absent'`\n * because running out of budget must not read as \"not there\": the caller would post a duplicate\n * report on every later push.\n */\n private async findMarkedComment(prNumber: number, marker: string): Promise<{ id: number } | 'absent' | 'unknown'> {\n let next: string | undefined = `/issues/${prNumber}/comments?per_page=100`;\n // Defensive cap: 20 pages (2,000 comments) is far past any real PR; without it a malformed or\n // adversarial `Link` header could loop this call forever.\n for (let page = 0; next && page < 20; page += 1) {\n const res: Response = await this.requestRaw('GET', next);\n const body = (await res.json()) as any[];\n const match = body.find((c: any) => (c.body ?? '').includes(marker));\n if (match) return { id: match.id };\n next = nextPageUrl(res.headers.get('link'), this.apiUrl);\n }\n return next ? 'unknown' : 'absent';\n }\n\n /**\n * Find the comment carrying `marker` (an HTML comment embedded in the body) and replace its body,\n * or post `body` as a new comment when none exists and `options.createIfAbsent` is not false.\n * GitHub's comment PATCH endpoint is `/issues/comments/{id}`, not `/issues/{pr}/comments/{id}` —\n * a comment id is unique per repository, not scoped under the issue/PR that carries it.\n *\n * Named to match `GitHostProvider.upsertComment` exactly (not e.g. `upsertIssueComment`): a\n * `GitHubClient` registered directly as a provider must satisfy the interface's optional method\n * under its real name, or callers that feature-test via `gitHost.upsertComment` would silently\n * treat a fully-capable client as unsupported.\n */\n async upsertComment(\n prNumber: number,\n marker: string,\n body: string,\n options: { createIfAbsent?: boolean } = {}\n ): Promise<void> {\n const existing = await this.findMarkedComment(prNumber, marker);\n if (existing === 'unknown') {\n // Surfaces through the caller's warn-and-skip path; posting blind would duplicate the report.\n throw new Error(\n `PR #${prNumber} has too many comments to establish whether the \"${marker}\" comment already exists`\n );\n }\n if (existing !== 'absent') {\n await this.request('PATCH', `/issues/comments/${existing.id}`, { body });\n return;\n }\n if (options.createIfAbsent === false) return;\n await this.comment(prNumber, body);\n }\n}\n\n/**\n * The registrable GitHub provider: resolves its `GitHubClient` from the environment lazily, since\n * registration happens at aspect load, before credentials are known. A resolved client is memoized per\n * remote; an unresolved one is retried so a later call that does carry the remote URL can still succeed.\n */\nexport class GitHubHostProvider implements GitHostProvider {\n readonly name = 'github';\n\n private client: GitHubClient | undefined;\n\n /** The remote `client` was resolved for. */\n private clientRemote: string | undefined;\n\n /** The last `origin` URL seen, so a PR method can still recover `owner/repo` from it. */\n private remoteHint: string | undefined;\n\n /** Warnings already emitted: an unresolved client is retried on every call, its warning is not. */\n private warned = new Set<string>();\n\n constructor(private onWarning: WarnFn = noopWarn) {}\n\n matchesRemote(remoteUrl: string): boolean {\n const matches = isGitHubRemote(remoteUrl);\n // Only remember a remote that is ours — a foreign hint could later pair with GITHUB_REPOSITORY\n // into a client for the wrong repository.\n if (matches) this.remoteHint = remoteUrl;\n return matches;\n }\n\n /**\n * A known non-GitHub remote can never count as configured, however complete the environment looks:\n * on Actions the env is always set, so answering \"configured\" for a remote this provider declined to\n * claim would make it the sole-configured fallback and aim PRs at the wrong host's repository.\n */\n isConfigured(remoteUrl?: string): boolean {\n if (remoteUrl && !isGitHubRemote(remoteUrl)) return false;\n if (remoteUrl) this.remoteHint = remoteUrl;\n return Boolean(this.resolveClient(remoteUrl));\n }\n\n async findPrByBranch(branch: string): Promise<PrInfo | undefined> {\n return this.requireClient().findPrByBranch(branch);\n }\n\n async createPr(opts: { head: string; base: string; title: string; body: string }): Promise<PrInfo> {\n return this.requireClient().createPr(opts);\n }\n\n async closePr(prNumber: number, comment?: string): Promise<void> {\n return this.requireClient().closePr(prNumber, comment);\n }\n\n async comment(prNumber: number, body: string): Promise<void> {\n return this.requireClient().comment(prNumber, body);\n }\n\n async addLabel(prNumber: number, label: string): Promise<void> {\n return this.requireClient().addLabel(prNumber, label);\n }\n\n async upsertComment(\n prNumber: number,\n marker: string,\n body: string,\n options?: { createIfAbsent?: boolean }\n ): Promise<void> {\n return this.requireClient().upsertComment(prNumber, marker, body, options);\n }\n\n private resolveClient(remoteUrl?: string): GitHubClient | undefined {\n const remote = remoteUrl ?? this.remoteHint;\n // The client pins the remote's repository and API, so another remote needs its own client.\n if (!this.client || this.clientRemote !== remote) {\n this.client = GitHubClient.fromEnv(remote, this.warnOnce);\n this.clientRemote = remote;\n }\n return this.client;\n }\n\n private warnOnce: WarnFn = (message) => {\n if (this.warned.has(message)) return;\n this.warned.add(message);\n this.onWarning(message);\n };\n\n private requireClient(): GitHubClient {\n const client = this.resolveClient();\n if (!client) {\n throw new Error(\n `the github host provider is not configured: set BIT_GITHUB_TOKEN (or GITHUB_TOKEN), and either ` +\n `GITHUB_REPOSITORY or a GitHub \"origin\" remote (github.com, or the GITHUB_SERVER_URL host)`\n );\n }\n return client;\n }\n}\n"],"mappings":"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","ignoreList":[]}