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(codepipeline): Add CodeConnections source for creating codepipeline #31028

Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
import { Construct } from 'constructs';
import * as codepipeline from '../../../aws-codepipeline';
import * as iam from '../../../aws-iam';
import { Action } from '../action';
import { sourceArtifactBounds } from '../common';

/**
* The CodePipeline variables emitted by CodeStar source Action.
*/
export interface CodeConnectionsSourceVariables {
/** The name of the repository this action points to. */
readonly fullRepositoryName: string;
/** The name of the branch this action tracks. */
readonly branchName: string;
/** The date the currently last commit on the tracked branch was authored, in ISO-8601 format. */
readonly authorDate: string;
/** The SHA1 hash of the currently last commit on the tracked branch. */
readonly commitId: string;
/** The message of the currently last commit on the tracked branch. */
readonly commitMessage: string;
/** The connection ARN this source uses. */
readonly connectionArn: string;
}

/**
* Construction properties for `CodeStarConnectionsSourceAction`.
*/
export interface CodeConnectionsSourceActionProps extends codepipeline.CommonAwsActionProps {
/**
* The output artifact that this action produces.
* Can be used as input for further pipeline actions.
*/
readonly output: codepipeline.Artifact;

/**
* The ARN of the CodeStar Connection created in the AWS console
* that has permissions to access this GitHub or BitBucket repository.
*
* @example 'arn:aws:codestar-connections:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh'
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-create.html
*/
readonly connectionArn: string;

/**
* The owning user or organization of the repository.
*
* @example 'aws'
*/
readonly owner: string;

/**
* The name of the repository.
*
* @example 'aws-cdk'
*/
readonly repo: string;

/**
* The branch to build.
*
* @default 'master'
*/
readonly branch?: string;

// long URL in @see
/**
* Whether the output should be the contents of the repository
* (which is the default),
* or a link that allows CodeBuild to clone the repository before building.
*
* **Note**: if this option is true,
* then only CodeBuild actions can use the resulting `output`.
*
* @default false
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodestarConnectionSource.html#action-reference-CodestarConnectionSource-config
*/
readonly codeBuildCloneOutput?: boolean;

/**
* Controls automatically starting your pipeline when a new commit
* is made on the configured repository and branch. If unspecified,
* the default value is true, and the field does not display by default.
*
* @default true
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodestarConnectionSource.html
*/
readonly triggerOnPush?: boolean;
}

/**
* A CodePipeline source action for the CodeStar Connections source,
* which allows connecting to GitHub and BitBucket.
*/
export class CodeConnectionsSourceAction extends Action {
/**
* The name of the property that holds the ARN of the CodeStar Connection
* inside of the CodePipeline Artifact's metadata.
*
* @internal
*/
public static readonly _CONNECTION_ARN_PROPERTY = 'CodeConnectionsArnProperty';

private readonly props: CodeConnectionsSourceActionProps;

constructor(props: CodeConnectionsSourceActionProps) {
super({
...props,
category: codepipeline.ActionCategory.SOURCE,
owner: 'AWS', // because props also has a (different!) owner property!
provider: 'CodeConnections',
artifactBounds: sourceArtifactBounds(),
outputs: [props.output],
});

this.props = props;
}

/** The variables emitted by this action. */
public get variables(): CodeConnectionsSourceVariables {
return {
fullRepositoryName: this.variableExpression('FullRepositoryName'),
branchName: this.variableExpression('BranchName'),
authorDate: this.variableExpression('AuthorDate'),
commitId: this.variableExpression('CommitId'),
commitMessage: this.variableExpression('CommitMessage'),
connectionArn: this.variableExpression('ConnectionArn'),
};
}

protected bound(_scope: Construct, _stage: codepipeline.IStage, options: codepipeline.ActionBindOptions): codepipeline.ActionConfig {
// https://docs.aws.amazon.com/codepipeline/latest/userguide/security-iam.html#how-to-update-role-new-services
options.role.addToPrincipalPolicy(new iam.PolicyStatement({
actions: [
'codeconnections:UseConnection',
],
resources: [
this.props.connectionArn,
],
}));

// the action needs to write the output to the pipeline bucket
options.bucket.grantReadWrite(options.role);
options.bucket.grantPutAcl(options.role);

// if codeBuildCloneOutput is true,
// save the connectionArn in the Artifact instance
// to be read by the CodeBuildAction later
if (this.props.codeBuildCloneOutput === true) {
this.props.output.setMetadata(CodeConnectionsSourceAction._CONNECTION_ARN_PROPERTY,
this.props.connectionArn);
}

return {
configuration: {
ConnectionArn: this.props.connectionArn,
FullRepositoryId: `${this.props.owner}/${this.props.repo}`,
BranchName: this.props.branch ?? 'master',
OutputArtifactFormat: this.props.codeBuildCloneOutput === true
? 'CODEBUILD_CLONE_REF'
: undefined,
DetectChanges: this.props.triggerOnPush,
},
};
}
}
1 change: 1 addition & 0 deletions packages/aws-cdk-lib/aws-codepipeline-actions/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './alexa-ask/deploy-action';
export * from './bitbucket/source-action';
export * from './codestar-connections/source-action';
export * from './codeconnections/source-action';
export * from './cloudformation';
export * from './codebuild/build-action';
export * from './codecommit/source-action';
Expand Down
109 changes: 109 additions & 0 deletions packages/aws-cdk-lib/pipelines/lib/codepipeline/codepipeline-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,19 @@ export abstract class CodePipelineSource extends Step implements ICodePipelineAc
return new CodeStarConnectionSource(repoString, branch, props);
}

