Skip to content
This repository was archived by the owner on Jun 28, 2022. It is now read-only.

Commit

Permalink
fix: github pipelines (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
arantespp authored Sep 23, 2021
1 parent 0093fa0 commit f112b63
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 233 deletions.
9 changes: 5 additions & 4 deletions packages/cli/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ module.exports = {
collectCoverage: true,
coverageThreshold: {
global: {
branches: 30,
functions: 50,
lines: 55,
statements: 60,
branches: 34,
functions: 54,
lines: 59,
statements: 62,
},
},
preset: 'ts-jest',
setupFiles: ['<rootDir>/setupTests.js'],
silent: true,
};
5 changes: 1 addition & 4 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@
"@octokit/webhooks": "^9.6.0",
"@slack/webhook": "^6.0.0",
"adm-zip": "^0.5.5",
"app-root-path": "^3.0.0",
"aws-sdk": "^2.906.0",
"builtin-modules": "^3.2.0",
"change-case": "^4.1.2",
"deep-equal": "^2.0.5",
"deepmerge": "^4.2.2",
"dotenv": "^10.0.0",
"esbuild": "^0.12.26",
"find-up": "^5.0.0",
"glob": "^7.1.7",
Expand All @@ -56,12 +56,9 @@
},
"devDependencies": {
"@types/adm-zip": "^0.4.34",
"@types/app-root-path": "^1.2.4",
"@types/aws-lambda": "^8.10.76",
"@types/deep-equal": "^1.0.1",
"@types/eslint": "^7.2.10",
"@types/faker": "^5.5.5",
"@types/jest": "^26.0.23",
"@types/js-yaml": "^4.0.1",
"@types/mime-types": "^2.1.0",
"@types/node": "^15.0.3",
Expand Down
121 changes: 107 additions & 14 deletions packages/cli/src/deploy/cicd/lambdas/githubWebhooksApiV1.handler.spec.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
/* eslint-disable import/first */

// const webhooksOnErrorMock = jest.fn();

// const webhooksReceiveMock = jest.fn();

// jest.mock('@octokit/webhooks', () => ({
// Webhooks: jest.fn().mockReturnValue({
// onError: webhooksOnErrorMock,
// receive: webhooksReceiveMock,
// }),
// }));

const putObjectMock = jest.fn().mockReturnValue({ promise: jest.fn() });

jest.mock('aws-sdk', () => ({
Expand All @@ -20,6 +9,13 @@ jest.mock('aws-sdk', () => ({
}),
}));

const executeTasksMock = jest.fn();

jest.mock('./executeTasks', () => ({
executeTasks: executeTasksMock,
shConditionalCommands: jest.fn(),
}));

import {
githubWebhooksApiV1Handler,
webhooks,
Expand All @@ -44,12 +40,78 @@ beforeEach(() => {
delete process.env.PIPELINES_JSON;
delete process.env.TRIGGER_PIPELINES_OBJECT_KEY_PREFIX;
delete process.env.BASE_STACK_BUCKET_NAME;
});

webhooksReceiveMock.mockClear();
afterEach(() => {
jest.clearAllMocks();
});

test('should call S3 putObject', async () => {
process.env.PIPELINES_JSON = JSON.stringify(['main']);
test.each([['opened'], ['reopened'], ['synchronize']])(
'should execute pr handler with action %s',
async (action) => {
process.env.PIPELINES_JSON = JSON.stringify(['main', 'pr']);

const response = await handler({
headers: {
'X-GitHub-Delivery': xGitHubDelivery,
'X-GitHub-Event': 'pull_request',
'X-Hub-Signature-256': xHubSignature,
},
body: JSON.stringify({
action,
number: 1,
pull_request: {
draft: false,
head: {},
},
}),
});

expect(executeTasksMock).toHaveBeenCalledTimes(1);

expect(response).toMatchObject({ body: '{"ok":true}', statusCode: 200 });
},
);

test('should execute main handler only one time per webhook', async () => {
process.env.PIPELINES_JSON = JSON.stringify(['main', 'pr']);
process.env.TRIGGER_PIPELINES_OBJECT_KEY_PREFIX = 'some/prefix';
process.env.BASE_STACK_BUCKET_NAME = 'base-stack';

/**
* Execute first to add the main and pr listeners.
*/
await handler({
headers: {
'X-GitHub-Delivery': xGitHubDelivery,
'X-GitHub-Event': 'push',
'X-Hub-Signature-256': xHubSignature,
},
body: JSON.stringify({}),
});

await handler({
headers: {
'X-GitHub-Delivery': xGitHubDelivery,
'X-GitHub-Event': 'push',
'X-Hub-Signature-256': xHubSignature,
},
body: JSON.stringify({ ref: 'refs/heads/main' }),
});

expect(putObjectMock).toHaveBeenCalledWith(
expect.objectContaining({
Body: expect.any(Buffer),
Bucket: 'base-stack',
Key: 'some/prefix/main.zip',
}),
);

expect(putObjectMock).toHaveBeenCalledTimes(1);
});

test('should call S3 putObject for tag', async () => {
process.env.PIPELINES_JSON = JSON.stringify(['tag', 'main']);
process.env.TRIGGER_PIPELINES_OBJECT_KEY_PREFIX = 'some/prefix';
process.env.BASE_STACK_BUCKET_NAME = 'base-stack';

Expand All @@ -72,6 +134,37 @@ test('should call S3 putObject', async () => {
}),
);

expect(putObjectMock).toHaveBeenCalledTimes(1);

expect(response).toMatchObject({ body: '{"ok":true}', statusCode: 200 });
});

test('should call S3 putObject for main', async () => {
process.env.PIPELINES_JSON = JSON.stringify(['tag', 'main']);
process.env.TRIGGER_PIPELINES_OBJECT_KEY_PREFIX = 'some/prefix';
process.env.BASE_STACK_BUCKET_NAME = 'base-stack';

const body = { ref: 'refs/tags/' };

const response: any = await handler({
headers: {
'X-GitHub-Delivery': xGitHubDelivery,
'X-GitHub-Event': 'push',
'X-Hub-Signature-256': xHubSignature,
},
body: JSON.stringify(body),
});

expect(putObjectMock).toHaveBeenCalledWith(
expect.objectContaining({
Body: expect.any(Buffer),
Bucket: 'base-stack',
Key: 'some/prefix/tag.zip',
}),
);

expect(putObjectMock).toHaveBeenCalledTimes(1);

expect(response).toMatchObject({ body: '{"ok":true}', statusCode: 200 });
});

Expand Down
179 changes: 93 additions & 86 deletions packages/cli/src/deploy/cicd/lambdas/githubWebhooksApiV1.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ import { getProcessEnvVariable } from './getProcessEnvVariable';

const s3 = new S3();

/**
* Put outside of the handler to be able to spy on it.
*/
export const webhooks = new Webhooks({ secret: '123' });

/**
* When this file is saved on S3, a CodePipeline pipeline is started.
*/
Expand Down Expand Up @@ -43,6 +38,99 @@ const putJobDetails = async ({
.promise();
};

/**
* Put outside of the handler to be able to spy on it.
*/
export const webhooks = new Webhooks({ secret: '123' });

const getPipelines = () => {
const pipelines: Pipeline[] = JSON.parse(
process.env.PIPELINES_JSON || JSON.stringify([]),
);

return pipelines;
};

webhooks.on('push', async (details) => {
if (!getPipelines().includes('tag')) {
return;
}

if (details.payload.ref.startsWith('refs/tags/')) {
await putJobDetails({ pipeline: 'tag', details });
}
});

webhooks.on('push', async (details) => {
if (!getPipelines().includes('main')) {
return;
}

if (details.payload.ref === 'refs/heads/main') {
await putJobDetails({ pipeline: 'main', details });
}
});

webhooks.on(
['pull_request.opened', 'pull_request.reopened', 'pull_request.synchronize'],
async ({ payload }) => {
if (!getPipelines().includes('pr')) {
return;
}

if (payload.pull_request.draft) {
return;
}

await executeTasks({
commands: [
shConditionalCommands({
conditionalCommands: getPrCommands({
branch: payload.pull_request.head.ref,
}),
}),
],
tags: [
{ key: 'Pipeline', value: 'pr' },
{ key: 'PullRequest', value: payload.number.toString() },
{ key: 'PullRequestTitle', value: payload.pull_request.title },
{ key: 'PullRequestUrl', value: payload.pull_request.url },
{ key: 'Action', value: payload.action },
{ key: 'Branch', value: payload.pull_request.head.ref },
],
});
},
);

webhooks.on(['pull_request.closed'], async ({ payload }) => {
if (!getPipelines().includes('closed-pr')) {
return;
}

/**
* https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-cpu-memory-error.html
*/
await executeTasks({
cpu: '256',
memory: '512',
commands: [
shConditionalCommands({
conditionalCommands: getClosedPrCommands({
branch: payload.pull_request.head.ref,
}),
}),
],
tags: [
{ key: 'Pipeline', value: 'pr' },
{ key: 'PullRequest', value: payload.number.toString() },
{ key: 'PullRequestTitle', value: payload.pull_request.title },
{ key: 'PullRequestUrl', value: payload.pull_request.url },
{ key: 'Action', value: payload.action },
{ key: 'Branch', value: payload.pull_request.head.ref },
],
});
});

export const githubWebhooksApiV1Handler: ProxyHandler = async (
event,
context,
Expand Down Expand Up @@ -76,87 +164,6 @@ export const githubWebhooksApiV1Handler: ProxyHandler = async (
throw new Error("X-Hub-Signature-256 or X-Hub-Signature doesn't exist.");
}

const pipelines: Pipeline[] = JSON.parse(
process.env.PIPELINES_JSON || JSON.stringify([]),
);

if (pipelines.includes('pr')) {
webhooks.on(
[
'pull_request.opened',
'pull_request.reopened',
'pull_request.ready_for_review',
'pull_request.synchronize',
],
async ({ payload }) => {
if (payload.pull_request.draft) {
return;
}

await executeTasks({
commands: [
shConditionalCommands({
conditionalCommands: getPrCommands({
branch: payload.pull_request.head.ref,
}),
}),
],
tags: [
{ key: 'Pipeline', value: 'pr' },
{ key: 'PullRequest', value: payload.number.toString() },
{ key: 'PullRequestTitle', value: payload.pull_request.title },
{ key: 'PullRequestUrl', value: payload.pull_request.url },
{ key: 'Action', value: payload.action },
{ key: 'Branch', value: payload.pull_request.head.ref },
],
});
},
);
}

if (pipelines.includes('closed-pr')) {
webhooks.on(['pull_request.closed'], async ({ payload }) => {
/**
* https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-cpu-memory-error.html
*/
await executeTasks({
cpu: '256',
memory: '512',
commands: [
shConditionalCommands({
conditionalCommands: getClosedPrCommands({
branch: payload.pull_request.head.ref,
}),
}),
],
tags: [
{ key: 'Pipeline', value: 'pr' },
{ key: 'PullRequest', value: payload.number.toString() },
{ key: 'PullRequestTitle', value: payload.pull_request.title },
{ key: 'PullRequestUrl', value: payload.pull_request.url },
{ key: 'Action', value: payload.action },
{ key: 'Branch', value: payload.pull_request.head.ref },
],
});
});
}

if (pipelines.includes('main')) {
webhooks.on('push', async (details) => {
if (details.payload.ref === 'refs/heads/main') {
await putJobDetails({ pipeline: 'main', details });
}
});
}

if (pipelines.includes('tag')) {
webhooks.on('push', async (details) => {
if (details.payload.ref.startsWith('refs/tags/')) {
await putJobDetails({ pipeline: 'tag', details });
}
});
}

webhooks.onError((onErrorEvent) => {
throw onErrorEvent;
});
Expand Down
Loading

0 comments on commit f112b63

Please sign in to comment.