Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
112 changes: 112 additions & 0 deletions API.md

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions src/awscdk/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ export interface IamRoleConfig {
*/
export interface CDKPipelineOptions {

/**
* A unique name for this pipeline, used as a prefix for workflow files,
* concurrency groups, and artifact names to prevent collisions in monorepos.
*
* @default - the project name if the project has a parent (monorepo subproject), otherwise no prefix
*/
readonly pipelineName?: string;

/**
* the name of the branch to deploy from
* @default main
Expand Down Expand Up @@ -203,6 +211,9 @@ export abstract class CDKPipeline extends Component {
public readonly stackPrefix: string;
public readonly branchName: string;

/** Prefix for workflow files, concurrency groups, and artifact names to prevent collisions in monorepos. */
protected readonly namePrefix: string;

constructor(protected app: awscdk.AwsCdkTypeScriptApp, protected baseOptions: CDKPipelineOptions) {
super(app);

Expand All @@ -215,6 +226,8 @@ export abstract class CDKPipeline extends Component {
// );
this.project.gitignore.exclude('/cdk-outputs-*.json');

const pipelineName = baseOptions.pipelineName ?? (app.parent ? app.name : undefined);
this.namePrefix = pipelineName ? `${pipelineName}-` : '';
this.stackPrefix = baseOptions.stackPrefix ?? app.name;
this.branchName = baseOptions.branchName ?? 'main'; // TODO use defaultReleaseBranch of NodeProject

Expand Down
36 changes: 18 additions & 18 deletions src/awscdk/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class GithubCDKPipeline extends CDKPipeline {
});

// Initialize the deployment workflow on GitHub.
this.deploymentWorkflow = this.app.github!.addWorkflow('deploy');
this.deploymentWorkflow = this.app.github!.addWorkflow(`${this.namePrefix}deploy`);
this.deploymentWorkflow.on({
push: {
branches: [this.branchName],
Expand Down Expand Up @@ -146,7 +146,7 @@ export class GithubCDKPipeline extends CDKPipeline {
* Creates a workflow for deploying feature branches when PRs are labeled with 'feature-deployment'.
*/
private createFeatureDeployWorkflow(): void {
const workflow = this.app.github!.addWorkflow('deploy-feature');
const workflow = this.app.github!.addWorkflow(`${this.namePrefix}deploy-feature`);

workflow.on({
pullRequestTarget: {
Expand All @@ -161,8 +161,8 @@ export class GithubCDKPipeline extends CDKPipeline {
this.provideDeployStep({ name: 'feature', env: this.baseOptions.featureStages!.env }),
new CdkOutputsSummaryStep(this.project, { stageName: 'feature' }),
new UploadArtifactStep(this.project, {
name: 'cdk-outputs-feature',
path: 'cdk-outputs-feature.json',
name: `${this.namePrefix}cdk-outputs-feature`,
path: `${this.namePrefix}cdk-outputs-feature.json`,
}),
].map(s => s.toGithub());

Expand All @@ -176,7 +176,7 @@ export class GithubCDKPipeline extends CDKPipeline {
idToken: JobPermission.WRITE,
}, ...(steps.flatMap(s => s.permissions).filter(p => p != undefined) as JobPermissions[])),
concurrency: {
'group': 'deploy-feature-${{ github.event.pull_request.number }}',
'group': `${this.namePrefix}deploy-feature-\${{ github.event.pull_request.number }}`,
'cancel-in-progress': false,
},
env: {
Expand All @@ -203,7 +203,7 @@ export class GithubCDKPipeline extends CDKPipeline {
* Creates a workflow for destroying feature branches when PRs are closed or unlabeled.
*/
private createFeatureDestroyWorkflow(): void {
const workflow = this.app.github!.addWorkflow('destroy-feature');
const workflow = this.app.github!.addWorkflow(`${this.namePrefix}destroy-feature`);

workflow.on({
pullRequestTarget: {
Expand Down Expand Up @@ -233,7 +233,7 @@ export class GithubCDKPipeline extends CDKPipeline {
idToken: JobPermission.WRITE,
}, ...(steps.flatMap(s => s.permissions).filter(p => p != undefined) as JobPermissions[])),
concurrency: {
'group': 'destroy-feature-${{ github.event.pull_request.number }}',
'group': `${this.namePrefix}destroy-feature-\${{ github.event.pull_request.number }}`,
'cancel-in-progress': false,
},
env: {
Expand Down Expand Up @@ -265,7 +265,7 @@ export class GithubCDKPipeline extends CDKPipeline {
steps.push(this.provideSynthStep());

steps.push(new UploadArtifactStep(this.project, {
name: 'cloud-assembly',
name: `${this.namePrefix}cloud-assembly`,
path: `${this.app.cdkConfig.cdkout}/`,
}));

Expand Down Expand Up @@ -307,7 +307,7 @@ export class GithubCDKPipeline extends CDKPipeline {
const steps = [
new SimpleCommandStep(this.project, ['git config --global user.name "github-actions" && git config --global user.email "github-actions@github.com"']),
new DownloadArtifactStep(this.project, {
name: 'cloud-assembly',
name: `${this.namePrefix}cloud-assembly`,
path: `${this.app.cdkConfig.cdkout}/`,
}),
this.provideInstallStep(),
Expand Down Expand Up @@ -367,13 +367,13 @@ export class GithubCDKPipeline extends CDKPipeline {
this.provideDeployStep(stage),
new CdkOutputsSummaryStep(this.project, { stageName: stage.name }),
new UploadArtifactStep(this.project, {
name: `cdk-outputs-${stage.name}`,
name: `${this.namePrefix}cdk-outputs-${stage.name}`,
path: `cdk-outputs-${stage.name}.json`,
}),
].map(s => s.toGithub());

// Create new workflow for deployment
const stageWorkflow = this.app.github!.addWorkflow(`release-${stage.name}`);
const stageWorkflow = this.app.github!.addWorkflow(`${this.namePrefix}release-${stage.name}`);
stageWorkflow.on({
workflowDispatch: {
inputs: {
Expand All @@ -392,7 +392,7 @@ export class GithubCDKPipeline extends CDKPipeline {
environment: stage.githubEnvironment ?? stage.name,
},
concurrency: {
'group': `deploy-${stage.name}`,
'group': `${this.namePrefix}deploy-${stage.name}`,
'cancel-in-progress': false,
},
env: {
Expand Down Expand Up @@ -430,14 +430,14 @@ export class GithubCDKPipeline extends CDKPipeline {
) {
const steps = [
new DownloadArtifactStep(this.project, {
name: 'cloud-assembly',
name: `${this.namePrefix}cloud-assembly`,
path: `${this.app.cdkConfig.cdkout}/`,
}),
this.provideInstallStep(),
this.provideDeployStep(stage),
new CdkOutputsSummaryStep(this.project, { stageName: stage.name }),
new UploadArtifactStep(this.project, {
name: `cdk-outputs-${stage.name}`,
name: `${this.namePrefix}cdk-outputs-${stage.name}`,
path: `cdk-outputs-${stage.name}.json`,
}),
].map(s => s.toGithub());
Expand All @@ -449,7 +449,7 @@ export class GithubCDKPipeline extends CDKPipeline {
environment: stage.githubEnvironment ?? stage.name,
},
concurrency: {
'group': `deploy-${stage.name}`,
'group': `${this.namePrefix}deploy-${stage.name}`,
'cancel-in-progress': false,
},
needs: [`assetUpload${useGithubEnvironmentsForAssetUpload ? `-${stage.name}` : ''}`, ...steps.flatMap(s => s.needs), ...jobDependencies],
Expand Down Expand Up @@ -491,13 +491,13 @@ export class GithubCDKPipeline extends CDKPipeline {
this.provideDeployStep(stage),
new CdkOutputsSummaryStep(this.project, { stageName: stage.name }),
new UploadArtifactStep(this.project, {
name: `cdk-outputs-${stage.name}`,
name: `${this.namePrefix}cdk-outputs-${stage.name}`,
path: `cdk-outputs-${stage.name}.json`,
}),
].map(s => s.toGithub());

// Create new workflow for deployment
const stageWorkflow = this.app.github!.addWorkflow(`deploy-${stage.name}`);
const stageWorkflow = this.app.github!.addWorkflow(`${this.namePrefix}deploy-${stage.name}`);
stageWorkflow.on({
workflowDispatch: {},
});
Expand All @@ -506,7 +506,7 @@ export class GithubCDKPipeline extends CDKPipeline {
needs: steps.flatMap(s => s.needs),
runsOn: this.options.runnerTags ?? DEFAULT_RUNNER_TAGS,
concurrency: {
'group': `deploy-${stage.name}`,
'group': `${this.namePrefix}deploy-${stage.name}`,
'cancel-in-progress': false,
},
env: {
Expand Down
38 changes: 19 additions & 19 deletions src/awscdk/gitlab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class GitlabCDKPipeline extends CDKPipeline {
*/
protected setupSnippets() {
this.config.addJobs({
'.artifacts_cdk': {
[`.${this.namePrefix}artifacts_cdk`]: {
artifacts: {
when: gitlab.CacheWhen.ON_SUCCESS,
expireIn: '30 days',
Expand All @@ -106,7 +106,7 @@ export class GitlabCDKPipeline extends CDKPipeline {
paths: ['cdk.out'],
},
},
'.artifacts_cdkdeploy': {
[`.${this.namePrefix}artifacts_cdkdeploy`]: {
artifacts: {
when: gitlab.CacheWhen.ON_SUCCESS,
expireIn: '30 days',
Expand All @@ -115,7 +115,7 @@ export class GitlabCDKPipeline extends CDKPipeline {
paths: ['cdk-outputs-*.json'],
},
},
'.aws_base': {
[`.${this.namePrefix}aws_base`]: {
image: { name: this.jobImage },
idTokens: {
AWS_TOKEN: {
Expand Down Expand Up @@ -150,8 +150,8 @@ export class GitlabCDKPipeline extends CDKPipeline {

this.config.addStages('synth');
this.config.addJobs({
synth: {
extends: ['.aws_base', '.artifacts_cdk', ...gitlabSteps.flatMap(s => s.extensions)],
[`${this.namePrefix}synth`]: {
extends: [`.${this.namePrefix}aws_base`, `.${this.namePrefix}artifacts_cdk`, ...gitlabSteps.flatMap(s => s.extensions)],
needs: gitlabSteps.flatMap(s => s.needs),
stage: 'synth',
tags: this.options.runnerTags?.synth ?? this.options.runnerTags?.default,
Expand Down Expand Up @@ -181,11 +181,11 @@ export class GitlabCDKPipeline extends CDKPipeline {

this.config.addStages('publish_assets');
this.config.addJobs({
publish_assets: {
extends: ['.aws_base', ...gitlabSteps.flatMap(s => s.extensions)],
[`${this.namePrefix}publish_assets`]: {
extends: [`.${this.namePrefix}aws_base`, ...gitlabSteps.flatMap(s => s.extensions)],
stage: 'publish_assets',
tags: this.options.runnerTags?.assetPublishing ?? this.options.runnerTags?.default,
needs: [{ job: 'synth', artifacts: true }, ...gitlabSteps.flatMap(s => s.needs)],
needs: [{ job: `${this.namePrefix}synth`, artifacts: true }, ...gitlabSteps.flatMap(s => s.needs)],
script: gitlabSteps.flatMap(s => s.commands),
variables: gitlabSteps.reduce((acc, step) => ({ ...acc, ...step.env }), {}),
},
Expand Down Expand Up @@ -216,24 +216,24 @@ export class GitlabCDKPipeline extends CDKPipeline {
this.config.addStages(stage.name);
this.config.addJobs({
...(stage.diffType !== CdkDiffType.NONE) && {
[`diff-${stage.name}`]: {
extends: ['.aws_base', ...diffSteps.flatMap(s => s.extensions)],
[`${this.namePrefix}diff-${stage.name}`]: {
extends: [`.${this.namePrefix}aws_base`, ...diffSteps.flatMap(s => s.extensions)],
stage: stage.name,
tags: this.options.runnerTags?.diff?.[stage.name] ?? this.options.runnerTags?.deployment?.[stage.name] ?? this.options.runnerTags?.default,
only: {
refs: [this.branchName],
},
needs: [
{ job: 'synth', artifacts: true },
{ job: 'publish_assets' },
{ job: `${this.namePrefix}synth`, artifacts: true },
{ job: `${this.namePrefix}publish_assets` },
...diffSteps.flatMap(s => s.needs),
],
script: diffSteps.flatMap(s => s.commands),
variables: diffSteps.reduce((acc, step) => ({ ...acc, ...step.env }), {}),
},
},
[`deploy-${stage.name}`]: {
extends: ['.aws_base', '.artifacts_cdkdeploy', ...deploySteps.flatMap(s => s.extensions)],
[`${this.namePrefix}deploy-${stage.name}`]: {
extends: [`.${this.namePrefix}aws_base`, `.${this.namePrefix}artifacts_cdkdeploy`, ...deploySteps.flatMap(s => s.extensions)],
stage: stage.name,
tags: this.options.runnerTags?.deployment?.[stage.name] ?? this.options.runnerTags?.default,
...stage.manualApproval && {
Expand All @@ -243,9 +243,9 @@ export class GitlabCDKPipeline extends CDKPipeline {
refs: [this.branchName],
},
needs: [
{ job: 'synth', artifacts: true },
{ job: 'publish_assets' },
...(stage.diffType !== CdkDiffType.NONE) ? [{ job: `diff-${stage.name}` }] : [],
{ job: `${this.namePrefix}synth`, artifacts: true },
{ job: `${this.namePrefix}publish_assets` },
...(stage.diffType !== CdkDiffType.NONE) ? [{ job: `${this.namePrefix}diff-${stage.name}` }] : [],
...deploySteps.flatMap(s => s.needs),
],
script: deploySteps.flatMap(s => s.commands),
Expand All @@ -271,8 +271,8 @@ export class GitlabCDKPipeline extends CDKPipeline {

this.config.addStages(stage.name);
this.config.addJobs({
[`deploy-${stage.name}`]: {
extends: ['.aws_base', '.artifacts_cdkdeploy', ...steps.flatMap(s => s.extensions)],
[`${this.namePrefix}deploy-${stage.name}`]: {
extends: [`.${this.namePrefix}aws_base`, `.${this.namePrefix}artifacts_cdkdeploy`, ...steps.flatMap(s => s.extensions)],
stage: stage.name,
tags: this.options.runnerTags?.deployment?.[stage.name] ?? this.options.runnerTags?.default,
...stage.deployOnPush && {
Expand Down
12 changes: 12 additions & 0 deletions src/drift/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ export interface DriftErrorHandler {
}

export interface DriftDetectionWorkflowOptions {
/**
* A unique name for this pipeline, used as a prefix for workflow files
* and artifact names to prevent collisions in monorepos.
*
* @default - no prefix
*/
readonly pipelineName?: string;

/**
* Name of the workflow
* @default "drift-detection"
Expand All @@ -79,9 +87,13 @@ export abstract class DriftDetectionWorkflow extends Component {
public readonly schedule: string;
protected readonly stages: DriftDetectionStageOptions[];

/** Prefix for workflow files and artifact names to prevent collisions in monorepos. */
protected readonly namePrefix: string;

constructor(project: Project, options: DriftDetectionWorkflowOptions) {
super(project);

this.namePrefix = options.pipelineName ? `${options.pipelineName}-` : '';
this.name = options.name ?? 'drift-detection';
this.schedule = options.schedule ?? '0 0 * * *';
this.stages = options.stages;
Expand Down
8 changes: 4 additions & 4 deletions src/drift/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class GitHubDriftDetectionWorkflow extends DriftDetectionWorkflow {
this.permissions = options.permissions;
this.createIssues = options.createIssues ?? false;

this.workflow = (this.project as GitHubProject).github!.addWorkflow('drift-detection');
this.workflow = (this.project as GitHubProject).github!.addWorkflow(`${this.namePrefix}drift-detection`);
this.workflow.on({
schedule: [{
cron: this.schedule,
Expand Down Expand Up @@ -82,8 +82,8 @@ export class GitHubDriftDetectionWorkflow extends DriftDetectionWorkflow {
name: 'Upload results',
uses: 'actions/upload-artifact@v4',
with: {
name: `drift-results-${stage.name}`,
path: `drift-results-${stage.name}.json`,
name: `${this.namePrefix}drift-results-${stage.name}`,
path: `${this.namePrefix}drift-results-${stage.name}.json`,
},
},
...(this.createIssues ? [{
Expand Down Expand Up @@ -127,7 +127,7 @@ export class GitHubDriftDetectionWorkflow extends DriftDetectionWorkflow {
private generateIssueCreationScript(stage: DriftDetectionStageOptions): string {
return `
const fs = require('fs');
const resultsFile = 'drift-results-${stage.name}.json';
const resultsFile = '${this.namePrefix}drift-results-${stage.name}.json';

if (!fs.existsSync(resultsFile)) {
console.log('No results file found');
Expand Down
10 changes: 5 additions & 5 deletions src/drift/gitlab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class GitLabDriftDetectionWorkflow extends DriftDetectionWorkflow {
this.config.addStages('drift-detection', 'summary');

this.config.addJobs({
'.drift-detection': {
[`.${this.namePrefix}drift-detection`]: {
stage: 'drift-detection',
tags: this.runnerTags,
image: { name: this.image },
Expand Down Expand Up @@ -60,14 +60,14 @@ export class GitLabDriftDetectionWorkflow extends DriftDetectionWorkflow {

// Add job for each stage
for (const stage of this.stages) {
const jobName = `drift:${stage.name}`;
const jobName = `${this.namePrefix}drift:${stage.name}`;

const driftStep = new DriftDetectionStep(this.project, stage);
const stepConfig = driftStep.toGitlab();

this.config.addJobs({
[jobName]: {
extends: ['.drift-detection'],
extends: [`.${this.namePrefix}drift-detection`],
variables: {
...stepConfig.env,
},
Expand All @@ -79,10 +79,10 @@ export class GitLabDriftDetectionWorkflow extends DriftDetectionWorkflow {

// Add summary job
this.config.addJobs({
'drift:summary': {
[`${this.namePrefix}drift:summary`]: {
stage: 'summary',
tags: this.runnerTags,
needs: this.stages.map(s => `drift:${s.name}`),
needs: this.stages.map(s => `${this.namePrefix}drift:${s.name}`),
only: {
refs: ['schedules'],
variables: ['$CI_PIPELINE_SOURCE == "schedule"', '$DRIFT_DETECTION == "true"'],
Expand Down
Loading
Loading