@shipfox/api-integration-github 12.7.0 → 13.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,21 +25,23 @@ import {
25
25
  type TriggerReference,
26
26
  } from '@shipfox/api-integration-spi';
27
27
  import type {GithubApiClient, GithubRepository} from '#api/client.js';
28
- import {config} from '#config.js';
29
28
  import {getGithubInstallationByConnectionId} from '#db/installations.js';
29
+ import {configuredGithubAppBotLogin} from './bot-identity.js';
30
30
  import {GithubIntegrationProviderError} from './errors.js';
31
31
 
32
32
  type GithubIntegrationConnection = IntegrationConnection<'github'>;
33
33
 
34
34
  const GITHUB_PROVIDER = 'github';
35
- const GITHUB_APP_BOT_SUFFIX = '[bot]';
36
35
  const SEARCH_PAGE_SIZE = 100;
37
36
  const SEARCH_MAX_PAGES_PER_REQUEST = 5;
38
37
 
39
38
  export class GithubSourceControlProvider
40
39
  implements SourceControlProvider<GithubIntegrationConnection>
41
40
  {
42
- constructor(private readonly github: GithubApiClient) {}
41
+ constructor(
42
+ private readonly github: GithubApiClient,
43
+ private readonly appBotLogin: () => string | undefined = configuredGithubAppBotLogin,
44
+ ) {}
43
45
 
44
46
  async listRepositories(
45
47
  input: ListRepositoriesInput<GithubIntegrationConnection>,
@@ -204,7 +206,11 @@ export class GithubSourceControlProvider
204
206
  repositoryId,
205
207
  permissions: input.permissions,
206
208
  });
207
- const gitAuthor = githubAppGitAuthor();
209
+ const botLogin = this.appBotLogin();
210
+ const gitAuthor =
211
+ botLogin && input.permissions?.contents === 'write'
212
+ ? await githubAppGitAuthor(this.github, token, botLogin)
213
+ : undefined;
208
214
 
209
215
  return {
210
216
  repositoryUrl: repository.cloneUrl,
@@ -250,13 +256,23 @@ function sameGithubRepository(
250
256
  return Boolean(firstName && secondName && firstName.toLowerCase() === secondName.toLowerCase());
251
257
  }
252
258
 
253
- function githubAppGitAuthor(): CheckoutSpec['gitAuthor'] {
254
- const appUsername = config.GITHUB_APP_USERNAME?.trim();
255
- if (!appUsername) return undefined;
256
- const name = appUsername.endsWith(GITHUB_APP_BOT_SUFFIX)
257
- ? appUsername
258
- : `${appUsername}${GITHUB_APP_BOT_SUFFIX}`;
259
- return {name, email: `${config.GITHUB_APP_ID}+${name}@users.noreply.github.com`};
259
+ async function githubAppGitAuthor(
260
+ github: GithubApiClient,
261
+ installationAccessToken: string,
262
+ name: string,
263
+ ): Promise<CheckoutSpec['gitAuthor']> {
264
+ if (!github.getBotUser) {
265
+ throw new GithubIntegrationProviderError(
266
+ 'provider-unavailable',
267
+ 'GitHub bot identity resolution is unavailable',
268
+ );
269
+ }
270
+
271
+ const botUser = await github.getBotUser({username: name, installationAccessToken});
272
+ return {
273
+ name: botUser.login,
274
+ email: `${botUser.id}+${botUser.login}@users.noreply.github.com`,
275
+ };
260
276
  }
261
277
 
262
278
  function toRepositorySnapshot(repository: GithubRepository): RepositorySnapshot {