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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
65 changes: 65 additions & 0 deletions .claude/commands/new-alert-channel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Add a New Alert Channel Construct

**Input:** $ARGUMENTS

Interpret the arguments as a description of the new alert channel: its name, what service it integrates with, and its configuration properties. If arguments are missing or unclear, ask before proceeding.

There are two alert channel families:

- **Webhook-based** (e.g., Telegram, Incident.io, MS Teams) — extends `WebhookAlertChannel`, routes through `webhook-alert-channel-codegen.ts`. Use **TelegramAlertChannel** as reference.
- **Standalone** (e.g., Slack, Opsgenie, PagerDuty) — extends `AlertChannel` directly, routes through `alert-channel-codegen.ts`. Use **SlackAlertChannel** as reference.

Determine which family applies based on the integration. If unsure, ask.

All paths below are relative to `packages/cli/`.

## Phase 1: Core Construct File (new file)

- [ ] `src/constructs/{name}-alert-channel.ts`
- **Webhook-based**: Class extending `WebhookAlertChannel`. Define `{Name}AlertChannelProps` extending `AlertChannelProps`. In the constructor, call `super(logicalId, props)` (add `// @ts-ignore` above the call — the props type mismatch with `WebhookAlertChannelProps` is expected), then set `this.webhookType = 'WEBHOOK_{UPPER_NAME}'`, `this.method`, `this.url`, and `this.template`. Implement `describe()` and `synthesize()` (synthesize returns `type: 'WEBHOOK'` with a `config` object containing `name`, `webhookType`, `url`, `template`, `method`, `headers`, `queryParameters`, `webhookSecret`).
- **Standalone**: Class extending `AlertChannel`. Define `{Name}AlertChannelProps` extending `AlertChannelProps`. In the constructor, call `super(logicalId, props)` and `Session.registerConstruct(this)`. Implement `describe()` and `synthesize()` (synthesize returns a unique `type` string and a `config` object with channel-specific properties).

## Phase 2: Code Generation File (new file)

- [ ] `src/constructs/{name}-alert-channel-codegen.ts`
- Class `{Name}AlertChannelCodegen` extending `Codegen<{Name}AlertChannelResource>`.
- Define `{Name}AlertChannelResource` interface extending the appropriate parent (`WebhookAlertChannelResource` or `AlertChannelResource`).
- Implement `describe()`, `prepare()`, and `gencode()`. For **webhook-based** channels, also implement `validateSafety()` to reject unexpected values for method, headers, queryParameters, and webhookSecret (standalone channels do not need this).
- `prepare()`: resolve file path via `context.filePath()`, register with `context.registerAlertChannel()`.
- `gencode()`: look up alert channel, add imports, emit `new {Name}AlertChannel(...)` expression using `file.section(decl(...))` pattern. Call `buildAlertChannelProps()` from `./alert-channel-codegen.js`.

## Phase 3: Registry (modify existing files)

- [ ] `src/constructs/index.ts` — Add export: `export * from './{name}-alert-channel.js'`

- [ ] **Webhook-based** — `src/constructs/webhook-alert-channel-codegen.ts`:
1. Add `'WEBHOOK_{UPPER_NAME}'` to `WebhookType` union
2. Import `{Name}AlertChannelCodegen`
3. Add property and initialize in constructor
4. Add entry to `codegensByWebhookType` map

- [ ] **Standalone** — `src/constructs/alert-channel-codegen.ts`:
1. Add `'{UPPER_NAME}'` to `AlertChannelType` union
2. Import `{Name}AlertChannelCodegen`
3. Add property and initialize in constructor
4. Add entry to `codegensByType` map

## Phase 4: Tests (new file)

- [ ] `src/constructs/__tests__/{name}-alert-channel.spec.ts` — Unit tests covering: construct instantiation, `synthesize()` output structure, property mapping, and `describe()`. Follow existing alert channel tests as template.

## Phase 5: Build and Verify

- [ ] `pnpm --filter checkly run prepare` — Rebuild.
- [ ] `pnpm --filter checkly test` — Run unit tests.
- [ ] `pnpm lint:fix` — Fix formatting (run from repo root).

## Naming Conventions

