From c5e81eab43c5ecf5774d0780561867caff34f4bd Mon Sep 17 00:00:00 2001 From: Rogerio Angeliski Date: Thu, 24 Jun 2021 12:00:43 -0300 Subject: [PATCH] refactor to a isolated module Signed-off-by: Rogerio Angeliski --- .changeset/twelve-deers-explode.md | 2 +- .../scaffolder-backend-module-rails.yaml | 9 + microsite/static/img/rails-icon.png | Bin 0 -> 5439 bytes packages/backend/package.json | 2 + .../.eslintrc.js | 3 + .../scaffolder-backend-module-rails/README.md | 225 ++++++++++++++++++ .../Rails.dockerfile | 0 .../api-report.md | 22 ++ .../package.json | 44 ++++ .../src/actions/fetch/index.ts | 16 ++ .../src/actions/fetch/rails/index.test.ts} | 23 +- .../src/actions/fetch/rails/index.ts} | 23 +- .../rails/railsArgumentResolver.test.ts | 3 +- .../fetch}/rails/railsArgumentResolver.ts | 0 .../fetch/rails/railsNewRunner.test.ts} | 28 ++- .../actions/fetch/rails/railsNewRunner.ts} | 24 +- .../src/actions/index.ts | 16 ++ .../src/index.ts | 16 ++ plugins/scaffolder-backend/api-report.md | 6 +- plugins/scaffolder-backend/package.json | 4 +- .../actions/builtin/createBuiltinActions.ts | 10 +- .../scaffolder/actions/builtin/fetch/index.ts | 2 +- .../src/scaffolder/stages/templater/index.ts | 1 - 23 files changed, 423 insertions(+), 56 deletions(-) create mode 100644 microsite/data/plugins/scaffolder-backend-module-rails.yaml create mode 100644 microsite/static/img/rails-icon.png create mode 100644 plugins/scaffolder-backend-module-rails/.eslintrc.js create mode 100644 plugins/scaffolder-backend-module-rails/README.md rename plugins/{scaffolder-backend/scripts => scaffolder-backend-module-rails}/Rails.dockerfile (100%) create mode 100644 plugins/scaffolder-backend-module-rails/api-report.md create mode 100644 plugins/scaffolder-backend-module-rails/package.json create mode 100644 plugins/scaffolder-backend-module-rails/src/actions/fetch/index.ts rename plugins/{scaffolder-backend/src/scaffolder/actions/builtin/fetch/rails.test.ts => scaffolder-backend-module-rails/src/actions/fetch/rails/index.test.ts} (86%) rename plugins/{scaffolder-backend/src/scaffolder/actions/builtin/fetch/rails.ts => scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts} (90%) rename plugins/{scaffolder-backend/src/scaffolder/stages/templater => scaffolder-backend-module-rails/src/actions/fetch}/rails/railsArgumentResolver.test.ts (95%) rename plugins/{scaffolder-backend/src/scaffolder/stages/templater => scaffolder-backend-module-rails/src/actions/fetch}/rails/railsArgumentResolver.ts (100%) rename plugins/{scaffolder-backend/src/scaffolder/stages/templater/rails/index.test.ts => scaffolder-backend-module-rails/src/actions/fetch/rails/railsNewRunner.test.ts} (89%) rename plugins/{scaffolder-backend/src/scaffolder/stages/templater/rails/index.ts => scaffolder-backend-module-rails/src/actions/fetch/rails/railsNewRunner.ts} (84%) create mode 100644 plugins/scaffolder-backend-module-rails/src/actions/index.ts create mode 100644 plugins/scaffolder-backend-module-rails/src/index.ts diff --git a/.changeset/twelve-deers-explode.md b/.changeset/twelve-deers-explode.md index c5ce1318a6..0d34392eab 100644 --- a/.changeset/twelve-deers-explode.md +++ b/.changeset/twelve-deers-explode.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend': patch --- -Created a Rails templater to scaffold apps +Export the `fetchContents` from scaffolder-backend diff --git a/microsite/data/plugins/scaffolder-backend-module-rails.yaml b/microsite/data/plugins/scaffolder-backend-module-rails.yaml new file mode 100644 index 0000000000..5f5a29cf3c --- /dev/null +++ b/microsite/data/plugins/scaffolder-backend-module-rails.yaml @@ -0,0 +1,9 @@ +--- +title: Scaffolder Backend Module Rails +author: Rogerio Angeliski +authorUrl: https://angeliski.com.br/ +category: Scaffolder +description: Here you can find all Rails related features to improve your scaffolder. +documentation: https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend-module-rails/README.md +iconUrl: img/rails-icon.png +npmPackageName: '@backstage/plugin-scaffolder-backend-module-rails' diff --git a/microsite/static/img/rails-icon.png b/microsite/static/img/rails-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f7b8b69bd9695a8dc98b7bb4b5f848e2ab6eccdf GIT binary patch literal 5439 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 literal 0 HcmV?d00001 diff --git a/packages/backend/package.json b/packages/backend/package.json index ed6fbd56b5..c3e693865f 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -31,6 +31,7 @@ "@backstage/catalog-client": "^0.3.15", "@backstage/catalog-model": "^0.8.2", "@backstage/config": "^0.1.5", + "@backstage/integration": "^0.5.6", "@backstage/plugin-app-backend": "^0.3.13", "@backstage/plugin-auth-backend": "^0.3.15", "@backstage/plugin-badges-backend": "^0.1.6", @@ -42,6 +43,7 @@ "@backstage/plugin-proxy-backend": "^0.2.9", "@backstage/plugin-rollbar-backend": "^0.1.11", "@backstage/plugin-scaffolder-backend": "^0.12.4", + "@backstage/plugin-scaffolder-backend-module-rails": "^0.1.1", "@backstage/plugin-search-backend": "^0.2.0", "@backstage/plugin-search-backend-node": "^0.2.0", "@backstage/plugin-techdocs-backend": "^0.8.5", diff --git a/plugins/scaffolder-backend-module-rails/.eslintrc.js b/plugins/scaffolder-backend-module-rails/.eslintrc.js new file mode 100644 index 0000000000..16a033dbc6 --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint.backend')], +}; diff --git a/plugins/scaffolder-backend-module-rails/README.md b/plugins/scaffolder-backend-module-rails/README.md new file mode 100644 index 0000000000..3c0c9da53e --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/README.md @@ -0,0 +1,225 @@ +# scaffolder-backend-module-rails + +Welcome to the Rails Module for Scaffolder. + +Here you can find all Rails related features to improve your scaffolder: + +- Rails Action to use the `new` command +- More features are coming + +## Getting started + +You need to configure the action in your backend: + +``` +yarn add @backstage/plugin-scaffolder-backend-module-rails +``` + +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 +const actions = [ + createFetchRailsAction({ + integrations, + reader, + containerRunner, + }), +]; + +return await createRouter({ + preparers, + templaters, + publishers, + 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: rails-demo + title: Rails template + description: scaffolder Rails app +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 + railsArguments: + title: arguments to run the rails new command + type: object + properties: + minimal: + title: minimal + description: Preconfigure a minimal rails app + type: boolean + skipBundle: + title: skipBundle + description: Don't run bundle install + type: boolean + skipWebpackInstall: + title: skipWebpackInstall + description: Don't run Webpack install + type: boolean + api: + title: api + description: Preconfigure smaller stack for API only apps + type: boolean + template: + title: template + description: Path to some application template (can be a filesystem path or URL) + type: string + default: './rails-template-file.rb' + webpacker: + title: webpacker + description: + 'Preconfigure Webpack with a particular framework (options: react, + vue, angular, elm, stimulus)' + type: string + enum: + - react + - vue + - angular + - elm + - stimulus + database: + title: database + description: 'Preconfigure for selected database (options: mysql/postgresql/sqlite3/oracle/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)' + type: string + enum: + - mysql + - postgresql + - sqlite3 + - oracle + - sqlserver + - jdbcmysql + - jdbcsqlite3 + - jdbcpostgresql + - jdbc + railsVersion: + title: Rails version in Gemfile + description: + 'Set up the application with Gemfile pointing to a specific version + (options: dev, edge, master)' + type: string + enum: + - dev + - edge + - master + + steps: + - id: fetch-base + name: Fetch Base + action: fetch:rails + input: + url: ./template + values: + name: '{{ parameters.name }}' + owner: '{{ parameters.owner }}' + system: '{{ parameters.system }}' + railsArguments: '{{ json parameters.railsArguments }}' + + - name: Write Catalog information + action: catalog:write + input: + component: + apiVersion: 'backstage.io/v1alpha1' + kind: Component + metadata: + name: '{{ parameters.name }}' + annotations: + github.com/project-slug: '{{ projectSlug parameters.repoUrl }}' + spec: + type: service + lifecycle: production + owner: '{{ parameters.owner }}' + + - 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 }}' +``` + +We have a [Docker image](https://github.com/backstage/backstage/blob/master/plugins/scaffolder-backend-module-rails/Rails.dockerfile) you can use to build your own. diff --git a/plugins/scaffolder-backend/scripts/Rails.dockerfile b/plugins/scaffolder-backend-module-rails/Rails.dockerfile similarity index 100% rename from plugins/scaffolder-backend/scripts/Rails.dockerfile rename to plugins/scaffolder-backend-module-rails/Rails.dockerfile diff --git a/plugins/scaffolder-backend-module-rails/api-report.md b/plugins/scaffolder-backend-module-rails/api-report.md new file mode 100644 index 0000000000..95d9c1bd9f --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/api-report.md @@ -0,0 +1,22 @@ +## API Report File for "@backstage/plugin-scaffolder-backend-module-rails" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ContainerRunner } from '@backstage/backend-common'; +import { ScmIntegrations } from '@backstage/integration'; +import { TemplateAction } from '@backstage/plugin-scaffolder-backend'; +import { UrlReader } from '@backstage/backend-common'; + +// @public (undocumented) +export function createFetchRailsAction(options: { + reader: UrlReader; + integrations: ScmIntegrations; + containerRunner: ContainerRunner; +}): TemplateAction; + + +// (No @packageDocumentation comment for this package) + +``` diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json new file mode 100644 index 0000000000..79b123cdb6 --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/package.json @@ -0,0 +1,44 @@ +{ + "name": "@backstage/plugin-scaffolder-backend-module-rails", + "version": "0.1.1", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "scripts": { + "build": "backstage-cli plugin:build", + "start": "backstage-cli plugin:serve", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "diff": "backstage-cli plugin:diff", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", + "clean": "backstage-cli clean" + }, + "dependencies": { + "@backstage/backend-common": "^0.8.3", + "@backstage/plugin-scaffolder-backend": "^0.12.2", + "@backstage/config": "^0.1.5", + "@backstage/errors": "^0.1.1", + "@backstage/integration": "^0.5.6", + "command-exists": "^1.2.9", + "fs-extra": "^9.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.7.1", + "@types/jest": "^26.0.7", + "@types/node": "^14.14.32", + "@types/command-exists": "^1.2.0", + "@types/fs-extra": "^9.0.1", + "@types/mock-fs": "^4.13.0", + "jest-when": "^3.1.0", + "mock-fs": "^4.13.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/scaffolder-backend-module-rails/src/actions/fetch/index.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/index.ts new file mode 100644 index 0000000000..7d590c9a1a --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/index.ts @@ -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 './rails'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/rails.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.test.ts similarity index 86% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/rails.test.ts rename to plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.test.ts index ebc62e9277..cedc768f88 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/rails.test.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.test.ts @@ -15,24 +15,31 @@ */ const mockRailsTemplater = { run: jest.fn() }; -jest.mock('./helpers'); -jest.mock('../../../stages/templater', () => { +jest.mock('@backstage/plugin-scaffolder-backend', () => ({ + ...jest.requireActual('@backstage/plugin-scaffolder-backend'), + fetchContents: jest.fn(), +})); +jest.mock('./railsNewRunner', () => { return { - Rails: jest.fn().mockImplementation(() => { + RailsNewRunner: jest.fn().mockImplementation(() => { return mockRailsTemplater; }), }; }); -import { getVoidLogger, UrlReader } from '@backstage/backend-common'; +import { + ContainerRunner, + getVoidLogger, + UrlReader, +} from '@backstage/backend-common'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; import mock from 'mock-fs'; import os from 'os'; import { resolve as resolvePath } from 'path'; import { PassThrough } from 'stream'; -import { createFetchRailsAction } from './rails'; -import { fetchContents } from './helpers'; +import { createFetchRailsAction } from './index'; +import { fetchContents } from '@backstage/plugin-scaffolder-backend'; describe('fetch:rails', () => { const integrations = ScmIntegrations.fromConfig( @@ -68,10 +75,14 @@ describe('fetch:rails', () => { readTree: jest.fn(), search: jest.fn(), }; + const containerRunner: ContainerRunner = { + runContainer: jest.fn(), + }; const action = createFetchRailsAction({ integrations, reader: mockReader, + containerRunner, }); beforeEach(() => { diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/rails.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts similarity index 90% rename from plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/rails.ts rename to plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts index 203db5004e..e2dc8fd95a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/rails.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/index.ts @@ -14,22 +14,25 @@ * limitations under the License. */ -import { DockerContainerRunner, UrlReader } from '@backstage/backend-common'; +import { ContainerRunner, UrlReader } from '@backstage/backend-common'; import { JsonObject } from '@backstage/config'; import { InputError } from '@backstage/errors'; import { ScmIntegrations } from '@backstage/integration'; import fs from 'fs-extra'; +import { + createTemplateAction, + fetchContents, +} from '@backstage/plugin-scaffolder-backend'; + import { resolve as resolvePath } from 'path'; -import { Rails, TemplaterValues } from '../../../stages/templater'; -import { createTemplateAction } from '../../createTemplateAction'; -import { fetchContents } from './helpers'; -import Docker from 'dockerode'; +import { RailsNewRunner } from './railsNewRunner'; export function createFetchRailsAction(options: { reader: UrlReader; integrations: ScmIntegrations; + containerRunner: ContainerRunner; }) { - const { reader, integrations } = options; + const { reader, integrations, containerRunner } = options; return createTemplateAction<{ url: string; @@ -39,7 +42,7 @@ export function createFetchRailsAction(options: { }>({ id: 'fetch:rails', description: - 'Downloads a template from the given URL into the workspace, and runs a rails generator on it.', + 'Downloads a template from the given URL into the workspace, and runs a rails new generator on it.', schema: { input: { type: 'object', @@ -152,12 +155,10 @@ export function createFetchRailsAction(options: { outputPath: workDir, }); - const dockerClient = new Docker(); - const containerRunner = new DockerContainerRunner({ dockerClient }); - const templateRunner = new Rails({ containerRunner }); + const templateRunner = new RailsNewRunner({ containerRunner }); const values = { - ...(ctx.input.values as TemplaterValues), + ...ctx.input.values, imageName: ctx.input.imageName, }; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/railsArgumentResolver.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts similarity index 95% rename from plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/railsArgumentResolver.test.ts rename to plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts index 370d9de380..a8c10625c2 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/railsArgumentResolver.test.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.test.ts @@ -15,7 +15,6 @@ */ import { railsArgumentResolver } from './railsArgumentResolver'; -import { TemplaterValues } from '../types'; describe('railsArgumentResolver', () => { describe('when provide the parameter', () => { @@ -33,7 +32,7 @@ describe('railsArgumentResolver', () => { 'should include the argument to execution %p -> %p', (passedArguments: object, expected: Array) => { // that step is to ensure the validation between the TemplaterValues and the resolver - const values: TemplaterValues = { + const values = { owner: 'r', storePath: '', railsArguments: passedArguments, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/railsArgumentResolver.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts similarity index 100% rename from plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/railsArgumentResolver.ts rename to plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsArgumentResolver.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/index.test.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsNewRunner.test.ts similarity index 89% rename from plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/index.test.ts rename to plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsNewRunner.test.ts index 534899eec1..dc3f824236 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/index.test.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsNewRunner.test.ts @@ -16,7 +16,7 @@ const runCommand = jest.fn(); const commandExists = jest.fn(); -jest.mock('../helpers', () => ({ runCommand })); +jest.mock('@backstage/plugin-scaffolder-backend', () => ({ runCommand })); jest.mock('command-exists', () => commandExists); jest.mock('fs-extra'); @@ -26,7 +26,7 @@ import fs from 'fs-extra'; import path from 'path'; import { PassThrough } from 'stream'; -import { Rails } from './index'; +import { RailsNewRunner } from './railsNewRunner'; describe('Rails Templater', () => { const containerRunner: jest.Mocked = { @@ -39,6 +39,7 @@ describe('Rails Templater', () => { describe('when running on docker', () => { it('should run the correct bindings for the volumes', async () => { + const logStream = new PassThrough(); const values = { owner: 'angeliski', storePath: 'https://github.com/angeliski/rails-project', @@ -51,10 +52,11 @@ describe('Rails Templater', () => { .spyOn(fs, 'realpath') .mockImplementation(x => Promise.resolve(x.toString())); - const templater = new Rails({ containerRunner }); + const templater = new RailsNewRunner({ containerRunner }); await templater.run({ workspacePath: 'tempdir', values, + logStream, }); expect(containerRunner.runContainer).toHaveBeenCalledWith({ @@ -67,11 +69,12 @@ describe('Rails Templater', () => { [path.join('tempdir', 'intermediate')]: '/output', }, workingDir: '/input', - logStream: undefined, + logStream: logStream, }); }); it('should use the provided imageName', async () => { + const logStream = new PassThrough(); const values = { owner: 'angeliski', storePath: 'https://github.com/angeliski/rails-project', @@ -81,10 +84,11 @@ describe('Rails Templater', () => { jest.spyOn(fs, 'readdir').mockResolvedValueOnce(['newthing'] as any); - const templater = new Rails({ containerRunner }); + const templater = new RailsNewRunner({ containerRunner }); await templater.run({ workspacePath: 'tempdir', values, + logStream, }); expect(containerRunner.runContainer).toHaveBeenCalledWith( @@ -106,7 +110,7 @@ describe('Rails Templater', () => { jest.spyOn(fs, 'readdir').mockResolvedValueOnce(['newthing'] as any); - const templater = new Rails({ containerRunner }); + const templater = new RailsNewRunner({ containerRunner }); await templater.run({ workspacePath: 'tempdir', values, @@ -128,6 +132,7 @@ describe('Rails Templater', () => { }); it('update the template path to correct location', async () => { + const logStream = new PassThrough(); const values = { owner: 'angeliski', storePath: 'https://github.com/angeliski/rails-project', @@ -141,10 +146,11 @@ describe('Rails Templater', () => { .spyOn(fs, 'realpath') .mockImplementation(x => Promise.resolve(x.toString())); - const templater = new Rails({ containerRunner }); + const templater = new RailsNewRunner({ containerRunner }); await templater.run({ workspacePath: 'tempdir', values, + logStream, }); expect(containerRunner.runContainer).toHaveBeenCalledWith({ @@ -162,7 +168,7 @@ describe('Rails Templater', () => { [path.join('tempdir', 'intermediate')]: '/output', }, workingDir: '/input', - logStream: undefined, + logStream: logStream, }); }); }); @@ -181,7 +187,7 @@ describe('Rails Templater', () => { jest.spyOn(fs, 'readdir').mockResolvedValueOnce(['newthing'] as any); commandExists.mockImplementationOnce(() => () => true); - const templater = new Rails({ containerRunner }); + const templater = new RailsNewRunner({ containerRunner }); await templater.run({ workspacePath: 'tempdir', values, @@ -211,7 +217,7 @@ describe('Rails Templater', () => { jest.spyOn(fs, 'readdir').mockResolvedValueOnce(['newthing'] as any); commandExists.mockImplementationOnce(() => () => true); - const templater = new Rails({ containerRunner }); + const templater = new RailsNewRunner({ containerRunner }); await templater.run({ workspacePath: 'tempdir', values, @@ -239,7 +245,7 @@ describe('Rails Templater', () => { .spyOn(fs, 'readdir') .mockImplementationOnce(() => Promise.resolve([])); - const templater = new Rails({ containerRunner }); + const templater = new RailsNewRunner({ containerRunner }); await expect( templater.run({ workspacePath: 'tempdir', diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/index.ts b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsNewRunner.ts similarity index 84% rename from plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/index.ts rename to plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsNewRunner.ts index 57ee26e106..3e18490587 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/templater/rails/index.ts +++ b/plugins/scaffolder-backend-module-rails/src/actions/fetch/rails/railsNewRunner.ts @@ -17,12 +17,16 @@ import { ContainerRunner } from '@backstage/backend-common'; import fs from 'fs-extra'; import path from 'path'; -import { runCommand } from '../helpers'; +import { runCommand } from '@backstage/plugin-scaffolder-backend'; import commandExists from 'command-exists'; -import { TemplaterBase, TemplaterRunOptions } from '../types'; -import { railsArgumentResolver } from './railsArgumentResolver'; +import { + railsArgumentResolver, + RailsRunOptions, +} from './railsArgumentResolver'; +import { JsonObject } from '@backstage/config'; +import { Writable } from 'stream'; -export class Rails implements TemplaterBase { +export class RailsNewRunner { private readonly containerRunner: ContainerRunner; constructor({ containerRunner }: { containerRunner: ContainerRunner }) { @@ -33,7 +37,11 @@ export class Rails implements TemplaterBase { workspacePath, values, logStream, - }: TemplaterRunOptions): Promise { + }: { + workspacePath: string; + values: JsonObject; + logStream: Writable; + }): Promise { const intermediateDir = path.join(workspacePath, 'intermediate'); await fs.ensureDir(intermediateDir); const resultDir = path.join(workspacePath, 'result'); @@ -53,7 +61,7 @@ export class Rails implements TemplaterBase { if (commandExistsToRun) { const arrayExtraArguments = railsArgumentResolver( workspacePath, - railsArguments, + railsArguments as RailsRunOptions, ); await runCommand({ @@ -68,10 +76,10 @@ export class Rails implements TemplaterBase { } else { const arrayExtraArguments = railsArgumentResolver( '/input', - railsArguments, + railsArguments as RailsRunOptions, ); await this.containerRunner.runContainer({ - imageName: imageName, + imageName: imageName as string, command: baseCommand, args: [...baseArguments, `/output/${name}`, ...arrayExtraArguments], mountDirs, diff --git a/plugins/scaffolder-backend-module-rails/src/actions/index.ts b/plugins/scaffolder-backend-module-rails/src/actions/index.ts new file mode 100644 index 0000000000..1b47db9e03 --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/src/actions/index.ts @@ -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'; diff --git a/plugins/scaffolder-backend-module-rails/src/index.ts b/plugins/scaffolder-backend-module-rails/src/index.ts new file mode 100644 index 0000000000..4f06b14a86 --- /dev/null +++ b/plugins/scaffolder-backend-module-rails/src/index.ts @@ -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'; diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index ab3ea433c6..e30542aca7 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -11,7 +11,7 @@ import { createPullRequest } from 'octokit-plugin-create-pull-request'; import express from 'express'; import { JsonObject } from '@backstage/config'; import { JsonValue } from '@backstage/config'; -import { Logger } from 'winston'; +import { Logger as Logger_2 } from 'winston'; import { PluginDatabaseManager } from '@backstage/backend-common'; import { Schema } from 'jsonschema'; import { ScmIntegrationRegistry } from '@backstage/integration'; @@ -23,7 +23,7 @@ import { Writable } from 'stream'; // @public (undocumented) export type ActionContext = { baseUrl?: string; - logger: Logger; + logger: Logger_2; logStream: Writable; token?: string | undefined; workspacePath: string; @@ -131,7 +131,7 @@ export interface RouterOptions { // (undocumented) database: PluginDatabaseManager; // (undocumented) - logger: Logger; + logger: Logger_2; // (undocumented) reader: UrlReader; // (undocumented) diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index a6db486594..a88413d611 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -62,8 +62,7 @@ "octokit-plugin-create-pull-request": "^3.9.3", "uuid": "^8.2.0", "winston": "^3.2.1", - "yaml": "^1.10.0", - "dockerode": "^3.2.1" + "yaml": "^1.10.0" }, "devDependencies": { "@backstage/cli": "^0.7.3", @@ -73,7 +72,6 @@ "@types/git-url-parse": "^9.0.0", "@types/mock-fs": "^4.13.0", "@types/supertest": "^2.0.8", - "@types/dockerode": "^3.2.1", "jest-when": "^3.1.0", "mock-fs": "^4.13.0", "msw": "^0.29.0", diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index fa2fcbfcee..08d7bbf824 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -24,11 +24,7 @@ import { } from './catalog'; import { createDebugLogAction } from './debug'; -import { - createFetchCookiecutterAction, - createFetchPlainAction, - createFetchRailsAction, -} from './fetch'; +import { createFetchCookiecutterAction, createFetchPlainAction } from './fetch'; import { createFilesystemDeleteAction, createFilesystemRenameAction, @@ -66,10 +62,6 @@ export const createBuiltinActions = (options: { integrations, containerRunner, }), - createFetchRailsAction({ - reader, - integrations, - }), createPublishGithubAction({ integrations, config, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/index.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/index.ts index 9557a88a4c..82bc387f26 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/index.ts @@ -16,4 +16,4 @@ export { createFetchPlainAction } from './plain'; export { createFetchCookiecutterAction } from './cookiecutter'; -export { createFetchRailsAction } from './rails'; +export * from './helpers'; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/templater/index.ts b/plugins/scaffolder-backend/src/scaffolder/stages/templater/index.ts index 139ff2207e..4d80f86946 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/templater/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/templater/index.ts @@ -18,4 +18,3 @@ export * from './types'; export * from './helpers'; export * from './templaters'; export * from './cra'; -export * from './rails';