feat(createBuiltinActions): adds bitbucket:pipelines:run action to built in actions
Signed-off-by: Matthew Prinold <matthewprinold@gmail.com>
This commit is contained in:
+14
-6
@@ -47,6 +47,14 @@ describe('bitbucket:pipelines:run', () => {
|
||||
output: jest.fn(),
|
||||
createTemporaryDirectory: jest.fn(),
|
||||
};
|
||||
const responseJson = {
|
||||
repository: {
|
||||
links: {
|
||||
html: { href: 'https://bitbucket.org/test-workspace/test-repo-slug' },
|
||||
},
|
||||
},
|
||||
build_number: 1,
|
||||
};
|
||||
const worker = setupServer();
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
@@ -71,7 +79,7 @@ describe('bitbucket:pipelines:run', () => {
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json({}),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -103,7 +111,7 @@ describe('bitbucket:pipelines:run', () => {
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json({}),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -137,7 +145,7 @@ describe('bitbucket:pipelines:run', () => {
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json({}),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -173,7 +181,7 @@ describe('bitbucket:pipelines:run', () => {
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json({}),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -212,7 +220,7 @@ describe('bitbucket:pipelines:run', () => {
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json({}),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -253,7 +261,7 @@ describe('bitbucket:pipelines:run', () => {
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json({}),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
+82
-4
@@ -45,6 +45,16 @@ describe('bitbucket:pipelines:run', () => {
|
||||
output: jest.fn(),
|
||||
createTemporaryDirectory: jest.fn(),
|
||||
};
|
||||
const workspace = 'test-workspace';
|
||||
const repo_slug = 'test-repo-slug';
|
||||
const responseJson = {
|
||||
repository: {
|
||||
links: {
|
||||
html: { href: 'https://bitbucket.org/test-workspace/test-repo-slug' },
|
||||
},
|
||||
},
|
||||
build_number: 1,
|
||||
};
|
||||
const worker = setupServer();
|
||||
setupRequestMockHandlers(worker);
|
||||
|
||||
@@ -52,10 +62,27 @@ describe('bitbucket:pipelines:run', () => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should call the bitbucket api for running a pipeline', async () => {
|
||||
it('should throw if there is no integration credentials or token provided', async () => {
|
||||
const configNoCreds = new ConfigReader({
|
||||
integrations: {
|
||||
bitbucketCloud: [],
|
||||
},
|
||||
});
|
||||
|
||||
const integrationsNoCreds = ScmIntegrations.fromConfig(configNoCreds);
|
||||
const actionNoCreds = createBitbucketPipelinesRunAction({
|
||||
integrations: integrationsNoCreds,
|
||||
});
|
||||
const testContext = Object.assign({}, mockContext, {
|
||||
input: { workspace, repo_slug },
|
||||
});
|
||||
await expect(actionNoCreds.handler(testContext)).rejects.toThrow(
|
||||
/Authorization has not been provided for Bitbucket Cloud/,
|
||||
);
|
||||
});
|
||||
|
||||
it('should call the bitbucket api for running a pipeline with integration credentials', async () => {
|
||||
expect.assertions(1);
|
||||
const workspace = 'test-workspace';
|
||||
const repo_slug = 'test-repo-slug';
|
||||
worker.use(
|
||||
rest.post(
|
||||
`https://api.bitbucket.org/2.0/repositories/${workspace}/${repo_slug}/pipelines`,
|
||||
@@ -64,7 +91,7 @@ describe('bitbucket:pipelines:run', () => {
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json({}),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -75,4 +102,55 @@ describe('bitbucket:pipelines:run', () => {
|
||||
});
|
||||
await action.handler(testContext);
|
||||
});
|
||||
|
||||
it('should call the bitbucket api for running a pipeline with input token', async () => {
|
||||
expect.assertions(1);
|
||||
worker.use(
|
||||
rest.post(
|
||||
`https://api.bitbucket.org/2.0/repositories/${workspace}/${repo_slug}/pipelines`,
|
||||
(req, res, ctx) => {
|
||||
expect(req.headers.get('Authorization')).toBe('Bearer abc');
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const testContext = Object.assign({}, mockContext, {
|
||||
input: { workspace, repo_slug, token: 'abc' },
|
||||
});
|
||||
await action.handler(testContext);
|
||||
});
|
||||
|
||||
it('should call outputs with the correct data', async () => {
|
||||
worker.use(
|
||||
rest.post(
|
||||
`https://api.bitbucket.org/2.0/repositories/${workspace}/${repo_slug}/pipelines`,
|
||||
(_, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(201),
|
||||
ctx.set('Content-Type', 'application/json'),
|
||||
ctx.json(responseJson),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const testContext = Object.assign({}, mockContext, {
|
||||
input: { workspace, repo_slug, token: 'abc' },
|
||||
});
|
||||
await action.handler(testContext);
|
||||
expect(testContext.output).toHaveBeenCalledWith('buildNumber', 1);
|
||||
expect(testContext.output).toHaveBeenCalledWith(
|
||||
'repoUrl',
|
||||
'https://bitbucket.org/test-workspace/test-repo-slug',
|
||||
);
|
||||
expect(testContext.output).toHaveBeenCalledWith(
|
||||
'pipelinesUrl',
|
||||
'https://bitbucket.org/test-workspace/test-repo-slug/pipelines',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+39
-12
@@ -16,10 +16,9 @@
|
||||
|
||||
import { examples } from './bitbucketCloudPipelinesRun.examples';
|
||||
import { createTemplateAction } from '@backstage/plugin-scaffolder-node';
|
||||
import fetch from 'node-fetch';
|
||||
import fetch, { Response } from 'node-fetch';
|
||||
import * as inputProps from './inputProperties';
|
||||
import { ScmIntegrationRegistry } from '@backstage/integration';
|
||||
import { InputError } from '@backstage/errors';
|
||||
import { getAuthorizationHeader } from './helpers';
|
||||
|
||||
const id = 'bitbucket:pipelines:run';
|
||||
@@ -44,7 +43,7 @@ export const createBitbucketPipelinesRunAction = (options: {
|
||||
schema: {
|
||||
input: {
|
||||
type: 'object',
|
||||
required: ['workspace', 'repo_url'],
|
||||
required: ['workspace', 'repo_slug'],
|
||||
properties: {
|
||||
workspace: inputProps.workspace,
|
||||
repo_slug: inputProps.repo_slug,
|
||||
@@ -52,24 +51,36 @@ export const createBitbucketPipelinesRunAction = (options: {
|
||||
token: inputProps.token,
|
||||
},
|
||||
},
|
||||
output: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
buildNumber: {
|
||||
title: 'Build number',
|
||||
type: 'number',
|
||||
},
|
||||
repoUrl: {
|
||||
title: 'A URL to the pipeline repositry',
|
||||
type: 'string',
|
||||
},
|
||||
repoContentsUrl: {
|
||||
title: 'A URL to the pipeline',
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
supportsDryRun: false,
|
||||
async handler(ctx) {
|
||||
const { workspace, repo_slug, body, token } = ctx.input;
|
||||
const host = 'bitbucket.org';
|
||||
const integrationConfig = integrations.bitbucketCloud.byHost(host);
|
||||
if (!integrationConfig) {
|
||||
throw new InputError(
|
||||
`No matching integration configuration for host ${host}, please check your integrations config`,
|
||||
);
|
||||
}
|
||||
|
||||
const authorization = getAuthorizationHeader(
|
||||
token ? { token } : integrationConfig.config,
|
||||
token ? { token } : integrationConfig!.config,
|
||||
);
|
||||
|
||||
let response: Response;
|
||||
try {
|
||||
const response = await fetch(
|
||||
response = await fetch(
|
||||
`https://api.bitbucket.org/2.0/repositories/${workspace}/${repo_slug}/pipelines`,
|
||||
{
|
||||
method: 'POST',
|
||||
@@ -81,10 +92,26 @@ export const createBitbucketPipelinesRunAction = (options: {
|
||||
body: JSON.stringify(body) ?? {},
|
||||
},
|
||||
);
|
||||
const data = await response.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Unable to run pipeline, ${e}`);
|
||||
}
|
||||
|
||||
if (response.status !== 201) {
|
||||
throw new Error(
|
||||
`Unable to run pipeline, ${response.status} ${
|
||||
response.statusText
|
||||
}, ${await response.text()}`,
|
||||
);
|
||||
}
|
||||
|
||||
const responseObject = await response.json();
|
||||
|
||||
ctx.output('buildNumber', responseObject.build_number);
|
||||
ctx.output('repoUrl', responseObject.repository.links.html.href);
|
||||
ctx.output(
|
||||
'pipelinesUrl',
|
||||
`${responseObject.repository.links.html.href}/pipelines`,
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -60,6 +60,7 @@ import {
|
||||
createPublishBitbucketCloudAction,
|
||||
createPublishBitbucketServerAction,
|
||||
createPublishBitbucketServerPullRequestAction,
|
||||
createBitbucketPipelinesRunAction,
|
||||
} from '@backstage/plugin-scaffolder-backend-module-bitbucket';
|
||||
|
||||
import {
|
||||
@@ -223,6 +224,9 @@ export const createBuiltinActions = (
|
||||
integrations,
|
||||
githubCredentialsProvider,
|
||||
}),
|
||||
createBitbucketPipelinesRunAction({
|
||||
integrations,
|
||||
}),
|
||||
];
|
||||
|
||||
return actions as TemplateAction[];
|
||||
|
||||
Reference in New Issue
Block a user