| Concept | Pattern | Example (Telegram) |
|---------|---------|-------------------|
| File name | `{name}-alert-channel.ts` | `telegram-alert-channel.ts` |
| Class name | `{Name}AlertChannel` | `TelegramAlertChannel` |
| Props interface | `{Name}AlertChannelProps` | `TelegramAlertChannelProps` |
| Webhook type | `WEBHOOK_{UPPER_NAME}` | `WEBHOOK_TELEGRAM` |
| Codegen class | `{Name}AlertChannelCodegen` | `TelegramAlertChannelCodegen` |
88 changes: 88 additions & 0 deletions .claude/commands/new-monitor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Add a New Monitor Construct

**Input:** $ARGUMENTS

Interpret the arguments as a description of the new monitor: its name, what it monitors, its custom properties, and its assertion sources. If arguments are missing or unclear, ask before proceeding.

Use an existing monitor as your reference implementation. For monitors with assertions and requests (the common case), use **IcmpMonitor** or **DnsMonitor**. For simpler constructs without assertions, use **HeartbeatMonitor**.

All paths below are relative to `packages/cli/` unless noted otherwise.

## Phase 1: Core Construct Files (new files)

Create these three files (skip assertion + request if the construct has no assertions):

- [ ] `src/constructs/{name}-monitor.ts` — Class extending `Monitor` (from `./monitor.js`). Define `{Name}MonitorProps` extending `MonitorProps`. Implement `constructor`, `describe()`, `validate()`, `synthesize()`. The constructor must call `Session.registerConstruct(this)`, `this.addSubscriptions()`, and `this.addPrivateLocationCheckAssignments()`. `synthesize()` must include `checkType: '{UPPER_NAME}'` and spread `super.synthesize()`.

- [ ] `src/constructs/{name}-assertion.ts` — Define `{Name}AssertionSource` union type, `{Name}Assertion` type alias using `CoreAssertion`, and `{Name}AssertionBuilder` class with static methods per assertion source. Use `NumericAssertionBuilder` for numeric sources (e.g., latency) and `GeneralAssertionBuilder` for text/JSON sources. Import builders from `./internal/assertion.js`.

- [ ] `src/constructs/{name}-request.ts` — Define `{Name}Request` interface with request configuration properties. Include an `assertions?: Array<{Name}Assertion>` field if assertions are supported.

## Phase 2: Code Generation Files (new files)

- [ ] `src/constructs/{name}-monitor-codegen.ts` — Class `{Name}MonitorCodegen` extending `Codegen<{Name}MonitorResource>`. Define `{Name}MonitorResource` extending `MonitorResource` with `checkType: '{UPPER_NAME}'`. Implement `describe()` and `gencode()`. Follow the exact pattern in `IcmpMonitorCodegen.gencode()`: resolve output path via `context.filePath()`, get file handle via `this.program.generatedConstructFile()`, add imports with `file.namedImport()`, emit the `new {Name}Monitor(...)` expression via `file.section()`, and call `buildMonitorProps()` from `./monitor-codegen.js`.

- [ ] `src/constructs/{name}-assertion-codegen.ts` — Export `valueFor{Name}Assertion()` function. Switch on `assertion.source`, delegate to `valueForNumericAssertion` or `valueForGeneralAssertion` from `./internal/assertion-codegen.js`.

- [ ] `src/constructs/{name}-request-codegen.ts` — Export `valueFor{Name}Request()` function. Build an object value with request fields, calling `valueFor{Name}Assertion()` for each assertion.

## Phase 3: Central Registry (modify existing files)

- [ ] `src/constructs/index.ts` — Add three export lines:
```
export * from './{name}-monitor.js'
export * from './{name}-assertion.js'
export * from './{name}-request.js'
```

- [ ] `src/constructs/check-codegen.ts` — (1) Import `{Name}MonitorCodegen` and `{Name}MonitorResource`. (2) Add property `{name}MonitorCodegen: {Name}MonitorCodegen` to `CheckCodegen`. (3) Initialize in constructor. (4) Add `case '{UPPER_NAME}':` in both the `describe()` and `gencode()` switch statements.

- [ ] `src/constants.ts` — Add `{UPPER_NAME}: '{UPPER_NAME}'` to the `CheckTypes` object.

## Phase 4: Reporter and Formatter Integration (modify existing files)

