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);
},
},
],