Skip to content

feat: persist plugin parse options under plugins.<name>#19

Closed
liamcervante wants to merge 4 commits into
mainfrom
plugin-options-config
Closed

feat: persist plugin parse options under plugins.<name>#19
liamcervante wants to merge 4 commits into
mainfrom
plugin-options-config

Conversation

@liamcervante

Copy link
Copy Markdown
Contributor

Summary

Makes plugins the source of truth for their own parse options and persists them under a generic, plugin-keyed plugins.<name> section, replacing the deprecated terraform.* / aws.* fields. Additive and backwards-compatible — config never interprets the blob. This is a fresh reimplementation that supersedes #18.

Depends on the raw_options fields from infracost/proto#81 (merged, v1.158.0) and pairs with the plugin-side emit/read in infracost/parser#185.

Generation (write)

  • Emit parse options under plugins.<type>, keyed by the consuming plugin (CDK folds into cloudformation), as a native YAML map. The deprecated terraform.* / aws.* fields are no longer written.
  • When a plugin authored a raw_options blob during identification (only when it returned environments authoritatively) it is persisted verbatim. Otherwise — when IdentifyEnvironments returns no environments — config sideloads the var files it attributed locally into a terraform-family blob. Those var files rely on the whole-directory (sibling/pibling) attribution config performs in its tree passes, which the plugins cannot yet reproduce; this sideload is the one deliberate, minimal special case, expected to go away once IdentifyAllProjects moves that attribution plugin-side.

Read (load)

  • Fold the deprecated structured terraform.* / aws.* fields (and the repo-level terraform.source_map) into plugins.<name> on load, so old and hand-written configs keep working and consumers read only the new style. Isolated in config_plugins_compat.go, marked for removal once the deprecated fields go.
  • Merge repo-level plugins: defaults into each project's blob.

Precedence

deprecated field > per-project blob > repo-level default. Nested maps merge recursively; lists are atomic, with the per-project value winning (lists replace, never concatenate).

Other

  • ConfigSHA now includes the plugins blob so generated configs still hash their var files / workspace once terraform.* is no longer written.
  • Bumps proto to v1.158.0. Config version stays 0.3 (additive within the version; a bump would make older strict parsers reject the file).

Testing

  • go build ./..., go vet ./..., gofmt all clean.
  • go test ./... green, including the 77 _WithPlugins tests that run against the real downloaded plugin binaries.
  • New plugins_test.go covers the generation sideload, the aws.* fold, CDK → cloudformation keying, the repo-level merge, and both precedence orderings.

Notes for reviewers

  • The published plugins don't emit raw_options yet (parser#185 is unmerged), so today the plugin path exercises the sideload branch rather than the plugin-blob branch. Both produce identical plugins.terraform.tfVarsFiles, so behaviour is correct either way; the plugin-blob branch will be exercised by real plugins once parser#185 ships.
  • ConfigSHA is additive (hashes terraform.* and plugins), so migrating a repo from the old style to the new style changes its sha — a deliberate, accepted one-time churn rather than making old- and new-style configs hash identically.

Make plugins the source of truth for their own parse options and persist them
under a generic, plugin-keyed plugins.<name> section, replacing the deprecated
terraform.* / aws.* fields. Additive and backwards-compatible - config never
interprets the blob.

Generation:
- Emit parse options under plugins.<type>, keyed by the consuming plugin (CDK
  folds into cloudformation), as a native YAML map. The deprecated terraform.* /
  aws.* fields are no longer written.
- When a plugin authored a raw_options blob during identification (only when it
  returned environments authoritatively) it is persisted verbatim. Otherwise -
  when IdentifyEnvironments returns no environments - config sideloads the var
  files it attributed locally into a terraform-family blob. Those var files rely
  on the whole-directory (sibling/pibling) attribution config performs in its
  tree passes, which the plugins cannot yet reproduce; this sideload is the one
  deliberate, minimal special case, expected to go away once IdentifyAllProjects
  moves that attribution plugin-side.

Read:
- Fold the deprecated structured terraform.* / aws.* fields (and the repo-level
  terraform.source_map) into plugins.<name> on load, so old and hand-written
  configs keep working and consumers read only the new style. Isolated in
  config_plugins_compat.go, marked for removal once the deprecated fields go.
- Merge repo-level `plugins:` defaults into each project's blob. Precedence is
  deprecated field > per-project blob > repo-level default; nested maps merge
  recursively, lists are atomic with the per-project value winning.

Other:
- ConfigSHA includes the plugins blob so generated configs still hash their var
  files / workspace once terraform.* is no longer written.
- Bump proto to v1.158.0 for the raw_options fields. Config version stays 0.3.
@liamcervante
liamcervante requested a review from a team July 13, 2026 07:31
@liamcervante
liamcervante marked this pull request as ready for review July 13, 2026 07:32
Add // Deprecated: markers pointing each folded field at its plugins.<name>
equivalent (tfVarsFiles, workspace, vars, terraformCloudConfiguration,
regexSourceMap, awsContext), so external consumers get an IDE/staticcheck signal
to move to the plugins blob. Credentials are left unmarked: the terraform cloud
token and spacelift api key are not parse options and are not folded (the token
travels via GenericOptions.CredentialSets; spacelift is an upstream integration
secret). config's own package is exempt from the deprecation warning (staticcheck
same-package rule), so the fold/normalize/ConfigSHA reads are unaffected.
…ns blob

Workspace is a caller-sourced runtime option that is also read outside the plugin
(the project's workspace in the cost output / provider input), so it is passed to
the plugin via GenericOptions.Workspace rather than the opaque raw_options blob.

- Un-deprecate ProjectTerraform.Workspace; it stays a top-level field and is still
  written by generation (terraform.workspace = env).
- Stop folding terraform.workspace into plugins.terraform.workspace, and stop
  sideloading workspace into the generated blob (only tfVarsFiles is sideloaded).
- Drop workspace from hasTerraformFields (no longer a folded field).

Tests updated: the load-fold cases no longer expect a workspace blob entry, and
the precedence tests use var files (still folded) instead of workspace.
Terraform Cloud config (terraform.cloud.host/org/workspace) is caller-sourced and
read outside the plugin - the caller passes it to the plugin via
GenericOptions.TerraformCloudConfiguration and reads the host to build the
terraform-cloud credential set. So, like the workspace, it stays a top-level typed
field and is NOT folded into the plugins blob.

- Un-deprecate TerraformCloud (host/org/workspace); it is the authoring surface.
- Stop folding terraform.cloud into plugins.terraform.terraformCloudConfiguration.
- Drop cloud fields from hasTerraformFields (no longer folded).

The token remains a credential (never in the blob; via GenericOptions.CredentialSets
or INFRACOST_TERRAFORM_CLOUD_TOKEN).
@liamcervante
liamcervante force-pushed the plugin-options-config branch from abe99bf to 17f8854 Compare July 13, 2026 11:55
@liamcervante
liamcervante removed the request for review from a team July 13, 2026 15:22
@liamcervante

Copy link
Copy Markdown
Contributor Author

closed in favour of #21

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.

1 participant