@shipfox/api-integration-github 12.7.0 → 14.0.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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +23 -0
- package/dist/api/client.d.ts +21 -3
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +115 -6
- package/dist/api/client.js.map +1 -1
- package/dist/api/installation-token-envelope.d.ts.map +1 -1
- package/dist/api/installation-token-envelope.js.map +1 -1
- package/dist/core/agent-tools.d.ts.map +1 -1
- package/dist/core/agent-tools.js +2 -6
- package/dist/core/agent-tools.js.map +1 -1
- package/dist/core/bot-identity.d.ts +4 -0
- package/dist/core/bot-identity.d.ts.map +1 -0
- package/dist/core/bot-identity.js +15 -0
- package/dist/core/bot-identity.js.map +1 -0
- package/dist/core/source-control.d.ts +4 -2
- package/dist/core/source-control.d.ts.map +1 -1
- package/dist/core/source-control.js +42 -11
- package/dist/core/source-control.js.map +1 -1
- package/dist/index.d.ts +78 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/api/client.test.ts +267 -9
- package/src/api/client.ts +184 -9
- package/src/api/installation-token-envelope.ts +3 -1
- package/src/core/agent-tools.test.ts +1 -0
- package/src/core/agent-tools.ts +2 -9
- package/src/core/bot-identity.test.ts +19 -0
- package/src/core/bot-identity.ts +19 -0
- package/src/core/install.test.ts +3 -0
- package/src/core/source-control.test.ts +180 -1
- package/src/core/source-control.ts +65 -11
- package/src/index.test.ts +3 -1
- package/src/index.ts +2 -0
- package/src/presentation/routes/install.test.ts +3 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {config} from '#config.js';
|
|
2
|
+
|
|
3
|
+
const GITHUB_APP_BOT_SUFFIX = '[bot]';
|
|
4
|
+
|
|
5
|
+
export function githubBotLogin(username: string): string {
|
|
6
|
+
const normalized = username.trim();
|
|
7
|
+
return normalized.toLowerCase().endsWith(GITHUB_APP_BOT_SUFFIX)
|
|
8
|
+
? normalized
|
|
9
|
+
: `${normalized}${GITHUB_APP_BOT_SUFFIX}`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function configuredGithubAppBotLogin(): string | undefined {
|
|
13
|
+
const configuredUsername = config.GITHUB_APP_USERNAME?.trim();
|
|
14
|
+
return configuredUsername ? githubBotLogin(configuredUsername) : undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function githubAppBotLogin(): string {
|
|
18
|
+
return configuredGithubAppBotLogin() ?? githubBotLogin(config.GITHUB_APP_SLUG);
|
|
19
|
+
}
|
package/src/core/install.test.ts
CHANGED
|
@@ -37,6 +37,9 @@ function githubClient(overrides: Partial<GithubApiClient> = {}): GithubApiClient
|
|
|
37
37
|
fetchRepositoryFile: vi.fn(() => {
|
|
38
38
|
throw new Error('not used');
|
|
39
39
|
}),
|
|
40
|
+
listRepositoryCommits: vi.fn(() => {
|
|
41
|
+
throw new Error('not used');
|
|
42
|
+
}),
|
|
40
43
|
createInstallationAccessToken: vi.fn(() =>
|
|
41
44
|
Promise.resolve({
|
|
42
45
|
token: 'ghs_installationtoken',
|
|
@@ -8,6 +8,7 @@ const VALID_COMMIT = 'a'.repeat(40);
|
|
|
8
8
|
function githubClient(overrides: Partial<GithubApiClient> = {}): GithubApiClient {
|
|
9
9
|
return {
|
|
10
10
|
exchangeOAuthCode: vi.fn(() => Promise.resolve('token')),
|
|
11
|
+
getBotUser: vi.fn(() => Promise.resolve({id: 12_345, login: 'shipfox-test[bot]'})),
|
|
11
12
|
listUserInstallations: vi.fn(() => Promise.resolve({installationIds: [], nextCursor: null})),
|
|
12
13
|
getInstallation: vi.fn(() => {
|
|
13
14
|
throw new Error('not used');
|
|
@@ -56,6 +57,9 @@ function githubClient(overrides: Partial<GithubApiClient> = {}): GithubApiClient
|
|
|
56
57
|
size: 58,
|
|
57
58
|
}),
|
|
58
59
|
),
|
|
60
|
+
listRepositoryCommits: vi.fn(() =>
|
|
61
|
+
Promise.resolve([{sha: 'a'.repeat(40)}, {sha: 'b'.repeat(40)}]),
|
|
62
|
+
),
|
|
59
63
|
createInstallationAccessToken: vi.fn(() =>
|
|
60
64
|
Promise.resolve({
|
|
61
65
|
token: 'ghs_installationtoken',
|
|
@@ -258,6 +262,96 @@ describe('GithubSourceControlProvider', () => {
|
|
|
258
262
|
});
|
|
259
263
|
});
|
|
260
264
|
|
|
265
|
+
it('resolves a branch ref to the commit it points at', async () => {
|
|
266
|
+
await createInstallation();
|
|
267
|
+
const github = githubClient();
|
|
268
|
+
const provider = new GithubSourceControlProvider(github);
|
|
269
|
+
|
|
270
|
+
const result = await provider.resolveRef({
|
|
271
|
+
connection: connection(),
|
|
272
|
+
externalRepositoryId: 'github:42',
|
|
273
|
+
ref: 'refs/heads/main',
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
expect(result).toEqual({ref: 'refs/heads/main', commit: VALID_COMMIT});
|
|
277
|
+
expect(github.listRepositoryCommits).toHaveBeenCalledWith({
|
|
278
|
+
installationId,
|
|
279
|
+
repositoryId: 42,
|
|
280
|
+
ref: 'refs/heads/main',
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it('resolves a tag ref to the commit it points at', async () => {
|
|
285
|
+
await createInstallation();
|
|
286
|
+
const github = githubClient({
|
|
287
|
+
listRepositoryCommits: vi.fn(() => Promise.resolve([{sha: 'c'.repeat(40)}])),
|
|
288
|
+
});
|
|
289
|
+
const provider = new GithubSourceControlProvider(github);
|
|
290
|
+
|
|
291
|
+
const result = await provider.resolveRef({
|
|
292
|
+
connection: connection(),
|
|
293
|
+
externalRepositoryId: 'github:42',
|
|
294
|
+
ref: 'refs/tags/v1.0.0',
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
expect(result).toEqual({ref: 'refs/tags/v1.0.0', commit: 'c'.repeat(40)});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('maps a ref with no commits to ref-not-found', async () => {
|
|
301
|
+
await createInstallation();
|
|
302
|
+
const github = githubClient({
|
|
303
|
+
listRepositoryCommits: vi.fn(() => Promise.resolve([])),
|
|
304
|
+
});
|
|
305
|
+
const provider = new GithubSourceControlProvider(github);
|
|
306
|
+
|
|
307
|
+
const result = provider.resolveRef({
|
|
308
|
+
connection: connection(),
|
|
309
|
+
externalRepositoryId: 'github:42',
|
|
310
|
+
ref: 'refs/heads/missing',
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
await expect(result).rejects.toMatchObject({reason: 'ref-not-found'});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it('rejects a commit response with an invalid object id', async () => {
|
|
317
|
+
await createInstallation();
|
|
318
|
+
const github = githubClient({
|
|
319
|
+
listRepositoryCommits: vi.fn(() => Promise.resolve([{sha: 'not-a-commit'}])),
|
|
320
|
+
});
|
|
321
|
+
const provider = new GithubSourceControlProvider(github);
|
|
322
|
+
|
|
323
|
+
const result = provider.resolveRef({
|
|
324
|
+
connection: connection(),
|
|
325
|
+
externalRepositoryId: 'github:42',
|
|
326
|
+
ref: 'refs/heads/main',
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
await expect(result).rejects.toMatchObject({
|
|
330
|
+
reason: 'malformed-provider-response',
|
|
331
|
+
message: 'GitHub ref "refs/heads/main" resolved to an invalid commit',
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it.each([
|
|
336
|
+
'a'.repeat(40),
|
|
337
|
+
'refs/pull/17/head',
|
|
338
|
+
'main',
|
|
339
|
+
'-evil',
|
|
340
|
+
])('rejects ref %s as ref-invalid', async (ref) => {
|
|
341
|
+
await createInstallation();
|
|
342
|
+
const github = githubClient();
|
|
343
|
+
const provider = new GithubSourceControlProvider(github);
|
|
344
|
+
|
|
345
|
+
const result = provider.resolveRef({
|
|
346
|
+
connection: connection(),
|
|
347
|
+
externalRepositoryId: 'github:42',
|
|
348
|
+
ref,
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
await expect(result).rejects.toMatchObject({reason: 'ref-invalid'});
|
|
352
|
+
expect(github.listRepositoryCommits).not.toHaveBeenCalled();
|
|
353
|
+
});
|
|
354
|
+
|
|
261
355
|
it('fetches repository file contents using the provider-owned repository id', async () => {
|
|
262
356
|
await createInstallation();
|
|
263
357
|
const github = githubClient();
|
|
@@ -349,7 +443,7 @@ describe('GithubSourceControlProvider', () => {
|
|
|
349
443
|
},
|
|
350
444
|
gitAuthor: {
|
|
351
445
|
name: 'shipfox-test[bot]',
|
|
352
|
-
email: '
|
|
446
|
+
email: '12345+shipfox-test[bot]@users.noreply.github.com',
|
|
353
447
|
},
|
|
354
448
|
});
|
|
355
449
|
expect(result.repositoryUrl).not.toContain('ghs_installationtoken');
|
|
@@ -358,6 +452,91 @@ describe('GithubSourceControlProvider', () => {
|
|
|
358
452
|
repositoryId: 42,
|
|
359
453
|
permissions: {contents: 'write'},
|
|
360
454
|
});
|
|
455
|
+
expect(github.getBotUser).toHaveBeenCalledWith({
|
|
456
|
+
username: 'shipfox-test[bot]',
|
|
457
|
+
installationAccessToken: 'ghs_installationtoken',
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
it('propagates bot identity resolution failures for write checkouts', async () => {
|
|
462
|
+
await createInstallation();
|
|
463
|
+
const github = githubClient({
|
|
464
|
+
getBotUser: vi.fn(() =>
|
|
465
|
+
Promise.reject(
|
|
466
|
+
new GithubIntegrationProviderError('provider-rejected', 'bot user not found'),
|
|
467
|
+
),
|
|
468
|
+
),
|
|
469
|
+
});
|
|
470
|
+
const provider = new GithubSourceControlProvider(github);
|
|
471
|
+
|
|
472
|
+
const result = provider.createCheckoutSpec({
|
|
473
|
+
connection: connection(),
|
|
474
|
+
externalRepositoryId: 'github:42',
|
|
475
|
+
permissions: {contents: 'write'},
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
await expect(result).rejects.toMatchObject({reason: 'provider-rejected'});
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it('propagates unexpected bot lookup errors', async () => {
|
|
482
|
+
await createInstallation();
|
|
483
|
+
const github = githubClient({
|
|
484
|
+
getBotUser: vi.fn(() => Promise.reject(new Error('unexpected lookup failure'))),
|
|
485
|
+
});
|
|
486
|
+
const provider = new GithubSourceControlProvider(github);
|
|
487
|
+
|
|
488
|
+
const result = provider.createCheckoutSpec({
|
|
489
|
+
connection: connection(),
|
|
490
|
+
externalRepositoryId: 'github:42',
|
|
491
|
+
permissions: {contents: 'write'},
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
await expect(result).rejects.toThrow('unexpected lookup failure');
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it('rejects write checkout when the bot identity resolver is unavailable', async () => {
|
|
498
|
+
await createInstallation();
|
|
499
|
+
const github = githubClient();
|
|
500
|
+
delete github.getBotUser;
|
|
501
|
+
const provider = new GithubSourceControlProvider(github);
|
|
502
|
+
|
|
503
|
+
const result = provider.createCheckoutSpec({
|
|
504
|
+
connection: connection(),
|
|
505
|
+
externalRepositoryId: 'github:42',
|
|
506
|
+
permissions: {contents: 'write'},
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
await expect(result).rejects.toMatchObject({reason: 'provider-unavailable'});
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it('omits the author and bot lookup for read-only checkouts', async () => {
|
|
513
|
+
await createInstallation();
|
|
514
|
+
const github = githubClient();
|
|
515
|
+
const provider = new GithubSourceControlProvider(github);
|
|
516
|
+
|
|
517
|
+
const result = await provider.createCheckoutSpec({
|
|
518
|
+
connection: connection(),
|
|
519
|
+
externalRepositoryId: 'github:42',
|
|
520
|
+
permissions: {contents: 'read'},
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
expect(result.gitAuthor).toBeUndefined();
|
|
524
|
+
expect(github.getBotUser).not.toHaveBeenCalled();
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
it('omits the author and bot lookup when the App username is unset', async () => {
|
|
528
|
+
await createInstallation();
|
|
529
|
+
const github = githubClient();
|
|
530
|
+
const provider = new GithubSourceControlProvider(github, () => undefined);
|
|
531
|
+
|
|
532
|
+
const result = await provider.createCheckoutSpec({
|
|
533
|
+
connection: connection(),
|
|
534
|
+
externalRepositoryId: 'github:42',
|
|
535
|
+
permissions: {contents: 'write'},
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
expect(result.gitAuthor).toBeUndefined();
|
|
539
|
+
expect(github.getBotUser).not.toHaveBeenCalled();
|
|
361
540
|
});
|
|
362
541
|
|
|
363
542
|
it('defaults the checkout ref to the repository default branch', async () => {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type IntegrationConnection,
|
|
11
11
|
isRecord,
|
|
12
12
|
isValidGitObjectId,
|
|
13
|
+
isValidResolvableRef,
|
|
13
14
|
isValidTriggerRef,
|
|
14
15
|
type ListFilesInput,
|
|
15
16
|
type ListRepositoriesInput,
|
|
@@ -20,26 +21,30 @@ import {
|
|
|
20
21
|
type RepositoryPage,
|
|
21
22
|
type RepositorySnapshot,
|
|
22
23
|
type RepositoryVisibility,
|
|
24
|
+
type ResolvedRef,
|
|
25
|
+
type ResolveRefInput,
|
|
23
26
|
type ResolveRepositoryInput,
|
|
24
27
|
type SourceControlProvider,
|
|
25
28
|
type TriggerReference,
|
|
26
29
|
} from '@shipfox/api-integration-spi';
|
|
27
30
|
import type {GithubApiClient, GithubRepository} from '#api/client.js';
|
|
28
|
-
import {config} from '#config.js';
|
|
29
31
|
import {getGithubInstallationByConnectionId} from '#db/installations.js';
|
|
32
|
+
import {configuredGithubAppBotLogin} from './bot-identity.js';
|
|
30
33
|
import {GithubIntegrationProviderError} from './errors.js';
|
|
31
34
|
|
|
32
35
|
type GithubIntegrationConnection = IntegrationConnection<'github'>;
|
|
33
36
|
|
|
34
37
|
const GITHUB_PROVIDER = 'github';
|
|
35
|
-
const GITHUB_APP_BOT_SUFFIX = '[bot]';
|
|
36
38
|
const SEARCH_PAGE_SIZE = 100;
|
|
37
39
|
const SEARCH_MAX_PAGES_PER_REQUEST = 5;
|
|
38
40
|
|
|
39
41
|
export class GithubSourceControlProvider
|
|
40
42
|
implements SourceControlProvider<GithubIntegrationConnection>
|
|
41
43
|
{
|
|
42
|
-
constructor(
|
|
44
|
+
constructor(
|
|
45
|
+
private readonly github: GithubApiClient,
|
|
46
|
+
private readonly appBotLogin: () => string | undefined = configuredGithubAppBotLogin,
|
|
47
|
+
) {}
|
|
43
48
|
|
|
44
49
|
async listRepositories(
|
|
45
50
|
input: ListRepositoriesInput<GithubIntegrationConnection>,
|
|
@@ -192,6 +197,37 @@ export class GithubSourceControlProvider
|
|
|
192
197
|
};
|
|
193
198
|
}
|
|
194
199
|
|
|
200
|
+
async resolveRef(input: ResolveRefInput<GithubIntegrationConnection>): Promise<ResolvedRef> {
|
|
201
|
+
if (!isValidResolvableRef(input.ref)) {
|
|
202
|
+
throw new GithubIntegrationProviderError(
|
|
203
|
+
'ref-invalid',
|
|
204
|
+
`GitHub ref ${formatRefForMessage(input.ref)} is not a resolvable branch or tag name`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
const installationId = await this.installationId(input.connection.id);
|
|
208
|
+
const {repositoryId} = parseGithubRepositoryLocator(input.externalRepositoryId);
|
|
209
|
+
const commits = await this.github.listRepositoryCommits({
|
|
210
|
+
installationId,
|
|
211
|
+
repositoryId,
|
|
212
|
+
ref: input.ref,
|
|
213
|
+
});
|
|
214
|
+
const commit = commits[0]?.sha;
|
|
215
|
+
if (!commit) {
|
|
216
|
+
throw new GithubIntegrationProviderError(
|
|
217
|
+
'ref-not-found',
|
|
218
|
+
`GitHub ref ${formatRefForMessage(input.ref)} does not resolve to a commit`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (!isValidGitObjectId(commit)) {
|
|
222
|
+
throw new GithubIntegrationProviderError(
|
|
223
|
+
'malformed-provider-response',
|
|
224
|
+
`GitHub ref ${formatRefForMessage(input.ref)} resolved to an invalid commit`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return {ref: input.ref, commit};
|
|
229
|
+
}
|
|
230
|
+
|
|
195
231
|
async createCheckoutSpec(
|
|
196
232
|
input: CreateCheckoutSpecInput<GithubIntegrationConnection>,
|
|
197
233
|
): Promise<CheckoutSpec> {
|
|
@@ -204,7 +240,11 @@ export class GithubSourceControlProvider
|
|
|
204
240
|
repositoryId,
|
|
205
241
|
permissions: input.permissions,
|
|
206
242
|
});
|
|
207
|
-
const
|
|
243
|
+
const botLogin = this.appBotLogin();
|
|
244
|
+
const gitAuthor =
|
|
245
|
+
botLogin && input.permissions?.contents === 'write'
|
|
246
|
+
? await githubAppGitAuthor(this.github, token, botLogin)
|
|
247
|
+
: undefined;
|
|
208
248
|
|
|
209
249
|
return {
|
|
210
250
|
repositoryUrl: repository.cloneUrl,
|
|
@@ -250,13 +290,27 @@ function sameGithubRepository(
|
|
|
250
290
|
return Boolean(firstName && secondName && firstName.toLowerCase() === secondName.toLowerCase());
|
|
251
291
|
}
|
|
252
292
|
|
|
253
|
-
function
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
293
|
+
function formatRefForMessage(ref: string): string {
|
|
294
|
+
return JSON.stringify(ref);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function githubAppGitAuthor(
|
|
298
|
+
github: GithubApiClient,
|
|
299
|
+
installationAccessToken: string,
|
|
300
|
+
name: string,
|
|
301
|
+
): Promise<CheckoutSpec['gitAuthor']> {
|
|
302
|
+
if (!github.getBotUser) {
|
|
303
|
+
throw new GithubIntegrationProviderError(
|
|
304
|
+
'provider-unavailable',
|
|
305
|
+
'GitHub bot identity resolution is unavailable',
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const botUser = await github.getBotUser({username: name, installationAccessToken});
|
|
310
|
+
return {
|
|
311
|
+
name: botUser.login,
|
|
312
|
+
email: `${botUser.id}+${botUser.login}@users.noreply.github.com`,
|
|
313
|
+
};
|
|
260
314
|
}
|
|
261
315
|
|
|
262
316
|
function toRepositorySnapshot(repository: GithubRepository): RepositorySnapshot {
|
package/src/index.test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {githubEventCatalog} from '@shipfox/api-integration-github-dto';
|
|
1
2
|
import {githubInstallationTokenNamespace} from '#api/installation-token-envelope.js';
|
|
2
3
|
import {createGithubIntegrationProvider} from '#index.js';
|
|
3
4
|
|
|
@@ -19,7 +20,7 @@ vi.mock('#core/webhook-processor.js', () => ({
|
|
|
19
20
|
describe('createGithubIntegrationProvider', () => {
|
|
20
21
|
it('shares installation-token cleanup with the direct and composed processors', async () => {
|
|
21
22
|
const deleteSecrets = vi.fn(() => Promise.resolve(1));
|
|
22
|
-
createGithubIntegrationProvider({
|
|
23
|
+
const provider = createGithubIntegrationProvider({
|
|
23
24
|
github: {} as never,
|
|
24
25
|
getExistingGithubConnection: vi.fn(() => Promise.resolve(undefined)),
|
|
25
26
|
connectGithubInstallation: vi.fn() as never,
|
|
@@ -31,6 +32,7 @@ describe('createGithubIntegrationProvider', () => {
|
|
|
31
32
|
getIntegrationConnectionById: vi.fn(() => Promise.resolve(undefined)),
|
|
32
33
|
deleteSecrets,
|
|
33
34
|
});
|
|
35
|
+
expect(provider.eventCatalog).toBe(githubEventCatalog);
|
|
34
36
|
const processorOptions = state.processorOptions as {
|
|
35
37
|
deleteInstallationTokenSecret: (params: {
|
|
36
38
|
workspaceId: string;
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {githubEventCatalog} from '@shipfox/api-integration-github-dto';
|
|
1
2
|
import type {
|
|
2
3
|
GetIntegrationConnectionByIdFn,
|
|
3
4
|
PublishIntegrationEventReceivedFn,
|
|
@@ -102,6 +103,7 @@ export function createGithubIntegrationProvider(options: CreateGithubIntegration
|
|
|
102
103
|
return {
|
|
103
104
|
provider: 'github' as const,
|
|
104
105
|
displayName: 'GitHub',
|
|
106
|
+
eventCatalog: githubEventCatalog,
|
|
105
107
|
adapters: {
|
|
106
108
|
source_control: new GithubSourceControlProvider(github),
|
|
107
109
|
agent_tools: new GithubAgentToolsProvider({
|
|
@@ -61,6 +61,9 @@ function githubClient(overrides: Partial<GithubApiClient> = {}): GithubApiClient
|
|
|
61
61
|
fetchRepositoryFile: vi.fn(() => {
|
|
62
62
|
throw new Error('not used');
|
|
63
63
|
}),
|
|
64
|
+
listRepositoryCommits: vi.fn(() => {
|
|
65
|
+
throw new Error('not used');
|
|
66
|
+
}),
|
|
64
67
|
createInstallationAccessToken: vi.fn(() =>
|
|
65
68
|
Promise.resolve({
|
|
66
69
|
token: 'ghs_installationtoken',
|