feat(scaffolder): make the scaffolder repository a little more flexible so we can load from multiple sources
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 { DiskRepository } from './disk';
|
||||
import * as path from 'path';
|
||||
describe('Template Repository', () => {
|
||||
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 DiskRepository(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 DiskRepository(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 DiskRepository(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 DiskRepository(testTemplateDir);
|
||||
|
||||
await repository.reindex();
|
||||
|
||||
const templates = await repository.list();
|
||||
|
||||
expect(templates).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 glob from 'glob';
|
||||
import { promises as fs } from 'fs';
|
||||
import { logger } from 'lib/logger';
|
||||
import { Template, RepositoryBase as Base } from '.';
|
||||
|
||||
export class DiskRepository implements Base {
|
||||
private repository: Template[] = [];
|
||||
|
||||
constructor(private repoDir = `${__dirname}/templates`) {
|
||||
this.reindex();
|
||||
}
|
||||
|
||||
public async list(): Promise<Template[]> {
|
||||
return this.repository;
|
||||
}
|
||||
|
||||
public async reindex(): Promise<void> {
|
||||
this.repository = await this.index();
|
||||
}
|
||||
|
||||
public async prepare(template: string): Promise<string> {
|
||||
return template;
|
||||
}
|
||||
|
||||
private async index(): Promise<Template[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
glob(`${this.repoDir}/**/template-info.json`, async (err, matches) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
const fileContents: Array<{
|
||||
path: string;
|
||||
contents: string;
|
||||
}> = await Promise.all(
|
||||
matches.map(async (path: string) => ({
|
||||
path,
|
||||
contents: await fs.readFile(path, 'utf-8'),
|
||||
})),
|
||||
);
|
||||
|
||||
const validFiles = fileContents.reduce(
|
||||
(templates: Template[], currentFile) => {
|
||||
try {
|
||||
const parsed: Template = JSON.parse(currentFile.contents);
|
||||
return [...templates, parsed];
|
||||
} catch (ex) {
|
||||
logger.error('Failure parsing JSON for template', {
|
||||
path: currentFile.path,
|
||||
});
|
||||
}
|
||||
|
||||
return templates;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
resolve(validFiles as Template[]);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const Repository = new DiskRepository();
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 { RepositoryBase, Repository } from '.';
|
||||
|
||||
describe('Repository Interface Test', () => {
|
||||
const mockRepo = new (class MockRepository implements RepositoryBase {
|
||||
list = jest.fn();
|
||||
prepare = jest.fn();
|
||||
reindex = jest.fn();
|
||||
|
||||
public reset = () => {
|
||||
this.list.mockReset();
|
||||
this.prepare.mockReset();
|
||||
this.reindex.mockReset();
|
||||
};
|
||||
})();
|
||||
|
||||
afterEach(() => mockRepo.reset());
|
||||
|
||||
it('should call list of the set repo when calling list', async () => {
|
||||
Repository.setRepository(mockRepo);
|
||||
|
||||
await Repository.list();
|
||||
|
||||
expect(mockRepo.list).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should reindex on the repo when calling reindex', async () => {
|
||||
Repository.setRepository(mockRepo);
|
||||
|
||||
await Repository.reindex();
|
||||
|
||||
expect(mockRepo.reindex).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call prepare with the correct id when calling prepare', async () => {
|
||||
Repository.setRepository(mockRepo);
|
||||
|
||||
await Repository.prepare('testid');
|
||||
|
||||
expect(mockRepo.prepare).toHaveBeenCalledWith('testid');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
import { DiskRepository } from './disk';
|
||||
|
||||
/*
|
||||
* 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 interface Template {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
ownerId: string;
|
||||
}
|
||||
|
||||
export abstract class RepositoryBase {
|
||||
abstract async list(): Promise<Template[]>;
|
||||
abstract async reindex(): Promise<void>;
|
||||
// returns a directory to run cookiecutter in
|
||||
abstract async prepare(id: string): Promise<string>;
|
||||
}
|
||||
|
||||
class Interface implements RepositoryBase {
|
||||
repo?: RepositoryBase;
|
||||
|
||||
constructor() {
|
||||
this.repo = new DiskRepository();
|
||||
}
|
||||
|
||||
public setRepository(repo: RepositoryBase) {
|
||||
this.repo = repo;
|
||||
}
|
||||
|
||||
list = () => this.repo!.list();
|
||||
prepare = (id: string) => this.repo!.prepare(id);
|
||||
reindex = () => this.repo!.reindex();
|
||||
}
|
||||
|
||||
export const Repository = new Interface();
|
||||
@@ -13,26 +13,31 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// /*
|
||||
// * 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 { plugiroutn } from './plugin';
|
||||
import { router } from './plugin';
|
||||
|
||||
// describe('scaffolder', () => {
|
||||
// it('should export plugin', () => {
|
||||
// expect(plugin).toBeDefined();
|
||||
// });
|
||||
// });
|
||||
import { Repository, Template } from 'lib/repo';
|
||||
import supertest from 'supertest';
|
||||
import express from 'express';
|
||||
|
||||
|
||||
describe('scaffolder backend', () => {
|
||||
const app = express().use(router);
|
||||
const mockTemplate: Template = {
|
||||
id: 'test-mock-template',
|
||||
name: 'mock',
|
||||
description: 'test for tests',
|
||||
ownerId: 'lol',
|
||||
};
|
||||
|
||||
it('should return a list of templates that are in the directory which the plugin is initialised in', async () => {
|
||||
jest.spyOn(Repository, 'list').mockResolvedValue([mockTemplate]);
|
||||
|
||||
const { body } = await supertest(app)
|
||||
.get('/v1/templates')
|
||||
.send();
|
||||
|
||||
expect(body.length).toBe(1);
|
||||
expect(body[0]).toStrictEqual(mockTemplate);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,14 +33,8 @@ import express from 'express';
|
||||
export const router = express.Router();
|
||||
|
||||
router.get('/v1/templates', async (_, res) => {
|
||||
res
|
||||
.status(200)
|
||||
.send([
|
||||
{ id: 'component1' },
|
||||
{ id: 'component2' },
|
||||
{ id: 'component3' },
|
||||
{ id: 'component4' },
|
||||
]);
|
||||
const templates = await Repository.list();
|
||||
res.status(200).json(templates);
|
||||
});
|
||||
|
||||
router.get('/v1/template/:templateId', async (_, res) => {
|
||||
|
||||
Reference in New Issue
Block a user