Skip to content

Commit e62a14b

Browse files
committed
feat: allow checks and groups to refer to resources they are linked to
Covers private locations and alert channels.
1 parent c13e8b7 commit e62a14b

30 files changed

+536
-220
lines changed

Diff for: packages/cli/src/commands/import/plan.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import { splitConfigFilePath } from '../../services/util'
1212
import { loadChecklyConfig } from '../../services/checkly-config-loader'
1313
import { ImportPlan } from '../../rest/projects'
1414
import { Program, Output } from '../../sourcegen'
15-
import { ConstructCodegen } from '../../constructs/construct-codegen'
15+
import { ConstructCodegen, sortResources } from '../../constructs/construct-codegen'
16+
import { Context } from '../../constructs/internal/codegen'
1617

1718
export default class ImportPlanCommand extends AuthCommand {
1819
static coreCommand = true
@@ -91,10 +92,17 @@ export default class ImportPlanCommand extends AuthCommand {
9192
try {
9293
const program = new Program()
9394
const codegen = new ConstructCodegen(program)
95+
const context = new Context()
9496

9597
if (plan.changes) {
98+
sortResources(plan.changes.resources as any)
99+
100+
for (const resource of plan.changes.resources) {
101+
codegen.prepare(resource.logicalId, resource as any, context)
102+
}
103+
96104
for (const resource of plan.changes.resources) {
97-
codegen.gencode(resource.logicalId, resource as any)
105+
codegen.gencode(resource.logicalId, resource as any, context)
98106
}
99107
}
100108

Diff for: packages/cli/src/constructs/alert-channel-codegen.ts

+45-27
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
1-
import { Codegen } from './internal/codegen'
1+
import { Codegen, Context } from './internal/codegen'
22
import { Program, ObjectValueBuilder } from '../sourcegen'
33

4-
import { EmailAlertChannelCodegen, EmailAlertChannelResource } from './email-alert-channel-codegen'
5-
import { OpsgenieAlertChannelCodegen, OpsgenieAlertChannelResource } from './opsgenie-alert-channel-codegen'
6-
import { PagerdutyAlertChannelCodegen, PagerdutyAlertChannelResource } from './pagerduty-alert-channel-codegen'
7-
import { PhoneCallAlertChannelCodegen, PhoneCallAlertChannelResource } from './phone-call-alert-channel-codegen'
8-
import { SlackAlertChannelCodegen, SlackAlertChannelResource } from './slack-alert-channel-codegen'
9-
import { SmsAlertChannelCodegen, SmsAlertChannelResource } from './sms-alert-channel-codegen'
10-
import { WebhookAlertChannelCodegen, WebhookAlertChannelResource } from './webhook-alert-channel-codegen'
4+
import { EmailAlertChannelCodegen } from './email-alert-channel-codegen'
5+
import { OpsgenieAlertChannelCodegen } from './opsgenie-alert-channel-codegen'
6+
import { PagerdutyAlertChannelCodegen } from './pagerduty-alert-channel-codegen'
7+
import { PhoneCallAlertChannelCodegen } from './phone-call-alert-channel-codegen'
8+
import { SlackAlertChannelCodegen } from './slack-alert-channel-codegen'
9+
import { SmsAlertChannelCodegen } from './sms-alert-channel-codegen'
10+
import { WebhookAlertChannelCodegen } from './webhook-alert-channel-codegen'
11+
12+
export type AlertChannelType =
13+
'CALL' |
14+
'EMAIL' |
15+
'OPSGENIE' |
16+
'PAGERDUTY' |
17+
'SLACK' |
18+
'SMS' |
19+
'WEBHOOK'
1120

1221
export interface AlertChannelResource {
13-
type: string
22+
id: number
23+
type: AlertChannelType
1424
sendRecovery: boolean
1525
sendFailure: boolean
1626
sendDegraded: boolean
@@ -48,6 +58,7 @@ export class AlertChannelCodegen extends Codegen<AlertChannelResource> {
4858
slackCodegen: SlackAlertChannelCodegen
4959
smsCodegen: SmsAlertChannelCodegen
5060
webhookCodegen: WebhookAlertChannelCodegen
61+
codegensByType: Record<AlertChannelType, Codegen<any>>
5162

5263
constructor (program: Program) {
5364
super(program)
@@ -58,26 +69,33 @@ export class AlertChannelCodegen extends Codegen<AlertChannelResource> {
5869
this.slackCodegen = new SlackAlertChannelCodegen(program)
5970
this.smsCodegen = new SmsAlertChannelCodegen(program)
6071
this.webhookCodegen = new WebhookAlertChannelCodegen(program)
72+
73+
this.codegensByType = {
74+
CALL: this.phoneCallCodegen,
75+
EMAIL: this.emailCodegen,
76+
OPSGENIE: this.opsgenieCodegen,
77+
PAGERDUTY: this.pagerdutyCodegen,
78+
SLACK: this.slackCodegen,
79+
SMS: this.smsCodegen,
80+
WEBHOOK: this.webhookCodegen,
81+
}
82+
}
83+
84+
prepare (logicalId: string, resource: AlertChannelResource, context: Context): void {
85+
const codegen = this.codegensByType[resource.type]
86+
if (codegen === undefined) {
87+
throw new Error(`Unable to generate code for unsupported alert channel type '${resource.type}'.`)
88+
}
89+
90+
codegen.prepare(logicalId, resource, context)
6191
}
6292

63-
gencode (logicalId: string, resource: AlertChannelResource): void {
64-
switch (resource.type) {
65-
case 'CALL':
66-
return this.phoneCallCodegen.gencode(logicalId, resource as PhoneCallAlertChannelResource)
67-
case 'EMAIL':
68-
return this.emailCodegen.gencode(logicalId, resource as EmailAlertChannelResource)
69-
case 'OPSGENIE':
70-
return this.opsgenieCodegen.gencode(logicalId, resource as OpsgenieAlertChannelResource)
71-
case 'PAGERDUTY':
72-
return this.pagerdutyCodegen.gencode(logicalId, resource as PagerdutyAlertChannelResource)
73-
case 'SLACK':
74-
return this.slackCodegen.gencode(logicalId, resource as SlackAlertChannelResource)
75-
case 'SMS':
76-
return this.smsCodegen.gencode(logicalId, resource as SmsAlertChannelResource)
77-
case 'WEBHOOK':
78-
return this.webhookCodegen.gencode(logicalId, resource as WebhookAlertChannelResource)
79-
default:
80-
throw new Error(`Unable to generate code for unsupported alert channel type '${resource.type}'.`)
93+
gencode (logicalId: string, resource: AlertChannelResource, context: Context): void {
94+
const codegen = this.codegensByType[resource.type]
95+
if (codegen === undefined) {
96+
throw new Error(`Unable to generate code for unsupported alert channel type '${resource.type}'.`)
8197
}
98+
99+
codegen.gencode(logicalId, resource, context)
82100
}
83101
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Codegen, Context } from './internal/codegen'
2+
3+
export interface AlertChannelSubscriptionResource {
4+
alertChannelId: number
5+
groupId?: number
6+
checkId?: string
7+
}
8+
9+
export class AlertChannelSubscriptionCodegen extends Codegen<AlertChannelSubscriptionResource> {
10+
prepare (logicalId: string, resource: AlertChannelSubscriptionResource, context: Context): void {
11+
if (resource.checkId !== undefined) {
12+
context.registerAlertChannelCheckSubscription(resource.alertChannelId, resource.checkId)
13+
}
14+
15+
if (resource.groupId !== undefined) {
16+
context.registerAlertChannelGroupSubscription(resource.alertChannelId, resource.groupId)
17+
}
18+
}
19+
20+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
21+
gencode (logicalId: string, resource: AlertChannelSubscriptionResource, context: Context): void {
22+
// Nothing to generate for this resource.
23+
}
24+
}

Diff for: packages/cli/src/constructs/api-check-codegen.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Codegen } from './internal/codegen'
1+
import { Codegen, Context } from './internal/codegen'
22
import { expr, ident, Program, Value } from '../sourcegen'
33
import { Assertion, Request } from './api-check'
44
import { buildCheckProps, CheckResource } from './check-codegen'
@@ -40,7 +40,7 @@ export function valueForAssertion (program: Program, assertion: Assertion): Valu
4040
const construct = 'ApiCheck'
4141

4242
export class ApiCheckCodegen extends Codegen<ApiCheckResource> {
43-
gencode (logicalId: string, resource: ApiCheckResource): void {
43+
gencode (logicalId: string, resource: ApiCheckResource, context: Context): void {
4444
this.program.import(construct, 'checkly/constructs')
4545

4646
this.program.section(expr(ident(construct), builder => {
@@ -145,7 +145,7 @@ export class ApiCheckCodegen extends Codegen<ApiCheckResource> {
145145
builder.number('maxResponseTime', resource.maxResponseTime)
146146
}
147147

148-
buildCheckProps(this.program, builder, resource)
148+
buildCheckProps(this.program, builder, resource, context)
149149
})
150150
})
151151
}))

Diff for: packages/cli/src/constructs/browser-check-codegen.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Codegen } from './internal/codegen'
1+
import { Codegen, Context } from './internal/codegen'
22
import { expr, ident } from '../sourcegen'
33
import { buildCheckProps, CheckResource } from './check-codegen'
44
import { PlaywrightConfigResource, valueForPlaywrightConfig } from './playwright-config-codegen'
@@ -14,7 +14,7 @@ export interface BrowserCheckResource extends CheckResource{
1414
const construct = 'BrowserCheck'
1515

1616
export class BrowserCheckCodegen extends Codegen<BrowserCheckResource> {
17-
gencode (logicalId: string, resource: BrowserCheckResource): void {
17+
gencode (logicalId: string, resource: BrowserCheckResource, context: Context): void {
1818
this.program.import(construct, 'checkly/constructs')
1919

2020
this.program.section(expr(ident(construct), builder => {
@@ -39,7 +39,7 @@ export class BrowserCheckCodegen extends Codegen<BrowserCheckResource> {
3939
builder.value('playwrightConfig', valueForPlaywrightConfig(resource.playwrightConfig))
4040
}
4141

42-
buildCheckProps(this.program, builder, resource)
42+
buildCheckProps(this.program, builder, resource, context)
4343
})
4444
})
4545
}))

Diff for: packages/cli/src/constructs/check-codegen.ts

+46-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Codegen } from './internal/codegen'
1+
import { Codegen, Context } from './internal/codegen'
22
import { Program, ObjectValueBuilder } from '../sourcegen'
33
import { AlertEscalationResource, valueForAlertEscalation } from './alert-escalation-policy-codegen'
44
import { ApiCheckCodegen, ApiCheckResource } from './api-check-codegen'
@@ -9,11 +9,11 @@ import { FrequencyResource, valueForFrequency } from './frequency-codegen'
99
import { HeartbeatCheckCodegen, HeartbeatCheckResource } from './heartbeat-check-codegen'
1010
import { valueForKeyValuePair } from './key-value-pair-codegen'
1111
import { MultiStepCheckCodegen, MultiStepCheckResource } from './multi-step-check-codegen'
12-
import { valueForRef } from './ref-codegen'
1312
import { RetryStrategyResource, valueForRetryStrategy } from './retry-strategy-codegen'
1413
import { TcpCheckCodegen, TcpCheckResource } from './tcp-check-codegen'
1514

1615
export interface CheckResource {
16+
id: string
1717
checkType: string
1818
name: string
1919
activated?: boolean
@@ -22,7 +22,6 @@ export interface CheckResource {
2222
shouldFail?: boolean
2323
runtimeId?: string
2424
locations?: string[]
25-
// TODO: privateLocations
2625
tags?: string[]
2726
frequency?: FrequencyResource
2827
environmentVariables?: EnvironmentVariable[]
@@ -37,6 +36,7 @@ export function buildCheckProps (
3736
program: Program,
3837
builder: ObjectValueBuilder,
3938
resource: CheckResource,
39+
context: Context,
4040
): void {
4141
builder.string('name', resource.name)
4242

@@ -65,9 +65,21 @@ export function buildCheckProps (
6565
})
6666
}
6767

68-
// if (resource.privateLocations) {
69-
// // TODO: privateLocations - live variables
70-
// }
68+
const privateLocationIds = (() => {
69+
try {
70+
return context.lookupCheckPrivateLocations(resource.id)
71+
} catch (err) {
72+
}
73+
})()
74+
75+
if (privateLocationIds !== undefined) {
76+
builder.array('privateLocations', builder => {
77+
for (const privateLocationId of privateLocationIds) {
78+
const privateLocationVariable = context.lookupPrivateLocation(privateLocationId)
79+
builder.value(privateLocationVariable)
80+
}
81+
})
82+
}
7183

7284
if (resource.tags) {
7385
const tags = resource.tags
@@ -91,17 +103,30 @@ export function buildCheckProps (
91103
})
92104
}
93105

94-
// if (resource.groupId) {
95-
// builder.value('groupId', valueForRef(program, resource.groupId))
96-
// }
106+
if (resource.groupId) {
107+
try {
108+
const groupVariable = context.lookupCheckGroup(resource.groupId)
109+
builder.value('group', groupVariable)
110+
} catch (err) {
111+
throw new Error('Check belongs to a group that is not being imported.')
112+
}
113+
}
97114

98-
// if (resource.group) {
99-
// // TODO: group - live variables
100-
// }
115+
const alertChannelIds = (() => {
116+
try {
117+
return context.lookupCheckAlertChannels(resource.id)
118+
} catch (err) {
119+
}
120+
})()
101121

102-
// if (resource.alertChannels) {
103-
// // TODO: alertChannels - live variables
104-
// }
122+
if (alertChannelIds !== undefined) {
123+
builder.array('alertChannels', builder => {
124+
for (const alertChannelId of alertChannelIds) {
125+
const alertChannelVariable = context.lookupAlertChannel(alertChannelId)
126+
builder.value(alertChannelVariable)
127+
}
128+
})
129+
}
105130

106131
if (resource.alertSettings) {
107132
builder.value('alertEscalationPolicy', valueForAlertEscalation(program, resource.alertSettings))
@@ -136,20 +161,20 @@ export class CheckCodegen extends Codegen<CheckResource> {
136161
this.tcpCheckCodegen = new TcpCheckCodegen(program)
137162
}
138163

139-
gencode (logicalId: string, resource: CheckResource): void {
164+
gencode (logicalId: string, resource: CheckResource, context: Context): void {
140165
const { checkType } = resource
141166

142167
switch (checkType) {
143168
case 'BROWSER':
144-
return this.browserCheckCodegen.gencode(logicalId, resource as BrowserCheckResource)
169+
return this.browserCheckCodegen.gencode(logicalId, resource as BrowserCheckResource, context)
145170
case 'API':
146-
return this.apiCheckCodegen.gencode(logicalId, resource as ApiCheckResource)
171+
return this.apiCheckCodegen.gencode(logicalId, resource as ApiCheckResource, context)
147172
case 'TCP':
148-
return this.tcpCheckCodegen.gencode(logicalId, resource as TcpCheckResource)
173+
return this.tcpCheckCodegen.gencode(logicalId, resource as TcpCheckResource, context)
149174
case 'MULTI_STEP':
150-
return this.multiStepCheckCodegen.gencode(logicalId, resource as MultiStepCheckResource)
175+
return this.multiStepCheckCodegen.gencode(logicalId, resource as MultiStepCheckResource, context)
151176
case 'HEARTBEAT':
152-
return this.heartbeatCheckCodegen.gencode(logicalId, resource as HeartbeatCheckResource)
177+
return this.heartbeatCheckCodegen.gencode(logicalId, resource as HeartbeatCheckResource, context)
153178
default:
154179
throw new Error(`Unable to generate code for unsupported check type '${checkType}'.`)
155180
}

0 commit comments

Comments
 (0)