Skip to content

Commit

Permalink
My proposal.
Browse files Browse the repository at this point in the history
  • Loading branch information
skinny85 committed May 1, 2019
1 parent 7f44b0b commit 0af5b2b
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 69 deletions.
161 changes: 149 additions & 12 deletions packages/@aws-cdk/aws-codebuild/lib/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,141 @@ export interface ExternalGitBuildSourceProps extends GitBuildSourceProps {
/**
* A list of lists of WebhookFilter objects used to determine which webhook events are triggered.
*/
readonly filterGroups?: WebhookFilter[][];
readonly filterGroups?: FilterGroup[];
}

export enum EventAction {
PUSH = 'PUSH',
PULL_REQUEST_CREATED = 'PULL_REQUEST_CREATED',
PULL_REQUEST_UPDATED = 'PULL_REQUEST_UPDATED',
PULL_REQUEST_REOPENED = 'PULL_REQUEST_REOPENED',
}

export class FilterGroup {
public static inEventOf(...actions: EventAction[]): FilterGroup {
return new FilterGroup(new Set(actions));
}

private readonly actions = new Set<EventAction>();
private readonly filters = new Array<CfnProject.WebhookFilterProperty>();

private constructor(actions: Set<EventAction>) {
this.actions = actions;
}

public andBranchIs(branchName: string): FilterGroup {
return this.addHeadBranchFilter(branchName, true);
}

public andBranchIsNot(branchName: string): FilterGroup {
return this.addHeadBranchFilter(branchName, false);
}

public andTagIs(tagName: string): FilterGroup {
return this.addHeadTagFilter(tagName, true);
}

public andTagIsNot(tagName: string): FilterGroup {
return this.addHeadTagFilter(tagName, false);
}

public andHeadRefIs(pattern: string) {
return this.addHeadRefFilter(pattern, true);
}

public andHeadRefIsNot(pattern: string) {
return this.addHeadRefFilter(pattern, false);
}

public andActorAccountIs(pattern: string): FilterGroup {
return this.addActorAccountId(pattern, true);
}

public andActorAccountIsNot(pattern: string): FilterGroup {
return this.addActorAccountId(pattern, false);
}

public andBaseBranchIs(branchName: string): FilterGroup {
return this.addBaseBranchFilter(branchName, true);
}

public andBaseBranchIsNot(branchName: string): FilterGroup {
return this.addBaseBranchFilter(branchName, false);
}

public andBaseTagIs(tagName: string): FilterGroup {
return this.addBaseTagFilter(tagName, true);
}

public andBaseTagIsNot(tagName: string): FilterGroup {
return this.addBaseTagFilter(tagName, false);
}

public andBaseRefIs(pattern: string): FilterGroup {
return this.addBaseRefFilter(pattern, true);
}

public andBaseRefIsNot(pattern: string): FilterGroup {
return this.addBaseRefFilter(pattern, false);
}

public andFilePathIs(pattern: string): FilterGroup {
return this.addFilePathFilter(pattern, true);
}

public andFilePathIsNot(pattern: string): FilterGroup {
return this.addFilePathFilter(pattern, false);
}

/** @internal */
public _toJson(): CfnProject.WebhookFilterProperty[] {
const eventFilter: CfnProject.WebhookFilterProperty = {
type: 'EVENT',
pattern: set2Array(this.actions).join(', '),
};
return [eventFilter].concat(this.filters);
}

private addHeadBranchFilter(branchName: string, include: boolean): FilterGroup {
return this.addHeadRefFilter(`refs/heads/${branchName}`, include);
}

private addHeadTagFilter(tagName: string, include: boolean): FilterGroup {
return this.addHeadRefFilter(`refs/tags/${tagName}`, include);
}

private addHeadRefFilter(refName: string, include: boolean) {
return this.addFilter('HEAD_REF', refName, include);
}

private addActorAccountId(accountId: string, include: boolean) {
return this.addFilter('ACTOR_ACCOUNT_ID', accountId, include);
}

private addBaseBranchFilter(branchName: string, include: boolean): FilterGroup {
return this.addBaseRefFilter(`refs/heads/${branchName}`, include);
}

private addBaseTagFilter(tagName: string, include: boolean): FilterGroup {
return this.addBaseRefFilter(`refs/tags/${tagName}`, include);
}

private addBaseRefFilter(refName: string, include: boolean) {
return this.addFilter('BASE_REF', refName, include);
}

private addFilePathFilter(pattern: string, include: boolean): FilterGroup {
return this.addFilter('FILE_PATH', pattern, include);
}

private addFilter(type: string, pattern: string, include: boolean) {
this.filters.push({
type,
pattern,
excludeMatchedPattern: include ? undefined : true,
});
return this;
}
}

