Merge pull request #3778 from backstage/freben/scaffold-gitlab

scaffolder-backend: gitlab preparer uses integrations token
This commit is contained in:
Ben Lambert
2020-12-19 01:53:58 +01:00
committed by GitHub
4 changed files with 66 additions and 20 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
GitLab preparer uses the right token (primarily the same one as the publisher, falling back to the integrations token)
+1
View File
@@ -32,6 +32,7 @@
"@backstage/backend-common": "^0.4.1",
"@backstage/catalog-model": "^0.6.0",
"@backstage/config": "^0.1.2",
"@backstage/integration": "^0.1.4",
"@gitbeaker/core": "^25.2.0",
"@gitbeaker/node": "^25.2.0",
"@octokit/rest": "^18.0.0",
@@ -42,7 +42,7 @@ const mockEntityWithProtocol = (protocol: string): TemplateEntityV1alpha1 => ({
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',
'A GraphQL starter template for backstage to get you up and running\nthe best practices with GraphQL\n',
uid: '9cf16bad-16e0-4213-b314-c4eec773c50b',
etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2',
generation: 1,
@@ -89,16 +89,41 @@ describe('GitLabPreparer', () => {
);
});
it(`calls the clone command with the correct arguments if an access token is provided for a repository using the ${protocol} protocol`, async () => {
it(`calls the clone command with the correct arguments if an access token is provided in integrations for a repository using the ${protocol} protocol`, async () => {
const preparer = new GitlabPreparer(
new ConfigReader({
catalog: {
processors: {
gitlabApi: {
privateToken: 'fake-token',
integrations: {
gitlab: [
{
host: 'gitlab.com',
token: 'fake-token',
},
],
},
}),
);
mockEntity = mockEntityWithProtocol(protocol);
await preparer.prepare(mockEntity, { logger: getVoidLogger() });
expect(mocks.Clone.clone).toHaveBeenNthCalledWith(
1,
'https://gitlab.com/benjdlambert/backstage-graphql-template',
expect.any(String),
{
fetchOpts: {
callbacks: {
credentials: expect.anything(),
},
},
},
);
});
it(`calls the clone command with the correct arguments if an access token is provided in scaffolder for a repository using the ${protocol} protocol`, async () => {
const preparer = new GitlabPreparer(
new ConfigReader({
scaffolder: {
gitlab: { api: { token: 'fake-token' } },
},
}),
);
mockEntity = mockEntityWithProtocol(protocol);
@@ -13,24 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import os from 'os';
import fs from 'fs-extra';
import path from 'path';
import { TemplateEntityV1alpha1 } from '@backstage/catalog-model';
import { parseLocationAnnotation } from '../helpers';
import { InputError } from '@backstage/backend-common';
import { PreparerBase, PreparerOptions } from './types';
import { TemplateEntityV1alpha1 } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import {
GitLabIntegrationConfig,
readGitLabIntegrationConfigs,
} from '@backstage/integration';
import fs from 'fs-extra';
import GitUriParser from 'git-url-parse';
import { Clone, Cred } from 'nodegit';
import { Config } from '@backstage/config';
import os from 'os';
import path from 'path';
import { parseLocationAnnotation } from '../helpers';
import { PreparerBase, PreparerOptions } from './types';
export class GitlabPreparer implements PreparerBase {
private readonly privateToken: string;
private readonly integrations: GitLabIntegrationConfig[];
private readonly scaffolderToken: string | undefined;
constructor(config: Config) {
this.privateToken =
config.getOptionalString('catalog.processors.gitlabApi.privateToken') ??
'';
this.integrations = readGitLabIntegrationConfigs(
config.getOptionalConfigArray('integrations.gitlab') ?? [],
);
this.scaffolderToken = config.getOptionalString(
'scaffolder.gitlab.api.token',
);
}
async prepare(
@@ -58,12 +66,12 @@ export class GitlabPreparer implements PreparerBase {
template.spec.path ?? '.',
);
const options = this.privateToken
const token = this.getToken(parsedGitLocation.resource);
const options = token
? {
fetchOpts: {
callbacks: {
credentials: () =>
Cred.userpassPlaintextNew('oauth2', this.privateToken),
credentials: () => Cred.userpassPlaintextNew('oauth2', token),
},
},
}
@@ -73,4 +81,11 @@ export class GitlabPreparer implements PreparerBase {
return path.resolve(tempDir, templateDirectory);
}
private getToken(host: string): string | undefined {
return (
this.scaffolderToken ||
this.integrations.find(c => c.host === host)?.token
);
}
}