Skip to content

Commit 37a5244

Browse files
author
Mathias Åhsberg
committed
Add initial support for Bitbucket Cloud scaffolding
1 parent d9eba5b commit 37a5244

File tree

3 files changed

+43
-14
lines changed

3 files changed

+43
-14
lines changed

.changeset/bitbucket-scaffolder.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@backstage/plugin-scaffolder-backend': minor
3+
---
4+
5+
Add scaffolding support for Bitbucket Cloud and Server.

plugins/scaffolder-backend/src/scaffolder/stages/prepare/bitbucket.ts

+4-10
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ import { Config } from '@backstage/config';
2626

2727
export class BitbucketPreparer implements PreparerBase {
2828
private readonly privateToken: string;
29-
private readonly user: string;
29+
private readonly username: string;
3030

3131
constructor(config: Config) {
32-
this.user =
32+
this.username =
3333
config.getOptionalString('scaffolder.bitbucket.api.username') ?? '';
3434
this.privateToken =
3535
config.getOptionalString('scaffolder.bitbucket.api.token') ?? '';
@@ -50,13 +50,7 @@ export class BitbucketPreparer implements PreparerBase {
5050
const templateId = template.metadata.name;
5151

5252
const repo = GitUriParser(location);
53-
let repositoryCheckoutUrl;
54-
// could be refactor once https://github.com/IonicaBizau/git-url-parse/pull/117 has been published
55-
if (repo.source === 'bitbucket.org') {
56-
repositoryCheckoutUrl = `${repo.protocol}://${repo.resource}/${repo.owner}/${repo.name}`;
57-
} else {
58-
repositoryCheckoutUrl = `${repo.protocol}://${repo.resource}/scm/${repo.owner}/${repo.name}`;
59-
}
53+
const repositoryCheckoutUrl = repo.toString('https');
6054

6155
const tempDir = await fs.promises.mkdtemp(
6256
path.join(workingDirectory, templateId),
@@ -72,7 +66,7 @@ export class BitbucketPreparer implements PreparerBase {
7266
fetchOpts: {
7367
callbacks: {
7468
credentials: () =>
75-
Cred.userpassPlaintextNew(this.user, this.privateToken),
69+
Cred.userpassPlaintextNew(this.username, this.privateToken),
7670
},
7771
},
7872
}

plugins/scaffolder-backend/src/scaffolder/stages/publish/bitbucket.ts

+34-4
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export class BitbucketPublisher implements PublisherBase {
5050
values: RequiredTemplateValues & Record<string, JsonValue>,
5151
): Promise<PublisherResult> {
5252
const [project, name] = values.storePath.split('/');
53-
if (this.host === 'bitbucket.org') {
53+
if (this.host === 'https://bitbucket.org') {
5454
return this.createBitbucketCloudRepository(project, name);
5555
}
5656
return this.createBitbucketServerRepository(project, name);
@@ -60,9 +60,39 @@ export class BitbucketPublisher implements PublisherBase {
6060
project: string,
6161
name: string,
6262
): Promise<PublisherResult> {
63-
throw new Error(
64-
`Failed to create ${project}/${name} on bitbucket.org which is currently not supported`,
65-
);
63+
let response: Response;
64+
const buffer = Buffer.from(`${this.username}:${this.token}`, 'utf8');
65+
66+
const options: RequestInit = {
67+
method: 'POST',
68+
body: JSON.stringify({}),
69+
headers: {
70+
Authorization: `Basic ${buffer.toString('base64')}`,
71+
'Content-Type': 'application/json',
72+
},
73+
};
74+
try {
75+
response = await fetch(
76+
`https://api.bitbucket.org/2.0/repositories/${project}/${name}`,
77+
options,
78+
);
79+
} catch (e) {
80+
throw new Error(`Unable to create repository, ${e}`);
81+
}
82+
if (response.status === 200) {
83+
const r = await response.json();
84+
let remoteUrl = '';
85+
for (const link of r.links.clone) {
86+
if (link.name === 'https') {
87+
remoteUrl = link.href;
88+
}
89+
}
90+
91+
// TODO use the urlReader to get the defautl branch
92+
const catalogInfoUrl = `${r.links.html.href}/src/master/catalog-info.yaml`;
93+
return { remoteUrl, catalogInfoUrl };
94+
}
95+
throw new Error(`Not a valid response code ${await response.text()}`);
6696
}
6797

6898
private async createBitbucketServerRepository(

0 commit comments

Comments
 (0)