feat: add !unset YAML function to delete keys from configuration
what
- Add new
!unsetYAML function that completely removes keys from configuration during inheritance and merging - Implement processing in both stack merging (
yaml_func_utils.go) and config loading (process_yaml.go) - Add comprehensive unit tests for all functionality
- Create documentation with examples and use cases
- Update YAML functions index documentation
why
- Users need a way to explicitly remove inherited configuration values, not just override them with
null - Current workarounds require physically removing or commenting out keys in parent configurations
- This addresses GitHub issue #227: "A YAML way of undefining a value without removing the key"
- Provides fine-grained control over configuration inheritance in complex stack hierarchies
Key Features
-
Complete removal: Unlike setting to
null,!unsetcompletely removes the key from configuration - Inheritance control: Child configurations can remove values inherited from parents
- Works everywhere: Functions in all Atmos configuration sections (vars, settings, env, metadata, etc.)
- Type-safe: Operates after YAML parsing, ensuring no syntax breakage
- Respects skip list: Can be disabled via skip list if needed
Examples
Basic Usage
# parent.yaml
components:
terraform:
vpc:
vars:
enable_nat_gateway: true
enable_vpn_gateway: true
# child.yaml
import:
- parent
components:
terraform:
vpc:
vars:
enable_vpn_gateway: !unset # Completely removes this key
Removing Nested Values
config:
database:
host: "prod.db.example.com"
backup_enabled: true
# Override:
config:
database:
backup_enabled: !unset # Remove backup config
host: "dev.db.example.com"
Testing
All tests pass:
- β Unit tests for config processing
- β Unit tests for stack processing
- β Integration tests with other YAML functions
- β Skip list functionality tests
- β Inheritance scenario tests
references
- Closes #227
- Related to #267 (YAML Explicit Typing support)
π€ Generated with Claude Code
Summary by CodeRabbit
-
New Features
- Added a YAML !unset function to remove keys or list items during config processing and inheritance. Works at any depth, supports multiple unsets, and coexists with other YAML functions.
-
Tests
- Introduced comprehensive tests covering flat and nested structures, arrays, multiple/nested unsets, inheritance scenarios, and edge cases.
-
Documentation
- Added dedicated docs and examples for !unset, including usage in stack manifests, nested removals, list handling, and guidance on expected behavior.
[!WARNING]
Rate limit exceeded
@osterman has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 23 minutes and 28 seconds before requesting another review.
β How to resolve this issue?
After the wait time has elapsed, a review can be triggered using the
@coderabbitai reviewcommand as a PR comment. Alternatively, push new commits to this PR.We recommend that you space out your commits to avoid hitting the rate limit.
π¦ How do rate limits work?
CodeRabbit enforces hourly rate limits for each developer per organization.
Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.
Please see our FAQ for further information.
π₯ Commits
Reviewing files that changed from the base of the PR and between 3728a05733708c7a3476b405733e8205ffa3f0d9 and 4626beb90a1c5da3636a8e8e8ec164dcf1a29221.
π Files selected for processing (8)
internal/exec/yaml_func_unset_test.go(1 hunks)pkg/config/load_config_test.go(1 hunks)pkg/config/process_yaml.go(3 hunks)pkg/config/process_yaml_unset_test.go(1 hunks)pkg/utils/array_cleanup.go(1 hunks)pkg/utils/array_cleanup_test.go(1 hunks)pkg/utils/yaml_utils.go(4 hunks)website/docs/functions/yaml/unset.mdx(1 hunks)
π Walkthrough
Walkthrough
Adds a new !unset YAML function and supporting logic to mark and remove values during YAML processing. Implements UnsetMarker propagation across maps/sequences, updates processing flow for scalar/mapping handling, adds tests validating unset behavior in various scenarios, and documents the feature.
Changes
| Cohort / File(s) | Summary |
|---|---|
YAML unset core implementationinternal/exec/yaml_func_utils.go, pkg/utils/yaml_utils.go, pkg/config/process_yaml.go |
Introduces UnsetMarker type and !unset tag constant; extends node processing (mapping/scalar/sequence) to detect and propagate unset markers; updates scalar dispatch to remove keys on !unset; integrates tag into recognized YAML functions. |
Unit tests for unsetinternal/exec/yaml_func_unset_test.go, pkg/config/process_yaml_unset_test.go |
Adds comprehensive tests covering flat/nested maps, arrays, multiple/nested unsets, skip-lists, interactions with other tags, inheritance-like scenarios, empty/invalid cases, and overall preprocessing behavior. |
Documentationwebsite/docs/functions/yaml/index.mdx, website/docs/functions/yaml/unset.mdx |
Documents the new !unset YAML function with overview, usage examples, detailed behavior, use cases, and references; updates function index. |
Sequence Diagram(s)
sequenceDiagram
autonumber
participant U as User YAML
participant L as YAML Loader
participant P as processYaml
participant M as processMappingNode / processChildren
participant S as processScalarNode
participant C as processCustomTags
participant U$ as UnsetMarker
participant V as Viper Store
U->>L: Provide YAML with !unset
L->>P: Parse AST Node
alt Mapping/Sequence
P->>M: Traverse keys/items
loop For each key/item
M->>S: Process value node
S->>C: Check custom tag
alt tag == !unset
C-->>S: Return UnsetMarker
S-->>M: Propagate UnsetMarker
M-->>V: Skip set/remove key/item
else other/regular tag
C-->>S: Resolved value
S-->>M: Value
M-->>V: Set value
end
end
else Scalar (top-level)
P->>S: Process scalar
S->>C: Check tag
alt tag == !unset
C-->>S: UnsetMarker
S-->>V: Remove key at path
else regular
C-->>S: Resolved value
S-->>V: Set value
end
end
note over U$,V: UnsetMarker is a signal to delete/omit<br/>without storing a concrete value.
Estimated code review effort
π― 4 (Complex) | β±οΈ ~60 minutes
Suggested labels
minor
Suggested reviewers
- aknysh
Pre-merge checks and finishing touches
β Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | β οΈ Warning | Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
β Passed checks (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | β Passed | Check skipped - CodeRabbitβs high-level summary is enabled. |
| Title Check | β Passed | The title clearly and concisely describes the introduction of the !unset YAML function for deleting keys, matching the primary change in the pull request. |
| Linked Issues Check | β Passed | The pull request implements the sentinel !unset tag, propagates an UnsetMarker through processing, removes keys during merging and config loading, and includes tests verifying inheritance and omission behaviors as specified in issue #227. |
| Out of Scope Changes Check | β Passed | All modifications relate directly to supporting the new !unset YAML function through implementation, testing, or documentation, with no unrelated changes detected. |
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
[!WARNING]
This PR exceeds the recommended limit of 1,000 lines.
Large PRs are difficult to review and may be rejected due to their size.
Please verify that this PR does not address multiple issues. Consider refactoring it into smaller, more focused PRs to facilitate a smoother review process.
π₯ This pull request now has conflicts. Could you fix it @osterman? π
[!WARNING]
Changelog Entry Required
This PR is labeled
minorormajorbut doesn't include a changelog entry.Action needed: Add a new blog post in
website/blog/to announce this change.Example filename:
website/blog/2025-12-01-feature-name.mdxAlternatively: If this change doesn't require a changelog entry, remove the
minorormajorlabel.
[!WARNING]
Changelog Entry Required
This PR is labeled
minorormajorbut doesn't include a changelog entry.Action needed: Add a new blog post in
website/blog/to announce this change.Example filename:
website/blog/2025-12-06-feature-name.mdxAlternatively: If this change doesn't require a changelog entry, remove the
minorormajorlabel.
π₯ This pull request now has conflicts. Could you fix it @osterman? π
[!WARNING]
Changelog Entry Required
This PR is labeled
minorormajorbut doesn't include a changelog entry.Action needed: Add a new blog post in
website/blog/to announce this change.Example filename:
website/blog/2025-12-09-feature-name.mdxAlternatively: If this change doesn't require a changelog entry, remove the
minorormajorlabel.
π₯ This pull request now has conflicts. Could you fix it @osterman? π
[!WARNING]
Changelog Entry Required
This PR is labeled
minorormajorbut doesn't include a changelog entry.Action needed: Add a new blog post in
website/blog/to announce this change.Example filename:
website/blog/2025-12-09-feature-name.mdxAlternatively: If this change doesn't require a changelog entry, remove the
minorormajorlabel.
π₯ This pull request now has conflicts. Could you fix it @osterman? π
[!WARNING]
Changelog Entry Required
This PR is labeled
minorormajorbut doesn't include a changelog entry.Action needed: Add a new blog post in
website/blog/to announce this change.Example filename:
website/blog/2025-12-09-feature-name.mdxAlternatively: If this change doesn't require a changelog entry, remove the
minorormajorlabel.
[!WARNING]
Changelog Entry Required
This PR is labeled
minorormajorbut doesn't include a changelog entry.Action needed: Add a new blog post in
website/blog/to announce this change.Example filename:
website/blog/2025-12-10-feature-name.mdxAlternatively: If this change doesn't require a changelog entry, remove the
minorormajorlabel.
Codecov Report
:x: Patch coverage is 74.48276% with 37 lines in your changes missing coverage. Please review.
:white_check_mark: Project coverage is 73.13%. Comparing base (448d405) to head (164f6e2).
:x: Your patch check has failed because the patch coverage (74.48%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.
Additional details and impacted files
@@ Coverage Diff @@
## main #1521 +/- ##
==========================================
+ Coverage 73.11% 73.13% +0.01%
==========================================
Files 550 551 +1
Lines 53168 53307 +139
==========================================
+ Hits 38873 38984 +111
- Misses 11439 11454 +15
- Partials 2856 2869 +13
| Flag | Coverage Ξ | |
|---|---|---|
| unittests | 73.13% <74.48%> (+0.01%) |
:arrow_up: |
Flags with carried forward coverage won't be shown. Click here to find out more.
| Files with missing lines | Coverage Ξ | |
|---|---|---|
| pkg/utils/yaml_utils.go | 81.15% <50.00%> (+0.05%) |
:arrow_up: |
| internal/exec/yaml_func_utils.go | 87.71% <72.72%> (-1.98%) |
:arrow_down: |
| pkg/utils/array_cleanup.go | 91.54% <91.54%> (ΓΈ) |
|
| pkg/config/process_yaml.go | 67.15% <52.00%> (-2.05%) |
:arrow_down: |
:rocket: New features to boost your workflow:
- :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
[!WARNING]
Changelog Entry Required
This PR is labeled
minorormajorbut doesn't include a changelog entry.Action needed: Add a new blog post in
website/blog/to announce this change.Example filename:
website/blog/2025-12-18-feature-name.mdxAlternatively: If this change doesn't require a changelog entry, remove the
minorormajorlabel.