Skip to content

Add campaign CRUD client methods and check management#611

Open
jamescarr wants to merge 9 commits intoOpsLevel:mainfrom
jamescarr:jamescarr/add-campaign-crud
Open

Add campaign CRUD client methods and check management#611
jamescarr wants to merge 9 commits intoOpsLevel:mainfrom
jamescarr:jamescarr/add-campaign-crud

Conversation

@jamescarr
Copy link
Copy Markdown

@jamescarr jamescarr commented Apr 9, 2026

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) plus checksCopyToCampaign for associating checks, but the Go SDK only has a ListCampaigns query. 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, reminder
  • CampaignUpdateInput — id + optional fields for name, ownerId, filterId, projectBrief, reminder
  • CampaignScheduleUpdateInput — id, startDate, targetDate
  • CampaignEndInput — id, checksToPromote
  • CampaignUnscheduleInput — id
  • CampaignReminderInput — frequency, frequencyUnit, timeOfDay, timezone, channels, message, daysOfWeek, defaultSlackChannel
  • ChecksCopyToCampaignInput — campaignId, checkIds

Payload types (payload.go):

Added response types for each mutation: CampaignCreatePayload,
CampaignUpdatePayload, CampaignDeletePayload,
CampaignScheduleUpdatePayload, CampaignUnschedulePayload,
CampaignEndPayload, ChecksCopyToCampaignPayload.

Client methods (campaign.go):

Method GraphQL Operation Description
GetCampaign(id) account.campaign(id:) Read a single campaign by ID
CreateCampaign(input) campaignCreate Create a draft campaign
UpdateCampaign(input) campaignUpdate Update campaign fields
DeleteCampaign(id) campaignDelete Delete a campaign
ScheduleCampaign(input) campaignScheduleUpdate Set start and target dates
UnscheduleCampaign(id) campaignUnschedule Revert to draft
EndCampaign(input) campaignEnd End campaign, optionally promote checks
CopyChecksToCampaign(input) checksCopyToCampaign Copy rubric checks into a campaign
ListCampaignChecks(id) account.campaign.checks List checks belonging to a campaign (paginated)

All methods follow the existing SDK patterns (client.Mutate / client.Query + HandleErrors). GetCampaign uses the account { campaign(id: $id) } query path discovered via schema introspection.

Tests (campaign_test.go):

Full test coverage for all new methods including edge cases:

  • CRUD operations (create, get, update, delete)
  • Schedule/unschedule lifecycle
  • CopyChecksToCampaign
  • ListCampaignChecks (with results and empty campaign)

Checklist

  • I have run this code, and it appears to resolve the stated issue.
  • This PR does not reduce total test coverage

@jamescarr jamescarr force-pushed the jamescarr/add-campaign-crud branch from 7877f45 to ea1f16b Compare April 9, 2026 17:18
@jamescarr jamescarr changed the title Add campaign CRUD client methods WIP: Add campaign CRUD client methods Apr 9, 2026
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
@jamescarr jamescarr force-pushed the jamescarr/add-campaign-crud branch from ea1f16b to 2fc76ed Compare April 13, 2026 16:08
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
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
@jamescarr
Copy link
Copy Markdown
Author

jamescarr commented Apr 13, 2026

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
@jamescarr jamescarr changed the title WIP: Add campaign CRUD client methods Add campaign CRUD client methods Apr 13, 2026
@jamescarr jamescarr changed the title Add campaign CRUD client methods Add campaign CRUD client methods and check management Apr 13, 2026
…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
@jamescarr jamescarr force-pushed the jamescarr/add-campaign-crud branch from c154bf6 to 5795287 Compare April 16, 2026 03:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add campaign CRUD client methods and check management

1 participant