Use integration config in bitbucket preparer

This commit is contained in:
Johan Haals
2021-01-18 10:13:07 +01:00
parent 7c52806a48
commit fdecdfd747
@@ -16,19 +16,54 @@
import { PublisherBase, PublisherOptions, PublisherResult } from './types';
import { initRepoAndPush } from './helpers';
import { RequiredTemplateValues } from '../templater';
import { JsonValue } from '../../../../../../packages/config/src';
import fetch from 'cross-fetch';
import { Config } from '@backstage/config';
import {
BitbucketIntegrationConfig,
readBitbucketIntegrationConfigs,
} from '@backstage/integration';
import { Logger } from 'winston';
import gitUrlParse from 'git-url-parse';
export class BitbucketPublisher implements PublisherBase {
private readonly host: string;
private readonly username: string;
private readonly token: string;
private readonly host?: string;
private readonly username?: string;
private readonly token?: string;
private readonly integrations: BitbucketIntegrationConfig[];
constructor(host: string, username: string, token: string) {
this.host = host;
this.username = username;
this.token = token;
constructor(config: Config, { logger }: { logger: Logger }) {
this.integrations = readBitbucketIntegrationConfigs(
config.getOptionalConfigArray('integrations.bitbucket') ?? [],
);
if (!this.integrations.length) {
logger.warn(
'Integrations for Bitbucket in Scaffolder are not set. This will cause errors in a future release. Please migrate to using integrations config and specifying tokens under hostnames',
);
}
this.token = config.getOptionalString('scaffolder.bitbucket.api.token');
if (this.token) {
logger.warn(
"DEPRECATION: Using the token format under 'scaffolder.bitbucket.api.token' will not be respected in future releases. Please consider using integrations config instead",
);
}
this.host = config.getOptionalString('scaffolder.bitbucket.api.host');
if (this.host) {
logger.warn(
"DEPRECATION: Using the apiBaseUrl format under 'scaffolder.bitbucket.api.host' will not be respected in future releases. Please consider using integrations config instead",
);
}
this.username = config.getOptionalString(
'scaffolder.bitbucket.api.username',
);
if (this.username) {
logger.warn(
"DEPRECATION: Using the apiBaseUrl format under 'scaffolder.bitbucket.api.username' will not be respected in future releases. Please consider using integrations config instead",
);
}
}
async publish({
@@ -36,33 +71,61 @@ export class BitbucketPublisher implements PublisherBase {
directory,
logger,
}: PublisherOptions): Promise<PublisherResult> {
const result = await this.createRemote(values);
const { resource: host, owner: project, name } = gitUrlParse(
values.storePath,
);
const token = this.getToken(host);
if (!token) {
throw new Error('No token provided to create the remote repository');
}
const username = this.getUsername(host);
if (!username) {
throw new Error('No username provided to create the remote repository');
}
const apiUrl = this.getHost(host);
if (!apiUrl) {
throw new Error('No host provided to create the remote repository');
}
const description = values.description as string;
const result = await this.createRemote({
project,
name,
description,
host,
});
await initRepoAndPush({
dir: directory,
remoteUrl: result.remoteUrl,
auth: {
username: this.username,
password: this.token,
username: username,
password: token,
},
logger,
});
return result;
}
private async createRemote(
values: RequiredTemplateValues & Record<string, JsonValue>,
): Promise<PublisherResult> {
if (this.host === 'https://bitbucket.org') {
return this.createBitbucketCloudRepository(values);
private async createRemote(opts: {
project: string;
name: string;
description: string;
host: string;
}): Promise<PublisherResult> {
if (opts.host === 'https://bitbucket.org') {
return this.createBitbucketCloudRepository(opts);
}
return this.createBitbucketServerRepository(values);
return this.createBitbucketServerRepository(opts);
}
private async createBitbucketCloudRepository(
values: RequiredTemplateValues & Record<string, JsonValue>,
): Promise<PublisherResult> {
const [project, name] = values.storePath.split('/');
private async createBitbucketCloudRepository(opts: {
project: string;
name: string;
description: string;
}): Promise<PublisherResult> {
const { project, name, description } = opts;
let response: Response;
const buffer = Buffer.from(`${this.username}:${this.token}`, 'utf8');
@@ -71,7 +134,7 @@ export class BitbucketPublisher implements PublisherBase {
method: 'POST',
body: JSON.stringify({
scm: 'git',
description: values.description,
description: description,
}),
headers: {
Authorization: `Basic ${buffer.toString('base64')}`,
@@ -102,17 +165,19 @@ export class BitbucketPublisher implements PublisherBase {
throw new Error(`Not a valid response code ${await response.text()}`);
}
private async createBitbucketServerRepository(
values: RequiredTemplateValues & Record<string, JsonValue>,
): Promise<PublisherResult> {
const [project, name] = values.storePath.split('/');
private async createBitbucketServerRepository(opts: {
project: string;
name: string;
description: string;
}): Promise<PublisherResult> {
const { project, name, description } = opts;
let response: Response;
const options: RequestInit = {
method: 'POST',
body: JSON.stringify({
name: name,
description: values.description,
description: description,
}),
headers: {
Authorization: `Bearer ${this.token}`,
@@ -140,4 +205,18 @@ export class BitbucketPublisher implements PublisherBase {
}
throw new Error(`Not a valid response code ${await response.text()}`);
}
private getToken(host: string): string | undefined {
return this.token || this.integrations.find(c => c.host === host)?.token;
}
private getUsername(host: string): string | undefined {
return (
this.username || this.integrations.find(c => c.host === host)?.username
);
}
private getHost(host: string): string | undefined {
return this.host || this.integrations.find(c => c.host === host)?.host;
}
}