Merge pull request #6385 from backstage/blam/move-out-cookiecutter-action

Move Cookiecutter to it's own module
This commit is contained in:
Ben Lambert
2021-07-16 12:54:23 +02:00
committed by GitHub
15 changed files with 305 additions and 21 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
- Move out the `cookiecutter` templating to its own module that is depended on by the `scaffolder-backend` plugin. No breaking change yet, but we will drop first class support for `cookiecutter` in the future and it will become an opt-in feature.
@@ -0,0 +1,3 @@
module.exports = {
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
};
@@ -0,0 +1,162 @@
# scaffolder-backend-module-cookiecutter
Welcome to the `fetch:cookiecutter` action for the `scaffolder-backend`.
## Getting started
You need to configure the action in your backend:
## From your Backstage root directory
```
cd packages/backend
yarn add @backstage/plugin-scaffolder-backend-module-cookiecutter
```
Configure the action:
(you can check the [docs](https://backstage.io/docs/features/software-templates/writing-custom-actions#registering-custom-actions) to see all options):
```typescript
// packages/backend/src/plugins/scaffolder.ts
const actions = [
createFetchCookiecutterAction({
integrations,
reader,
containerRunner,
}),
...createBuiltInActions({
...
})
];
return await createRouter({
containerRunner,
logger,
config,
database,
catalogClient,
reader,
actions,
});
```
After that you can use the action in your template:
```yaml
apiVersion: backstage.io/v1beta2
kind: Template
metadata:
name: cookiecutter-demo
title: Cookiecutter Test
description: Cookiecutter example
spec:
owner: backstage/techdocs-core
type: service
parameters:
- title: Fill in some steps
required:
- name
- owner
properties:
name:
title: Name
type: string
description: Unique name of the component
ui:autofocus: true
ui:options:
rows: 5
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
allowedKinds:
- Group
system:
title: System
type: string
description: System of the component
ui:field: EntityPicker
ui:options:
allowedKinds:
- System
defaultKind: System
- title: Choose a location
required:
- repoUrl
- dryRun
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
dryRun:
title: Only perform a dry run, don't publish anything
type: boolean
default: false
steps:
- id: fetch-base
name: Fetch Base
action: fetch:cookiecutter
input:
url: ./template
values:
name: '{{ parameters.name }}'
owner: '{{ parameters.owner }}'
system: '{{ parameters.system }}'
destination: '{{ parseRepoUrl parameters.repoUrl }}'
- id: publish
if: '{{ not parameters.dryRun }}'
name: Publish
action: publish:github
input:
allowedHosts: ['github.com']
description: 'This is {{ parameters.name }}'
repoUrl: '{{ parameters.repoUrl }}'
- id: register
if: '{{ not parameters.dryRun }}'
name: Register
action: catalog:register
input:
repoContentsUrl: '{{ steps.publish.output.repoContentsUrl }}'
catalogInfoPath: '/catalog-info.yaml'
- name: Results
if: '{{ parameters.dryRun }}'
action: debug:log
input:
listWorkspace: true
output:
links:
- title: Repository
url: '{{ steps.publish.output.remoteUrl }}'
- title: Open in catalog
icon: 'catalog'
entityRef: '{{ steps.register.output.entityRef }}'
```
You can also visit the `/create/actions` route in your Backstage application to find out more about the parameters this action accepts when it's installed to configure how you like.
### Environment setup
The environment needs to have either `cookiecutter` installed and be available in the `PATH` or access to a `docker` daemon so it can spin up a docker container with `cookiecutter` available.
If you are running Backstage from a Docker container and you want to avoid calling a container inside a container, you can set up `cookiecutter` in your own image, this will use the local installation instead.
You can do so by including the following lines in the last step of your Dockerfile:
```dockerfile
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip3 install cookiecutter
```
@@ -0,0 +1,23 @@
## API Report File for "@backstage/plugin-scaffolder-backend-module-cookiecutter"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
/// <reference types="node" />
import { ContainerRunner } from '@backstage/backend-common';
import { ScmIntegrations } from '@backstage/integration';
import { TemplateAction } from '@backstage/plugin-scaffolder-backend';
import { UrlReader } from '@backstage/backend-common';
// Warning: (ae-missing-release-tag) "createFetchCookiecutterAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createFetchCookiecutterAction(options: {
reader: UrlReader;
integrations: ScmIntegrations;
containerRunner: ContainerRunner;
}): TemplateAction<any>;
// (No @packageDocumentation comment for this package)
```
@@ -0,0 +1,45 @@
{
"name": "@backstage/plugin-scaffolder-backend-module-cookiecutter",
"version": "0.1.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"scripts": {
"start": "backstage-cli backend:dev",
"build": "backstage-cli backend:build",
"lint": "backstage-cli lint",
"test": "backstage-cli test",
"prepack": "backstage-cli prepack",
"postpack": "backstage-cli postpack",
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.8.6",
"@backstage/errors": "^0.1.1",
"@backstage/integration": "^0.5.7",
"@backstage/plugin-scaffolder-backend": "^0.14.0",
"@backstage/config": "^0.1.5",
"command-exists": "^1.2.9",
"fs-extra": "10.0.0",
"winston": "^3.2.1",
"cross-fetch": "^3.0.6",
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.7.3",
"@types/fs-extra": "^9.0.1",
"@types/mock-fs": "^4.13.0",
"@types/jest": "^26.0.7",
"@types/command-exists": "^1.2.0",
"mock-fs": "^4.13.0",
"msw": "^0.29.0"
},
"files": [
"dist"
]
}
@@ -17,9 +17,12 @@ const runCommand = jest.fn();
const commandExists = jest.fn();
const fetchContents = jest.fn();
jest.mock('./helpers', () => ({ fetchContents }));
jest.mock('@backstage/plugin-scaffolder-backend', () => ({
...jest.requireActual('@backstage/plugin-scaffolder-backend'),
fetchContents,
runCommand,
}));
jest.mock('command-exists', () => commandExists);
jest.mock('../helpers', () => ({ runCommand }));
import {
getVoidLogger,
@@ -33,7 +36,7 @@ import os from 'os';
import { PassThrough } from 'stream';
import { createFetchCookiecutterAction } from './cookiecutter';
import { join } from 'path';
import { ActionContext } from '../../types';
import type { ActionContext } from '@backstage/plugin-scaffolder-backend';
describe('fetch:cookiecutter', () => {
const integrations = ScmIntegrations.fromConfig(
@@ -26,9 +26,11 @@ import commandExists from 'command-exists';
import fs from 'fs-extra';
import path, { resolve as resolvePath } from 'path';
import { Writable } from 'stream';
import { runCommand } from '../helpers';
import { createTemplateAction } from '../../createTemplateAction';
import { fetchContents } from './helpers';
import {
runCommand,
createTemplateAction,
fetchContents,
} from '@backstage/plugin-scaffolder-backend';
export class CookiecutterRunner {
private readonly containerRunner: ContainerRunner;
@@ -136,7 +138,7 @@ export function createFetchCookiecutterAction(options: {
}>({
id: 'fetch:cookiecutter',
description:
"Downloads a template from the given URL into the workspace, and runs cookiecutter on it. This action is deprecated in favor of 'fetch:template'. See https://backstage.io/docs/features/software-templates/builtin-actions#migrating-from-fetch-cookiecutter-to-fetch-template for more details.",
'Downloads a template from the given URL into the workspace, and runs cookiecutter on it.',
schema: {
input: {
type: 'object',
@@ -0,0 +1,16 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 { createFetchCookiecutterAction } from './cookiecutter';
@@ -0,0 +1,16 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 * from './fetch';
@@ -0,0 +1,16 @@
/*
* Copyright 2021 The Backstage Authors
*
* 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 * from './actions';
+2 -8
View File
@@ -8,6 +8,7 @@
import { CatalogApi } from '@backstage/catalog-client';
import { Config } from '@backstage/config';
import { ContainerRunner } from '@backstage/backend-common';
import { createFetchCookiecutterAction } from '@backstage/plugin-scaffolder-backend-module-cookiecutter';
import { createPullRequest } from 'octokit-plugin-create-pull-request';
import express from 'express';
import { JsonObject } from '@backstage/config';
@@ -78,14 +79,7 @@ export function createCatalogWriteAction(): TemplateAction<any>;
// @public
export function createDebugLogAction(): TemplateAction<any>;
// Warning: (ae-missing-release-tag) "createFetchCookiecutterAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export function createFetchCookiecutterAction(options: {
reader: UrlReader;
integrations: ScmIntegrations;
containerRunner: ContainerRunner;
}): TemplateAction<any>;
export { createFetchCookiecutterAction };
// Warning: (ae-missing-release-tag) "createFetchPlainAction" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
+1
View File
@@ -35,6 +35,7 @@
"@backstage/config": "^0.1.5",
"@backstage/errors": "^0.1.1",
"@backstage/integration": "^0.5.8",
"@backstage/plugin-scaffolder-backend-module-cookiecutter": "^0.1.0",
"@gitbeaker/core": "^30.2.0",
"@gitbeaker/node": "^30.2.0",
"@octokit/rest": "^18.5.3",
@@ -24,11 +24,8 @@ import {
} from './catalog';
import { createDebugLogAction } from './debug';
import {
createFetchCookiecutterAction,
createFetchPlainAction,
createFetchTemplateAction,
} from './fetch';
import { createFetchPlainAction, createFetchTemplateAction } from './fetch';
import { createFetchCookiecutterAction } from '@backstage/plugin-scaffolder-backend-module-cookiecutter';
import {
createFilesystemDeleteAction,
createFilesystemRenameAction,
@@ -15,6 +15,5 @@
*/
export { createFetchPlainAction } from './plain';
export { createFetchCookiecutterAction } from './cookiecutter';
export { createFetchTemplateAction } from './template';
export { fetchContents } from './helpers';
@@ -20,4 +20,6 @@ export * from './debug';
export * from './fetch';
export * from './filesystem';
export * from './publish';
export { createFetchCookiecutterAction } from '@backstage/plugin-scaffolder-backend-module-cookiecutter';
export { runCommand } from './helpers';