Add campaign CRUD client methods and check management#611
Conversation
7877f45 to
ea1f16b
Compare
Adds GetCampaign, CreateCampaign, UpdateCampaign, DeleteCampaign, ScheduleCampaign, and UnscheduleCampaign client methods along with their corresponding input and payload types. These are needed by the terraform-provider-opslevel campaign resource. Made-with: Cursor
ea1f16b to
2fc76ed
Compare
The OpsLevel API doesn't have a campaignSchedule mutation. Scheduling is done by passing startDate/targetDate in campaignCreate/campaignUpdate. Removes ScheduleCampaign method and CampaignScheduleUpdateInput. Made-with: Cursor
The OpsLevel API uses a separate campaignScheduleUpdate mutation (not campaignSchedule, and not fields on create/update inputs). Also uses generic DeleteInput for campaignDelete/campaignUnschedule. Made-with: Cursor
Made-with: Cursor
Replace CheckIdsToCopy on CampaignCreateInput with a dedicated CopyChecksToCampaign method that calls the checksCopyToCampaign GraphQL mutation. This is the correct API for associating rubric checks with a campaign after creation. Changes: - Add ChecksCopyToCampaignInput and ChecksCopyToCampaignPayload types - Add Client.CopyChecksToCampaign method - Remove CheckIdsToCopy from CampaignCreateInput (not a real API field) - Add comprehensive tests for all campaign CRUD operations (Create, Get, Update, Delete, Schedule, Unschedule, CopyChecks) - Add test fixtures in campaigns.tpl for all operations Made-with: Cursor
Adds a lightweight query for fetching a campaign's checks (id + name only) to enable matching and deleting campaign checks when rubric check IDs are removed from the Terraform resource's check_ids list. Made-with: Cursor
|
Alright, tested a full path of create, update and delete. required_providers {
opslevel = {
source = "jamescarr/opslevel"
version = "1.10.9"
}resource "opslevel_campaign" "demo_may_rollout" {
name = "June 2026 Demo Checks Rollout (Revised)"
owner_id = data.opslevel_team.staff.id
filter_id = data.opslevel_filter.tier1.id
start_date = "2026-06-15"
target_date = "2026-08-15"
check_ids = [
opslevel_check_manual.demo_secret_rotation.id,
opslevel_check_manual.demo_dependency_scanning.id,
opslevel_check_manual.demo_error_budget.id,
]
project_brief = <<-EOT
## Overview
Three checks are being enabled on **June 15, 2026** as part of the
revised sandbox demo rollout. All Tier 1 services must pass by **August 15, 2026**.
## Checks Included
| Check | Category | What it verifies |
|-------|----------|-----------------|
| DEMO-001 | Security | Secrets rotated every 90 days |
| DEMO-002 | Security | Dependency vulnerability scanning |
| DEMO-003 | Reliability | Error budget defined and tracked |
## What you need to do
1. Review each check's notes for pass criteria
2. Implement any missing requirements
3. Mark manual checks as passing with a comment explaining evidence
## Resources
- [OpsLevel Checks as Code](https://engineering.index/guides/architecture/opslevel-checks/)
- Questions? Reach out in #service-opslevel
EOT
}Opslevel Output |
Adds a test verifying ListCampaignChecks returns an empty slice when a campaign has no checks, plus the supporting template. Made-with: Cursor
…cursive pagination Aligns GetCampaign with the empty-ID convention used by GetCategory, GetScorecard, etc. Converts ListCampaignChecks from iterative to recursive pagination to match the rest of the SDK. Made-with: Cursor
c154bf6 to
5795287
Compare
|
@andrewstillv15 🔴 P0 —
|


Closes #612
Add full campaign lifecycle management to the Go SDK via GraphQL.
Problem
The OpsLevel GraphQL API exposes full campaign mutation support (
campaignCreate,campaignUpdate,campaignDelete,campaignScheduleUpdate,campaignUnschedule,campaignEnd) pluschecksCopyToCampaignfor associating checks, but the Go SDK only has aListCampaignsquery. There are no client methods for creating, reading, updating, deleting, scheduling, or managing campaign checks — which blocks the Terraform provider from managing campaigns as code.Solution
Input types (
input.go):Added GraphQL input structs matching the API schema:
CampaignCreateInput— name, ownerId, filterId, projectBrief, checkIdsToCopy, reminderCampaignUpdateInput— id + optional fields for name, ownerId, filterId, projectBrief, reminderCampaignScheduleUpdateInput— id, startDate, targetDateCampaignEndInput— id, checksToPromoteCampaignUnscheduleInput— idCampaignReminderInput— frequency, frequencyUnit, timeOfDay, timezone, channels, message, daysOfWeek, defaultSlackChannelChecksCopyToCampaignInput— campaignId, checkIdsPayload types (
payload.go):Added response types for each mutation:
CampaignCreatePayload,CampaignUpdatePayload,CampaignDeletePayload,CampaignScheduleUpdatePayload,CampaignUnschedulePayload,CampaignEndPayload,ChecksCopyToCampaignPayload.Client methods (
campaign.go):GetCampaign(id)account.campaign(id:)CreateCampaign(input)campaignCreateUpdateCampaign(input)campaignUpdateDeleteCampaign(id)campaignDeleteScheduleCampaign(input)campaignScheduleUpdateUnscheduleCampaign(id)campaignUnscheduleEndCampaign(input)campaignEndCopyChecksToCampaign(input)checksCopyToCampaignListCampaignChecks(id)account.campaign.checksAll methods follow the existing SDK patterns (
client.Mutate/client.Query+HandleErrors).GetCampaignuses theaccount { campaign(id: $id) }query path discovered via schema introspection.Tests (
campaign_test.go):Full test coverage for all new methods including edge cases:
CopyChecksToCampaignListCampaignChecks(with results and empty campaign)Checklist