From 46211fa5bea80aa108d3cfc03dc9a945ea23e7a7 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Wed, 27 Jan 2021 11:26:59 +0100 Subject: [PATCH] Update prepare test --- .../stages/prepare/bitbucket.test.ts | 100 ++++------------ .../scaffolder/stages/prepare/file.test.ts | 71 ++++------- .../scaffolder/stages/prepare/github.test.ts | 108 +++++------------ .../scaffolder/stages/prepare/gitlab.test.ts | 112 ++++-------------- 4 files changed, 99 insertions(+), 292 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.test.ts index ff74fffdd7..84e72eafb8 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.test.ts @@ -14,21 +14,13 @@ * limitations under the License. */ -jest.doMock('fs-extra', () => ({ - promises: { - mkdtemp: jest.fn(dir => `${dir}-static`), - }, -})); - +import fs from 'fs-extra'; import { BitbucketPreparer } from './bitbucket'; -import { - TemplateEntityV1alpha1, - LOCATION_ANNOTATION, -} from '@backstage/catalog-model'; import { getVoidLogger, Git } from '@backstage/backend-common'; +jest.mock('fs-extra'); + describe('BitbucketPreparer', () => { - let mockEntity: TemplateEntityV1alpha1; const logger = getVoidLogger(); const mockGitClient = { clone: jest.fn(), @@ -38,44 +30,6 @@ describe('BitbucketPreparer', () => { beforeEach(() => { jest.clearAllMocks(); - mockEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Template', - metadata: { - annotations: { - [LOCATION_ANNOTATION]: - 'bitbucket:https://bitbucket.org/backstage-project/backstage-repo', - }, - name: 'graphql-starter', - title: 'GraphQL Service', - description: - 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', - uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', - etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', - generation: 1, - }, - spec: { - type: 'website', - templater: 'cookiecutter', - path: './template', - schema: { - $schema: 'http://json-schema.org/draft-07/schema#', - required: ['storePath', 'owner'], - properties: { - owner: { - type: 'string', - title: 'Owner', - description: 'Who is going to own this component', - }, - storePath: { - type: 'string', - title: 'Store path', - description: 'GitHub store path in org/repo format', - }, - }, - }, - }, - }; }); const preparer = BitbucketPreparer.fromConfig({ @@ -84,12 +38,20 @@ describe('BitbucketPreparer', () => { appPassword: 'fake-password', }); + const prepareOptions = { + url: 'https://bitbucket.org/backstage-project/backstage-repo', + logger, + workspacePath: '/tmp', + }; + it('calls the clone command with the correct arguments for a repository', async () => { - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); + await preparer.prepare(prepareOptions); expect(mockGitClient.clone).toHaveBeenCalledWith({ url: 'https://bitbucket.org/backstage-project/backstage-repo', - dir: expect.any(String), + dir: '/tmp/checkout', }); + expect(fs.move).toHaveBeenCalledWith('/tmp/checkout', '/tmp/template'); + expect(fs.rmdir).toHaveBeenCalledWith('/tmp/template/.git'); }); it('calls the clone command with the correct arguments if an app password is provided for a repository', async () => { @@ -98,7 +60,7 @@ describe('BitbucketPreparer', () => { username: 'fake-user', appPassword: 'fake-password', }); - await preparer.prepare(mockEntity, { logger }); + await preparer.prepare(prepareOptions); expect(Git.fromAuth).toHaveBeenCalledWith({ logger, @@ -108,22 +70,22 @@ describe('BitbucketPreparer', () => { }); it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { - delete mockEntity.spec.path; - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); + await preparer.prepare(prepareOptions); expect(mockGitClient.clone).toHaveBeenCalledWith({ url: 'https://bitbucket.org/backstage-project/backstage-repo', - dir: expect.any(String), + dir: '/tmp/checkout', }); }); - it('return the temp directory with the path to the folder if it is specified', async () => { - mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, { - logger: getVoidLogger(), + it('moves a template subdirectory to checkout if specified', async () => { + await preparer.prepare({ + url: 'https://bitbucket.org/foo/bar/src/master/1/2/3', + logger, + workspacePath: '/tmp', }); - - expect(response.split('\\').join('/')).toMatch( - /\/template\/test\/1\/2\/3$/, + expect(fs.move).toHaveBeenCalledWith( + '/tmp/checkout/1/2/3', + '/tmp/template', ); }); @@ -133,7 +95,7 @@ describe('BitbucketPreparer', () => { token: 'fake-token', }); - await preparer.prepare(mockEntity, { logger }); + await preparer.prepare(prepareOptions); expect(Git.fromAuth).toHaveBeenCalledWith({ logger, @@ -141,16 +103,4 @@ describe('BitbucketPreparer', () => { password: 'fake-token', }); }); - - it('return the working directory with the path to the folder if it is specified', async () => { - mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, { - workingDirectory: '/workDir', - logger: getVoidLogger(), - }); - - expect(response.split('\\').join('/')).toMatch( - /\/workDir\/graphql-starter-static\/template\/test\/1\/2\/3$/, - ); - }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.test.ts index 2b328f420b..6e7f70ac3d 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.test.ts @@ -14,57 +14,34 @@ * limitations under the License. */ -import os from 'os'; -import fs from 'fs-extra'; -import YAML from 'yaml'; -import { FilePreparer } from './file'; -import path from 'path'; -import { - TemplateEntityV1alpha1, - LOCATION_ANNOTATION, -} from '@backstage/catalog-model'; import { getVoidLogger } from '@backstage/backend-common'; +import fs from 'fs-extra'; +import { FilePreparer } from './file'; -const setupTest = async (fixturePath: string) => { - const locationForTemplateYaml = path.resolve( - path.dirname( - require.resolve('@backstage/plugin-scaffolder-backend/package'), - ), - 'fixtures', - fixturePath, - ); - - const [parsedDocument] = YAML.parseAllDocuments( - await fs.readFile(locationForTemplateYaml, 'utf-8'), - ); - - const template: TemplateEntityV1alpha1 = parsedDocument.toJSON(); - template.metadata.annotations = { - [LOCATION_ANNOTATION]: `file:${locationForTemplateYaml}`, - }; - - const filePreparer = new FilePreparer(); - const resultDir = await filePreparer.prepare(template, { - logger: getVoidLogger(), - workingDirectory: os.tmpdir(), - }); - - return { filePreparer, template, resultDir }; -}; +jest.mock('fs-extra'); describe('File preparer', () => { - it('excludes the yaml file from the temp folder', async () => { - const { resultDir } = await setupTest('test-simple-template/template.yaml'); - expect(fs.existsSync(`${resultDir}/template.yaml`)).toBe(false); - }); + const logger = getVoidLogger(); + const preparer = new FilePreparer(); + it('prepares templates from a file path', async () => { + await preparer.prepare({ + url: 'file:///path/to/template', + logger, + workspacePath: '/tmp', + }); + expect(fs.copy).toHaveBeenCalledWith('/path/to/template', '/tmp/checkout', { + recursive: true, + }); + expect(fs.ensureDir).toHaveBeenCalledWith('/tmp/checkout'); - it('resolves relative path from the template', async () => { - const { resultDir } = await setupTest('test-simple-template/template.yaml'); - expect(fs.existsSync(`${resultDir}/expected_file.ts`)).toBe(true); - }); - - it('resolves relative path from the nested template', async () => { - const { resultDir } = await setupTest('test-nested-template/template.yaml'); - expect(fs.existsSync(`${resultDir}/expected_file.ts`)).toBe(true); + await expect( + preparer.prepare({ + url: 'file://not/full/path', + logger, + workspacePath: '/tmp', + }), + ).rejects.toThrow( + "Wrong location protocol, should be 'file', file://not/full/path", + ); }); }); 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 b43545f5fc..ac3be609fa 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts @@ -14,12 +14,7 @@ * limitations under the License. */ -jest.doMock('fs-extra', () => ({ - promises: { - mkdtemp: jest.fn(dir => `${dir}-static`), - }, -})); - +import fs from 'fs-extra'; import { GithubPreparer } from './github'; import { TemplateEntityV1alpha1, @@ -27,6 +22,8 @@ import { } from '@backstage/catalog-model'; import { getVoidLogger, Git } from '@backstage/backend-common'; +jest.mock('fs-extra'); + describe('GitHubPreparer', () => { let mockEntity: TemplateEntityV1alpha1; const mockGitClient = { @@ -38,44 +35,6 @@ describe('GitHubPreparer', () => { beforeEach(() => { jest.clearAllMocks(); - mockEntity = { - apiVersion: 'backstage.io/v1alpha1', - kind: 'Template', - metadata: { - annotations: { - [LOCATION_ANNOTATION]: - 'github:https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', - }, - name: 'graphql-starter', - title: 'GraphQL Service', - description: - 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', - uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', - etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', - generation: 1, - }, - spec: { - type: 'website', - templater: 'cookiecutter', - path: './template', - schema: { - $schema: 'http://json-schema.org/draft-07/schema#', - required: ['storePath', 'owner'], - properties: { - owner: { - type: 'string', - title: 'Owner', - description: 'Who is going to own this component', - }, - storePath: { - type: 'string', - title: 'Store path', - description: 'GitHub store path in org/repo format', - }, - }, - }, - }, - }; }); const preparer = GithubPreparer.fromConfig({ @@ -84,58 +43,47 @@ describe('GitHubPreparer', () => { }); it('calls the clone command with the correct arguments for a repository', async () => { - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); + await preparer.prepare({ + url: + 'https://github.com/benjdlambert/backstage-graphql-template/blob/master/templates/graphql-starter/template', + logger, + workspacePath: '/tmp', + }); expect(mockGitClient.clone).toHaveBeenCalledWith({ url: 'https://github.com/benjdlambert/backstage-graphql-template', dir: expect.any(String), }); + expect(fs.move).toHaveBeenCalledWith( + '/tmp/checkout/templates/graphql-starter/template', + '/tmp/template', + ); + expect(fs.rmdir).toHaveBeenCalledWith('/tmp/template/.git'); }); it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { - delete mockEntity.spec.path; - - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); + await preparer.prepare({ + url: + 'https://github.com/benjdlambert/backstage-graphql-template/blob/master', + logger, + workspacePath: '/tmp', + }); expect(mockGitClient.clone).toHaveBeenCalledWith({ url: 'https://github.com/benjdlambert/backstage-graphql-template', dir: expect.any(String), }); - }); - - it('return the temp directory with the path to the folder if it is specified', async () => { - const preparer = GithubPreparer.fromConfig({ - host: 'github.com', - token: 'fake-token', - }); - mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, { - logger: getVoidLogger(), - }); - expect(response.split('\\').join('/')).toMatch( - /\/template\/test\/1\/2\/3$/, - ); - }); - - it('return the working directory with the path to the folder if it is specified', async () => { - const preparer = GithubPreparer.fromConfig({ - host: 'github.com', - token: 'fake-token', - }); - - mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, { - workingDirectory: '/workDir', - logger: getVoidLogger(), - }); - - expect(response.split('\\').join('/')).toMatch( - /\/workDir\/graphql-starter-static\/template\/test\/1\/2\/3$/, - ); + expect(fs.move).toHaveBeenCalledWith('/tmp/checkout', '/tmp/template'); + expect(fs.rmdir).toHaveBeenCalledWith('/tmp/template/.git'); }); it('calls the clone command with token', async () => { - await preparer.prepare(mockEntity, { logger }); + await preparer.prepare({ + url: + 'https://github.com/benjdlambert/backstage-graphql-template/blob/master', + logger, + workspacePath: '/tmp', + }); expect(Git.fromAuth).toHaveBeenCalledWith({ logger, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts index 19cbf793e4..8bb602fb34 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/gitlab.test.ts @@ -13,60 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -jest.doMock('fs-extra', () => ({ - promises: { - mkdtemp: jest.fn(dir => `${dir}-static`), - }, -})); - +import fs from 'fs-extra'; import { GitlabPreparer } from './gitlab'; -import { - TemplateEntityV1alpha1, - LOCATION_ANNOTATION, -} from '@backstage/catalog-model'; import { getVoidLogger, Git } from '@backstage/backend-common'; -const mockTemplate = (): TemplateEntityV1alpha1 => ({ - apiVersion: 'backstage.io/v1alpha1', - kind: 'Template', - metadata: { - annotations: { - [LOCATION_ANNOTATION]: - 'url:https://gitlab.com/benjdlambert/backstage-graphql-template/-/blob/master/template.yaml', - }, - name: 'graphql-starter', - title: 'GraphQL Service', - description: - 'A GraphQL starter template for backstage to get you up and running\nthe best practices with GraphQL\n', - uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', - etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', - generation: 1, - }, - spec: { - type: 'website', - templater: 'cookiecutter', - path: './template', - schema: { - $schema: 'http://json-schema.org/draft-07/schema#', - required: ['storePath', 'owner'], - properties: { - owner: { - type: 'string', - title: 'Owner', - description: 'Who is going to own this component', - }, - storePath: { - type: 'string', - title: 'Store path', - description: 'GitHub store path in org/repo format', - }, - }, - }, - }, -}); +jest.mock('fs-extra'); describe('GitLabPreparer', () => { - let mockEntity: TemplateEntityV1alpha1; const mockGitClient = { clone: jest.fn(), }; @@ -81,61 +34,40 @@ describe('GitLabPreparer', () => { host: 'gitlab.com', token: 'fake-token', }); - it(`calls the clone command with the correct arguments for a repository`, async () => { - mockEntity = mockTemplate(); - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); + it(`calls the clone command with the correct arguments for a repository`, async () => { + await preparer.prepare({ + url: + 'https://gitlab.com/benjdlambert/backstage-graphql-template/-/blob/master', + logger, + workspacePath: '/tmp', + }); expect(mockGitClient.clone).toHaveBeenCalledWith({ url: 'https://gitlab.com/benjdlambert/backstage-graphql-template', - dir: expect.any(String), + dir: '/tmp/checkout', }); - }); - - it(`calls the clone command with the correct arguments if an access token is provided in integrations for a repository`, async () => { - mockEntity = mockTemplate(); - - await preparer.prepare(mockEntity, { logger }); expect(Git.fromAuth).toHaveBeenCalledWith({ logger, username: 'oauth2', password: 'fake-token', }); + + expect(fs.move).toHaveBeenCalledWith('/tmp/checkout', '/tmp/template'); + expect(fs.rmdir).toHaveBeenCalledWith('/tmp/template/.git'); }); - it(`calls the clone command with the correct arguments for a repository when no path is provided`, async () => { - mockEntity = mockTemplate(); - delete mockEntity.spec.path; - - await preparer.prepare(mockEntity, { logger: getVoidLogger() }); - - expect(mockGitClient.clone).toHaveBeenCalledWith({ - url: 'https://gitlab.com/benjdlambert/backstage-graphql-template', - dir: expect.any(String), + it(`clones the template from a sub directory if specified`, async () => { + await preparer.prepare({ + url: + 'https://gitlab.com/benjdlambert/backstage-graphql-template/-/blob/master/1/2/3', + logger, + workspacePath: '/tmp', }); - }); - - it(`return the temp directory with the path to the folder if it is specified`, async () => { - mockEntity = mockTemplate(); - mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, { - logger: getVoidLogger(), - }); - expect(response.split('\\').join('/')).toMatch( - /\/template\/test\/1\/2\/3$/, - ); - }); - - it('return the working directory with the path to the folder if it is specified', async () => { - mockEntity.spec.path = './template/test/1/2/3'; - const response = await preparer.prepare(mockEntity, { - workingDirectory: '/workDir', - logger: getVoidLogger(), - }); - - expect(response.split('\\').join('/')).toMatch( - /\/workDir\/graphql-starter-static\/template\/test\/1\/2\/3$/, + expect(fs.move).toHaveBeenCalledWith( + '/tmp/checkout/1/2/3', + '/tmp/template', ); }); });