- [ ] `src/reporters/util.ts` — Add `if (checkResult.checkType === '{UPPER_NAME}')` block in `formatCheckResult()`. Define `format{Name}Request()` and `format{Name}Response()` functions, and add subsections for request errors, connection errors, and assertions as appropriate. Follow the ICMP or DNS block as a template.

- [ ] `src/formatters/batch-stats.ts` — Add detection logic for the new check type in `buildColumns()` and add metric-specific columns if the construct has unique metrics (not standard response time).

- [ ] `src/rest/analytics.ts` — Add entry to `checkTypeToPath` map and `defaultMetrics` map.

## Phase 5: AI Context (new file + modify existing)

- [ ] `src/ai-context/references/configure-{name}-monitors.md` — New markdown reference. Follow the pattern of `configure-icmp-monitors.md`.

- [ ] `src/ai-context/context.ts` — Add entry to `REFERENCES` array and add an `{UPPER_NAME}_MONITOR` entry to `EXAMPLE_CONFIGS`.

## Phase 6: Tests (new files + modify existing)

- [ ] `src/constructs/__tests__/{name}-monitor.spec.ts` — Unit tests covering: default synthesis, group assignment, request properties, validation, assertion builder methods. Follow `icmp-monitor.spec.ts` as template.

- [ ] `e2e/__tests__/fixtures/deploy-project/{name}.check.ts` — Minimal construct instantiation with `activated: false`.

- [ ] `e2e/__tests__/deploy.spec.ts` — Add the new construct's logical ID to expected `Create:` output in deploy test assertions.

## Phase 7: Examples (new files, paths relative to repo root)

- [ ] `examples/advanced-project/src/__checks__/uptime/{name}.check.ts` — TypeScript example with group, assertions, and doc link comments.

- [ ] `examples/advanced-project-js/src/__checks__/uptime/{name}.check.js` — JavaScript equivalent.

## Phase 8: Build and Verify

- [ ] `pnpm --filter checkly run prepare` — Rebuild (compiles TS + regenerates AI context).
- [ ] `pnpm --filter checkly test` — Run unit tests.
- [ ] `pnpm run sync:skills` — Sync AI context to published skills (from repo root).
- [ ] `pnpm lint:fix` — Fix formatting (run from repo root).

## Naming Conventions