/**
* Returns a CodeConnection source.
*
* @param repoString A string that encodes owner and repository separated by a slash (e.g. 'owner/repo'). The provided string must be resolvable at runtime.
* @param branch The branch to use.
* @param props The source properties, including the connection ARN.
*
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-create.html
*/
public static codeConnection(repoString: string, branch: string, props: CodeConnectionsSourceOptions): CodePipelineSource {
return new CodeConnectionsSource(repoString, branch, props);
}

/**
* Returns a CodeCommit source.
*
Expand Down Expand Up @@ -469,6 +482,102 @@ class CodeStarConnectionSource extends CodePipelineSource {
}
}

/**
* Configuration options for CodeConnection source
*/
export interface CodeConnectionsSourceOptions {
/**
* The ARN of the CodeConnection created in the AWS console
* that has permissions to access this GitHub or BitBucket repository.
*
* @example 'arn:aws:codeconnection:us-east-1:123456789012:connection/12345678-abcd-12ab-34cdef5678gh'
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/connections-create.html
*/
readonly connectionArn: string;

/**
* If this is set, the next CodeBuild job clones the repository (instead of CodePipeline downloading the files).
*
* This provides access to repository history, and retains symlinks (symlinks would otherwise be
* removed by CodePipeline).
*
* **Note**: if this option is true, only CodeBuild jobs can use the output artifact.
*
* @default false
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodeConnectionSource.html#action-reference-CodeConnectionSource-config
*/
readonly codeBuildCloneOutput?: boolean;

/**
* Controls automatically starting your pipeline when a new commit
* is made on the configured repository and branch. If unspecified,
* the default value is true, and the field does not display by default.
*
* @default true
* @see https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodeConnectionSource.html
*/
readonly triggerOnPush?: boolean;

/**
* The action name used for this source in the CodePipeline
*
* @default - The repository string
*/
readonly actionName?: string;
}

class CodeConnectionsSource extends CodePipelineSource {
private readonly owner: string;
private readonly repo: string;

constructor(repoString: string, readonly branch: string, readonly props: CodeConnectionsSourceOptions) {
super(repoString);

if (!this.isValidRepoString(repoString)) {
throw new Error(`CodeConnection repository name should be a resolved string like '<owner>/<repo>' or '<owner>/<group1>/<group2>/.../<repo>', got '${repoString}'`);
}

const parts = repoString.split('/');

this.owner = parts[0];
this.repo = parts.slice(1).join('/');
this.configurePrimaryOutput(new FileSet('Source', this));
}

private isValidRepoString(repoString: string) {
if (Token.isUnresolved(repoString)) {
return false;
}

const parts = repoString.split('/');

// minimum length is 2 (owner/repo) and
// maximum length is 22 (owner/parent group/twenty sub groups/repo).
// maximum length is based on limitation of GitLab, see https://docs.gitlab.com/ee/user/group/subgroups/
if (parts.length < 2 || parts.length > 23) {
return false;
}

// check if all element in parts is not empty
return parts.every(element => element !== '');
}

protected getAction(output: Artifact, actionName: string, runOrder: number, variablesNamespace?: string) {
return new cp_actions.CodeConnectionsSourceAction({
output,
actionName: this.props.actionName ?? actionName,
runOrder,
connectionArn: this.props.connectionArn,
owner: this.owner,
repo: this.repo,
branch: this.branch,
codeBuildCloneOutput: this.props.codeBuildCloneOutput,
triggerOnPush: this.props.triggerOnPush,
variablesNamespace,
});
}
}

/**
* Configuration options for a CodeCommit source
*/
Expand Down
Loading