Use cookie cutter installed on host

This commit is contained in:
Tim Jacomb
2020-08-25 11:27:56 +01:00
parent 20b61b816f
commit 118e4861be
4 changed files with 76 additions and 16 deletions
+1
View File
@@ -27,6 +27,7 @@
"@octokit/rest": "^18.0.0",
"@types/dockerode": "^2.5.32",
"@types/express": "^4.17.6",
"command-exists-promise": "^2.0.2",
"compression": "^1.7.4",
"cors": "^2.8.5",
"dockerode": "^3.2.0",
@@ -15,11 +15,13 @@
*/
import fs from 'fs-extra';
import { JsonValue } from '@backstage/config';
import { runDockerContainer } from './helpers';
import { runDockerContainer, runCommand } from './helpers';
import { TemplaterBase, TemplaterRunOptions } from '.';
import path from 'path';
import { TemplaterRunResult } from './types';
const commandExists = require('command-exists-promise');
export class CookieCutter implements TemplaterBase {
private async fetchTemplateCookieCutter(
directory: string,
@@ -51,21 +53,30 @@ export class CookieCutter implements TemplaterBase {
const templateDir = options.directory;
const resultDir = await fs.promises.mkdtemp(`${options.directory}-result`);
await runDockerContainer({
imageName: 'spotify/backstage-cookiecutter',
args: [
'cookiecutter',
'--no-input',
'-o',
'/result',
'/template',
'--verbose',
],
templateDir,
resultDir,
logStream: options.logStream,
dockerClient: options.dockerClient,
});
const cookieCutterInstalled = await commandExists('cookiecutter');
if (cookieCutterInstalled) {
await runCommand({
command: 'cookiecutter',
args: ['--no-input', '-o', resultDir, templateDir, '--verbose'],
logStream: options.logStream,
});
} else {
await runDockerContainer({
imageName: 'spotify/backstage-cookiecutter',
args: [
'cookiecutter',
'--no-input',
'-o',
'/result',
'/template',
'--verbose',
],
templateDir,
resultDir,
logStream: options.logStream,
dockerClient: options.dockerClient,
});
}
return {
resultDir: path.resolve(resultDir, options.values.component_id as string),
@@ -18,6 +18,7 @@ import Docker from 'dockerode';
import fs from 'fs';
import { TemplateEntityV1alpha1 } from '@backstage/catalog-model';
import { InputError } from '@backstage/backend-common';
import { spawn } from 'child_process';
export type RunDockerContainerOptions = {
imageName: string;
@@ -29,6 +30,12 @@ export type RunDockerContainerOptions = {
createOptions?: Docker.ContainerCreateOptions;
};
export type RunCommandOptions = {
command: string;
args: string[];
logStream?: Writable;
};
/**
* Gets the templater key to use for templating from the entity
* @param entity Template entity
@@ -43,6 +50,42 @@ export const getTemplaterKey = (entity: TemplateEntityV1alpha1): string => {
return templater;
};
/**
*
* @param options the options object
* @param options.command the command to run
* @param options.args the arguments to pass the command
* @param options.logStream the log streamer to capture log messages
*/
export const runCommand = async ({
command,
args,
logStream = new PassThrough(),
}: RunCommandOptions) => {
await new Promise((resolve, reject) => {
const process = spawn(command, args);
process.stdout.on('data', stream => {
logStream.write(stream);
});
process.stderr.on('data', stream => {
logStream.write(stream);
});
process.on('error', error => {
return reject(error);
});
process.on('close', code => {
if (code !== 0) {
return reject(`Command ${command} failed, exit code: ${code}`);
}
return resolve();
});
});
};
/**
*
* @param options the options object