|
import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; |
|
import { InputError } from '@backstage/errors'; |
|
import { z } from 'zod'; |
|
import { Git } from '@backstage/backend-common'; |
|
import { Config } from '@backstage/config'; |
|
import { ScmIntegrationRegistry } from '@backstage/integration'; |
|
import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; |
|
import fs from 'fs-extra'; |
|
|
|
export const bitbucketClone = (options: { |
|
integrations: ScmIntegrationRegistry; |
|
config: Config; |
|
}) => { |
|
const { integrations, config } = options; |
|
|
|
return createTemplateAction({ |
|
id: 'bitbucket:clone', |
|
schema: { |
|
input: z.object({ |
|
branch: z.string().optional().default('main'), |
|
targetPath: z.string().optional().default('./repository'), |
|
repoUrl: z.string().optional().describe('The remote URL of the file'), |
|
repo: z.string().optional().default(''), |
|
host: z.string().optional().default('bitbucket.org'), |
|
workspace: z.string().optional().default(''), |
|
}), |
|
}, |
|
|
|
async handler(ctx) { |
|
const { |
|
repoUrl, |
|
branch = 'main', |
|
targetPath = './repostiory', |
|
} = ctx.input; |
|
|
|
const { repo, host = 'bitbucket.org', workspace } = repoUrl |
|
? parseRepoUrl(repoUrl, integrations) |
|
: ctx.input; |
|
|
|
if (!workspace || !repo) { |
|
throw new InputError( |
|
`Repository location not configured, please check your input. Either repoUrl or [workspace and repo] must be provided`, |
|
); |
|
} |
|
|
|
const integrationConfig = integrations.bitbucketCloud.byHost(host); |
|
if (!integrationConfig) { |
|
throw new InputError( |
|
`No matching integration configuration for host ${host}, please check your integrations config`, |
|
); |
|
} |
|
|
|
const { username, appPassword } = integrationConfig.config; |
|
if (!username || !appPassword) { |
|
throw new InputError( |
|
`No username or appPassword found for host ${host}, please check your integrations config`, |
|
); |
|
} |
|
|
|
const remoteUrl = `https://${host}/${workspace}/${repo}`; |
|
|
|
await Git.fromAuth({ |
|
username, |
|
password: appPassword, |
|
logger: ctx.logger, |
|
}).clone({ |
|
url: remoteUrl, |
|
dir: `${ctx.workspacePath}/${targetPath}`, |
|
ref: branch, |
|
}); |
|
}, |
|
}); |
|
}; |
|
|
|
export const bitbucketPush = (options: { |
|
integrations: ScmIntegrationRegistry; |
|
config: Config; |
|
}) => { |
|
const { integrations, config } = options; |
|
|
|
return createTemplateAction({ |
|
id: 'bitbucket:push', |
|
schema: { |
|
input: z.object({ |
|
dir: z.string(), |
|
host: z.string().optional().default('bitbucket.org'), |
|
gitAuthorName: z.string().optional(), |
|
gitAuthorEmail: z.string().optional(), |
|
}), |
|
output: z.object({ |
|
commitsha: z.string().nullable(), |
|
}), |
|
}, |
|
|
|
async handler(ctx) { |
|
const { |
|
dir, |
|
host = 'bitbucket.org', |
|
gitAuthorEmail, |
|
gitAuthorName, |
|
} = ctx.input; |
|
|
|
if (!host) { |
|
throw new InputError(`host not configured, please check your input`); |
|
} |
|
|
|
const integrationConfig = integrations.bitbucketCloud.byHost(host); |
|
if (!integrationConfig) { |
|
throw new InputError( |
|
`No matching integration configuration for host ${host}, please check your integrations config`, |
|
); |
|
} |
|
|
|
const { username, appPassword } = integrationConfig.config; |
|
if (!username || !appPassword) { |
|
throw new InputError( |
|
`No username or appPassword found for host ${host}, please check your integrations config`, |
|
); |
|
} |
|
|
|
const git = Git.fromAuth({ |
|
username, |
|
password: appPassword, |
|
logger: ctx.logger, |
|
}); |
|
|
|
await git.add({ |
|
dir: `${ctx.workspacePath}/${dir}`, |
|
filepath: '.', |
|
}); |
|
|
|
const gitAuthorInfo = { |
|
name: gitAuthorName |
|
? gitAuthorName |
|
: config.getOptionalString('scaffolder.defaultAuthor.name'), |
|
email: gitAuthorEmail |
|
? gitAuthorEmail |
|
: config.getOptionalString('scaffolder.defaultAuthor.email'), |
|
}; |
|
|
|
const authorInfo = { |
|
name: gitAuthorInfo?.name ?? 'Scaffolder', |
|
email: gitAuthorInfo?.email ?? 'scaffolder@backstage.io', |
|
}; |
|
|
|
const commitHash = await git.commit({ |
|
dir: `${ctx.workspacePath}/${dir}`, |
|
message: 'New commit from Scaffolder', |
|
author: authorInfo, |
|
committer: authorInfo, |
|
}); |
|
|
|
await git.push({ |
|
dir: `${ctx.workspacePath}/${dir}`, |
|
remote: 'origin', |
|
}); |
|
|
|
ctx.output('commitsha', commitHash); |
|
}, |
|
}); |
|
}; |
|
|
|
export const createFile = () => { |
|
return createTemplateAction({ |
|
id: 'create:file', |
|
schema: { |
|
input: z.object({ |
|
contents: z.string().describe('The contents of the file'), |
|
filename: z |
|
.string() |
|
.describe('The filename of the file that will be created'), |
|
}), |
|
}, |
|
|
|
async handler(ctx) { |
|
const { filename, contents } = ctx.input; |
|
await fs.outputFile(`${ctx.workspacePath}/${filename}`, contents); |
|
}, |
|
}); |
|
}; |