| Concept | Pattern | Example (ICMP) |
|---------|---------|----------------|
| File names | `{name}-monitor.ts` | `icmp-monitor.ts` |
| Class name | `{Name}Monitor` | `IcmpMonitor` |
| Props interface | `{Name}MonitorProps` | `IcmpMonitorProps` |
| Check type constant | `{UPPER_NAME}` | `ICMP` |
| Assertion builder | `{Name}AssertionBuilder` | `IcmpAssertionBuilder` |
| Request interface | `{Name}Request` | `IcmpRequest` |
| Codegen class | `{Name}MonitorCodegen` | `IcmpMonitorCodegen` |
| AI context reference | `configure-{name}-monitors.md` | `configure-icmp-monitors.md` |
14 changes: 8 additions & 6 deletions .github/workflows/check-ai-context.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
pull_request:
branches:
- main
- next/*
paths:
- "packages/cli/**"

Expand All @@ -14,14 +15,15 @@ jobs:
pull-requests: write
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v5
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: "npm"
cache-dependency-path: package-lock.json
- run: npm config set fund false && npm set audit false
- run: npm ci
- run: npm run prepare
cache: "pnpm"
- run: pnpm install --frozen-lockfile
- run: pnpm run sync:skills
- name: Check for uncommitted changes in skills/
run: git diff --exit-code skills/
- name: Comment on PR if skills/ is out of date
Expand All @@ -36,5 +38,5 @@ jobs:
Please run the following locally and commit the changes:

\`\`\`
npm run prepare
pnpm run sync:skills
\`\`\`"
14 changes: 7 additions & 7 deletions .github/workflows/release-canary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ jobs:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
- uses: pnpm/action-setup@v5
with:
version: 10
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for trusted publishing support
run: |
npm install -g npm@latest
echo "npm version: $(npm --version)"
cache: "pnpm"
# Extract the dynamic value from the canary label if present
- name: Extract CANARY_TAG
id: extract-canary
Expand All @@ -36,11 +36,11 @@ jobs:
# Ensure that the README is published with the package
- run: rm -f packages/cli/README.md && cp README.md packages/cli
- run: echo "PR_VERSION=0.0.0-pr.${{github.event.pull_request.number}}.$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- run: npm ci
- run: npm version ${{ env.PR_VERSION }} --workspace packages/cli
- run: pnpm install --frozen-lockfile
- run: pnpm --filter checkly version ${{ env.PR_VERSION }} --no-git-tag-version
# Publish to npm with the additional tag if CANARY_TAG is set
- run: |
npm publish --workspace packages/cli --tag experimental
pnpm --filter checkly publish --tag experimental --no-git-checks
if [[ -n "$CANARY_TAG" ]]; then
echo "Publishing with additional tag: $CANARY_TAG"
npm dist-tag add checkly@$PR_VERSION $CANARY_TAG
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/release-create-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v5
with:
version: 10
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm publish --workspace packages/create-cli
cache: "pnpm"
- run: pnpm install --frozen-lockfile
- run: pnpm --filter create-checkly publish --no-git-checks
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# Slack failure alert
Expand Down
44 changes: 18 additions & 26 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,28 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v5
with:
version: 10
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for trusted publishing support
run: |
npm install -g npm@latest
echo "npm version: $(npm --version)"
cache: "pnpm"
# Ensure that the README is published with the package
- run: rm -f packages/cli/README.md && cp README.md packages/cli
- run: npm ci
- run: pnpm install --frozen-lockfile
- name: Add SHORT_SHA env property with commit short sha
run: echo "SHORT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Set version and publish prerelease for 'cli' package
run: |
npm --no-git-tag-version version ${{ github.event.release.tag_name }}-prerelease-${{ env.SHORT_SHA }} --workspace packages/cli
npm publish --provenance --workspace packages/cli --tag prerelease
pnpm --filter checkly version ${{ github.event.release.tag_name }}-prerelease-${{ env.SHORT_SHA }} --no-git-tag-version
pnpm --filter checkly publish --provenance --tag prerelease --no-git-checks
- name: Set version and publish prerelease for 'create-cli' package
run: |
npm --no-git-tag-version version ${{ github.event.release.tag_name }}-prerelease-${{ env.SHORT_SHA }} --workspace packages/create-cli
npm publish --provenance --workspace packages/create-cli --tag prerelease
- name: Output prerelease packages versions
run: |
npm pkg get version --workspace packages/cli
npm pkg get version --workspace packages/create-cli
pnpm --filter create-checkly version ${{ github.event.release.tag_name }}-prerelease-${{ env.SHORT_SHA }} --no-git-tag-version
pnpm --filter create-checkly publish --provenance --tag prerelease --no-git-checks
- name: Save LLM rules as an artifact
uses: actions/upload-artifact@v4
with:
Expand Down Expand Up @@ -103,29 +99,25 @@ jobs:
- uses: actions/checkout@v3
with:
ref: main
- uses: pnpm/action-setup@v5
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Upgrade npm for trusted publishing support
run: |
npm install -g npm@latest
echo "npm version: $(npm --version)"
cache: "pnpm"
# Ensure that the README is published with the package
- run: rm -f packages/cli/README.md && cp README.md packages/cli
- run: npm ci
- run: pnpm install --frozen-lockfile
- name: Set version and publish 'cli' package
run: |
npm --no-git-tag-version version ${{ github.event.release.tag_name }} --workspace packages/cli
npm publish --provenance --workspace packages/cli
pnpm --filter checkly version ${{ github.event.release.tag_name }} --no-git-tag-version
pnpm --filter checkly publish --provenance --no-git-checks
- name: Set version and publish 'create-cli' package
run: |
npm --no-git-tag-version version ${{ github.event.release.tag_name }} --workspace packages/create-cli
npm publish --provenance --workspace packages/create-cli
- name: Output final packages versions
run: |
npm pkg get version --workspace packages/cli
npm pkg get version --workspace packages/create-cli
pnpm --filter create-checkly version ${{ github.event.release.tag_name }} --no-git-tag-version
pnpm --filter create-checkly publish --provenance --no-git-checks
- name: Save LLM rules as an artifact
uses: actions/upload-artifact@v4
with:
Expand Down
Loading
Loading