Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(codebuild): add support of organization webhook in github source #31740

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
17 changes: 16 additions & 1 deletion packages/aws-cdk-lib/aws-codebuild/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Example:
```ts
const gitHubSource = codebuild.Source.gitHub({
owner: 'awslabs',
repo: 'aws-cdk',
repo: 'aws-cdk', // optional, default: undefined if unspecified will create organization webhook
webhook: true, // optional, default: true if `webhookFilters` were provided, false otherwise
webhookTriggersBatchBuild: true, // optional, default is false
webhookFilters: [
Expand All @@ -76,6 +76,21 @@ const gitHubSource = codebuild.Source.gitHub({
});
```

The `GitHubSource` is also able to trigger all repos in GitHub Organizations
Example:
```ts
const gitHubSource = codebuild.Source.gitHub({
owner: 'aws',
webhookTriggersBatchBuild: true, // optional, default is false
webhookFilters: [
codebuild.FilterGroup
.inEventOf(codebuild.EventAction.WORKFLOW_JOB_QUEUED)
.andRepositoryNameIs("aws-.*")
.andRepositoryNameIsNot("aws-cdk-lib"),
], // optional, by default all pushes and Pull Requests will trigger a build
});
```

To provide GitHub credentials, please either go to AWS CodeBuild Console to connect
or call `ImportSourceCredentials` to persist your personal access token.
Example:
Expand Down
52 changes: 45 additions & 7 deletions packages/aws-cdk-lib/aws-codebuild/lib/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ enum WebhookFilterTypes {
HEAD_REF = 'HEAD_REF',
ACTOR_ACCOUNT_ID = 'ACTOR_ACCOUNT_ID',
BASE_REF = 'BASE_REF',
REPOSITORY_NAME = 'REPOSITORY_NAME',
}

/**
Expand Down Expand Up @@ -421,6 +422,30 @@ export class FilterGroup {
return this.addFilePathFilter(pattern, false);
}

/**
* Create a new FilterGroup with an added condition:
* the push that is the source of the event affect only a repository name that matches the given pattern.
* Note that you can only use this method if this Group contains only the `WORKFLOW_JOB_QUEUED` event action,
* only for GitHub sources and only for organization webhook.
*
* @param pattern a regular expression
*/
public andRepositoryNameIs(pattern: string): FilterGroup {
return this.addRepositoryNameFilter(pattern, true);
}

/**
* Create a new FilterGroup with an added condition:
* the push that is the source of the event must not affect a repository name that matches the given pattern.
* Note that you can only use this method if this Group contains only the `WORKFLOW_JOB_QUEUED` event action,
* only for GitHub sources and only for organization webhook.
*
* @param pattern a regular expression
*/
public andRepositoryNameIsNot(pattern: string): FilterGroup {
return this.addRepositoryNameFilter(pattern, false);
}

/** @internal */
public get _actions(): EventAction[] {
return set2Array(this.actions);
Expand Down Expand Up @@ -475,6 +500,10 @@ export class FilterGroup {
return this.addFilter(WebhookFilterTypes.FILE_PATH, pattern, include);
}

private addRepositoryNameFilter(pattern: string, include: boolean): FilterGroup {
return this.addFilter(WebhookFilterTypes.REPOSITORY_NAME, pattern, include);
}

private addFilter(type: WebhookFilterTypes, pattern: string, include: boolean) {
return new FilterGroup(this.actions, this.filters.concat([{
type,
Expand Down Expand Up @@ -718,7 +747,7 @@ abstract class CommonGithubSource extends ThirdPartyGitSource {
*/
export interface GitHubSourceProps extends CommonGithubSourceProps {
/**
* The GitHub account/user that owns the repo.
* The GitHub Organization/user that owns the repo.
*
* @example 'awslabs'
*/
Expand All @@ -728,31 +757,40 @@ export interface GitHubSourceProps extends CommonGithubSourceProps {
* The name of the repo (without the username).
*
* @example 'aws-cdk'
* @default undefined will create an organization webhook
*/
readonly repo: string;
readonly repo?: string;
}

/**
* GitHub Source definition for a CodeBuild project.
*/
class GitHubSource extends CommonGithubSource {
public readonly type = GITHUB_SOURCE_TYPE;
private readonly httpsCloneUrl: string;

private readonly sourceLocation: string;
private readonly organization?: string;
protected readonly webhookFilters: FilterGroup[];
constructor(props: GitHubSourceProps) {
super(props);
this.httpsCloneUrl = `https://github.com/${props.owner}/${props.repo}.git`;
this.organization = props.repo === undefined ? props.owner : undefined;
this.webhookFilters = props.webhookFilters || this.organization ? [FilterGroup.inEventOf(EventAction.WORKFLOW_JOB_QUEUED)] : [];
this.sourceLocation = this.organization ? 'CODEBUILD_DEFAULT_WEBHOOK_SOURCE_LOCATION' : `https://github.com/${props.owner}/${props.repo}.git`;
}

public bind(_scope: Construct, project: IProject): SourceConfig {
const superConfig = super.bind(_scope, project);
return {
sourceProperty: {
...superConfig.sourceProperty,
location: this.httpsCloneUrl,
location: this.sourceLocation,
},
sourceVersion: superConfig.sourceVersion,
buildTriggers: superConfig.buildTriggers,
buildTriggers: {
...superConfig.buildTriggers,
scopeConfiguration: this.organization ? {
name: this.organization,
} : undefined,
},
};
}
}
Expand Down
25 changes: 25 additions & 0 deletions packages/aws-cdk-lib/aws-codebuild/test/project.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,31 @@ describe('GitHub source', () => {
});
});

test('can create organizational webhook', () => {
// GIVEN
const stack = new cdk.Stack();

// WHEN
new codebuild.Project(stack, 'Project', {
source: codebuild.Source.gitHub({
owner: 'testowner',
}),
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::CodeBuild::Project', {
Source: {
Type: 'GITHUB',
Location: 'CODEBUILD_DEFAULT_WEBHOOK_SOURCE_LOCATION',
},
Triggers: {
ScopeConfiguration: {
Name: 'testowner',
},
},
});
});

test('can be added to a CodePipeline', () => {
const stack = new cdk.Stack();
const project = new codebuild.Project(stack, 'Project', {
Expand Down
Loading