From 22fbe0aaab21373f67989158973eb1f19739957d Mon Sep 17 00:00:00 2001 From: blam Date: Sat, 20 Jun 2020 05:56:48 +0200 Subject: [PATCH 1/6] feat(scaffolder): added the ability to process github remote sources, without authenication for now at least --- packages/backend/src/plugins/scaffolder.ts | 3 + plugins/scaffolder-backend/package.json | 4 + plugins/scaffolder-backend/scripts/mock-data | 16 +- .../src/scaffolder/prepare/github.ts | 58 +++++ .../src/scaffolder/prepare/index.ts | 1 + .../src/scaffolder/prepare/types.ts | 2 +- .../scaffolder-backend/src/service/router.ts | 15 +- yarn.lock | 201 ++++++++++++++++-- 8 files changed, 274 insertions(+), 26 deletions(-) create mode 100644 plugins/scaffolder-backend/src/scaffolder/prepare/github.ts diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index ce3a7ea2bd..95d28eacb1 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -18,6 +18,7 @@ import { CookieCutter, createRouter, FilePreparer, + GithubPreparer, Preparers, } from '@backstage/plugin-scaffolder-backend'; import type { PluginEnvironment } from '../types'; @@ -25,9 +26,11 @@ import type { PluginEnvironment } from '../types'; export default async function createPlugin({ logger }: PluginEnvironment) { const templater = new CookieCutter(); const filePreparer = new FilePreparer(); + const githubPreparer = new GithubPreparer(); const preparers = new Preparers(); preparers.register('file', filePreparer); + preparers.register('github', githubPreparer); return await createRouter({ preparers, templater, logger }); } diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 0edf7a8fe9..e586300b15 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -30,14 +30,18 @@ "express": "^4.17.1", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.0", + "git-url-parse": "^11.1.2", "globby": "^11.0.0", "helmet": "^3.22.0", "morgan": "^1.10.0", + "nodegit": "0.26.5", "winston": "^3.2.1" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.9", "@types/fs-extra": "^9.0.1", + "@types/git-url-parse": "^9.0.0", + "@types/nodegit": "0.26.5", "@types/supertest": "^2.0.8", "supertest": "^4.0.2", "yaml": "^1.10.0" diff --git a/plugins/scaffolder-backend/scripts/mock-data b/plugins/scaffolder-backend/scripts/mock-data index be3fa2b6cf..7f534fec97 100755 --- a/plugins/scaffolder-backend/scripts/mock-data +++ b/plugins/scaffolder-backend/scripts/mock-data @@ -1,8 +1,14 @@ #!/usr/bin/env bash -curl \ ---location \ ---request POST 'localhost:7000/catalog/locations' \ ---header 'Content-Type: application/json' \ ---data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/react-ssr-template/template.yaml\"}" +# curl \ +# --location \ +# --request POST 'localhost:7000/catalog/locations' \ +# --header 'Content-Type: application/json' \ +# --data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/react-ssr-template/template.yaml\"}" + +curl \ + --location \ + --request POST 'localhost:7000/catalog/locations' \ + --header 'Content-Type: application/json' \ + --data-raw "{\"type\": \"github\", \"target\": \"https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml\"}" diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts new file mode 100644 index 0000000000..3f711bc477 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts @@ -0,0 +1,58 @@ +/* + * 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 path from 'path'; +import os from 'os'; +import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; +import { parseLocationAnnotation } from './helpers'; +import { InputError } from '@backstage/backend-common'; +import { PreparerBase } from './types'; +import GitUriParser from 'git-url-parse'; +import { Clone, CheckoutOptions } from 'nodegit'; + +export class GithubPreparer implements PreparerBase { + async prepare(template: TemplateEntityV1alpha1): Promise { + const { protocol, location } = parseLocationAnnotation(template); + + if (protocol !== 'github') { + throw new InputError( + `Wrong location protocol: ${protocol}, should be 'github'`, + ); + } + const templateId = template.metadata.name; + + const parsedGitLocation = GitUriParser(location); + const repositoryCheckoutUrl = parsedGitLocation.toString('https'); + const tempDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), templateId), + ); + + const templateDirectory = path.join( + `${path.dirname(parsedGitLocation.filepath)}`, + template.spec.path ?? '.', + ); + + const checkoutOptions = new CheckoutOptions(); + checkoutOptions.paths = [templateDirectory]; + + await Clone.clone(repositoryCheckoutUrl, tempDir, { + checkoutOpts: checkoutOptions, + // TODO(blam): Maybe need some auth here? + }); + + return path.resolve(tempDir, templateDirectory); + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/index.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/index.ts index 0b1a72eaa3..4ae4f68164 100644 --- a/plugins/scaffolder-backend/src/scaffolder/prepare/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/index.ts @@ -17,3 +17,4 @@ export * from './preparers'; export * from './types'; export * from './helpers'; export * from './file'; +export * from './github'; diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/types.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/types.ts index 3251bd2780..a6e42c465f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/prepare/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/types.ts @@ -29,4 +29,4 @@ export type PreparerBuilder = { get(template: TemplateEntityV1alpha1): PreparerBase; }; -export type RemoteProtocol = 'file'; +export type RemoteProtocol = 'file' | 'github'; diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index c9b92494fd..ce0324ead2 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -44,19 +44,20 @@ export async function createRouter( kind: 'Template', metadata: { annotations: { - 'backstage.io/managed-by-location': `file:${__dirname}/../../sample-templates/react-ssr-template/template.yaml`, + 'backstage.io/managed-by-location': + 'github:https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', }, - name: 'react-ssr-template', - title: 'React SSR Template', + name: 'graphql-starter', + title: 'GraphQL Service', description: - 'Next.js application skeleton for creating isomorphic web applications.', - uid: '7357f4c5-aa58-4a1e-9670-18931eef771f', - etag: 'YWUxZWQyY2EtZDkxMC00MDM0LWI0ODAtMDgwMWY0YzdlMWIw', + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', generation: 1, }, spec: { type: 'cookiecutter', - path: '.', + path: './template', }, }; diff --git a/yarn.lock b/yarn.lock index b1b521b438..11be8c5742 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3568,6 +3568,11 @@ dependencies: "@types/node" "*" +"@types/git-url-parse@^9.0.0": + version "9.0.0" + resolved "https://registry.npmjs.org/@types/git-url-parse/-/git-url-parse-9.0.0.tgz#aac1315a44fa4ed5a52c3820f6c3c2fb79cbd12d" + integrity sha512-kA2RxBT/r/ZuDDKwMl+vFWn1Z0lfm1/Ik6Qb91wnSzyzCDa/fkM8gIOq6ruB7xfr37n6Mj5dyivileUVKsidlg== + "@types/glob@^7.1.1": version "7.1.1" resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" @@ -3767,6 +3772,13 @@ resolved "https://registry.npmjs.org/@types/node/-/node-12.12.30.tgz#3501e6f09b954de9c404671cefdbcc5d9d7c45f6" integrity sha512-sz9MF/zk6qVr3pAnM0BSQvYIBK44tS75QC5N+VbWSE4DjCV/pJ+UzCW/F+vVnl7TkOPcuwQureKNtSSwjBTaMg== +"@types/nodegit@0.26.5": + version "0.26.5" + resolved "https://registry.npmjs.org/@types/nodegit/-/nodegit-0.26.5.tgz#f13032617da3894620b6132828f0136a65043e14" + integrity sha512-Dszf6yKBPLSPDC18QtY5LFRaRoE682/BHEhPQqwPtSBh0pG9uTfrhh1fnt61OSXiF8s4lBJunXbBpfwxvhQElQ== + dependencies: + "@types/node" "*" + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -4915,7 +4927,7 @@ arrify@^1.0.1: resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@^2.0.0: +asap@^2.0.0, asap@~2.0.3: version "2.0.6" resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -5480,6 +5492,14 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + bl@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz#52b71e9088515d0606d9dd9cc7aa48dc1f98e73a" @@ -5694,11 +5714,29 @@ btoa-lite@^1.0.0: resolved "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -6065,7 +6103,7 @@ chokidar@^3.2.2, chokidar@^3.3.0, chokidar@^3.3.1: optionalDependencies: fsevents "~2.1.2" -chownr@^1.1.1, chownr@^1.1.2: +chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.2: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -9190,6 +9228,15 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-extra@^7.0.0: + version "7.0.1" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^9.0.0: version "9.0.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3" @@ -11848,6 +11895,13 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +json5@^2.1.0: + version "2.1.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -13231,6 +13285,11 @@ nan@^2.12.1: resolved "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== +nan@^2.14.0: + version "2.14.1" + resolved "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" + integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== + nano-css@^5.2.1: version "5.3.0" resolved "https://registry.npmjs.org/nano-css/-/nano-css-5.3.0.tgz#9d3cd29788d48b6a07f52aa4aec7cf4da427b6b5" @@ -13335,6 +13394,23 @@ node-forge@^0.7.0: resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== +node-gyp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-4.0.0.tgz#972654af4e5dd0cd2a19081b4b46fe0442ba6f45" + integrity sha512-2XiryJ8sICNo6ej8d0idXDEMKfVfFK7kekGCtJAuelGsYHQxhj13KTf95swTCN2dZ/4lTfZ84Fu31jqJEEgjWA== + dependencies: + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^4.4.8" + which "1" + node-gyp@^5.0.2: version "5.1.0" resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz#8e31260a7af4a2e2f994b0673d4e0b3866156332" @@ -13424,6 +13500,22 @@ node-pre-gyp@^0.11.0: semver "^5.3.0" tar "^4" +node-pre-gyp@^0.13.0: + version "0.13.0" + resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42" + integrity sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + node-releases@^1.1.29, node-releases@^1.1.52: version "1.1.52" resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.52.tgz#bcffee3e0a758e92e44ecfaecd0a47554b0bcba9" @@ -13439,6 +13531,29 @@ node-request-interceptor@^0.2.5: debug "^4.1.1" headers-utils "^1.2.0" +nodegit-promise@~4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/nodegit-promise/-/nodegit-promise-4.0.0.tgz#5722b184f2df7327161064a791d2e842c9167b34" + integrity sha1-VyKxhPLfcycWEGSnkdLoQskWezQ= + dependencies: + asap "~2.0.3" + +nodegit@0.26.5: + version "0.26.5" + resolved "https://registry.npmjs.org/nodegit/-/nodegit-0.26.5.tgz#1534d8aaa52de7acfbbe18de28df2075de86f7d2" + integrity sha512-l9l2zhcJ0V7FYzPdXIsuJcXN8UnLuhQgM+377HJfCYE/eupL/OWtMVvUOq42F9dRsgC3bAYH9j2Xbwr0lpYVZQ== + dependencies: + fs-extra "^7.0.0" + json5 "^2.1.0" + lodash "^4.17.14" + nan "^2.14.0" + node-gyp "^4.0.0" + node-pre-gyp "^0.13.0" + promisify-node "~0.3.0" + ramda "^0.25.0" + request-promise-native "^1.0.5" + tar-fs "^1.16.3" + nodemon@^2.0.2: version "2.0.4" resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416" @@ -13455,6 +13570,13 @@ nodemon@^2.0.2: undefsafe "^2.0.2" update-notifier "^4.0.0" +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + nopt@^4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" @@ -13585,7 +13707,7 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -npmlog@^4.0.2, npmlog@^4.1.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -13884,7 +14006,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4, osenv@^0.1.5: +osenv@0, osenv@^0.1.4, osenv@^0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -15079,6 +15201,13 @@ promise.series@^0.2.0: resolved "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd" integrity sha1-LMfr6Vn8OmYZwEq029yeRS2GS70= +promisify-node@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/promisify-node/-/promisify-node-0.3.0.tgz#b4b55acf90faa7d2b8b90ca396899086c03060cf" + integrity sha1-tLVaz5D6p9K4uQyjlomQhsAwYM8= + dependencies: + nodegit-promise "~4.0.0" + prompts@^2.0.1: version "2.3.2" resolved "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" @@ -15174,6 +15303,14 @@ public-encrypt@^4.0.0: randombytes "^2.0.1" safe-buffer "^5.1.2" +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + pump@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" @@ -15284,6 +15421,11 @@ ramda@^0.21.0: resolved "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= +ramda@^0.25.0: + version "0.25.0" + resolved "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" + integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -15889,7 +16031,7 @@ read@1, read@~1.0.1: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -16367,6 +16509,13 @@ rifm@^0.7.0: dependencies: "@babel/runtime" "^7.3.1" +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@2.6.3: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -16374,13 +16523,6 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -16681,6 +16823,11 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + send@0.17.1: version "0.17.1" resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -17807,6 +17954,16 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tar-fs@^1.16.3: + version "1.16.3" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" + integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + tar-fs@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" @@ -17817,6 +17974,19 @@ tar-fs@~2.0.1: pump "^3.0.0" tar-stream "^2.0.0" +tar-stream@^1.1.2: + version "1.6.2" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + tar-stream@^2.0.0: version "2.1.2" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz#6d5ef1a7e5783a95ff70b69b97455a5968dc1325" @@ -18097,6 +18267,11 @@ to-arraybuffer@^1.0.0: resolved "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -19185,7 +19360,7 @@ which-pm-runs@^1.0.0: resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= -which@^1.2.14, which@^1.2.9, which@^1.3.1: +which@1, which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== From 2a0371c306c7390f48bacef9a3dbc1e0f7c5d254 Mon Sep 17 00:00:00 2001 From: blam Date: Sat, 20 Jun 2020 05:59:40 +0200 Subject: [PATCH 2/6] chore(scaffolder): resetting loading the mock data --- plugins/scaffolder-backend/scripts/mock-data | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/plugins/scaffolder-backend/scripts/mock-data b/plugins/scaffolder-backend/scripts/mock-data index 7f534fec97..be3fa2b6cf 100755 --- a/plugins/scaffolder-backend/scripts/mock-data +++ b/plugins/scaffolder-backend/scripts/mock-data @@ -1,14 +1,8 @@ #!/usr/bin/env bash -# curl \ -# --location \ -# --request POST 'localhost:7000/catalog/locations' \ -# --header 'Content-Type: application/json' \ -# --data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/react-ssr-template/template.yaml\"}" - - curl \ - --location \ - --request POST 'localhost:7000/catalog/locations' \ - --header 'Content-Type: application/json' \ - --data-raw "{\"type\": \"github\", \"target\": \"https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml\"}" +--location \ +--request POST 'localhost:7000/catalog/locations' \ +--header 'Content-Type: application/json' \ +--data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/react-ssr-template/template.yaml\"}" + From a25fc0be9e0781f162868ca57036fc5d7ec96453 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 22 Jun 2020 14:02:22 +0200 Subject: [PATCH 3/6] chore(scaffolder): added some tests for the refactored helper --- .../src/scaffolder/prepare/helpers.test.ts | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 plugins/scaffolder-backend/src/scaffolder/prepare/helpers.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/helpers.test.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/helpers.test.ts new file mode 100644 index 0000000000..6aa940783f --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/helpers.test.ts @@ -0,0 +1,171 @@ +/* + * 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 { parseLocationAnnotation } from './helpers'; +import { + TemplateEntityV1alpha1, + LOCATION_ANNOTATION, +} from '@backstage/catalog-model'; + +describe('Helpers', () => { + describe('parseLocationAnnotation', () => { + it('throws an exception when no annotation location', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + // [LOCATION_ANNOTATION]: + // 'github:https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(() => parseLocationAnnotation(mockEntity)).toThrow( + expect.objectContaining({ + name: 'InputError', + message: `No location annotation provided in entity: ${mockEntity.metadata.name}`, + }), + ); + }); + + it('should throw an error when the protocol part is not set in the location annotation', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: + ':https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(() => parseLocationAnnotation(mockEntity)).toThrow( + expect.objectContaining({ + name: 'InputError', + message: `Failure to parse either protocol or location for entity: ${mockEntity.metadata.name}`, + }), + ); + }); + it('should throw an error when the location part is not set in the location annotation', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: 'github:', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(() => parseLocationAnnotation(mockEntity)).toThrow( + expect.objectContaining({ + name: 'InputError', + message: `Failure to parse either protocol or location for entity: ${mockEntity.metadata.name}`, + }), + ); + }); + + it('should parse the location and protocol correctly for simple locations', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: 'file:./path', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(parseLocationAnnotation(mockEntity)).toEqual({ + protocol: 'file', + location: './path', + }); + }); + + it('should parse the location and protocol correctly for complex with unescaped locations', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: 'github:https://lol.com/:something/shello', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(parseLocationAnnotation(mockEntity)).toEqual({ + protocol: 'github', + location: 'https://lol.com/:something/shello', + }); + }); + }); +}); From 9d5e659df1c33954282ef097490808c0c341b29f Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 22 Jun 2020 14:27:56 +0200 Subject: [PATCH 4/6] chore(scaffolder): added some more tests for the github preparer --- .../src/scaffolder/prepare/github.test.ts | 79 +++++++++++++++++++ .../src/scaffolder/prepare/github.ts | 4 +- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts new file mode 100644 index 0000000000..ecf39cca8e --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts @@ -0,0 +1,79 @@ +/* + * 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. + */ + +const mocks = { + Clone: { clone: jest.fn() }, + CheckoutOptions: jest.fn(() => {}), +}; +jest.doMock('nodegit', () => mocks); +// require('nodegit'); + +import { GithubPreparer } from './github'; +import { + TemplateEntityV1alpha1, + LOCATION_ANNOTATION, +} from '@backstage/catalog-model'; + +describe('GitHubPreparer', () => { + let mockEntity: TemplateEntityV1alpha1; + beforeEach(() => { + jest.clearAllMocks(); + mockEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: + 'github:https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + }); + it('calls the clone command with the correct arguments for a repository', async () => { + const preparer = new GithubPreparer(); + await preparer.prepare(mockEntity); + expect(mocks.Clone.clone).toHaveBeenNthCalledWith( + 1, + 'https://github.com/benjdlambert/backstage-graphql-template', + expect.any(String), + { checkoutOpts: { paths: ['template'] } }, + ); + }); + it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { + const preparer = new GithubPreparer(); + delete mockEntity.spec.path; + await preparer.prepare(mockEntity); + expect(mocks.Clone.clone).toHaveBeenNthCalledWith( + 1, + 'https://github.com/benjdlambert/backstage-graphql-template', + expect.any(String), + { checkoutOpts: {} }, + ); + }); + it('resolves relative path from the template', async () => {}); + it('resolves relative path from the nested template', async () => {}); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts index 3f711bc477..b0ced7db2b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts @@ -46,7 +46,9 @@ export class GithubPreparer implements PreparerBase { ); const checkoutOptions = new CheckoutOptions(); - checkoutOptions.paths = [templateDirectory]; + if (template.spec.path) { + checkoutOptions.paths = [templateDirectory]; + } await Clone.clone(repositoryCheckoutUrl, tempDir, { checkoutOpts: checkoutOptions, From 6ab85e0e389a707b893f7a39c4ce798f57461755 Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 22 Jun 2020 15:56:39 +0200 Subject: [PATCH 5/6] chore(scaffolder): added some more tests to check that the path is returned properly --- .../src/scaffolder/prepare/github.test.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts index ecf39cca8e..44d53248d0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts @@ -74,6 +74,12 @@ describe('GitHubPreparer', () => { { checkoutOpts: {} }, ); }); - it('resolves relative path from the template', async () => {}); - it('resolves relative path from the nested template', async () => {}); + + it('return the temp directory with the path to the folder if it is specified', async () => { + const preparer = new GithubPreparer(); + mockEntity.spec.path = './template/test/1/2/3'; + const response = await preparer.prepare(mockEntity); + + expect(response).toMatch(new RegExp(/\/template\/test\/1\/2\/3$/)); + }); }); From 1302becd63a0e3b149748cf4f9411910d3853c9f Mon Sep 17 00:00:00 2001 From: blam Date: Mon, 22 Jun 2020 16:05:43 +0200 Subject: [PATCH 6/6] chore(scaffolder): Fixing linting issues --- packages/backend/src/plugins/scaffolder.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index e1e8a24fa1..95d28eacb1 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -32,7 +32,5 @@ export default async function createPlugin({ logger }: PluginEnvironment) { preparers.register('file', filePreparer); preparers.register('github', githubPreparer); - const preparers = new Preparers(); - return await createRouter({ preparers, templater, logger }); }