Add examples for fetch:rails scaffolder action & improve related tests
Signed-off-by: parmar-abhinav <abhinav.parmar@infosys.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-scaffolder-backend-module-rails': patch
|
||||
---
|
||||
|
||||
Add examples for fetch:rails scaffolder action & improve related tests
|
||||
@@ -51,7 +51,8 @@
|
||||
"@backstage/plugin-scaffolder-node": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"command-exists": "^1.2.9",
|
||||
"fs-extra": "^11.0.0"
|
||||
"fs-extra": "^11.0.0",
|
||||
"yaml": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/backend-test-utils": "workspace:^",
|
||||
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const mockRailsTemplater = { run: jest.fn() };
|
||||
jest.mock('@backstage/plugin-scaffolder-node', () => ({
|
||||
...jest.requireActual('@backstage/plugin-scaffolder-node'),
|
||||
fetchContents: jest.fn(),
|
||||
}));
|
||||
jest.mock('./railsNewRunner', () => {
|
||||
return {
|
||||
RailsNewRunner: jest.fn().mockImplementation(() => {
|
||||
return mockRailsTemplater;
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
import { ContainerRunner, UrlReader } from '@backstage/backend-common';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { ScmIntegrations } from '@backstage/integration';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { createFetchRailsAction } from './index';
|
||||
import { fetchContents } from '@backstage/plugin-scaffolder-node';
|
||||
import { createMockDirectory } from '@backstage/backend-test-utils';
|
||||
import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils';
|
||||
import { Writable } from 'stream';
|
||||
import { examples } from './index.examples';
|
||||
import yaml from 'yaml';
|
||||
|
||||
describe('fetch:rails', () => {
|
||||
const mockDir = createMockDirectory();
|
||||
const integrations = ScmIntegrations.fromConfig(
|
||||
new ConfigReader({
|
||||
integrations: {
|
||||
azure: [
|
||||
{ host: 'dev.azure.com', token: 'tokenlols' },
|
||||
{ host: 'myazurehostnotoken.com' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const mockContext = createMockActionContext({
|
||||
input: {
|
||||
url: 'https://rubyonrails.org/generator',
|
||||
targetPath: 'something',
|
||||
values: {
|
||||
help: 'me',
|
||||
},
|
||||
},
|
||||
templateInfo: {
|
||||
baseUrl: 'somebase',
|
||||
entityRef: 'template:default/myTemplate',
|
||||
},
|
||||
workspacePath: mockDir.path,
|
||||
});
|
||||
|
||||
const mockReader: UrlReader = {
|
||||
readUrl: jest.fn(),
|
||||
readTree: jest.fn(),
|
||||
search: jest.fn(),
|
||||
};
|
||||
const containerRunner: ContainerRunner = {
|
||||
runContainer: jest.fn(),
|
||||
};
|
||||
|
||||
const action = createFetchRailsAction({
|
||||
integrations,
|
||||
reader: mockReader,
|
||||
containerRunner,
|
||||
allowedImageNames: ['foo/rails-custom-image'],
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockDir.setContent({
|
||||
result: '{}',
|
||||
});
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it(`should ${examples[0].description}`, async () => {
|
||||
const input = yaml.parse(examples[0].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[1].description}`, async () => {
|
||||
const input = yaml.parse(examples[1].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[2].description}`, async () => {
|
||||
const input = yaml.parse(examples[2].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[3].description}`, async () => {
|
||||
const input = yaml.parse(examples[3].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[4].description}`, async () => {
|
||||
const input = yaml.parse(examples[4].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[5].description}`, async () => {
|
||||
const input = yaml.parse(examples[5].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[6].description}`, async () => {
|
||||
const input = yaml.parse(examples[6].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[7].description}`, async () => {
|
||||
const input = yaml.parse(examples[7].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[8].description}`, async () => {
|
||||
const input = yaml.parse(examples[8].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
|
||||
it(`should ${examples[9].description}`, async () => {
|
||||
const input = yaml.parse(examples[9].example).steps[0].input;
|
||||
|
||||
await action.handler({
|
||||
...mockContext,
|
||||
input: {
|
||||
...mockContext.input,
|
||||
...input,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchContents).toHaveBeenCalledWith({
|
||||
reader: mockReader,
|
||||
integrations,
|
||||
baseUrl: mockContext.templateInfo?.baseUrl,
|
||||
fetchUrl: input.url,
|
||||
outputPath: resolvePath(mockContext.workspacePath),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import { TemplateExample } from '@backstage/plugin-scaffolder-node';
|
||||
import yaml from 'yaml';
|
||||
|
||||
export const examples: TemplateExample[] = [
|
||||
{
|
||||
description: 'Fetch and template a minimal Rails app',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: true,
|
||||
skipBundle: true,
|
||||
skipWebpackInstall: true,
|
||||
skipTest: true,
|
||||
skipActionCable: true,
|
||||
skipActionMailer: true,
|
||||
skipActionMailbox: true,
|
||||
skipActiveStorage: true,
|
||||
skipActionText: true,
|
||||
skipActiveRecord: true,
|
||||
force: true,
|
||||
api: true,
|
||||
webpacker: 'react',
|
||||
database: 'postgresql',
|
||||
railsVersion: 'dev',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description: 'Fetch and template a Rails app with custom options',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
targetPath: 'custom-path',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: false,
|
||||
skipBundle: false,
|
||||
skipWebpackInstall: false,
|
||||
skipTest: false,
|
||||
skipActionCable: false,
|
||||
skipActionMailer: false,
|
||||
skipActionMailbox: false,
|
||||
skipActiveStorage: false,
|
||||
skipActionText: false,
|
||||
skipActiveRecord: false,
|
||||
force: false,
|
||||
api: false,
|
||||
webpacker: 'vue',
|
||||
database: 'mysql',
|
||||
railsVersion: 'edge',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description: 'Fetch and template a Rails app with Docker image',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: true,
|
||||
skipBundle: true,
|
||||
skipWebpackInstall: true,
|
||||
skipTest: true,
|
||||
skipActionCable: true,
|
||||
skipActionMailer: true,
|
||||
skipActionMailbox: true,
|
||||
skipActiveStorage: true,
|
||||
skipActionText: true,
|
||||
skipActiveRecord: true,
|
||||
force: true,
|
||||
api: true,
|
||||
webpacker: 'react',
|
||||
database: 'postgresql',
|
||||
railsVersion: 'dev',
|
||||
},
|
||||
imageName: 'custom/rails-image',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description:
|
||||
'Fetch and template a Rails app with different database and action mailer settings',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: false,
|
||||
skipBundle: false,
|
||||
skipWebpackInstall: false,
|
||||
skipTest: false,
|
||||
skipActionCable: false,
|
||||
skipActionMailer: false,
|
||||
skipActionMailbox: true,
|
||||
skipActiveStorage: false,
|
||||
skipActionText: false,
|
||||
skipActiveRecord: false,
|
||||
force: true,
|
||||
api: true,
|
||||
webpacker: 'angular',
|
||||
database: 'sqlite3',
|
||||
railsVersion: 'master',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description:
|
||||
'Fetch and template a Rails app with full options including action mailer and active storage',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: false,
|
||||
skipBundle: false,
|
||||
skipWebpackInstall: false,
|
||||
skipTest: false,
|
||||
skipActionCable: false,
|
||||
skipActionMailer: false,
|
||||
skipActionMailbox: false,
|
||||
skipActiveStorage: false,
|
||||
skipActionText: false,
|
||||
skipActiveRecord: false,
|
||||
force: false,
|
||||
api: false,
|
||||
webpacker: 'stimulus',
|
||||
database: 'postgresql',
|
||||
railsVersion: 'fromImage',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description:
|
||||
'Fetch and template a Rails app with API-only stack and custom template path',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: false,
|
||||
skipBundle: true,
|
||||
skipWebpackInstall: true,
|
||||
skipTest: true,
|
||||
skipActionCable: true,
|
||||
skipActionMailer: true,
|
||||
skipActionMailbox: true,
|
||||
skipActiveStorage: true,
|
||||
skipActionText: true,
|
||||
skipActiveRecord: true,
|
||||
force: true,
|
||||
api: true,
|
||||
webpacker: 'elm',
|
||||
database: 'mysql',
|
||||
railsVersion: 'dev',
|
||||
template: 'path/to/custom/template',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description: 'Fetch and template a Rails app with custom Webpack setup',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: false,
|
||||
skipBundle: false,
|
||||
skipWebpackInstall: false,
|
||||
skipTest: false,
|
||||
skipActionCable: false,
|
||||
skipActionMailer: false,
|
||||
skipActionMailbox: false,
|
||||
skipActiveStorage: false,
|
||||
skipActionText: false,
|
||||
skipActiveRecord: false,
|
||||
force: false,
|
||||
api: false,
|
||||
webpacker: 'angular',
|
||||
database: 'postgresql',
|
||||
railsVersion: 'dev',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description:
|
||||
'Fetch and template a Rails app with specific Rails version and Action Mailer enabled',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: false,
|
||||
skipBundle: false,
|
||||
skipWebpackInstall: false,
|
||||
skipTest: false,
|
||||
skipActionCable: false,
|
||||
skipActionMailer: false,
|
||||
skipActionMailbox: false,
|
||||
skipActiveStorage: false,
|
||||
skipActionText: false,
|
||||
skipActiveRecord: false,
|
||||
force: true,
|
||||
api: true,
|
||||
webpacker: 'react',
|
||||
database: 'sqlite3',
|
||||
railsVersion: 'master',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description:
|
||||
'Fetch and template a Rails app with specific database and Active Storage enabled',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: false,
|
||||
skipBundle: false,
|
||||
skipWebpackInstall: false,
|
||||
skipTest: false,
|
||||
skipActionCable: false,
|
||||
skipActionMailer: false,
|
||||
skipActionMailbox: false,
|
||||
skipActiveStorage: false,
|
||||
skipActionText: false,
|
||||
skipActiveRecord: false,
|
||||
force: true,
|
||||
api: true,
|
||||
webpacker: 'vue',
|
||||
database: 'postgresql',
|
||||
railsVersion: 'fromImage',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
{
|
||||
description:
|
||||
'Fetch and template a Rails app with full options including database and skip options',
|
||||
example: yaml.stringify({
|
||||
steps: [
|
||||
{
|
||||
id: 'fetchTemplate',
|
||||
action: 'fetch:rails',
|
||||
name: 'Fetch and Template Rails App',
|
||||
input: {
|
||||
url: 'https://github.com/backstage/backstage',
|
||||
values: {
|
||||
railsArguments: {
|
||||
minimal: false,
|
||||
skipBundle: true,
|
||||
skipWebpackInstall: true,
|
||||
skipTest: true,
|
||||
skipActionCable: true,
|
||||
skipActionMailer: true,
|
||||
skipActionMailbox: true,
|
||||
skipActiveStorage: true,
|
||||
skipActionText: true,
|
||||
skipActiveRecord: true,
|
||||
force: false,
|
||||
api: false,
|
||||
webpacker: 'stimulus',
|
||||
database: 'sqlite3',
|
||||
railsVersion: 'dev',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
];
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { RailsNewRunner } from './railsNewRunner';
|
||||
import { PassThrough } from 'stream';
|
||||
import { examples } from './index.examples';
|
||||
|
||||
/**
|
||||
* Creates the `fetch:rails` Scaffolder action.
|
||||
@@ -56,6 +57,7 @@ export function createFetchRailsAction(options: {
|
||||
id: 'fetch:rails',
|
||||
description:
|
||||
'Downloads a template from the given `url` into the workspace, and runs a rails new generator on it.',
|
||||
examples,
|
||||
schema: {
|
||||
input: {
|
||||
type: 'object',
|
||||
|
||||
Reference in New Issue
Block a user