From bbef36c91a41751b26c68fc9f2d9d45f6b49aff2 Mon Sep 17 00:00:00 2001 From: blam Date: Wed, 17 Jun 2020 10:49:26 +0200 Subject: [PATCH] chore(scaffolder): Remove the old storage API's as the catalog api is now in charge of thestorage of templkates --- packages/backend/src/plugins/scaffolder.ts | 4 +- plugins/scaffolder-backend/package.json | 1 + .../src/scaffolder/index.ts | 2 - .../src/scaffolder/storage/disk.test.ts | 84 ---------------- .../src/scaffolder/storage/disk.ts | 99 ------------------- .../src/scaffolder/storage/index.test.ts | 58 ----------- .../src/scaffolder/storage/index.ts | 38 ------- .../src/scaffolder/storage/types.ts | 24 +++++ .../src/service/standaloneServer.ts | 10 +- 9 files changed, 28 insertions(+), 292 deletions(-) delete mode 100644 plugins/scaffolder-backend/src/scaffolder/storage/disk.test.ts delete mode 100644 plugins/scaffolder-backend/src/scaffolder/storage/disk.ts delete mode 100644 plugins/scaffolder-backend/src/scaffolder/storage/index.test.ts create mode 100644 plugins/scaffolder-backend/src/scaffolder/storage/types.ts diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index 08e700bc74..35840daa5b 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -17,13 +17,11 @@ import { CookieCutter, createRouter, - DiskStorage, } from '@backstage/plugin-scaffolder-backend'; import type { PluginEnvironment } from '../types'; export default async function createPlugin({ logger }: PluginEnvironment) { - const storage = new DiskStorage({ logger }); const templater = new CookieCutter(); - return await createRouter({ storage, templater, logger }); + return await createRouter({ storage: null, templater, logger }); } diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 3d8d95164e..907efde362 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -22,6 +22,7 @@ }, "dependencies": { "@backstage/backend-common": "^0.1.1-alpha.8", + "@backstage/catalog-model": "^0.1.1-alpha.8", "compression": "^1.7.4", "cors": "^2.8.5", "dockerode": "^3.2.0", diff --git a/plugins/scaffolder-backend/src/scaffolder/index.ts b/plugins/scaffolder-backend/src/scaffolder/index.ts index a665b32ead..29a3d99ef0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/index.ts @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './storage'; export * from './templater'; -export * from './storage/disk'; export * from './templater/cookiecutter'; diff --git a/plugins/scaffolder-backend/src/scaffolder/storage/disk.test.ts b/plugins/scaffolder-backend/src/scaffolder/storage/disk.test.ts deleted file mode 100644 index 9cebb0d380..0000000000 --- a/plugins/scaffolder-backend/src/scaffolder/storage/disk.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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. - */ -import { DiskStorage } from './disk'; -import * as path from 'path'; - -describe('Disk Storage', () => { - it('should load a simple template from a simple directory', async () => { - const testTemplateDir = path.resolve( - __dirname, - '../../../test/mock-simple-template-dir', - ); - const templateInfo = require(`${testTemplateDir}/mock-template/template-info.json`); - - const repository = new DiskStorage({ directory: testTemplateDir }); - - await repository.reindex(); - - const templates = await repository.list(); - - expect(templates).toHaveLength(1); - expect(templates[0].id).toBe(templateInfo.id); - expect(templates[0].name).toBe(templateInfo.name); - expect(templates[0].description).toBe(templateInfo.description); - expect(templates[0].ownerId).toBe(templateInfo.ownerId); - }); - - it('should successfully load multiple templates from the same folder', async () => { - const testTemplateDir = path.resolve( - __dirname, - '../../../test/mock-multiple-templates-dir', - ); - - const repository = new DiskStorage({ directory: testTemplateDir }); - - await repository.reindex(); - - const templates = await repository.list(); - - expect(templates).toHaveLength(2); - }); - - it('should return empty array when there are no templates', async () => { - const testTemplateDir = path.resolve( - __dirname, - '/some-folder-that-deffo-does-not-exist', - ); - - const repository = new DiskStorage({ directory: testTemplateDir }); - - await repository.reindex(); - - const templates = await repository.list(); - - expect(templates).toHaveLength(0); - }); - - it('should be able to handle templates with invalid json and ignore them from the returned array', async () => { - const testTemplateDir = path.resolve( - __dirname, - '../../../test/mock-failing-template-dir', - ); - - const repository = new DiskStorage({ directory: testTemplateDir }); - - await repository.reindex(); - - const templates = await repository.list(); - - expect(templates).toHaveLength(1); - }); -}); diff --git a/plugins/scaffolder-backend/src/scaffolder/storage/disk.ts b/plugins/scaffolder-backend/src/scaffolder/storage/disk.ts deleted file mode 100644 index 28236cb86f..0000000000 --- a/plugins/scaffolder-backend/src/scaffolder/storage/disk.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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. - */ - -import globby from 'globby'; -import fs from 'fs-extra'; -import { Template, StorageBase as Base } from '.'; -import { Logger } from 'winston'; - -interface DiskIndexEntry { - contents: Template; - location: string; -} - -export class DiskStorage implements Base { - private repository: Template[] = []; - private localIndex: DiskIndexEntry[] = []; - - private repoDir: string; - private logger?: Logger; - constructor({ - directory = `${__dirname}/../../../sample-templates`, - logger, - }: { - directory?: string; - logger?: Logger; - }) { - this.repoDir = directory; - this.logger = logger; - } - - public async list(): Promise { - if (this.repository.length === 0) { - await this.reindex(); - } - - return this.repository; - } - - public async reindex(): Promise { - this.localIndex = await this.index(); - this.repository = this.localIndex.map(({ contents }) => contents); - } - - public async prepare(templateId: string): Promise { - const template = this.localIndex.find( - ({ contents }) => contents.id === templateId, - ); - - if (!template) { - throw new Error('Template no found'); - } - - const tempDir = await fs.promises.mkdtemp(templateId); - await fs.copy(template.location, tempDir); - return tempDir; - } - - private async index(): Promise { - const matches = await globby(`${this.repoDir}/**/template-info.json`); - - const fileContents: Array<{ - location: string; - contents: string; - }> = await Promise.all( - matches.map(async (location: string) => ({ - location, - contents: await fs.readFile(location, 'utf-8'), - })), - ); - - const validFiles: DiskIndexEntry[] = []; - - for (const file of fileContents) { - try { - const contents: Template = JSON.parse(file.contents); - validFiles.push({ location: file.location, contents }); - } catch (ex) { - this.logger?.error('Failure parsing JSON for template', { - path: file.location, - }); - } - } - - return validFiles; - } -} diff --git a/plugins/scaffolder-backend/src/scaffolder/storage/index.test.ts b/plugins/scaffolder-backend/src/scaffolder/storage/index.test.ts deleted file mode 100644 index b8e3131b63..0000000000 --- a/plugins/scaffolder-backend/src/scaffolder/storage/index.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ -import { StorageBase, createStorage } from '.'; -import * as winston from 'winston'; - -describe('Storage Interface Test', () => { - const mockStore = new (class MockStorage implements StorageBase { - list = jest.fn(); - prepare = jest.fn(); - reindex = jest.fn(); - - public reset = () => { - this.list.mockReset(); - this.prepare.mockReset(); - this.reindex.mockReset(); - }; - })(); - - const logger = winston.createLogger(); - - afterEach(() => mockStore.reset()); - - it('should call list of the set repo when calling list', async () => { - const store = createStorage({ store: mockStore, logger }); - await store.list(); - - expect(mockStore.list).toHaveBeenCalled(); - }); - - it('should reindex on the repo when calling reindex', async () => { - const store = createStorage({ store: mockStore, logger }); - - await store.reindex(); - - expect(mockStore.reindex).toHaveBeenCalled(); - }); - - it('should call prepare with the correct id when calling prepare', async () => { - const store = createStorage({ store: mockStore, logger }); - - await store.prepare('testid'); - - expect(mockStore.prepare).toHaveBeenCalledWith('testid'); - }); -}); diff --git a/plugins/scaffolder-backend/src/scaffolder/storage/index.ts b/plugins/scaffolder-backend/src/scaffolder/storage/index.ts index 4d16224ef7..f3b69cc361 100644 --- a/plugins/scaffolder-backend/src/scaffolder/storage/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/storage/index.ts @@ -1,5 +1,3 @@ -import { Logger } from 'winston'; - /* * Copyright 2020 Spotify AB * @@ -15,39 +13,3 @@ import { Logger } from 'winston'; * See the License for the specific language governing permissions and * limitations under the License. */ -export interface Template { - id: string; - name: string; - description: string; - ownerId: string; -} - -export abstract class StorageBase { - // lists all templates available - abstract async list(): Promise; - // can be used to build an index of the available templates; - abstract async reindex(): Promise; - // returns a directory to run the templaterin - abstract async prepare(id: string): Promise; -} - -export interface StorageConfig { - store?: StorageBase; - logger?: Logger; -} - -class Storage implements StorageBase { - store?: StorageBase; - - constructor({ store }: StorageConfig) { - this.store = store; - } - - list = () => this.store!.list(); - prepare = (id: string) => this.store!.prepare(id); - reindex = () => this.store!.reindex(); -} - -export const createStorage = (storageConfig: StorageConfig): StorageBase => { - return new Storage(storageConfig); -}; diff --git a/plugins/scaffolder-backend/src/scaffolder/storage/types.ts b/plugins/scaffolder-backend/src/scaffolder/storage/types.ts new file mode 100644 index 0000000000..80c860a911 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/storage/types.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ +import type { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; + +export type StorageBase = { + /** + * + * @param id + */ + prepare(template: TemplateEntityV1alpha1): Promise; +}; diff --git a/plugins/scaffolder-backend/src/service/standaloneServer.ts b/plugins/scaffolder-backend/src/service/standaloneServer.ts index 7f553bf4bf..cad937d304 100644 --- a/plugins/scaffolder-backend/src/service/standaloneServer.ts +++ b/plugins/scaffolder-backend/src/service/standaloneServer.ts @@ -16,12 +16,7 @@ import { Server } from 'http'; import { Logger } from 'winston'; -import { - createStorage, - createTemplater, - DiskStorage, - CookieCutter, -} from '../scaffolder'; +import { createTemplater, CookieCutter } from '../scaffolder'; import { createServiceBuilder, useHotMemoize } from '@backstage/backend-common'; import { createRouter } from './router'; export interface ServerOptions { @@ -34,12 +29,11 @@ export async function startStandaloneServer( options: ServerOptions, ): Promise { const logger = options.logger.child({ service: 'scaffolder-backend' }); - const store = useHotMemoize(module, () => new DiskStorage({ logger })); const templater = new CookieCutter(); logger.debug('Creating application...'); const router = await createRouter({ - storage: createStorage({ store, logger }), + storage: null, templater: createTemplater({ templater }), logger, });