chore(scaffolder): added simple create react app scaffolder
This commit is contained in:
@@ -21,6 +21,7 @@ import {
|
||||
GithubPreparer,
|
||||
Preparers,
|
||||
GithubPublisher,
|
||||
CreateReactAppTemplater,
|
||||
Templaters,
|
||||
} from '@backstage/plugin-scaffolder-backend';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
@@ -29,8 +30,10 @@ import Docker from 'dockerode';
|
||||
|
||||
export default async function createPlugin({ logger }: PluginEnvironment) {
|
||||
const cookiecutterTemplater = new CookieCutter();
|
||||
const craTemplater = new CreateReactAppTemplater();
|
||||
const templaters = new Templaters();
|
||||
templaters.register('cookiecutter', cookiecutterTemplater);
|
||||
templaters.register('cra', craTemplater);
|
||||
|
||||
const filePreparer = new FilePreparer();
|
||||
const githubPreparer = new GithubPreparer();
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
"morgan": "^1.10.0",
|
||||
"nodegit": "0.26.5",
|
||||
"uuid": "^8.2.0",
|
||||
"winston": "^3.2.1"
|
||||
"winston": "^3.2.1",
|
||||
"yaml": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.1.1-alpha.14",
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Template
|
||||
metadata:
|
||||
name: create-react-app-template
|
||||
title: Create React App Template
|
||||
description: A template that scaffolds an applications using the Create React App (CRA) templater.
|
||||
tags:
|
||||
- Experimental
|
||||
- React
|
||||
- CRA
|
||||
spec:
|
||||
owner: web@example.com
|
||||
templater: cra
|
||||
type: website
|
||||
path: '.'
|
||||
schema:
|
||||
required:
|
||||
- component_id
|
||||
- use_typescript
|
||||
properties:
|
||||
component_id:
|
||||
title: Name
|
||||
type: string
|
||||
description: Unique name of the component
|
||||
description:
|
||||
title: Description
|
||||
type: string
|
||||
description: Description of the component
|
||||
use_typescript:
|
||||
title: Use Typescript
|
||||
type: boolean
|
||||
description: Include typescript
|
||||
default: true
|
||||
@@ -3,6 +3,7 @@
|
||||
for URL in \
|
||||
'react-ssr-template' \
|
||||
'springboot-template' \
|
||||
'create-react-app' \
|
||||
; do \
|
||||
curl \
|
||||
--location \
|
||||
|
||||
@@ -23,7 +23,10 @@ export const makeLogStream = (meta: Record<string, JsonValue>) => {
|
||||
// Create an empty stream to collect all the log lines into
|
||||
// one variable for the API.
|
||||
const stream = new PassThrough();
|
||||
stream.on('data', chunk => log.push(chunk.toString()));
|
||||
stream.on('data', chunk => {
|
||||
const textValue = chunk.toString().trim();
|
||||
if (textValue?.length > 1) log.push(textValue);
|
||||
});
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
|
||||
@@ -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 fs from 'fs-extra';
|
||||
import { runDockerContainer } from './helpers';
|
||||
import { TemplaterBase, TemplaterRunOptions } from '.';
|
||||
import path from 'path';
|
||||
import { TemplaterRunResult } from './types';
|
||||
import * as yaml from 'yaml';
|
||||
|
||||
export class CreateReactAppTemplater implements TemplaterBase {
|
||||
public async run(options: TemplaterRunOptions): Promise<TemplaterRunResult> {
|
||||
const {
|
||||
component_id: componentName,
|
||||
use_typescript: withTypescript,
|
||||
description,
|
||||
owner,
|
||||
} = options.values;
|
||||
|
||||
const resultDir = await fs.promises.mkdtemp(`${options.directory}-result`);
|
||||
|
||||
await runDockerContainer({
|
||||
imageName: 'node:lts-alpine',
|
||||
args: [
|
||||
'create-react-app',
|
||||
componentName as string,
|
||||
withTypescript ? ' --template typescript' : '',
|
||||
],
|
||||
templateDir: options.directory,
|
||||
resultDir,
|
||||
logStream: options.logStream,
|
||||
dockerClient: options.dockerClient,
|
||||
createOptions: {
|
||||
Entrypoint: ['npx'],
|
||||
WorkingDir: '/result',
|
||||
},
|
||||
});
|
||||
|
||||
// Need to also make a component-info.yaml to store the data about the service.
|
||||
const componentInfo = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: componentName,
|
||||
description,
|
||||
},
|
||||
spec: {
|
||||
type: 'website',
|
||||
lifecycle: 'experimental',
|
||||
owner,
|
||||
},
|
||||
};
|
||||
|
||||
const finalDir = path.resolve(
|
||||
resultDir,
|
||||
options.values.component_id as string,
|
||||
);
|
||||
|
||||
await fs.promises.writeFile(
|
||||
`${finalDir}/component-info.yaml`,
|
||||
yaml.stringify(componentInfo),
|
||||
);
|
||||
|
||||
return {
|
||||
resultDir: finalDir,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ export type RunDockerContainerOptions = {
|
||||
resultDir: string;
|
||||
templateDir: string;
|
||||
dockerClient: Docker;
|
||||
createOptions?: Docker.ContainerCreateOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -59,8 +60,18 @@ export const runDockerContainer = async ({
|
||||
resultDir,
|
||||
templateDir,
|
||||
dockerClient,
|
||||
createOptions = {},
|
||||
}: RunDockerContainerOptions) => {
|
||||
await dockerClient.pull(imageName, {});
|
||||
await new Promise((resolve, reject) =>
|
||||
dockerClient.pull(imageName, {}, (err, res) => {
|
||||
console.warn(err, res);
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(res);
|
||||
}
|
||||
}),
|
||||
);
|
||||
const [{ Error: error, StatusCode: statusCode }] = await dockerClient.run(
|
||||
imageName,
|
||||
args,
|
||||
@@ -75,6 +86,7 @@ export const runDockerContainer = async ({
|
||||
`${await fs.promises.realpath(templateDir)}:/template`,
|
||||
],
|
||||
},
|
||||
...createOptions,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -17,3 +17,4 @@ export * from './cookiecutter';
|
||||
export * from './types';
|
||||
export * from './helpers';
|
||||
export * from './templaters';
|
||||
export * from './cra';
|
||||
|
||||
@@ -126,7 +126,7 @@ export const JobStage = ({ endedAt, startedAt, name, log, status }: Props) => {
|
||||
) : (
|
||||
<Suspense fallback={<LinearProgress />}>
|
||||
<div style={{ height: '20vh', width: '100%' }}>
|
||||
<LazyLog text={log.join('\n')} extraLines={1} />
|
||||
<LazyLog text={log.join('\n')} extraLines={1} follow />
|
||||
</div>
|
||||
</Suspense>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user