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: Add a new input flag to avoid commenting on stacks that have not changed. #85

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,20 @@ jobs:
failOnDestructiveChanges: false
githubToken: ${{ secrets.GITHUB_TOKEN }}
```

### Hide comments for unchanged stages

If you want to prevent unnecessary comments by hiding comments for stacks that
have not changed, you can enable this feature. This defaults to off, showing
comments for all stacks.

```yml
jobs:
Synth:
steps:
- name: Diff
uses: corymhall/cdk-diff-action@v1
with:
ignoreUnchangedStacks: true
githubToken: ${{ secrets.GITHUB_TOKEN }}
```
3 changes: 2 additions & 1 deletion src/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export async function run() {
noDiffForStages: getInput('noDiffForStages').split(','),
noFailOnDestructiveChanges: getInput('noFailOnDestructiveChanges').split(','),
cdkOutDir: getInput('cdkOutDir') ?? 'cdk.out',
ignoreUnchangedStacks: getBooleanInput('ignoreUnchangedStacks')
};
const octokit = github.getOctokit(inputs.githubToken);
const context = github.context;
Expand All @@ -26,7 +27,7 @@ export async function run() {
});
}
const comments = new Comments(octokit, context);
const processor = new StageProcessor(stages, inputs.allowedDestroyTypes);
const processor = new StageProcessor(stages, inputs.allowedDestroyTypes, inputs.ignoreUnchangedStacks);
try {
await processor.processStages(inputs.noFailOnDestructiveChanges);
} catch (e: any) {
Expand Down
7 changes: 7 additions & 0 deletions src/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,11 @@ export interface Inputs {
* @default cdk.out
*/
cdkOutDir: string;

/**
* Whether the workflow will comment for unchanged stacks
*
* @default - comment for unchanged stacks
*/
ignoreUnchangedStacks: boolean;
}
17 changes: 12 additions & 5 deletions src/stage-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export class StageProcessor {
constructor(
private readonly stages: StageInfo[],
private readonly allowedDestroyTypes: string[],
private readonly ignoreUnchangedStacks: boolean,
) {
this.stages.forEach(stage => {
this.stageComments[stage.name] = {
Expand Down Expand Up @@ -72,10 +73,12 @@ export class StageProcessor {
for (const stage of this.stages) {
for (const stack of stage.stacks) {
try {
const { comment, changes } = await this.diffStack(stack);
this.stageComments[stage.name].stackComments[stack.name].push(...comment);
const { comment, destructiveChanges, anyChanges } = await this.diffStack(stack);
if (anyChanges || !this.ignoreUnchangedStacks) {
this.stageComments[stage.name].stackComments[stack.name].push(...comment);
}
if (!ignoreDestructiveChanges.includes(stage.name)) {
this.stageComments[stage.name].destructiveChanges += changes;
this.stageComments[stage.name].destructiveChanges += destructiveChanges;
}
} catch (e: any) {
console.error('Error processing stages: ', e);
Expand All @@ -93,6 +96,9 @@ export class StageProcessor {
stackName,
}));
const stackComment = this.getCommentForStack(stageName, stackName, comment);
if (stackComment.length == 0) {
continue;
}
if (stackComment.join('\n').length > MAX_COMMENT_LENGTH) {
throw new Error(`Comment for stack ${stackName} is too long, please report this as a bug https://github.com/corymhall/cdk-diff-action/issues/new`);
}
Expand Down Expand Up @@ -145,13 +151,14 @@ export class StageProcessor {
return false;
}

private async diffStack(stack: StackInfo): Promise<{comment: string[]; changes: number}> {
private async diffStack(stack: StackInfo): Promise<{comment: string[]; destructiveChanges: number, anyChanges: boolean}> {
try {
const stackDiff = new StackDiff(stack, this.allowedDestroyTypes);
const { diff, changes } = await stackDiff.diffStack();
return {
comment: this.formatStackComment(stack.name, diff, changes),
changes: changes.destructiveChanges.length,
destructiveChanges: changes.destructiveChanges.length,
anyChanges: changes.destructiveChanges.length > 0 || changes.removedResources > 0 || changes.updatedResources > 0 || changes.createdResources > 0,
};

} catch (e: any) {
Expand Down
33 changes: 27 additions & 6 deletions test/stage-processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe('StageProcessor', () => {
name: 'Stage1',
stacks: [stackInfo],
},
], []);
], [], false);
await processor.processStages();
const p = (processor as any).stageComments;
expect(p).toEqual({
Expand All @@ -78,6 +78,27 @@ describe('StageProcessor', () => {
expect(p.Stage1.stackComments['my-stack']).toEqual(['No Changes for stack: my-stack :white_check_mark:']);
});

test('stage with no diffs and ignored', async () => {
cfnMock.on(GetTemplateCommand)
.resolves({
TemplateBody: JSON.stringify(stackInfo.content),
});
const processor = new StageProcessor([
{
name: 'Stage1',
stacks: [stackInfo],
},
], [], true);
await processor.processStages();
const p = (processor as any).stageComments;
expect(p).toEqual({
Stage1: expect.any(Object),
});
expect(p.Stage1.stackComments['my-stack']).toEqual([]);
expect(createCommentMock).toHaveBeenCalledTimes(0);
expect(updateCommentMock).toHaveBeenCalledTimes(0);
});

test('stage with diff', async () => {
cfnMock.on(GetTemplateCommand)
.resolves({
Expand All @@ -101,7 +122,7 @@ describe('StageProcessor', () => {
},
}],
},
], []);
], [], false);
await processor.processStages();
const p = (processor as any).stageComments;
expect(p).toEqual({
Expand Down Expand Up @@ -134,7 +155,7 @@ describe('StageProcessor', () => {
},
}],
},
], []);
], [], false);
await processor.processStages(['Stage1']);
const p = (processor as any).stageComments;
expect(p).toEqual({
Expand Down Expand Up @@ -167,7 +188,7 @@ describe('StageProcessor', () => {
},
}],
},
], []);
], [], false);
await processor.processStages(['Stage1']);
await processor.commentStages(new Comments({} as any, {} as any));
expect(createCommentMock).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -198,7 +219,7 @@ describe('StageProcessor', () => {
},
}],
},
], []);
], [], false);
findPreviousMock.mockResolvedValue(1);
await processor.processStages(['Stage1']);
await processor.commentStages(new Comments({} as any, {} as any));
Expand Down Expand Up @@ -231,7 +252,7 @@ describe('StageProcessor', () => {
name: 'Stage1',
stacks: createStacks(10),
},
], []);
], [], false);
findPreviousMock.mockResolvedValue(1);
await processor.processStages(['Stage1']);
await processor.commentStages(new Comments({} as any, {} as any));
Expand Down
Loading