From cc4683d185bb5c139804ce2bce3ef7379720162a Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 1 Jul 2020 16:44:09 +0200 Subject: [PATCH] chore(scaffolder): making some tests nicer and a little more readable and typescript compliant --- plugins/scaffolder-backend/package.json | 1 + .../scaffolder/stages/prepare/github.test.ts | 1 - .../publish/__mocks__/@octokit/rest/index.ts | 28 ++++++++ .../stages/publish/__mocks__/nodegit/index.ts | 39 +++++++++++ .../scaffolder/stages/publish/github.test.ts | 68 ++++++++++++++++++- .../src/scaffolder/stages/publish/github.ts | 17 ++--- 6 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 plugins/scaffolder-backend/src/scaffolder/stages/publish/__mocks__/@octokit/rest/index.ts create mode 100644 plugins/scaffolder-backend/src/scaffolder/stages/publish/__mocks__/nodegit/index.ts diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index c6237bc726..30de3a8b6f 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -43,6 +43,7 @@ }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.12", + "@octokit/types": "^5.0.1", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", "@types/nodegit": "0.26.5", diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts index 86377be6d0..f8552e063f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts @@ -19,7 +19,6 @@ const mocks = { CheckoutOptions: jest.fn(() => {}), }; jest.doMock('nodegit', () => mocks); -// require('nodegit'); import { GithubPreparer } from './github'; import { diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/__mocks__/@octokit/rest/index.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/__mocks__/@octokit/rest/index.ts new file mode 100644 index 0000000000..85bed3a223 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/__mocks__/@octokit/rest/index.ts @@ -0,0 +1,28 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const mockGithubClient = { + repos: { + createInOrg: jest.fn(), + createForAuthenticatedUser: jest.fn(), + }, +}; + +export class Octokit { + constructor() { + return mockGithubClient; + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/__mocks__/nodegit/index.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/__mocks__/nodegit/index.ts new file mode 100644 index 0000000000..aa0cb6a23b --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/__mocks__/nodegit/index.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const mockIndex = { + addAll: jest.fn(), + write: jest.fn(), + writeTree: jest.fn().mockResolvedValue('mockoid'), +}; + +const mockRepo = { + refreshIndex: jest.fn().mockResolvedValue(mockIndex), + createCommit: jest.fn(), +}; + +const mockRemote = { + push: jest.fn(), +}; + +const Repository = { init: jest.fn().mockResolvedValue(mockRepo) }; +const Remote = { create: jest.fn().mockResolvedValue(mockRemote) }; +const Signature = { now: jest.fn() }; +const Cred = { + userpassPlaintextNew: jest.fn(), +}; + +export { Repository, Remote, Signature, Cred }; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts index f91e8bb40e..aa439a4982 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts @@ -13,4 +13,70 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -describe('Github Store', () => {}); + +jest.mock('@octokit/rest'); +jest.mock('nodegit'); + +import { Octokit } from '@octokit/rest'; +import { OctokitResponse, ReposCreateInOrgResponseData } from '@octokit/types'; +import { GithubPublisher } from './github'; + +const { mockGithubClient } = require('@octokit/rest') as { + mockGithubClient: { repos: jest.Mocked }; +}; + +describe('Github Publisher', () => { + const publisher = new GithubPublisher({ client: new Octokit() }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('publish: createRemoteInGithub', () => { + it('should use octokit to create a repo in an organisation if the organisation property is set', async () => { + mockGithubClient.repos.createInOrg.mockResolvedValue({ + data: { + clone_url: 'mockclone', + }, + } as OctokitResponse); + + await publisher.publish({ + values: { + isOrg: true, + storePath: 'blam/test', + owner: 'bob', + }, + directory: '/tmp/test', + }); + + expect(mockGithubClient.repos.createInOrg).toHaveBeenCalledWith({ + org: 'blam', + name: 'test', + }); + }); + + it('should use octokit to create a repo in the authed user if the organisation property is not set', async () => { + mockGithubClient.repos.createForAuthenticatedUser.mockResolvedValue({ + data: { + clone_url: 'mockclone', + }, + } as OctokitResponse); + + await publisher.publish({ + values: { + storePath: 'blam/test', + owner: 'bob', + }, + directory: '/tmp/test', + }); + + expect( + mockGithubClient.repos.createForAuthenticatedUser, + ).toHaveBeenCalledWith({ + name: 'test', + }); + }); + }); + + describe('publish: createGitDirectory', () => {}); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts index 9aed55fd98..eba7def9af 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts @@ -40,17 +40,18 @@ export class GithubPublisher implements Publisher { return { remoteUrl }; } - private async createRemote(values: RequiredTemplateValues) { + private async createRemote( + values: RequiredTemplateValues & Record, + ) { const [owner, name] = values.storePath.split('/'); - const { - data: { clone_url: cloneUrl }, - } = await this.client.repos.createInOrg({ - name, - org: owner, - }); + const repoCreationPromise = values.isOrg + ? this.client.repos.createInOrg({ name, org: owner }) + : this.client.repos.createForAuthenticatedUser({ name }); - return cloneUrl; + const { data } = await repoCreationPromise; + + return data?.clone_url; } private async pushToRemote(directory: string, remote: string): Promise {