feat(scaffolder): Implementing the VCS steps in the processor

This commit is contained in:
blam
2020-06-28 02:06:33 +02:00
parent 294a2bb923
commit ee205ef23e
8 changed files with 199 additions and 20 deletions
@@ -1,7 +1,3 @@
#!/bin/sh
# Move all template files to the root folder
mv ./* ../
cd ..
rm -rf {{cookiecutter.component_id}}
# # # # # # # #
echo "Could do something here?"
@@ -1,9 +1,6 @@
name: Frontend CI
on:
push:
paths:
- '.'
on: [push, pull_request]
jobs:
build:
@@ -43,6 +43,7 @@ export class FilePreparer implements PreparerBase {
await fs.copy(parentDirectory, tempDir, {
filter: src => src !== location,
recursive: true,
});
return tempDir;
@@ -13,3 +13,64 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Storer } from './types';
import { Octokit } from '@octokit/rest';
import { TemplateEntityV1alpha1 } from '@backstage/catalog-model';
import { JsonValue } from '@backstage/config';
import { RequiredTemplateValues } from '../templater';
import { Repository, Remote, Signature, Cred } from 'nodegit';
import gitUrlParse from 'git-url-parse';
export class GithubStorer implements Storer {
private client: Octokit;
constructor({ client }: { client: Octokit }) {
this.client = client;
}
async createRemote({
values,
}: {
entity: TemplateEntityV1alpha1;
values: RequiredTemplateValues & Record<string, JsonValue>;
}) {
const {
data: { clone_url: cloneUrl },
} = await this.client.repos.createInOrg({
name: values.component_id,
org: values.org as string,
});
console.warn(cloneUrl);
return cloneUrl;
}
async pushToRemote(directory: string, remote: string): Promise<void> {
const repo = await Repository.init(directory, 0);
const index = await repo.refreshIndex();
await index.addAll();
await index.write();
const oid = await index.writeTree();
await repo.createCommit(
'HEAD',
Signature.now('Foo bar', 'foo@bar.com'),
Signature.now('Foo bar', 'foo@bar.com'),
'initial commit',
oid,
[],
);
const remoteRepo = await Remote.create(repo, 'origin', remote);
await remoteRepo.push(['refs/heads/master:refs/heads/master'], {
callbacks: {
credentials: () => {
return Cred.userpassPlaintextNew(
process.env.GITHUB_ACCESS_TOKEN as string,
'x-oauth-basic',
);
},
},
});
}
}
@@ -0,0 +1,23 @@
/*
* 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 { TemplateEntityV1alpha1 } from "@backstage/catalog-model";
import { RequiredTemplateValues } from "../templater";
import { JsonValue } from "@backstage/config";
export type Storer = {
createRemote(opts: { entity: TemplateEntityV1alpha1, values: RequiredTemplateValues & Record<string, JsonValue>}): Promise<string>;
pushToRemote(directory: string, remote: string): Promise<void>;
}
@@ -1,5 +1,3 @@
import { TemplaterBase, TemplaterRunOptions } from '.';
/*
* Copyright 2020 Spotify AB
*
@@ -18,7 +16,8 @@ import { TemplaterBase, TemplaterRunOptions } from '.';
import fs from 'fs-extra';
import { JsonValue } from '@backstage/config';
import { runDockerContainer } from './helpers';
import { TemplaterBase, TemplaterRunOptions } from '.';
import path from 'path';
export class CookieCutter implements TemplaterBase {
private async fetchTemplateCookieCutter(
directory: string,
@@ -66,6 +65,6 @@ export class CookieCutter implements TemplaterBase {
dockerClient: options.dockerClient,
});
return resultDir;
return path.resolve(resultDir, options.values.component_id);
}
}
@@ -22,6 +22,8 @@ import { TemplateEntityV1alpha1 } from '@backstage/catalog-model';
import Docker from 'dockerode';
import {} from '@backstage/backend-common';
import { StageContext } from '../scaffolder/jobs/types';
import { Octokit } from '@octokit/rest';
import { GithubStorer } from '../scaffolder/stages/store/github';
export interface RouterOptions {
preparers: PreparerBuilder;
templater: TemplaterBase;
@@ -33,9 +35,11 @@ export async function createRouter(
options: RouterOptions,
): Promise<express.Router> {
const router = Router();
const { preparers, templater, logger: parentLogger, dockerClient } = options;
const logger = parentLogger.child({ plugin: 'scaffolder' });
const githubClient = new Octokit({ auth: process.env.GITHUB_ACCESS_TOKEN });
const { preparers, templater, logger: parentLogger, dockerClient } = options;
const githubStorer = new GithubStorer({ client: githubClient });
const logger = parentLogger.child({ plugin: 'scaffolder' });
const jobProcessor = new JobProcessor();
router
@@ -83,7 +87,7 @@ export async function createRouter(
metadata: {
annotations: {
'backstage.io/managed-by-location':
'github:https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml',
'file:/Users/blam/dev/spotify/backstage/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml',
},
name: 'graphql-starter',
title: 'GraphQL Service',
@@ -96,13 +100,17 @@ export async function createRouter(
},
spec: {
type: 'cookiecutter',
path: './template',
path: '.',
},
};
const job = jobProcessor.create({
entity: mockEntity,
values: { component_id: 'blob' },
values: {
component_id: `blob${Date.now()}`,
org: 'hojden',
description: 'test',
},
stages: [
{
name: 'Prepare the skeleton',
@@ -131,12 +139,21 @@ export async function createRouter(
name: 'Create VCS Repo',
handler: async (ctx: StageContext<{ resultDir: string }>) => {
ctx.logger.info('Should now create the VCS repo');
const remoteUrl = await githubStorer.createRemote({
values: ctx.values,
entity: ctx.entity,
});
return { remoteUrl };
},
},
{
name: 'Push to remote',
handler: async ctx => {
handler: async (
ctx: StageContext<{ resultDir: string; remoteUrl: string }>,
) => {
ctx.logger.info('Should now push to the remote');
await githubStorer.pushToRemote(ctx.resultDir, ctx.remoteUrl);
},
},
],
+86 -1
View File
@@ -2328,6 +2328,18 @@
dependencies:
"@octokit/types" "^2.0.0"
"@octokit/core@^3.0.0":
version "3.1.0"
resolved "https://registry.npmjs.org/@octokit/core/-/core-3.1.0.tgz#9c3c9b23f7504668cfa057f143ccbf0c645a0ac9"
integrity sha512-yPyQSmxIXLieEIRikk2w8AEtWkFdfG/LXcw1KvEtK3iP0ENZLW/WYQmdzOKqfSaLhooz4CJ9D+WY79C8ZliACw==
dependencies:
"@octokit/auth-token" "^2.4.0"
"@octokit/graphql" "^4.3.1"
"@octokit/request" "^5.4.0"
"@octokit/types" "^5.0.0"
before-after-hook "^2.1.0"
universal-user-agent "^5.0.0"
"@octokit/endpoint@^5.5.0":
version "5.5.3"
resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.3.tgz#0397d1baaca687a4c8454ba424a627699d97c978"
@@ -2337,6 +2349,24 @@
is-plain-object "^3.0.0"
universal-user-agent "^5.0.0"
"@octokit/endpoint@^6.0.1":
version "6.0.3"
resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.3.tgz#dd09b599662d7e1b66374a177ab620d8cdf73487"
integrity sha512-Y900+r0gIz+cWp6ytnkibbD95ucEzDSKzlEnaWS52hbCDNcCJYO5mRmWW7HRAnDc7am+N/5Lnd8MppSaTYx1Yg==
dependencies:
"@octokit/types" "^5.0.0"
is-plain-object "^3.0.0"
universal-user-agent "^5.0.0"
"@octokit/graphql@^4.3.1":
version "4.5.1"
resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.5.1.tgz#162aed1490320b88ce34775b3f6b8de945529fa9"
integrity sha512-qgMsROG9K2KxDs12CO3bySJaYoUu2aic90qpFrv7A8sEBzZ7UFGvdgPKiLw5gOPYEYbS0Xf8Tvf84tJutHPulQ==
dependencies:
"@octokit/request" "^5.3.0"
"@octokit/types" "^5.0.0"
universal-user-agent "^5.0.0"
"@octokit/plugin-enterprise-rest@^6.0.1":
version "6.0.1"
resolved "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437"
@@ -2349,6 +2379,13 @@
dependencies:
"@octokit/types" "^2.0.1"
"@octokit/plugin-paginate-rest@^2.2.0":
version "2.2.3"
resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.2.3.tgz#a6ad4377e7e7832fb4bdd9d421e600cb7640ac27"
integrity sha512-eKTs91wXnJH8Yicwa30jz6DF50kAh7vkcqCQ9D7/tvBAP5KKkg6I2nNof8Mp/65G0Arjsb4QcOJcIEQY+rK1Rg==
dependencies:
"@octokit/types" "^5.0.0"
"@octokit/plugin-request-log@^1.0.0":
version "1.0.0"
resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e"
@@ -2362,6 +2399,14 @@
"@octokit/types" "^2.0.1"
deprecation "^2.3.1"
"@octokit/plugin-rest-endpoint-methods@4.0.0":
version "4.0.0"
resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.0.0.tgz#b02a2006dda8e908c3f8ab381dd5475ef5a810a8"
integrity sha512-emS6gysz4E9BNi9IrCl7Pm4kR+Az3MmVB0/DoDCmF4U48NbYG3weKyDlgkrz6Jbl4Mu4nDx8YWZwC4HjoTdcCA==
dependencies:
"@octokit/types" "^5.0.0"
deprecation "^2.3.1"
"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2":
version "1.2.1"
resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801"
@@ -2371,6 +2416,15 @@
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request-error@^2.0.0":
version "2.0.2"
resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.2.tgz#0e76b83f5d8fdda1db99027ea5f617c2e6ba9ed0"
integrity sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw==
dependencies:
"@octokit/types" "^5.0.1"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^5.2.0":
version "5.3.2"
resolved "https://registry.npmjs.org/@octokit/request/-/request-5.3.2.tgz#1ca8b90a407772a1ee1ab758e7e0aced213b9883"
@@ -2385,6 +2439,20 @@
once "^1.4.0"
universal-user-agent "^5.0.0"
"@octokit/request@^5.3.0", "@octokit/request@^5.4.0":
version "5.4.5"
resolved "https://registry.npmjs.org/@octokit/request/-/request-5.4.5.tgz#8df65bd812047521f7e9db6ff118c06ba84ac10b"
integrity sha512-atAs5GAGbZedvJXXdjtKljin+e2SltEs48B3naJjqWupYl2IUBbB/CJisyjbNHcKpHzb3E+OYEZ46G8eakXgQg==
dependencies:
"@octokit/endpoint" "^6.0.1"
"@octokit/request-error" "^2.0.0"
"@octokit/types" "^5.0.0"
deprecation "^2.0.0"
is-plain-object "^3.0.0"
node-fetch "^2.3.0"
once "^1.4.0"
universal-user-agent "^5.0.0"
"@octokit/rest@^16.28.4":
version "16.43.1"
resolved "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz#3b11e7d1b1ac2bbeeb23b08a17df0b20947eda6b"
@@ -2407,6 +2475,16 @@
once "^1.4.0"
universal-user-agent "^4.0.0"
"@octokit/rest@^18.0.0":
version "18.0.0"
resolved "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.0.tgz#7f401d9ce13530ad743dfd519ae62ce49bcc0358"
integrity sha512-4G/a42lry9NFGuuECnua1R1eoKkdBYJap97jYbWDNYBOUboWcM75GJ1VIcfvwDV/pW0lMPs7CEmhHoVrSV5shg==
dependencies:
"@octokit/core" "^3.0.0"
"@octokit/plugin-paginate-rest" "^2.2.0"
"@octokit/plugin-request-log" "^1.0.0"
"@octokit/plugin-rest-endpoint-methods" "4.0.0"
"@octokit/types@^2.0.0", "@octokit/types@^2.0.1":
version "2.5.0"
resolved "https://registry.npmjs.org/@octokit/types/-/types-2.5.0.tgz#f1bbd147e662ae2c79717d518aac686e58257773"
@@ -2414,6 +2492,13 @@
dependencies:
"@types/node" ">= 8"
"@octokit/types@^5.0.0", "@octokit/types@^5.0.1":
version "5.0.1"
resolved "https://registry.npmjs.org/@octokit/types/-/types-5.0.1.tgz#5459e9a5e9df8565dcc62c17a34491904d71971e"
integrity sha512-GorvORVwp244fGKEt3cgt/P+M0MGy4xEDbckw+K5ojEezxyMDgCaYPKVct+/eWQfZXOT7uq0xRpmrl/+hliabA==
dependencies:
"@types/node" ">= 8"
"@open-draft/until@^1.0.0":
version "1.0.3"
resolved "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca"
@@ -5364,7 +5449,7 @@ bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
dependencies:
tweetnacl "^0.14.3"
before-after-hook@^2.0.0:
before-after-hook@^2.0.0, before-after-hook@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635"
integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==