Skip to content

Fix opslevel_service dropping preferred_api_document_source when api_document_path is unset (#14748)#647

Open
saditya370 wants to merge 3 commits intomainfrom
fix/14748-preferred-api-document-source-without-path
Open

Fix opslevel_service dropping preferred_api_document_source when api_document_path is unset (#14748)#647
saditya370 wants to merge 3 commits intomainfrom
fix/14748-preferred-api-document-source-without-path

Conversation

@saditya370
Copy link
Copy Markdown
Collaborator

@saditya370 saditya370 commented Apr 29, 2026

Summary

Fixes #14748. Configuring preferred_api_document_source on opslevel_service without also setting api_document_path caused apply to fail with Provider produced inconsistent result after apply: .preferred_api_document_source: was cty.StringVal("PUSH"), but now null. The provider was gating the serviceApiDocSettingsUpdate mutation behind a non-empty api_document_path, so the user's preferred-source value was never sent to the backend — Terraform's plan/state consistency check then rejected the apply.

This is a provider-only fix. The GraphQL backend and opslevel-go client already accepted the two arguments independently; only the provider was incorrectly coupling them.

Changes

  • Add serviceApiDocSettingsUpdateInput(plan, state) helper in opslevel/resource_opslevel_service.go that decides when to call ServiceApiDocSettingsUpdate and with what arguments. Returns shouldUpdate=true whenever either field is configured in plan, or whenever either field was previously managed in state (so unsetting still works).
  • Create now uses the helper, fixing source-only configs.
  • Update now uses the same helper, fixing the prior bug where api_document_path being null silently cleared preferred_api_document_source.
  • Behavior is unchanged for path-only and path-plus-source configs — the helper returns the same arguments the old code sent.

Customer-reported repro

resource "opslevel_service" "example" {
  name                          = "example"
  preferred_api_document_source = "PUSH"
}

Before the fix: terraform apply errored with the inconsistent-result message and left an orphaned service in OpsLevel that Terraform did not record in state.

After the fix: apply succeeds, and a follow-up terraform plan reports No changes.

Test plan

  • New unit tests for serviceApiDocSettingsUpdateInput covering source-only PUSH, source-only PULL, path-only, unmanaged, unset previously-managed source, and unset previously-managed path — see opslevel/resource_opslevel_service_test.go.
  • New tftest regression resource_service_create_with_preferred_api_document_source_without_path reproducing the exact customer config and asserting api_document_path == null and preferred_api_document_source == "PUSH" after apply — see tests/service.tftest.hcl.
  • GOWORK=off go test ./opslevel passes.
  • GOWORK=off go vet ./... clean.
  • GOWORK=off task test passes (104 Terraform tests + Go unit tests).
  • Verified end-to-end against a live OpsLevel tenant: source-only PUSH and PULL configs apply cleanly, idempotent on re-plan, and the resulting services row in the database has the expected api_docs_source value with api_docs_path null.

@saditya370 saditya370 requested a review from wesleyjellis April 29, 2026 13:34
@saditya370 saditya370 self-assigned this Apr 29, 2026
resp.Diagnostics.AddError("opslevel client error", fmt.Sprintf("Unable to set provided 'api_document_path' %s with doc source '%s' for service. error: %s", apiDocPath, sourceEnum, err))
return
}
if shouldUpdate, apiDocPath, sourceEnum := serviceApiDocSettingsUpdateInput(planModel, nil); shouldUpdate {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue exists within create too, though it's not as visible. We should update that as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switched create over to use the same helper

managesApiDocSource = managesApiDocSource || !state.PreferredApiDocumentSource.IsNull()
}
if !managesApiDocPath && !managesApiDocSource {
return false, "", nil
Copy link
Copy Markdown
Contributor

@andrewstillv15 andrewstillv15 Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So within the rails api we have 3 states; nil (basically the clear state), set & omitted (no change), used to control both of these fields. Within terraform however we don't have that distinction, we only have set & null. Because of this we have to assume that both of these states will be explicitly managed.

The only scenario I can see us not wanting to send this api request in is one in which the state & plan values are equal.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense ,added an equality short-circuit so we only skip when plan == state, plus tests to make sure real changes still go through.

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.

2 participants