/**
Expand All @@ -136,26 +270,23 @@ export abstract class ExternalGitBuildSource extends GitBuildSource {
public readonly badgeSupported: boolean = true;
private readonly reportBuildStatus: boolean;
private readonly webhook?: boolean;
private readonly filterGroups?: WebhookFilter[][];
private readonly filterGroups: FilterGroup[];

protected constructor(props: ExternalGitBuildSourceProps) {
super(props);

this.webhook = props.webhook;
this.reportBuildStatus = props.reportBuildStatus === undefined ? true : props.reportBuildStatus;
this.filterGroups = props.filterGroups;
this.filterGroups = props.filterGroups || [];
}

public buildTriggers(): CfnProject.ProjectTriggersProperty | undefined {
if (!this.webhook && this.filterGroups) {
throw new Error("filterGroups property could only be set when webhook property is true");
}
return this.webhook === undefined
? undefined
: {
webhook: this.webhook,
filterGroups: this.filterGroups,
};
const anyFilterGroupsProvided = this.filterGroups.length > 0;
const webhook = this.webhook === undefined ? (anyFilterGroupsProvided ? true : undefined) : this.webhook;
return {
webhook,
filterGroups: anyFilterGroupsProvided ? this.filterGroups.map(fg => fg._toJson()) : undefined,
};
}

public toSourceJSON(): CfnProject.SourceProperty {
Expand Down Expand Up @@ -413,3 +544,9 @@ export enum SourceType {
BitBucket = 'BITBUCKET',
S3 = 'S3',
}

function set2Array<T>(set: Set<T>): T[] {
const ret: T[] = [];
set.forEach(el => ret.push(el));
return ret;
}
72 changes: 15 additions & 57 deletions packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import s3 = require('@aws-cdk/aws-s3');
import cdk = require('@aws-cdk/cdk');
import { Test } from 'nodeunit';
import codebuild = require('../lib');
import { WebhookFilterType } from '../lib';

// tslint:disable:object-literal-key-quotes

Expand Down Expand Up @@ -482,14 +481,8 @@ export = {
webhook: true,
reportBuildStatus: false,
filterGroups: [
[
{ type: WebhookFilterType.Event, pattern: 'PUSH' },
{ type: WebhookFilterType.HeadRef, pattern: 'master', excludeMatchedPattern: false },
],
[
{ type: WebhookFilterType.Event, pattern: 'PULL_REQUEST_OPEN' },
{ type: WebhookFilterType.BaseRef, pattern: 'master' },
],
codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andBranchIs('master'),
codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_CREATED).andBaseBranchIs('master'),
],
})
});
Expand All @@ -509,11 +502,11 @@ export = {
FilterGroups: [
[
{ Type: 'EVENT', Pattern: 'PUSH' },
{ Type: 'HEAD_REF', Pattern: 'master', ExcludeMatchedPattern: false },
{ Type: 'HEAD_REF', Pattern: 'refs/heads/master' },
],
[
{ Type: 'EVENT', Pattern: 'PULL_REQUEST_OPEN' },
{ Type: 'BASE_REF', Pattern: 'master' },
{ Type: 'EVENT', Pattern: 'PULL_REQUEST_CREATED' },
{ Type: 'BASE_REF', Pattern: 'refs/heads/master' },
],
],
},
Expand All @@ -532,14 +525,8 @@ export = {
webhook: true,
reportBuildStatus: false,
filterGroups: [
[
{ type: WebhookFilterType.Event, pattern: 'PUSH' },
{ type: WebhookFilterType.HeadRef, pattern: 'master', excludeMatchedPattern: false },
],
[
{ type: WebhookFilterType.Event, pattern: 'PULL_REQUEST_OPEN' },
{ type: WebhookFilterType.BaseRef, pattern: 'master' },
],
codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andBranchIs('master'),
codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_CREATED).andBaseBranchIs('master'),
],
})
});
Expand All @@ -560,11 +547,11 @@ export = {
FilterGroups: [
[
{ Type: 'EVENT', Pattern: 'PUSH' },
{ Type: 'HEAD_REF', Pattern: 'master', ExcludeMatchedPattern: false },
{ Type: 'HEAD_REF', Pattern: 'refs/heads/master' },
],
[
{ Type: 'EVENT', Pattern: 'PULL_REQUEST_OPEN' },
{ Type: 'BASE_REF', Pattern: 'master' },
{ Type: 'EVENT', Pattern: 'PULL_REQUEST_CREATED' },
{ Type: 'BASE_REF', Pattern: 'refs/heads/master' },
],
],
},
Expand All @@ -580,17 +567,10 @@ export = {
owner: 'testowner',
repo: 'testrepo',
cloneDepth: 5,
webhook: true,
reportBuildStatus: false,
filterGroups: [
[
{ type: WebhookFilterType.Event, pattern: 'PUSH' },
{ type: WebhookFilterType.HeadRef, pattern: 'master', excludeMatchedPattern: false },
],
[
{ type: WebhookFilterType.Event, pattern: 'PULL_REQUEST_OPEN' },
{ type: WebhookFilterType.BaseRef, pattern: 'master' },
],
codebuild.FilterGroup.inEventOf(codebuild.EventAction.PUSH).andBranchIs('master'),
codebuild.FilterGroup.inEventOf(codebuild.EventAction.PULL_REQUEST_CREATED).andBaseBranchIs('master'),
],
})
});
Expand All @@ -610,11 +590,11 @@ export = {
FilterGroups: [
[
{ Type: 'EVENT', Pattern: 'PUSH' },
{ Type: 'HEAD_REF', Pattern: 'master', ExcludeMatchedPattern: false },
{ Type: 'HEAD_REF', Pattern: 'refs/heads/master' },
],
[
{ Type: 'EVENT', Pattern: 'PULL_REQUEST_OPEN' },
{ Type: 'BASE_REF', Pattern: 'master' },
{ Type: 'EVENT', Pattern: 'PULL_REQUEST_CREATED' },
{ Type: 'BASE_REF', Pattern: 'refs/heads/master' },
],
],
},
Expand Down Expand Up @@ -1234,26 +1214,4 @@ export = {

test.done();
},

'filter groups validation'(test: Test) {
const stack = new cdk.Stack();

// should throw exception when webhook is not specified but filterGroups is
test.throws(() => {
new codebuild.Project(stack, 'Project', {
source: new codebuild.GitHubSource({
owner: 'testowner',
repo: 'testrepo',
cloneDepth: 3,
filterGroups: [
[
{ type: WebhookFilterType.Event, pattern: 'PUSH' }
]
],
})
});
}, Error, "filterGroups property could only be set when webhook property is true");

test.done();
}
};

0 comments on commit 0af5b2b

Please sign in to comment.