diff --git a/packages/backend-common/src/scm/git.ts b/packages/backend-common/src/scm/git.ts index 25115bab26..7e31b4e8e1 100644 --- a/packages/backend-common/src/scm/git.ts +++ b/packages/backend-common/src/scm/git.ts @@ -25,6 +25,8 @@ GitHub App token 'x-access-token' BitBucket 'x-token-auth' token GitLab 'oauth2' token From : https://isomorphic-git.org/docs/en/onAuth + +Azure 'notempty' token */ class SCM { constructor( diff --git a/packages/backend-common/src/scm/index.ts b/packages/backend-common/src/scm/index.ts index 76af535fd0..83a59310cd 100644 --- a/packages/backend-common/src/scm/index.ts +++ b/packages/backend-common/src/scm/index.ts @@ -13,4 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * as Git from './git'; +import * as Git from './git'; + +export { Git }; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.ts index 1e962bf223..16956cc8fb 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/azure.ts @@ -16,8 +16,8 @@ import { PublisherBase, PublisherOptions, PublisherResult } from './types'; import { GitApi } from 'azure-devops-node-api/GitApi'; +import { Git } from '@backstage/backend-common'; import { GitRepositoryCreateOptions } from 'azure-devops-node-api/interfaces/GitInterfaces'; -import { pushToRemoteUserPass } from './helpers'; import { JsonValue } from '@backstage/config'; import { RequiredTemplateValues } from '../templater'; @@ -33,11 +33,28 @@ export class AzurePublisher implements PublisherBase { async publish({ values, directory, + logger, }: PublisherOptions): Promise { const remoteUrl = await this.createRemote(values); - await pushToRemoteUserPass(directory, remoteUrl, 'notempty', this.token); const catalogInfoUrl = `${remoteUrl}?path=%2Fcatalog-info.yaml`; + const git = Git.fromAuth({ + username: 'notempty', + password: this.token, + logger, + }); + + await git.addRemote({ + dir: directory, + url: remoteUrl, + remoteName: 'origin', + }); + + await git.push({ + dir: directory, + remoteName: 'origin', + }); + return { remoteUrl, catalogInfoUrl }; } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts index 4fae8e8a5c..32b203bf51 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/gitlab.ts @@ -16,7 +16,7 @@ import { PublisherBase, PublisherOptions, PublisherResult } from './types'; import { Gitlab } from '@gitbeaker/core'; -import { pushToRemoteUserPass } from './helpers'; +import { Git } from '@backstage/backend-common'; import { JsonValue } from '@backstage/config'; import { RequiredTemplateValues } from '../templater'; @@ -32,9 +32,26 @@ export class GitlabPublisher implements PublisherBase { async publish({ values, directory, + logger, }: PublisherOptions): Promise { const remoteUrl = await this.createRemote(values); - await pushToRemoteUserPass(directory, remoteUrl, 'oauth2', this.token); + + const git = Git.fromAuth({ + password: this.token, + username: 'oauth2', + logger, + }); + + await git.addRemote({ + dir: directory, + url: remoteUrl, + remoteName: 'origin', + }); + + await git.push({ + dir: directory, + remoteName: 'origin', + }); return { remoteUrl }; } diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts new file mode 100644 index 0000000000..1dcf3fdee1 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/helpers.ts @@ -0,0 +1,85 @@ +/* + * 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 git from 'isomorphic-git'; +import globby from 'globby'; +import fs from 'fs'; +import http from 'isomorphic-git/http/node'; +import { Logger } from 'winston'; +/* +username password +GitHub | token 'x-oauth-basic' +GitHub App | token 'x-access-token' +BitBucket | 'x-token-auth' token +GitLab | 'oauth2' token +From : https://isomorphic-git.org/docs/en/onAuth +*/ +export async function push( + dir: string, + remote: string, + logger: Logger, + auth: { username: string; password: string }, +): Promise { + logger.info('Initializing Git Repo', dir); + await git.init({ + fs, + dir, + }); + + const paths = await globby(['./**', './**/.*'], { + cwd: dir, + gitignore: true, + }); + + logger.info('Adding files to repository', dir); + for (const filepath of paths) { + await git.add({ fs, dir, filepath }); + } + + logger.info('Creating commit', dir); + await git.commit({ + fs, + dir, + message: 'Initial commit', + author: { name: 'Scaffolder', email: 'scaffolder@backstage.io' }, + committer: { name: 'Scaffolder', email: 'scaffolder@backstage.io' }, + }); + + await git.addRemote({ + fs, + dir, + remote: 'origin', + url: remote, + }); + + logger.info('Pushing code to remote', remote); + await git.push({ + fs, + dir, + http, + headers: { + 'user-agent': 'git/@isomorphic-git', + }, + onProgress: event => { + const total = event.total + ? `${Math.round((event.loaded / event.total) * 100)}%` + : event.loaded; + logger.info(`status={${event.phase},total={${total}}}`); + }, + remote: 'origin', + onAuth: () => auth, + }); +}