@teambit/ci 1.0.631 → 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,5 +1,5 @@
1
1
  ;
2
- import * as overview_0 from '/home/circleci/Library/Caches/Bit/capsules/8891be5ad/teambit.git_ci@1.0.631/dist/ci.docs.mdx';
2
+ import * as overview_0 from '/home/circleci/Library/Caches/Bit/capsules/8891be5ad/teambit.git_ci@1.0.633/dist/ci.docs.mdx';
3
3
 
4
4
  export const compositions = [];
5
5
  export const overview = [overview_0];
@@ -44,8 +44,10 @@ export declare class SourceBranchDetector {
44
44
  */
45
45
  private getSourceBranchFromGitHubAPI;
46
46
  /**
47
- * Attempts to determine the GitHub repository (owner/repo) from environment variables
48
- * or by parsing the git remote origin URL. Works across different CI platforms.
47
+ * Attempts to determine the GitHub repository (owner/repo) and its host from the git remote origin URL
48
+ * or, without a GitHub origin, from environment variables. Works across different CI platforms.
49
+ * The origin comes first — as in `GitHubClient.fromEnv` — because it names both the repository the
50
+ * merge happened in and its host; the runner's variables may describe another repository or instance.
49
51
  */
50
52
  private getGitHubRepository;
51
53
  /**
@@ -11,6 +11,15 @@ function _git() {
11
11
  };
12
12
  return data;
13
13
  }
14
+ function _githubClient() {
15
+ const data = require("./sync/github-client");
16
+ _githubClient = function () {
17
+ return data;
18
+ };
19
+ return data;
20
+ }
21
+ /** A GitHub repository and the host it lives on — the host picks the API its lookups go to. */
22
+
14
23
  /**
15
24
  * Utility class for detecting source branch names in CI environments after PR merge.
16
25
  *
@@ -120,6 +129,11 @@ class SourceBranchDetector {
120
129
  this.logger.console('Not a GitHub repository, skipping GitHub API approach');
121
130
  return null;
122
131
  }
132
+ const api = (0, _githubClient().gitHubApiUrl)(githubRepository.host);
133
+ if ('error' in api) {
134
+ this.logger.console(`Skipping GitHub API approach: ${api.error}`);
135
+ return null;
136
+ }
123
137
 
124
138
  // Get commit SHA - use provided one or current HEAD
125
139
  const targetCommit = commitSha || (await _git().git.revparse(['HEAD']));
@@ -130,7 +144,7 @@ class SourceBranchDetector {
130
144
  this.logger.console(`Querying GitHub API for PR info using commit SHA: ${targetCommit.trim()}`);
131
145
 
132
146
  // Query GitHub API for pull requests associated with this commit
133
- const apiUrl = `https://api.github.com/repos/${githubRepository}/commits/${targetCommit.trim()}/pulls`;
147
+ const apiUrl = `${api.url}/repos/${githubRepository.repo}/commits/${targetCommit.trim()}/pulls`;
134
148
 
135
149
  // Try with token first (if available), then without token for public repos
136
150
  const githubToken = process.env.GITHUB_TOKEN;
@@ -177,45 +191,45 @@ class SourceBranchDetector {
177
191
  }
178
192
 
179
193
  /**
180
- * Attempts to determine the GitHub repository (owner/repo) from environment variables
181
- * or by parsing the git remote origin URL. Works across different CI platforms.
194
+ * Attempts to determine the GitHub repository (owner/repo) and its host from the git remote origin URL
195
+ * or, without a GitHub origin, from environment variables. Works across different CI platforms.
196
+ * The origin comes first — as in `GitHubClient.fromEnv` — because it names both the repository the
197
+ * merge happened in and its host; the runner's variables may describe another repository or instance.
182
198
  */
183
199
  async getGitHubRepository() {
184
200
  try {
185
- // First, try environment variables (GitHub Actions)
201
+ // First, parse the git remote origin URL (github.com, or the GITHUB_SERVER_URL host)
202
+ const remoteUrl = (await _git().git.raw(['config', '--get', 'remote.origin.url']).catch(() => undefined))?.trim();
203
+ const repoFromRemote = remoteUrl ? (0, _githubClient().parseGitHubRepo)(remoteUrl) : undefined;
204
+ const hostFromRemote = remoteUrl ? (0, _githubClient().remoteHost)(remoteUrl) : undefined;
205
+ if (repoFromRemote && hostFromRemote) {
206
+ this.logger.console(`Extracted GitHub repository from git remote: ${repoFromRemote} (${hostFromRemote})`);
207
+ return {
208
+ repo: repoFromRemote,
209
+ host: hostFromRemote
210
+ };
211
+ }
212
+
213
+ // GitHub Actions — the repository lives on the GITHUB_SERVER_URL instance
186
214
  if (process.env.GITHUB_REPOSITORY) {
187
215
  this.logger.console(`Found GitHub repository from GITHUB_REPOSITORY: ${process.env.GITHUB_REPOSITORY}`);
188
- return process.env.GITHUB_REPOSITORY;
216
+ return {
217
+ repo: process.env.GITHUB_REPOSITORY,
218
+ host: (0, _githubClient().gitHubServerHost)()
219
+ };
189
220
  }
190
221
 
191
- // CircleCI provides repository info in different format
222
+ // CircleCI provides repository info in different format, and the clone URL names the host
192
223
  if (process.env.CIRCLE_PROJECT_USERNAME && process.env.CIRCLE_PROJECT_REPONAME) {
193
224
  const repo = `${process.env.CIRCLE_PROJECT_USERNAME}/${process.env.CIRCLE_PROJECT_REPONAME}`;
194
- this.logger.console(`Found GitHub repository from CircleCI: ${repo}`);
195
- return repo;
196
- }
197
-
198
- // Fallback: parse from git remote origin URL
199
- this.logger.console('Attempting to extract GitHub repository from git remote origin');
200
- const remoteUrl = await _git().git.raw(['config', '--get', 'remote.origin.url']);
201
- if (remoteUrl) {
202
- const trimmedUrl = remoteUrl.trim();
203
-
204
- // Match GitHub URLs in various formats:
205
- // https://github.com/owner/repo.git
206
- // git@github.com:owner/repo.git
207
- // https://github.com/owner/repo
208
- const githubPatterns = [/github\.com[:/]([^/]+)\/([^/.]+)(?:\.git)?/, /github\.com\/([^/]+)\/([^/.]+)/];
209
- for (const pattern of githubPatterns) {
210
- const match = trimmedUrl.match(pattern);
211
- if (match) {
212
- const repo = `${match[1]}/${match[2]}`;
213
- this.logger.console(`Extracted GitHub repository from git remote: ${repo}`);
214
- return repo;
215
- }
216
- }
225
+ const host = (0, _githubClient().remoteHost)(process.env.CIRCLE_REPOSITORY_URL ?? '') ?? 'github.com';
226
+ this.logger.console(`Found GitHub repository from CircleCI: ${repo} (${host})`);
227
+ return {
228
+ repo,
229
+ host
230
+ };
217
231
  }
218
- this.logger.console('Unable to determine GitHub repository from environment or git remote');
232
+ this.logger.console('Unable to determine GitHub repository from git remote or environment');
219
233
  return null;
220
234
  } catch (e) {
221
235
  this.logger.console(`Error determining GitHub repository: ${e.toString()}`);
@@ -1 +1 @@
1
- {"version":3,"names":["_git","data","require","SourceBranchDetector","constructor","logger","getSourceBranchName","commitSha","githubBranch","getSourceBranchFromGitHubAPI","commitMessage","getGitCommitMessage","mergePattern","match","branchName","console","directMergePattern","directMatch","remoteTrackingPattern","remoteMatch","gitlabMergePattern","gitlabMatch","e","toString","githubRepository","getGitHubRepository","targetCommit","git","revparse","trim","apiUrl","githubToken","process","env","GITHUB_TOKEN","headers","Accept","Authorization","response","fetch","ok","status","statusText","pullRequests","json","length","pr","sourceBranch","head","ref","number","GITHUB_REPOSITORY","CIRCLE_PROJECT_USERNAME","CIRCLE_PROJECT_REPONAME","repo","remoteUrl","raw","trimmedUrl","githubPatterns","pattern","logOptions","maxCount","from","to","commit","log","latest","message","body","exports"],"sources":["source-branch-detector.ts"],"sourcesContent":["import type { Logger } from '@teambit/logger';\nimport { git } from './git';\n\n/**\n * Utility class for detecting source branch names in CI environments after PR merge.\n *\n * **Core Challenge**: When `bit ci merge` runs on CI after a PR is merged, the current\n * branch is main/master, but we need to identify which branch was just merged in order\n * to delete the corresponding Bit lane. CI environment variables like GITHUB_HEAD_REF\n * are only available during pull_request events, not push events after merge.\n *\n * **Solution Strategy**:\n * 1. GitHub API - Query PR information using current commit SHA (works post-merge)\n * 2. Commit message parsing - Extract branch names from merge commit messages\n * 3. Multi-platform repository detection - Works across GitHub Actions, CircleCI, etc.\n *\n * This enables automatic lane cleanup even when CI runs on main branch after merge.\n */\nexport class SourceBranchDetector {\n constructor(private logger: Logger) {}\n\n /**\n * Determines which branch was just merged into main/master in CI environments.\n *\n * **Use Case**: When CI runs `bit ci merge` after a PR merge, we're on main branch\n * but need to identify the source branch to delete its corresponding Bit lane.\n *\n * **Detection Methods** (in order of preference):\n * 1. GitHub API - Most reliable for GitHub repos (works with/without token)\n * 2. Commit message parsing - Universal fallback for all Git platforms\n *\n * @param commitSha - Optional commit SHA to query (if not provided, uses current HEAD)\n * @returns The source branch name that was merged, or null if undetectable\n * @example\n * ```typescript\n * const detector = new SourceBranchDetector(logger);\n * const branch = await detector.getSourceBranchName();\n * // Returns: \"feature/new-component\" (the branch that was just merged)\n * ```\n */\n async getSourceBranchName(commitSha?: string): Promise<string | null> {\n try {\n // Primary approach: GitHub API - query PR info from current commit SHA\n // This is the most reliable method for GitHub repositories\n const githubBranch = await this.getSourceBranchFromGitHubAPI(commitSha);\n if (githubBranch) {\n return githubBranch;\n }\n\n // Fallback: parse from git commit message (works universally)\n // This handles GitLab, Azure DevOps, and other platforms\n const commitMessage = await this.getGitCommitMessage(commitSha);\n if (commitMessage) {\n // Pattern: \"Merge pull request #123 from user/branch-name\"\n const mergePattern = /Merge pull request #\\d+ from [^/]+\\/(.+)/;\n const match = commitMessage.match(mergePattern);\n if (match) {\n const branchName = match[1];\n this.logger.console(`Found source branch from merge commit message: ${branchName}`);\n return branchName;\n }\n\n // Pattern: \"Merge branch 'branch-name' into main\"\n const directMergePattern = /Merge branch '([^']+)'/;\n const directMatch = commitMessage.match(directMergePattern);\n if (directMatch && directMatch[1] !== 'main' && directMatch[1] !== 'master') {\n const branchName = directMatch[1];\n this.logger.console(`Found source branch from direct merge commit: ${branchName}`);\n return branchName;\n }\n\n // Pattern: \"Merge remote-tracking branch 'origin/branch-name'\"\n const remoteTrackingPattern = /Merge remote-tracking branch 'origin\\/([^']+)'/;\n const remoteMatch = commitMessage.match(remoteTrackingPattern);\n if (remoteMatch && remoteMatch[1] !== 'main' && remoteMatch[1] !== 'master') {\n const branchName = remoteMatch[1];\n this.logger.console(`Found source branch from remote tracking merge: ${branchName}`);\n return branchName;\n }\n\n // GitLab-specific pattern: \"Merge branch 'feature-branch' into 'main'\"\n const gitlabMergePattern = /Merge branch '([^']+)' into '[^']+'/;\n const gitlabMatch = commitMessage.match(gitlabMergePattern);\n if (gitlabMatch && gitlabMatch[1] !== 'main' && gitlabMatch[1] !== 'master') {\n const branchName = gitlabMatch[1];\n this.logger.console(`Found source branch from GitLab merge commit: ${branchName}`);\n return branchName;\n }\n }\n\n this.logger.console('Unable to determine source branch name from API or git commit history');\n return null;\n } catch (e: any) {\n this.logger.console(`Error determining source branch name: ${e.toString()}`);\n return null;\n }\n }\n\n /**\n * Uses GitHub API to get pull request information from the current commit SHA.\n * This works even when running on push events after PR merge.\n * Enhanced to work with CircleCI and open source repos without tokens.\n */\n private async getSourceBranchFromGitHubAPI(commitSha?: string): Promise<string | null> {\n try {\n // Try to get GitHub repository info from environment or git remote\n const githubRepository = await this.getGitHubRepository();\n if (!githubRepository) {\n this.logger.console('Not a GitHub repository, skipping GitHub API approach');\n return null;\n }\n\n // Get commit SHA - use provided one or current HEAD\n const targetCommit = commitSha || (await git.revparse(['HEAD']));\n if (!targetCommit) {\n this.logger.console('Unable to get commit SHA');\n return null;\n }\n\n this.logger.console(`Querying GitHub API for PR info using commit SHA: ${targetCommit.trim()}`);\n\n // Query GitHub API for pull requests associated with this commit\n const apiUrl = `https://api.github.com/repos/${githubRepository}/commits/${targetCommit.trim()}/pulls`;\n\n // Try with token first (if available), then without token for public repos\n const githubToken = process.env.GITHUB_TOKEN;\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n };\n\n if (githubToken) {\n headers.Authorization = `Bearer ${githubToken}`;\n this.logger.console('Using GitHub token for API request');\n } else {\n this.logger.console('No GitHub token found, attempting public API access');\n }\n\n const response = await fetch(apiUrl, { headers });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n if (!githubToken) {\n this.logger.console(\n `GitHub API request failed (${response.status}): Repository may be private. Please set GITHUB_TOKEN environment variable.`\n );\n } else {\n this.logger.console(\n `GitHub API request failed (${response.status}): Token may be invalid or insufficient permissions`\n );\n }\n } else {\n this.logger.console(`GitHub API request failed: ${response.status} ${response.statusText}`);\n }\n return null;\n }\n\n const pullRequests = await response.json();\n\n if (pullRequests && pullRequests.length > 0) {\n // Get the first (most recent) PR that contains this commit\n const pr = pullRequests[0];\n const sourceBranch = pr.head.ref;\n this.logger.console(`Found source branch from GitHub API: ${sourceBranch} (PR #${pr.number})`);\n return sourceBranch;\n } else {\n this.logger.console('No pull requests found for current commit SHA');\n return null;\n }\n } catch (e: any) {\n this.logger.console(`Error querying GitHub API: ${e.toString()}`);\n return null;\n }\n }\n\n /**\n * Attempts to determine the GitHub repository (owner/repo) from environment variables\n * or by parsing the git remote origin URL. Works across different CI platforms.\n */\n private async getGitHubRepository(): Promise<string | null> {\n try {\n // First, try environment variables (GitHub Actions)\n if (process.env.GITHUB_REPOSITORY) {\n this.logger.console(`Found GitHub repository from GITHUB_REPOSITORY: ${process.env.GITHUB_REPOSITORY}`);\n return process.env.GITHUB_REPOSITORY;\n }\n\n // CircleCI provides repository info in different format\n if (process.env.CIRCLE_PROJECT_USERNAME && process.env.CIRCLE_PROJECT_REPONAME) {\n const repo = `${process.env.CIRCLE_PROJECT_USERNAME}/${process.env.CIRCLE_PROJECT_REPONAME}`;\n this.logger.console(`Found GitHub repository from CircleCI: ${repo}`);\n return repo;\n }\n\n // Fallback: parse from git remote origin URL\n this.logger.console('Attempting to extract GitHub repository from git remote origin');\n const remoteUrl = await git.raw(['config', '--get', 'remote.origin.url']);\n\n if (remoteUrl) {\n const trimmedUrl = remoteUrl.trim();\n\n // Match GitHub URLs in various formats:\n // https://github.com/owner/repo.git\n // git@github.com:owner/repo.git\n // https://github.com/owner/repo\n const githubPatterns = [/github\\.com[:/]([^/]+)\\/([^/.]+)(?:\\.git)?/, /github\\.com\\/([^/]+)\\/([^/.]+)/];\n\n for (const pattern of githubPatterns) {\n const match = trimmedUrl.match(pattern);\n if (match) {\n const repo = `${match[1]}/${match[2]}`;\n this.logger.console(`Extracted GitHub repository from git remote: ${repo}`);\n return repo;\n }\n }\n }\n\n this.logger.console('Unable to determine GitHub repository from environment or git remote');\n return null;\n } catch (e: any) {\n this.logger.console(`Error determining GitHub repository: ${e.toString()}`);\n return null;\n }\n }\n\n /**\n * Gets the git commit message for the specified commit\n */\n private async getGitCommitMessage(commitSha?: string): Promise<string | null> {\n try {\n const logOptions: any = { maxCount: 1 };\n if (commitSha) {\n logOptions.from = commitSha;\n logOptions.to = commitSha;\n }\n\n const commit = await git.log(logOptions);\n if (!commit.latest) {\n return null;\n }\n const { message, body } = commit.latest;\n return body ? `${message}\\n\\n${body}` : message;\n } catch (e: any) {\n this.logger.console(`Unable to read commit message: ${e.toString()}`);\n return null;\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_git","data","require","_githubClient","SourceBranchDetector","constructor","logger","getSourceBranchName","commitSha","githubBranch","getSourceBranchFromGitHubAPI","commitMessage","getGitCommitMessage","mergePattern","match","branchName","console","directMergePattern","directMatch","remoteTrackingPattern","remoteMatch","gitlabMergePattern","gitlabMatch","e","toString","githubRepository","getGitHubRepository","api","gitHubApiUrl","host","error","targetCommit","git","revparse","trim","apiUrl","url","repo","githubToken","process","env","GITHUB_TOKEN","headers","Accept","Authorization","response","fetch","ok","status","statusText","pullRequests","json","length","pr","sourceBranch","head","ref","number","remoteUrl","raw","catch","undefined","repoFromRemote","parseGitHubRepo","hostFromRemote","remoteHost","GITHUB_REPOSITORY","gitHubServerHost","CIRCLE_PROJECT_USERNAME","CIRCLE_PROJECT_REPONAME","CIRCLE_REPOSITORY_URL","logOptions","maxCount","from","to","commit","log","latest","message","body","exports"],"sources":["source-branch-detector.ts"],"sourcesContent":["import type { Logger } from '@teambit/logger';\nimport { git } from './git';\nimport { gitHubApiUrl, gitHubServerHost, parseGitHubRepo, remoteHost } from './sync/github-client';\n\n/** A GitHub repository and the host it lives on — the host picks the API its lookups go to. */\ninterface GitHubRepository {\n /** `owner/repo` */\n repo: string;\n host: string;\n}\n\n/**\n * Utility class for detecting source branch names in CI environments after PR merge.\n *\n * **Core Challenge**: When `bit ci merge` runs on CI after a PR is merged, the current\n * branch is main/master, but we need to identify which branch was just merged in order\n * to delete the corresponding Bit lane. CI environment variables like GITHUB_HEAD_REF\n * are only available during pull_request events, not push events after merge.\n *\n * **Solution Strategy**:\n * 1. GitHub API - Query PR information using current commit SHA (works post-merge)\n * 2. Commit message parsing - Extract branch names from merge commit messages\n * 3. Multi-platform repository detection - Works across GitHub Actions, CircleCI, etc.\n *\n * This enables automatic lane cleanup even when CI runs on main branch after merge.\n */\nexport class SourceBranchDetector {\n constructor(private logger: Logger) {}\n\n /**\n * Determines which branch was just merged into main/master in CI environments.\n *\n * **Use Case**: When CI runs `bit ci merge` after a PR merge, we're on main branch\n * but need to identify the source branch to delete its corresponding Bit lane.\n *\n * **Detection Methods** (in order of preference):\n * 1. GitHub API - Most reliable for GitHub repos (works with/without token)\n * 2. Commit message parsing - Universal fallback for all Git platforms\n *\n * @param commitSha - Optional commit SHA to query (if not provided, uses current HEAD)\n * @returns The source branch name that was merged, or null if undetectable\n * @example\n * ```typescript\n * const detector = new SourceBranchDetector(logger);\n * const branch = await detector.getSourceBranchName();\n * // Returns: \"feature/new-component\" (the branch that was just merged)\n * ```\n */\n async getSourceBranchName(commitSha?: string): Promise<string | null> {\n try {\n // Primary approach: GitHub API - query PR info from current commit SHA\n // This is the most reliable method for GitHub repositories\n const githubBranch = await this.getSourceBranchFromGitHubAPI(commitSha);\n if (githubBranch) {\n return githubBranch;\n }\n\n // Fallback: parse from git commit message (works universally)\n // This handles GitLab, Azure DevOps, and other platforms\n const commitMessage = await this.getGitCommitMessage(commitSha);\n if (commitMessage) {\n // Pattern: \"Merge pull request #123 from user/branch-name\"\n const mergePattern = /Merge pull request #\\d+ from [^/]+\\/(.+)/;\n const match = commitMessage.match(mergePattern);\n if (match) {\n const branchName = match[1];\n this.logger.console(`Found source branch from merge commit message: ${branchName}`);\n return branchName;\n }\n\n // Pattern: \"Merge branch 'branch-name' into main\"\n const directMergePattern = /Merge branch '([^']+)'/;\n const directMatch = commitMessage.match(directMergePattern);\n if (directMatch && directMatch[1] !== 'main' && directMatch[1] !== 'master') {\n const branchName = directMatch[1];\n this.logger.console(`Found source branch from direct merge commit: ${branchName}`);\n return branchName;\n }\n\n // Pattern: \"Merge remote-tracking branch 'origin/branch-name'\"\n const remoteTrackingPattern = /Merge remote-tracking branch 'origin\\/([^']+)'/;\n const remoteMatch = commitMessage.match(remoteTrackingPattern);\n if (remoteMatch && remoteMatch[1] !== 'main' && remoteMatch[1] !== 'master') {\n const branchName = remoteMatch[1];\n this.logger.console(`Found source branch from remote tracking merge: ${branchName}`);\n return branchName;\n }\n\n // GitLab-specific pattern: \"Merge branch 'feature-branch' into 'main'\"\n const gitlabMergePattern = /Merge branch '([^']+)' into '[^']+'/;\n const gitlabMatch = commitMessage.match(gitlabMergePattern);\n if (gitlabMatch && gitlabMatch[1] !== 'main' && gitlabMatch[1] !== 'master') {\n const branchName = gitlabMatch[1];\n this.logger.console(`Found source branch from GitLab merge commit: ${branchName}`);\n return branchName;\n }\n }\n\n this.logger.console('Unable to determine source branch name from API or git commit history');\n return null;\n } catch (e: any) {\n this.logger.console(`Error determining source branch name: ${e.toString()}`);\n return null;\n }\n }\n\n /**\n * Uses GitHub API to get pull request information from the current commit SHA.\n * This works even when running on push events after PR merge.\n * Enhanced to work with CircleCI and open source repos without tokens.\n */\n private async getSourceBranchFromGitHubAPI(commitSha?: string): Promise<string | null> {\n try {\n // Try to get GitHub repository info from environment or git remote\n const githubRepository = await this.getGitHubRepository();\n if (!githubRepository) {\n this.logger.console('Not a GitHub repository, skipping GitHub API approach');\n return null;\n }\n const api = gitHubApiUrl(githubRepository.host);\n if ('error' in api) {\n this.logger.console(`Skipping GitHub API approach: ${api.error}`);\n return null;\n }\n\n // Get commit SHA - use provided one or current HEAD\n const targetCommit = commitSha || (await git.revparse(['HEAD']));\n if (!targetCommit) {\n this.logger.console('Unable to get commit SHA');\n return null;\n }\n\n this.logger.console(`Querying GitHub API for PR info using commit SHA: ${targetCommit.trim()}`);\n\n // Query GitHub API for pull requests associated with this commit\n const apiUrl = `${api.url}/repos/${githubRepository.repo}/commits/${targetCommit.trim()}/pulls`;\n\n // Try with token first (if available), then without token for public repos\n const githubToken = process.env.GITHUB_TOKEN;\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github+json',\n 'X-GitHub-Api-Version': '2022-11-28',\n };\n\n if (githubToken) {\n headers.Authorization = `Bearer ${githubToken}`;\n this.logger.console('Using GitHub token for API request');\n } else {\n this.logger.console('No GitHub token found, attempting public API access');\n }\n\n const response = await fetch(apiUrl, { headers });\n\n if (!response.ok) {\n if (response.status === 401 || response.status === 403) {\n if (!githubToken) {\n this.logger.console(\n `GitHub API request failed (${response.status}): Repository may be private. Please set GITHUB_TOKEN environment variable.`\n );\n } else {\n this.logger.console(\n `GitHub API request failed (${response.status}): Token may be invalid or insufficient permissions`\n );\n }\n } else {\n this.logger.console(`GitHub API request failed: ${response.status} ${response.statusText}`);\n }\n return null;\n }\n\n const pullRequests = await response.json();\n\n if (pullRequests && pullRequests.length > 0) {\n // Get the first (most recent) PR that contains this commit\n const pr = pullRequests[0];\n const sourceBranch = pr.head.ref;\n this.logger.console(`Found source branch from GitHub API: ${sourceBranch} (PR #${pr.number})`);\n return sourceBranch;\n } else {\n this.logger.console('No pull requests found for current commit SHA');\n return null;\n }\n } catch (e: any) {\n this.logger.console(`Error querying GitHub API: ${e.toString()}`);\n return null;\n }\n }\n\n /**\n * Attempts to determine the GitHub repository (owner/repo) and its host from the git remote origin URL\n * or, without a GitHub origin, from environment variables. Works across different CI platforms.\n * The origin comes first — as in `GitHubClient.fromEnv` — because it names both the repository the\n * merge happened in and its host; the runner's variables may describe another repository or instance.\n */\n private async getGitHubRepository(): Promise<GitHubRepository | null> {\n try {\n // First, parse the git remote origin URL (github.com, or the GITHUB_SERVER_URL host)\n const remoteUrl = (await git.raw(['config', '--get', 'remote.origin.url']).catch(() => undefined))?.trim();\n const repoFromRemote = remoteUrl ? parseGitHubRepo(remoteUrl) : undefined;\n const hostFromRemote = remoteUrl ? remoteHost(remoteUrl) : undefined;\n if (repoFromRemote && hostFromRemote) {\n this.logger.console(`Extracted GitHub repository from git remote: ${repoFromRemote} (${hostFromRemote})`);\n return { repo: repoFromRemote, host: hostFromRemote };\n }\n\n // GitHub Actions — the repository lives on the GITHUB_SERVER_URL instance\n if (process.env.GITHUB_REPOSITORY) {\n this.logger.console(`Found GitHub repository from GITHUB_REPOSITORY: ${process.env.GITHUB_REPOSITORY}`);\n return { repo: process.env.GITHUB_REPOSITORY, host: gitHubServerHost() };\n }\n\n // CircleCI provides repository info in different format, and the clone URL names the host\n if (process.env.CIRCLE_PROJECT_USERNAME && process.env.CIRCLE_PROJECT_REPONAME) {\n const repo = `${process.env.CIRCLE_PROJECT_USERNAME}/${process.env.CIRCLE_PROJECT_REPONAME}`;\n const host = remoteHost(process.env.CIRCLE_REPOSITORY_URL ?? '') ?? 'github.com';\n this.logger.console(`Found GitHub repository from CircleCI: ${repo} (${host})`);\n return { repo, host };\n }\n\n this.logger.console('Unable to determine GitHub repository from git remote or environment');\n return null;\n } catch (e: any) {\n this.logger.console(`Error determining GitHub repository: ${e.toString()}`);\n return null;\n }\n }\n\n /**\n * Gets the git commit message for the specified commit\n */\n private async getGitCommitMessage(commitSha?: string): Promise<string | null> {\n try {\n const logOptions: any = { maxCount: 1 };\n if (commitSha) {\n logOptions.from = commitSha;\n logOptions.to = commitSha;\n }\n\n const commit = await git.log(logOptions);\n if (!commit.latest) {\n return null;\n }\n const { message, body } = commit.latest;\n return body ? `${message}\\n\\n${body}` : message;\n } catch (e: any) {\n this.logger.console(`Unable to read commit message: ${e.toString()}`);\n return null;\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+
3
+ function _chai() {
4
+ const data = require("chai");
5
+ _chai = function () {
6
+ return data;
7
+ };
8
+ return data;
9
+ }
10
+ function _git() {
11
+ const data = require("./git");
12
+ _git = function () {
13
+ return data;
14
+ };
15
+ return data;
16
+ }
17
+ function _sourceBranchDetector() {
18
+ const data = require("./source-branch-detector");
19
+ _sourceBranchDetector = function () {
20
+ return data;
21
+ };
22
+ return data;
23
+ }
24
+ /**
25
+ * The post-merge PR lookup sends GITHUB_TOKEN to the API it queries, so the API must be the one of the
26
+ * host the repository lives on — never the runner's enterprise API for a github.com repository, and
27
+ * never a GITHUB_API_URL the GITHUB_SERVER_URL instance can't vouch for.
28
+ */
29
+ describe('SourceBranchDetector GitHub API lookup', () => {
30
+ const envKeys = ['GITHUB_TOKEN', 'GITHUB_REPOSITORY', 'GITHUB_API_URL', 'GITHUB_SERVER_URL', 'CIRCLE_PROJECT_USERNAME', 'CIRCLE_PROJECT_REPONAME', 'CIRCLE_REPOSITORY_URL'];
31
+ const saved = {};
32
+ const realFetch = globalThis.fetch;
33
+ const realRaw = _git().git.raw;
34
+ const realLog = _git().git.log;
35
+ let calls;
36
+ let origin;
37
+ const logger = {
38
+ console: () => {}
39
+ };
40
+ const SHA = 'abc123';
41
+ beforeEach(() => {
42
+ envKeys.forEach(key => {
43
+ saved[key] = process.env[key];
44
+ delete process.env[key];
45
+ });
46
+ process.env.GITHUB_TOKEN = 'tok';
47
+ calls = [];
48
+ origin = '';
49
+ globalThis.fetch = async url => {
50
+ calls.push(String(url));
51
+ return new Response(JSON.stringify([{
52
+ number: 7,
53
+ head: {
54
+ ref: 'feature-x'
55
+ }
56
+ }]), {
57
+ status: 200,
58
+ headers: {
59
+ 'content-type': 'application/json'
60
+ }
61
+ });
62
+ };
63
+ _git().git.raw = async () => origin;
64
+ // the commit-message fallback finds nothing, so only the API can name the branch
65
+ _git().git.log = async () => ({
66
+ latest: {
67
+ message: 'squash',
68
+ body: ''
69
+ }
70
+ });
71
+ });
72
+ afterEach(() => {
73
+ globalThis.fetch = realFetch;
74
+ _git().git.raw = realRaw;
75
+ _git().git.log = realLog;
76
+ envKeys.forEach(key => {
77
+ if (saved[key] === undefined) delete process.env[key];else process.env[key] = saved[key];
78
+ });
79
+ });
80
+ const lookup = () => new (_sourceBranchDetector().SourceBranchDetector)(logger).getSourceBranchName(SHA);
81
+ it('queries api.github.com for a github.com origin, with no enterprise variables (unchanged default)', async () => {
82
+ origin = 'git@github.com:acme/shop.git';
83
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
84
+ (0, _chai().expect)(calls).to.deep.equal([`https://api.github.com/repos/acme/shop/commits/${SHA}/pulls`]);
85
+ });
86
+ describe('on a GHES-configured runner', () => {
87
+ beforeEach(() => {
88
+ process.env.GITHUB_SERVER_URL = 'https://ghe.corp.example';
89
+ process.env.GITHUB_API_URL = 'https://ghe.corp.example/api/v3';
90
+ });
91
+ it('queries api.github.com for a github.com origin', async () => {
92
+ origin = 'https://github.com/acme/shop.git';
93
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
94
+ (0, _chai().expect)(calls).to.deep.equal([`https://api.github.com/repos/acme/shop/commits/${SHA}/pulls`]);
95
+ });
96
+ it('queries api.github.com for a CircleCI github.com project', async () => {
97
+ process.env.CIRCLE_PROJECT_USERNAME = 'acme';
98
+ process.env.CIRCLE_PROJECT_REPONAME = 'shop';
99
+ process.env.CIRCLE_REPOSITORY_URL = 'git@github.com:acme/shop.git';
100
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
101
+ (0, _chai().expect)(calls).to.deep.equal([`https://api.github.com/repos/acme/shop/commits/${SHA}/pulls`]);
102
+ });
103
+ it('queries the GHES API for an enterprise origin, and for GITHUB_REPOSITORY on the enterprise runner', async () => {
104
+ origin = 'git@ghe.corp.example:acme/store.git';
105
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
106
+ process.env.GITHUB_REPOSITORY = 'acme/store';
107
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
108
+ (0, _chai().expect)(calls).to.deep.equal([`https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`, `https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`]);
109
+ });
110
+ it('prefers a github.com origin over GITHUB_REPOSITORY of the enterprise runner', async () => {
111
+ process.env.GITHUB_REPOSITORY = 'acme/store';
112
+ origin = 'https://github.com/acme/shop.git';
113
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
114
+ (0, _chai().expect)(calls).to.deep.equal([`https://api.github.com/repos/acme/shop/commits/${SHA}/pulls`]);
115
+ });
116
+ it('falls back to GITHUB_REPOSITORY on the enterprise host when origin is unreadable or not GitHub', async () => {
117
+ process.env.GITHUB_REPOSITORY = 'acme/store';
118
+ _git().git.raw = async () => {
119
+ throw new Error('no origin');
120
+ };
121
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
122
+ _git().git.raw = async () => 'https://gitlab.com/acme/shop.git';
123
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
124
+ (0, _chai().expect)(calls).to.deep.equal([`https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`, `https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`]);
125
+ });
126
+ it('derives <server>/api/v3 when GITHUB_API_URL is unset', async () => {
127
+ delete process.env.GITHUB_API_URL;
128
+ origin = 'https://ghe.corp.example/acme/store.git';
129
+ (0, _chai().expect)(await lookup()).to.equal('feature-x');
130
+ (0, _chai().expect)(calls).to.deep.equal([`https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`]);
131
+ });
132
+ it('sends nothing when GITHUB_API_URL is not on the enterprise host', async () => {
133
+ process.env.GITHUB_API_URL = 'https://api.github.com';
134
+ origin = 'https://ghe.corp.example/acme/store.git';
135
+ (0, _chai().expect)(await lookup()).to.equal(null);
136
+ (0, _chai().expect)(calls).to.have.lengthOf(0);
137
+ });
138
+ });
139
+ });
140
+
141
+ //# sourceMappingURL=source-branch-detector.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_chai","data","require","_git","_sourceBranchDetector","describe","envKeys","saved","realFetch","globalThis","fetch","realRaw","git","raw","realLog","log","calls","origin","logger","console","SHA","beforeEach","forEach","key","process","env","GITHUB_TOKEN","url","push","String","Response","JSON","stringify","number","head","ref","status","headers","latest","message","body","afterEach","undefined","lookup","SourceBranchDetector","getSourceBranchName","it","expect","to","equal","deep","GITHUB_SERVER_URL","GITHUB_API_URL","CIRCLE_PROJECT_USERNAME","CIRCLE_PROJECT_REPONAME","CIRCLE_REPOSITORY_URL","GITHUB_REPOSITORY","Error","have","lengthOf"],"sources":["source-branch-detector.spec.ts"],"sourcesContent":["import { expect } from 'chai';\nimport type { Logger } from '@teambit/logger';\nimport { git } from './git';\nimport { SourceBranchDetector } from './source-branch-detector';\n\n/**\n * The post-merge PR lookup sends GITHUB_TOKEN to the API it queries, so the API must be the one of the\n * host the repository lives on — never the runner's enterprise API for a github.com repository, and\n * never a GITHUB_API_URL the GITHUB_SERVER_URL instance can't vouch for.\n */\ndescribe('SourceBranchDetector GitHub API lookup', () => {\n const envKeys = [\n 'GITHUB_TOKEN',\n 'GITHUB_REPOSITORY',\n 'GITHUB_API_URL',\n 'GITHUB_SERVER_URL',\n 'CIRCLE_PROJECT_USERNAME',\n 'CIRCLE_PROJECT_REPONAME',\n 'CIRCLE_REPOSITORY_URL',\n ];\n const saved: Record<string, string | undefined> = {};\n const realFetch = globalThis.fetch;\n const realRaw = git.raw;\n const realLog = git.log;\n let calls: string[];\n let origin: string;\n\n const logger = { console: () => {} } as unknown as Logger;\n const SHA = 'abc123';\n\n beforeEach(() => {\n envKeys.forEach((key) => {\n saved[key] = process.env[key];\n delete process.env[key];\n });\n process.env.GITHUB_TOKEN = 'tok';\n calls = [];\n origin = '';\n globalThis.fetch = (async (url: any) => {\n calls.push(String(url));\n return new Response(JSON.stringify([{ number: 7, head: { ref: 'feature-x' } }]), {\n status: 200,\n headers: { 'content-type': 'application/json' },\n });\n }) as typeof fetch;\n (git as any).raw = async () => origin;\n // the commit-message fallback finds nothing, so only the API can name the branch\n (git as any).log = async () => ({ latest: { message: 'squash', body: '' } });\n });\n\n afterEach(() => {\n globalThis.fetch = realFetch;\n (git as any).raw = realRaw;\n (git as any).log = realLog;\n envKeys.forEach((key) => {\n if (saved[key] === undefined) delete process.env[key];\n else process.env[key] = saved[key];\n });\n });\n\n const lookup = () => new SourceBranchDetector(logger).getSourceBranchName(SHA);\n\n it('queries api.github.com for a github.com origin, with no enterprise variables (unchanged default)', async () => {\n origin = 'git@github.com:acme/shop.git';\n expect(await lookup()).to.equal('feature-x');\n expect(calls).to.deep.equal([`https://api.github.com/repos/acme/shop/commits/${SHA}/pulls`]);\n });\n\n describe('on a GHES-configured runner', () => {\n beforeEach(() => {\n process.env.GITHUB_SERVER_URL = 'https://ghe.corp.example';\n process.env.GITHUB_API_URL = 'https://ghe.corp.example/api/v3';\n });\n\n it('queries api.github.com for a github.com origin', async () => {\n origin = 'https://github.com/acme/shop.git';\n expect(await lookup()).to.equal('feature-x');\n expect(calls).to.deep.equal([`https://api.github.com/repos/acme/shop/commits/${SHA}/pulls`]);\n });\n\n it('queries api.github.com for a CircleCI github.com project', async () => {\n process.env.CIRCLE_PROJECT_USERNAME = 'acme';\n process.env.CIRCLE_PROJECT_REPONAME = 'shop';\n process.env.CIRCLE_REPOSITORY_URL = 'git@github.com:acme/shop.git';\n expect(await lookup()).to.equal('feature-x');\n expect(calls).to.deep.equal([`https://api.github.com/repos/acme/shop/commits/${SHA}/pulls`]);\n });\n\n it('queries the GHES API for an enterprise origin, and for GITHUB_REPOSITORY on the enterprise runner', async () => {\n origin = 'git@ghe.corp.example:acme/store.git';\n expect(await lookup()).to.equal('feature-x');\n process.env.GITHUB_REPOSITORY = 'acme/store';\n expect(await lookup()).to.equal('feature-x');\n expect(calls).to.deep.equal([\n `https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`,\n `https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`,\n ]);\n });\n\n it('prefers a github.com origin over GITHUB_REPOSITORY of the enterprise runner', async () => {\n process.env.GITHUB_REPOSITORY = 'acme/store';\n origin = 'https://github.com/acme/shop.git';\n expect(await lookup()).to.equal('feature-x');\n expect(calls).to.deep.equal([`https://api.github.com/repos/acme/shop/commits/${SHA}/pulls`]);\n });\n\n it('falls back to GITHUB_REPOSITORY on the enterprise host when origin is unreadable or not GitHub', async () => {\n process.env.GITHUB_REPOSITORY = 'acme/store';\n (git as any).raw = async () => {\n throw new Error('no origin');\n };\n expect(await lookup()).to.equal('feature-x');\n (git as any).raw = async () => 'https://gitlab.com/acme/shop.git';\n expect(await lookup()).to.equal('feature-x');\n expect(calls).to.deep.equal([\n `https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`,\n `https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`,\n ]);\n });\n\n it('derives <server>/api/v3 when GITHUB_API_URL is unset', async () => {\n delete process.env.GITHUB_API_URL;\n origin = 'https://ghe.corp.example/acme/store.git';\n expect(await lookup()).to.equal('feature-x');\n expect(calls).to.deep.equal([`https://ghe.corp.example/api/v3/repos/acme/store/commits/${SHA}/pulls`]);\n });\n\n it('sends nothing when GITHUB_API_URL is not on the enterprise host', async () => {\n process.env.GITHUB_API_URL = 'https://api.github.com';\n origin = 'https://ghe.corp.example/acme/store.git';\n expect(await lookup()).to.equal(null);\n expect(calls).to.have.lengthOf(0);\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
@@ -158,6 +158,34 @@ describe('GitHubHostProvider', () => {
158
158
  (0, _chai().expect)(selection.provider).to.equal(undefined);
159
159
  (0, _chai().expect)(selection.reason).to.contain('no git host provider is configured');
160
160
  });
161
+
162
+ // GitHub Enterprise Server: Actions names the instance in GITHUB_SERVER_URL, and that host's remotes
163
+ // must select this provider exactly as github.com remotes do — or the run degrades to git-only.
164
+ it('claims, configures and is selected for a GitHub Enterprise Server remote', () => {
165
+ const ghesKeys = ['GITHUB_API_URL', 'GITHUB_SERVER_URL'];
166
+ const savedGhes = ghesKeys.map(key => process.env[key]);
167
+ process.env.GITHUB_API_URL = 'https://ghe.corp.example/api/v3';
168
+ process.env.GITHUB_SERVER_URL = 'https://ghe.corp.example';
169
+ process.env.BIT_GITHUB_TOKEN = 'tok';
170
+ try {
171
+ ['https://ghe.corp.example/acme/store.git', 'git@ghe.corp.example:acme/store.git'].forEach(remote => {
172
+ const provider = new (_githubClient().GitHubHostProvider)();
173
+ (0, _chai().expect)(provider.matchesRemote(remote), remote).to.equal(true);
174
+ (0, _chai().expect)(provider.isConfigured(remote), remote).to.equal(true);
175
+ (0, _chai().expect)((0, _gitHostProvider().selectGitHostProvider)([new (_githubClient().GitHubHostProvider)()], remote).provider?.name, remote).to.equal('github');
176
+ });
177
+ ['https://evil.example/ghe.corp.example/x.git', 'https://ghe.corp.example.evil.com/x.git'].forEach(remote => {
178
+ (0, _chai().expect)(new (_githubClient().GitHubHostProvider)().matchesRemote(remote), remote).to.equal(false);
179
+ (0, _chai().expect)(new (_githubClient().GitHubHostProvider)().isConfigured(remote), remote).to.equal(false);
180
+ });
181
+ } finally {
182
+ ghesKeys.forEach((key, i) => {
183
+ if (savedGhes[i] === undefined) delete process.env[key];else process.env[key] = savedGhes[i];
184
+ });
185
+ }
186
+ // without GITHUB_SERVER_URL the same host is nobody's
187
+ (0, _chai().expect)(new (_githubClient().GitHubHostProvider)().matchesRemote('https://ghe.corp.example/acme/store.git')).to.equal(false);
188
+ });
161
189
  it('reports what is missing rather than failing obscurely when a PR call happens unconfigured', async () => {
162
190
  let message = '';
163
191
  await new (_githubClient().GitHubHostProvider)().findPrByBranch('lane-x').catch(err => {
@@ -1 +1 @@
1
- {"version":3,"names":["_chai","data","require","_gitHostProvider","_githubClient","fakeProvider","opts","unreachable","Promise","reject","Error","name","matchesRemote","remoteUrl","hostPattern","test","isConfigured","configured","findPrByBranch","createPr","closePr","comment","addLabel","github","gitlab","GH","UNCLAIMED","claimants","names","map","tied","SELECTION","undefined","describe","forEach","providers","remote","picks","reason","it","selection","selectGitHostProvider","expect","provider","to","equal","length","be","greaterThan","fragment","contain","seen","derivesRepoFromRemote","push","Boolean","includes","deep","envKeys","saved","beforeEach","key","process","env","afterEach","GitHubHostProvider","BIT_GITHUB_TOKEN","ours","theirs","GITHUB_REPOSITORY","message","catch","err"],"sources":["git-host-provider.spec.ts"],"sourcesContent":["import { expect } from 'chai';\nimport type { GitHostProvider, PrInfo } from './git-host-provider';\nimport { selectGitHostProvider } from './git-host-provider';\nimport { GitHubHostProvider } from './github-client';\n\n/**\n * A provider stub: only `name`, `matchesRemote` and `isConfigured` participate in selection, so the\n * PR methods reject — reaching them from `selectGitHostProvider` would be a bug worth failing on.\n */\nfunction fakeProvider(opts: {\n name: string;\n hostPattern: RegExp;\n configured: boolean | ((remoteUrl?: string) => boolean);\n}): GitHostProvider {\n const unreachable = () => Promise.reject(new Error(`${opts.name}: selection must not call PR methods`));\n return {\n name: opts.name,\n matchesRemote: (remoteUrl: string) => opts.hostPattern.test(remoteUrl),\n isConfigured: (remoteUrl?: string) =>\n typeof opts.configured === 'function' ? opts.configured(remoteUrl) : opts.configured,\n findPrByBranch: unreachable as () => Promise<PrInfo | undefined>,\n createPr: unreachable as () => Promise<PrInfo>,\n closePr: unreachable,\n comment: unreachable,\n addLabel: unreachable,\n };\n}\n\nconst github = (configured = true) => fakeProvider({ name: 'github', hostPattern: /github\\.com/, configured });\nconst gitlab = (configured = true) => fakeProvider({ name: 'gitlab', hostPattern: /gitlab\\.com/, configured });\nconst GH = 'https://github.com/acme/shop';\nconst UNCLAIMED = 'git@git.acme.internal:acme/shop.git';\n\nconst claimants = (...names: string[]) =>\n names.map((name) => fakeProvider({ name, hostPattern: /git\\.acme/, configured: false }));\nconst tied = (...names: string[]) =>\n names.map((name) => fakeProvider({ name, hostPattern: /github\\.com/, configured: true }));\n\n/**\n * A claimed remote is NEVER routed to a different provider: acting on the wrong host's PRs is worse\n * than degrading to git-only sync. The sole-configured fallback applies only when no provider claims\n * the remote at all. Every selection of nothing must explain itself; a successful one must stay quiet.\n *\n * [case, providers, remote url, selected provider name, reason fragments].\n */\nconst SELECTION: Array<[string, GitHostProvider[], string | undefined, string | undefined, string[]?]> = [\n ['by matching host', [github(), gitlab()], 'git@gitlab.com:acme/shop.git', 'gitlab'],\n ['by matching host, the other way round', [github(), gitlab()], GH, 'github'],\n [\n 'nothing when the claimant is unconfigured but another is',\n [github(false), gitlab(true)],\n GH,\n undefined,\n ['\"github\"', 'not configured'],\n ],\n ['nothing regardless of registration order', [gitlab(true), github(false)], GH, undefined, ['\"github\"']],\n ['nothing when nothing at all is configured', [github(false), gitlab(false)], GH, undefined, ['\"github\"']],\n [\n 'nothing, naming every claimant when several claim and none is configured',\n claimants('ghe-a', 'ghe-b'),\n 'https://git.acme.com/acme/shop',\n undefined,\n ['\"ghe-a\"', '\"ghe-b\"'],\n ],\n ['the sole configured provider when no remote url is known', [github(true)], undefined, 'github'],\n ['the sole configured of several when no remote url is known', [github(false), gitlab(true)], undefined, 'gitlab'],\n // e.g. a self-hosted GitLab on a custom domain, or an `insteadOf` rewrite of the origin url\n ['the sole configured provider for a remote no provider claims', [github(false), gitlab(true)], UNCLAIMED, 'gitlab'],\n [\n 'nothing when two configured providers both fail to claim',\n [github(true), gitlab(true)],\n UNCLAIMED,\n undefined,\n ['ambiguous'],\n ],\n [\n 'nothing when two are configured and there is no remote url',\n [github(true), gitlab(true)],\n undefined,\n undefined,\n ['ambiguous'],\n ],\n ['nothing when nothing is registered', [], GH, undefined, ['no git host provider is registered']],\n [\n 'nothing when nothing is configured and there is no remote',\n [github(false), gitlab(false)],\n undefined,\n undefined,\n ['no git host provider is configured'],\n ],\n ['the first registered when two configured providers claim the same remote', tied('first', 'second'), GH, 'first'],\n];\n\ndescribe('selectGitHostProvider', () => {\n SELECTION.forEach(([name, providers, remote, picks, reason]) => {\n it(`selects ${name}`, () => {\n const selection = selectGitHostProvider(providers, remote);\n expect(selection.provider?.name, name).to.equal(picks);\n if (picks) {\n expect(selection.reason, 'a successful selection stays quiet').to.equal(undefined);\n } else {\n expect((selection.reason ?? '').length, 'a skipped run must never be silent').to.be.greaterThan(0);\n (reason ?? []).forEach((fragment) => expect(selection.reason).to.contain(fragment));\n }\n });\n });\n\n it('passes the remote url to isConfigured, so a host can derive its repo from it', () => {\n const seen: Array<string | undefined> = [];\n const derivesRepoFromRemote = fakeProvider({\n name: 'github',\n hostPattern: /github\\.com/,\n configured: (remoteUrl) => {\n seen.push(remoteUrl);\n return Boolean(remoteUrl?.includes('github.com'));\n },\n });\n expect(selectGitHostProvider([derivesRepoFromRemote], GH).provider?.name).to.equal('github');\n expect(seen).to.deep.equal([GH]);\n expect(selectGitHostProvider([derivesRepoFromRemote], undefined).provider).to.equal(undefined);\n });\n});\n\n// The built-in provider, exercised through the interface it is registered as — the GitHub *client*\n// (API shapes, auth headers, remote parsing) is covered by github-client.spec.ts.\ndescribe('GitHubHostProvider', () => {\n const envKeys = ['GITHUB_TOKEN', 'BIT_GITHUB_TOKEN', 'GITHUB_REPOSITORY'] as const;\n const saved: Record<string, string | undefined> = {};\n\n beforeEach(() => {\n envKeys.forEach((key) => {\n saved[key] = process.env[key];\n delete process.env[key];\n });\n });\n\n afterEach(() => {\n envKeys.forEach((key) => {\n if (saved[key] === undefined) delete process.env[key];\n else process.env[key] = saved[key];\n });\n });\n\n it('is registrable without credentials: constructing it never throws and it reports unconfigured', () => {\n const provider = new GitHubHostProvider();\n expect(provider.name).to.equal('github');\n expect(provider.isConfigured(GH)).to.equal(false);\n const selection = selectGitHostProvider([provider], GH);\n expect(selection.provider).to.equal(undefined);\n expect(selection.reason).to.contain('\"github\"');\n });\n\n it('is configured once a token is present, deriving the repo from the remote url', () => {\n process.env.BIT_GITHUB_TOKEN = 'tok';\n expect(new GitHubHostProvider().isConfigured('git@github.com:acme/shop.git')).to.equal(true);\n // no repo resolvable (no GITHUB_REPOSITORY, no parseable remote) => still unconfigured\n expect(new GitHubHostProvider().isConfigured(undefined)).to.equal(false);\n // a look-alike host must not be parsed into a repo aimed at api.github.com\n expect(new GitHubHostProvider().isConfigured('https://mygithub.com/acme/shop')).to.equal(false);\n });\n\n it('remembers the remote url it was asked about, and only if that remote was ours', () => {\n process.env.BIT_GITHUB_TOKEN = 'tok';\n const ours = new GitHubHostProvider();\n expect(ours.matchesRemote('git@github.com:acme/shop.git')).to.equal(true);\n expect(ours.isConfigured()).to.equal(true);\n // without that hint the same call cannot resolve a repository\n expect(new GitHubHostProvider().isConfigured()).to.equal(false);\n // …and a non-github remote must not poison the hint\n const theirs = new GitHubHostProvider();\n expect(theirs.matchesRemote('https://gitlab.com/acme/shop.git')).to.equal(false);\n expect(theirs.isConfigured()).to.equal(false);\n });\n\n // On Actions the env is always set, so answering \"configured\" for an unclaimed remote would make\n // this the sole-configured fallback and aim PRs at whatever GITHUB_REPOSITORY named.\n it('is NOT configured or selected for a remote it does not claim, however complete the environment', () => {\n process.env.BIT_GITHUB_TOKEN = 'tok';\n process.env.GITHUB_REPOSITORY = 'acme/shop';\n expect(new GitHubHostProvider().isConfigured('https://gitlab.com/acme/shop.git')).to.equal(false);\n // non-vacuous: the very same environment DOES configure it for a github remote, and for no remote\n expect(new GitHubHostProvider().isConfigured(GH)).to.equal(true);\n expect(new GitHubHostProvider().isConfigured()).to.equal(true);\n const selection = selectGitHostProvider([new GitHubHostProvider()], 'https://gitlab.com/acme/shop.git');\n expect(selection.provider).to.equal(undefined);\n expect(selection.reason).to.contain('no git host provider is configured');\n });\n\n it('reports what is missing rather than failing obscurely when a PR call happens unconfigured', async () => {\n let message = '';\n await new GitHubHostProvider().findPrByBranch('lane-x').catch((err) => {\n message = err.message;\n });\n expect(message).to.contain('GITHUB_TOKEN');\n expect(message).to.contain('GITHUB_REPOSITORY');\n });\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_chai","data","require","_gitHostProvider","_githubClient","fakeProvider","opts","unreachable","Promise","reject","Error","name","matchesRemote","remoteUrl","hostPattern","test","isConfigured","configured","findPrByBranch","createPr","closePr","comment","addLabel","github","gitlab","GH","UNCLAIMED","claimants","names","map","tied","SELECTION","undefined","describe","forEach","providers","remote","picks","reason","it","selection","selectGitHostProvider","expect","provider","to","equal","length","be","greaterThan","fragment","contain","seen","derivesRepoFromRemote","push","Boolean","includes","deep","envKeys","saved","beforeEach","key","process","env","afterEach","GitHubHostProvider","BIT_GITHUB_TOKEN","ours","theirs","GITHUB_REPOSITORY","ghesKeys","savedGhes","GITHUB_API_URL","GITHUB_SERVER_URL","i","message","catch","err"],"sources":["git-host-provider.spec.ts"],"sourcesContent":["import { expect } from 'chai';\nimport type { GitHostProvider, PrInfo } from './git-host-provider';\nimport { selectGitHostProvider } from './git-host-provider';\nimport { GitHubHostProvider } from './github-client';\n\n/**\n * A provider stub: only `name`, `matchesRemote` and `isConfigured` participate in selection, so the\n * PR methods reject — reaching them from `selectGitHostProvider` would be a bug worth failing on.\n */\nfunction fakeProvider(opts: {\n name: string;\n hostPattern: RegExp;\n configured: boolean | ((remoteUrl?: string) => boolean);\n}): GitHostProvider {\n const unreachable = () => Promise.reject(new Error(`${opts.name}: selection must not call PR methods`));\n return {\n name: opts.name,\n matchesRemote: (remoteUrl: string) => opts.hostPattern.test(remoteUrl),\n isConfigured: (remoteUrl?: string) =>\n typeof opts.configured === 'function' ? opts.configured(remoteUrl) : opts.configured,\n findPrByBranch: unreachable as () => Promise<PrInfo | undefined>,\n createPr: unreachable as () => Promise<PrInfo>,\n closePr: unreachable,\n comment: unreachable,\n addLabel: unreachable,\n };\n}\n\nconst github = (configured = true) => fakeProvider({ name: 'github', hostPattern: /github\\.com/, configured });\nconst gitlab = (configured = true) => fakeProvider({ name: 'gitlab', hostPattern: /gitlab\\.com/, configured });\nconst GH = 'https://github.com/acme/shop';\nconst UNCLAIMED = 'git@git.acme.internal:acme/shop.git';\n\nconst claimants = (...names: string[]) =>\n names.map((name) => fakeProvider({ name, hostPattern: /git\\.acme/, configured: false }));\nconst tied = (...names: string[]) =>\n names.map((name) => fakeProvider({ name, hostPattern: /github\\.com/, configured: true }));\n\n/**\n * A claimed remote is NEVER routed to a different provider: acting on the wrong host's PRs is worse\n * than degrading to git-only sync. The sole-configured fallback applies only when no provider claims\n * the remote at all. Every selection of nothing must explain itself; a successful one must stay quiet.\n *\n * [case, providers, remote url, selected provider name, reason fragments].\n */\nconst SELECTION: Array<[string, GitHostProvider[], string | undefined, string | undefined, string[]?]> = [\n ['by matching host', [github(), gitlab()], 'git@gitlab.com:acme/shop.git', 'gitlab'],\n ['by matching host, the other way round', [github(), gitlab()], GH, 'github'],\n [\n 'nothing when the claimant is unconfigured but another is',\n [github(false), gitlab(true)],\n GH,\n undefined,\n ['\"github\"', 'not configured'],\n ],\n ['nothing regardless of registration order', [gitlab(true), github(false)], GH, undefined, ['\"github\"']],\n ['nothing when nothing at all is configured', [github(false), gitlab(false)], GH, undefined, ['\"github\"']],\n [\n 'nothing, naming every claimant when several claim and none is configured',\n claimants('ghe-a', 'ghe-b'),\n 'https://git.acme.com/acme/shop',\n undefined,\n ['\"ghe-a\"', '\"ghe-b\"'],\n ],\n ['the sole configured provider when no remote url is known', [github(true)], undefined, 'github'],\n ['the sole configured of several when no remote url is known', [github(false), gitlab(true)], undefined, 'gitlab'],\n // e.g. a self-hosted GitLab on a custom domain, or an `insteadOf` rewrite of the origin url\n ['the sole configured provider for a remote no provider claims', [github(false), gitlab(true)], UNCLAIMED, 'gitlab'],\n [\n 'nothing when two configured providers both fail to claim',\n [github(true), gitlab(true)],\n UNCLAIMED,\n undefined,\n ['ambiguous'],\n ],\n [\n 'nothing when two are configured and there is no remote url',\n [github(true), gitlab(true)],\n undefined,\n undefined,\n ['ambiguous'],\n ],\n ['nothing when nothing is registered', [], GH, undefined, ['no git host provider is registered']],\n [\n 'nothing when nothing is configured and there is no remote',\n [github(false), gitlab(false)],\n undefined,\n undefined,\n ['no git host provider is configured'],\n ],\n ['the first registered when two configured providers claim the same remote', tied('first', 'second'), GH, 'first'],\n];\n\ndescribe('selectGitHostProvider', () => {\n SELECTION.forEach(([name, providers, remote, picks, reason]) => {\n it(`selects ${name}`, () => {\n const selection = selectGitHostProvider(providers, remote);\n expect(selection.provider?.name, name).to.equal(picks);\n if (picks) {\n expect(selection.reason, 'a successful selection stays quiet').to.equal(undefined);\n } else {\n expect((selection.reason ?? '').length, 'a skipped run must never be silent').to.be.greaterThan(0);\n (reason ?? []).forEach((fragment) => expect(selection.reason).to.contain(fragment));\n }\n });\n });\n\n it('passes the remote url to isConfigured, so a host can derive its repo from it', () => {\n const seen: Array<string | undefined> = [];\n const derivesRepoFromRemote = fakeProvider({\n name: 'github',\n hostPattern: /github\\.com/,\n configured: (remoteUrl) => {\n seen.push(remoteUrl);\n return Boolean(remoteUrl?.includes('github.com'));\n },\n });\n expect(selectGitHostProvider([derivesRepoFromRemote], GH).provider?.name).to.equal('github');\n expect(seen).to.deep.equal([GH]);\n expect(selectGitHostProvider([derivesRepoFromRemote], undefined).provider).to.equal(undefined);\n });\n});\n\n// The built-in provider, exercised through the interface it is registered as — the GitHub *client*\n// (API shapes, auth headers, remote parsing) is covered by github-client.spec.ts.\ndescribe('GitHubHostProvider', () => {\n const envKeys = ['GITHUB_TOKEN', 'BIT_GITHUB_TOKEN', 'GITHUB_REPOSITORY'] as const;\n const saved: Record<string, string | undefined> = {};\n\n beforeEach(() => {\n envKeys.forEach((key) => {\n saved[key] = process.env[key];\n delete process.env[key];\n });\n });\n\n afterEach(() => {\n envKeys.forEach((key) => {\n if (saved[key] === undefined) delete process.env[key];\n else process.env[key] = saved[key];\n });\n });\n\n it('is registrable without credentials: constructing it never throws and it reports unconfigured', () => {\n const provider = new GitHubHostProvider();\n expect(provider.name).to.equal('github');\n expect(provider.isConfigured(GH)).to.equal(false);\n const selection = selectGitHostProvider([provider], GH);\n expect(selection.provider).to.equal(undefined);\n expect(selection.reason).to.contain('\"github\"');\n });\n\n it('is configured once a token is present, deriving the repo from the remote url', () => {\n process.env.BIT_GITHUB_TOKEN = 'tok';\n expect(new GitHubHostProvider().isConfigured('git@github.com:acme/shop.git')).to.equal(true);\n // no repo resolvable (no GITHUB_REPOSITORY, no parseable remote) => still unconfigured\n expect(new GitHubHostProvider().isConfigured(undefined)).to.equal(false);\n // a look-alike host must not be parsed into a repo aimed at api.github.com\n expect(new GitHubHostProvider().isConfigured('https://mygithub.com/acme/shop')).to.equal(false);\n });\n\n it('remembers the remote url it was asked about, and only if that remote was ours', () => {\n process.env.BIT_GITHUB_TOKEN = 'tok';\n const ours = new GitHubHostProvider();\n expect(ours.matchesRemote('git@github.com:acme/shop.git')).to.equal(true);\n expect(ours.isConfigured()).to.equal(true);\n // without that hint the same call cannot resolve a repository\n expect(new GitHubHostProvider().isConfigured()).to.equal(false);\n // …and a non-github remote must not poison the hint\n const theirs = new GitHubHostProvider();\n expect(theirs.matchesRemote('https://gitlab.com/acme/shop.git')).to.equal(false);\n expect(theirs.isConfigured()).to.equal(false);\n });\n\n // On Actions the env is always set, so answering \"configured\" for an unclaimed remote would make\n // this the sole-configured fallback and aim PRs at whatever GITHUB_REPOSITORY named.\n it('is NOT configured or selected for a remote it does not claim, however complete the environment', () => {\n process.env.BIT_GITHUB_TOKEN = 'tok';\n process.env.GITHUB_REPOSITORY = 'acme/shop';\n expect(new GitHubHostProvider().isConfigured('https://gitlab.com/acme/shop.git')).to.equal(false);\n // non-vacuous: the very same environment DOES configure it for a github remote, and for no remote\n expect(new GitHubHostProvider().isConfigured(GH)).to.equal(true);\n expect(new GitHubHostProvider().isConfigured()).to.equal(true);\n const selection = selectGitHostProvider([new GitHubHostProvider()], 'https://gitlab.com/acme/shop.git');\n expect(selection.provider).to.equal(undefined);\n expect(selection.reason).to.contain('no git host provider is configured');\n });\n\n // GitHub Enterprise Server: Actions names the instance in GITHUB_SERVER_URL, and that host's remotes\n // must select this provider exactly as github.com remotes do — or the run degrades to git-only.\n it('claims, configures and is selected for a GitHub Enterprise Server remote', () => {\n const ghesKeys = ['GITHUB_API_URL', 'GITHUB_SERVER_URL'];\n const savedGhes = ghesKeys.map((key) => process.env[key]);\n process.env.GITHUB_API_URL = 'https://ghe.corp.example/api/v3';\n process.env.GITHUB_SERVER_URL = 'https://ghe.corp.example';\n process.env.BIT_GITHUB_TOKEN = 'tok';\n try {\n ['https://ghe.corp.example/acme/store.git', 'git@ghe.corp.example:acme/store.git'].forEach((remote) => {\n const provider = new GitHubHostProvider();\n expect(provider.matchesRemote(remote), remote).to.equal(true);\n expect(provider.isConfigured(remote), remote).to.equal(true);\n expect(selectGitHostProvider([new GitHubHostProvider()], remote).provider?.name, remote).to.equal('github');\n });\n ['https://evil.example/ghe.corp.example/x.git', 'https://ghe.corp.example.evil.com/x.git'].forEach((remote) => {\n expect(new GitHubHostProvider().matchesRemote(remote), remote).to.equal(false);\n expect(new GitHubHostProvider().isConfigured(remote), remote).to.equal(false);\n });\n } finally {\n ghesKeys.forEach((key, i) => {\n if (savedGhes[i] === undefined) delete process.env[key];\n else process.env[key] = savedGhes[i];\n });\n }\n // without GITHUB_SERVER_URL the same host is nobody's\n expect(new GitHubHostProvider().matchesRemote('https://ghe.corp.example/acme/store.git')).to.equal(false);\n });\n\n it('reports what is missing rather than failing obscurely when a PR call happens unconfigured', async () => {\n let message = '';\n await new GitHubHostProvider().findPrByBranch('lane-x').catch((err) => {\n message = err.message;\n });\n expect(message).to.contain('GITHUB_TOKEN');\n expect(message).to.contain('GITHUB_REPOSITORY');\n });\n});\n"],"mappings":"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","ignoreList":[]}