diff --git a/.changeset/common-goats-raise.md b/.changeset/common-goats-raise.md new file mode 100644 index 0000000000..c2d797b719 --- /dev/null +++ b/.changeset/common-goats-raise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Use action context logger in Octokit client diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.test.ts b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts index d7e74f1b9c..f2063bd410 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts @@ -54,6 +54,9 @@ const initRepoAndPushMocked = initRepoAndPush as jest.Mock< Promise<{ commitHash: string }> >; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { users: { @@ -81,11 +84,7 @@ const mockOctokit = { request: jest.fn(), }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('publish:github', () => { @@ -114,6 +113,7 @@ describe('publish:github', () => { }); beforeEach(() => { + octokitMock.mockImplementation(() => mockOctokit); initRepoAndPushMocked.mockResolvedValue({ commitHash: '220f19cc36b551763d157f1b5e4a4b446165dbd6', }); @@ -139,6 +139,20 @@ describe('publish:github', () => { afterEach(jest.resetAllMocks); + it('should pass context logger to Octokit client', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'Organization' }, + }); + + mockOctokit.rest.repos.createInOrg.mockResolvedValue({ data: {} }); + + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should fail to create if the team is not found in the org', async () => { mockOctokit.rest.users.getByUsername.mockResolvedValue({ data: { type: 'Organization' }, diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.ts b/plugins/scaffolder-backend-module-github/src/actions/github.ts index fefa2ea780..c47e789bdd 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.ts @@ -242,7 +242,10 @@ export function createPublishGithubAction(options: { owner, repo, }); - const client = new Octokit(octokitOptions); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); const { remoteUrl, repoContentsUrl } = await ctx.checkpoint({ key: `create.github.repo.${owner}.${repo}`, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.test.ts index 7f0d9b0490..7739259c5d 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.test.ts @@ -24,6 +24,9 @@ import { TemplateAction } from '@backstage/plugin-scaffolder-node'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { createGithubActionsDispatchAction } from './githubActionsDispatch'; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { actions: { @@ -32,11 +35,7 @@ const mockOctokit = { }, }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('github:actions:dispatch', () => { @@ -63,6 +62,7 @@ describe('github:actions:dispatch', () => { beforeEach(() => { jest.resetAllMocks(); + octokitMock.mockImplementation(() => mockOctokit); githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); action = createGithubActionsDispatchAction({ @@ -71,6 +71,14 @@ describe('github:actions:dispatch', () => { }); }); + it('should pass context logger to Octokit client', async () => { + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should call the githubApis for creating WorkflowDispatch without an input object', async () => { mockOctokit.rest.actions.createWorkflowDispatch.mockResolvedValue({ data: { diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts index 4faa53e6b8..40e48bb902 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubActionsDispatch.ts @@ -104,16 +104,18 @@ export function createGithubActionsDispatchAction(options: { throw new InputError('Invalid repository owner provided in repoUrl'); } - const client = new Octokit( - await getOctokitOptions({ - integrations, - host, - owner, - repo, - credentialsProvider: githubCredentialsProvider, - token: providedToken, - }), - ); + const octokitOptions = await getOctokitOptions({ + integrations, + host, + owner, + repo, + credentialsProvider: githubCredentialsProvider, + token: providedToken, + }); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); await ctx.checkpoint({ key: `create.workflow.dispatch.${owner}.${repo}.${workflowId}`, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.test.ts index 56115c156c..c378afa17d 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.test.ts @@ -25,6 +25,9 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- import { TemplateAction } from '@backstage/plugin-scaffolder-node'; import { createGithubAutolinksAction } from './githubAutolinks'; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { repos: { @@ -33,11 +36,7 @@ const mockOctokit = { }, }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('github:autolinks:create', () => { @@ -55,6 +54,30 @@ describe('github:autolinks:create', () => { let action: TemplateAction; const workspacePath = createMockDirectory().resolve('workspace'); + it('should pass context logger to Octokit client', async () => { + githubCredentialsProvider = + DefaultGithubCredentialsProvider.fromIntegrations(integrations); + action = createGithubAutolinksAction({ + integrations, + githubCredentialsProvider, + }); + + octokitMock.mockImplementation(() => mockOctokit); + + const mockContext = createMockActionContext({ + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + }, + workspacePath, + }); + + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should call the githubApis for creating alphanumeric autolink reference', async () => { githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts index 396d85708f..50ed052458 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubAutolinks.ts @@ -97,16 +97,18 @@ export function createGithubAutolinksAction(options: { throw new InputError('Invalid repository owner provided in repoUrl'); } - const client = new Octokit( - await getOctokitOptions({ - integrations, - host, - owner, - repo, - credentialsProvider: githubCredentialsProvider, - token, - }), - ); + const octokitOptions = await getOctokitOptions({ + integrations, + host, + owner, + repo, + credentialsProvider: githubCredentialsProvider, + token, + }); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); await ctx.checkpoint({ key: `create.auto.link.${owner}.${repo}`, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.test.ts index 8e672af725..190743c556 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.test.ts @@ -20,6 +20,9 @@ import { TemplateAction } from '@backstage/plugin-scaffolder-node'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { repos: { @@ -29,13 +32,8 @@ const mockOctokit = { }, }, }; - jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('github:branch-protection:create', () => { @@ -59,6 +57,8 @@ describe('github:branch-protection:create', () => { }); beforeEach(() => { + octokitMock.mockImplementation(() => mockOctokit); + mockOctokit.rest.repos.get.mockResolvedValue({ data: { default_branch: 'master', @@ -72,6 +72,14 @@ describe('github:branch-protection:create', () => { afterEach(jest.resetAllMocks); + it('should pass context logger to Octokit client', async () => { + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should work with default params', async () => { await action.handler(mockContext); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts index ae8965ef9a..79eebb4096 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts @@ -128,7 +128,10 @@ export function createGithubBranchProtectionAction(options: { owner, repo, }); - const client = new Octokit(octokitOptions); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); const defaultBranch = await ctx.checkpoint({ key: `read.default.branch.${owner}.${repo}`, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.test.ts index 798aa7705e..794ec2cf65 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.test.ts @@ -20,6 +20,9 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { actions: { @@ -32,11 +35,7 @@ const mockOctokit = { }, }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU='; @@ -66,11 +65,28 @@ describe('github:deployKey:create', () => { beforeEach(() => { jest.resetAllMocks(); + octokitMock.mockImplementation(() => mockOctokit); + action = createGithubDeployKeyAction({ integrations, }); }); + it('should pass context logger to Octokit client', async () => { + mockOctokit.rest.actions.getRepoPublicKey.mockResolvedValue({ + data: { + key: publicKey, + key_id: 'keyid', + }, + }); + + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should work happy path', async () => { mockOctokit.rest.actions.getRepoPublicKey.mockResolvedValue({ data: { diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.ts b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.ts index 7eba3b94c8..1cb72dac3e 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubDeployKey.ts @@ -124,7 +124,10 @@ export function createGithubDeployKeyAction(options: { repo, }); - const client = new Octokit(octokitOptions); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); await ctx.checkpoint({ key: `create.deploy.key.${owner}.${repo}.${publicKey}`, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts index 1a4ffa5ea4..6a75bde69f 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts @@ -22,6 +22,10 @@ import { ScmIntegrations } from '@backstage/integration'; import { CatalogApi } from '@backstage/catalog-client'; import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; + const mockOctokit = { rest: { actions: { @@ -48,11 +52,7 @@ const mockCatalogClient: Partial = { }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); jest.mock('@backstage/catalog-client', () => ({ @@ -91,6 +91,8 @@ describe('github:environment:create', () => { }); beforeEach(() => { + octokitMock.mockImplementation(() => mockOctokit); + mockOctokit.rest.actions.getEnvironmentPublicKey.mockResolvedValue({ data: { key: publicKey, @@ -138,6 +140,14 @@ describe('github:environment:create', () => { afterEach(jest.resetAllMocks); + it('should pass context logger to Octokit client', async () => { + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should work happy path', async () => { await action.handler(mockContext); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts index f93cb49946..522b6ed8b5 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts @@ -192,8 +192,10 @@ Wildcard characters will not match \`/\`. For example, to match tags that begin owner, repo, }); - - const client = new Octokit(octokitOptions); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); const repositoryId = await ctx.checkpoint({ key: `get.repo.${owner}.${repo}`, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.test.ts index af1d7d552c..b1e1c6e87c 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.test.ts @@ -31,6 +31,9 @@ jest.mock('../util', () => { }; }); +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { issues: { @@ -39,11 +42,7 @@ const mockOctokit = { }, }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('github:issues:label', () => { @@ -71,6 +70,7 @@ describe('github:issues:label', () => { beforeEach(() => { jest.resetAllMocks(); + octokitMock.mockImplementation(() => mockOctokit); githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); action = createGithubIssuesLabelAction({ @@ -79,6 +79,14 @@ describe('github:issues:label', () => { }); }); + it('should pass context logger to Octokit client', async () => { + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should call the githubApi for adding labels', async () => { await action.handler(mockContext); expect(mockOctokit.rest.issues.addLabels).toHaveBeenCalledWith({ diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.ts b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.ts index 7dd116be79..f91bd01a73 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubIssuesLabel.ts @@ -89,16 +89,18 @@ export function createGithubIssuesLabelAction(options: { throw new InputError('Invalid repository owner provided in repoUrl'); } - const client = new Octokit( - await getOctokitOptions({ - integrations, - credentialsProvider: githubCredentialsProvider, - host, - owner, - repo, - token: providedToken, - }), - ); + const octokitOptions = await getOctokitOptions({ + integrations, + credentialsProvider: githubCredentialsProvider, + host, + owner, + repo, + token: providedToken, + }); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); try { await ctx.checkpoint({ diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.test.ts index 203014b67b..23e3077861 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.test.ts @@ -24,16 +24,16 @@ import { } from '@backstage/integration'; import { createGithubPagesEnableAction } from './githubPagesEnable'; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; + const mockOctokit = { request: jest.fn(), }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('github:pages', () => { @@ -61,6 +61,7 @@ describe('github:pages', () => { }); beforeEach(() => { + octokitMock.mockImplementation(() => mockOctokit); githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); action = createGithubPagesEnableAction({ @@ -71,6 +72,14 @@ describe('github:pages', () => { afterEach(jest.resetAllMocks); + it('should pass context logger to Octokit client', async () => { + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should work happy path', async () => { await action.handler(mockContext); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts index 7efee89a5d..01830a252d 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts @@ -112,7 +112,10 @@ export function createGithubPagesEnableAction(options: { owner, repo, }); - const client = new Octokit(octokitOptions); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); ctx.logger.info( `Attempting to enable GitHub Pages for ${owner}/${repo} with "${buildType}" build type, on source branch "${sourceBranch}" and source path "${sourcePath}"`, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts index bf340a485e..6f901d1d84 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.test.ts @@ -35,6 +35,9 @@ import { entityRefToName } from './gitHelpers'; const publicKey = '2Sg8iYjAxxmI2LvUXpJjkYrMxURPc8r+dB7TJyvvcCU='; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { users: { @@ -62,11 +65,7 @@ const mockOctokit = { request: jest.fn(), }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('github:repo:create', () => { @@ -93,6 +92,7 @@ describe('github:repo:create', () => { }); beforeEach(() => { + octokitMock.mockImplementation(() => mockOctokit); githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); action = createGithubRepoCreateAction({ @@ -110,6 +110,20 @@ describe('github:repo:create', () => { afterEach(jest.resetAllMocks); + it('should pass context logger to Octokit client', async () => { + mockOctokit.rest.users.getByUsername.mockResolvedValue({ + data: { type: 'Organization' }, + }); + + mockOctokit.rest.repos.createInOrg.mockResolvedValue({ data: {} }); + + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should call the githubApis with the correct values for createInOrg', async () => { mockOctokit.rest.users.getByUsername.mockResolvedValue({ data: { type: 'Organization' }, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts index 6899b3dff8..442af4057c 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts @@ -197,7 +197,10 @@ export function createGithubRepoCreateAction(options: { owner, repo, }); - const client = new Octokit(octokitOptions); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); const remoteUrl = await ctx.checkpoint({ key: `create.repo.and.topics.${owner}.${repo}`, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts index a3b2478ce6..7ef6e2d793 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts @@ -52,6 +52,9 @@ const initRepoAndPushMocked = initRepoAndPush as jest.Mock< Promise<{ commitHash: string }> >; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { repos: { @@ -60,11 +63,7 @@ const mockOctokit = { }, }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('github:repo:push', () => { @@ -93,6 +92,8 @@ describe('github:repo:push', () => { beforeEach(() => { jest.resetAllMocks(); + octokitMock.mockImplementation(() => mockOctokit); + initRepoAndPushMocked.mockResolvedValue({ commitHash: 'test123' }); githubCredentialsProvider = @@ -104,6 +105,21 @@ describe('github:repo:push', () => { }); }); + it('should pass context logger to Octokit client', async () => { + mockOctokit.rest.repos.get.mockResolvedValue({ + data: { + clone_url: 'https://github.com/clone/url.git', + html_url: 'https://github.com/html/url', + }, + }); + + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should call initRepoAndPush with the correct values', async () => { mockOctokit.rest.repos.get.mockResolvedValue({ data: { diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts index f74ce33865..990f3ff7ca 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts @@ -158,7 +158,10 @@ export function createGithubRepoPushAction(options: { repo, }); - const client = new Octokit(octokitOptions); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); const targetRepo = await client.rest.repos.get({ owner, repo }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.test.ts index 30bdcef20d..a42d251c49 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.test.ts @@ -24,6 +24,9 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- import { ConfigReader } from '@backstage/config'; import { TemplateAction } from '@backstage/plugin-scaffolder-node'; +import { Octokit } from 'octokit'; + +const octokitMock = Octokit as unknown as jest.Mock; const mockOctokit = { rest: { repos: { @@ -32,11 +35,7 @@ const mockOctokit = { }, }; jest.mock('octokit', () => ({ - Octokit: class { - constructor() { - return mockOctokit; - } - }, + Octokit: jest.fn(), })); describe('github:repository:webhook:create', () => { @@ -56,6 +55,7 @@ describe('github:repository:webhook:create', () => { beforeEach(() => { jest.resetAllMocks(); + octokitMock.mockImplementation(() => mockOctokit); githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); action = createGithubWebhookAction({ @@ -72,6 +72,14 @@ describe('github:repository:webhook:create', () => { }, }); + it('should pass context logger to Octokit client', async () => { + await action.handler(mockContext); + + expect(octokitMock).toHaveBeenCalledWith( + expect.objectContaining({ log: mockContext.logger }), + ); + }); + it('should call the githubApi for creating repository Webhook', async () => { const repoUrl = 'github.com?repo=repo&owner=owner'; const webhookUrl = 'https://example.com/payload'; diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.ts b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.ts index 39a659cd0a..7345f7dd9f 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubWebhook.ts @@ -149,16 +149,18 @@ export function createGithubWebhookAction(options: { throw new InputError('Invalid repository owner provided in repoUrl'); } - const client = new Octokit( - await getOctokitOptions({ - integrations, - credentialsProvider: githubCredentialsProvider, - host, - owner, - repo, - token: providedToken, - }), - ); + const octokitOptions = await getOctokitOptions({ + integrations, + credentialsProvider: githubCredentialsProvider, + host, + owner, + repo, + token: providedToken, + }); + const client = new Octokit({ + ...octokitOptions, + log: ctx.logger, + }); // If this is a dry run, log and return if (ctx.isDryRun) {