Skip to content

Commit a671ea8

Browse files
committed
add destructive changeset check
1 parent c156b38 commit a671ea8

2 files changed

Lines changed: 27 additions & 2 deletions

File tree

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,31 @@ It exposes the following main entry points via [packages/deploymentUtils/src/ind
7373
- `writeSchemas` – Writes JSON Schemas to disk, collapsing `examples` arrays into a single `example` value to be compatible with OAS.
7474
- `deleteProxygenDeployments` – Removes Proxygen PTL instances that correspond to closed GitHub pull requests for a given API.
7575
- Config helpers from `config/index` – used to resolve configuration and CloudFormation export values.
76+
- `checkDestructiveChangeSet` – Describes a CloudFormation change set, filters out replacements and removals (optionally applying time-bound waivers) and throws if anything destructive remains.
77+
78+
`checkDestructiveChangeSet(changeSetName, stackName, region, allowedChanges?)` is useful in CI pipelines for blocking deployments that would recreate or delete infrastructure. The optional `allowedChanges` array lets you provide short-lived waivers, for example:
79+
80+
```ts
81+
import {checkDestructiveChangeSet} from "@nhsdigital/eps-deployment-utils"
82+
83+
await checkDestructiveChangeSet(
84+
process.env.CDK_CHANGE_SET_NAME,
85+
process.env.STACK_NAME,
86+
process.env.AWS_REGION,
87+
[
88+
{
89+
LogicalResourceId: "MyAlarm",
90+
PhysicalResourceId: "monitoring-alarm",
91+
ResourceType: "AWS::CloudWatch::Alarm",
92+
StackName: "monitoring",
93+
ExpiryDate: "2026-03-01T00:00:00Z",
94+
AllowedReason: "Pending rename rollout"
95+
}
96+
]
97+
)
98+
```
99+
100+
Each waiver is effective only when the stack name, logical ID, physical ID, and resource type all match and the waiver’s `ExpiryDate` is later than the change set’s `CreationTime`. When no destructive changes remain, the helper logs a confirmation message; otherwise it prints the problematic resources and throws.
76101

77102
Typical usage pattern (pseudo-code):
78103

packages/deploymentUtils/tests/changesets/checkDestructiveChanges.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ vi.mock("@aws-sdk/client-cloudformation", () => {
2020
class CloudFormationClient {
2121
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2222
config: any
23-
constructor(config: {region: string}) {
23+
constructor(config: { region: string }) {
2424
this.config = config
2525
}
2626

@@ -112,7 +112,7 @@ describe("checkDestructiveChangeSet", () => {
112112
await expect(checkDestructiveChangeSet("cs", "stack", "eu-west-2")).resolves.toBeUndefined()
113113

114114
expect(mockCloudFormationSend).toHaveBeenCalledTimes(1)
115-
const command = mockCloudFormationSend.mock.calls[0][0] as {input: {ChangeSetName: string; StackName: string}}
115+
const command = mockCloudFormationSend.mock.calls[0][0] as { input: { ChangeSetName: string; StackName: string } }
116116
expect(command.input).toEqual({ChangeSetName: "cs", StackName: "stack"})
117117
expect(logSpy).toHaveBeenCalledWith("Change set cs for stack stack has no destructive changes.")
118118
expect(errorSpy).not.toHaveBeenCalled()

0 commit comments

Comments
 (0)