8000 feat(components): add support for disjunctive 'or' dependency requirements in linter rules by VLukiantsev · Pull Request #1341 · google/xmc · GitHub
[go: up one dir, main page]

Skip to content

feat(components): add support for disjunctive 'or' dependency requirements in linter rules - #1341

Merged
VLukiantsev merged 2 commits into
mainfrom
feat/components-linter-or-requires
Oct 21, 2026
Merged

VLukiantsev merged 2 commits into
mainfrom
feat/components-linter-or-requires

Conversation

@VLukiantsev
Copy link
Copy Markdown
Collaborator

Summary

Adds support for flat 1-level disjunctive (or) dependency requirements in pkg/components/linter (compatibilityMatrix.componentDependencies). This allows components such as metrics or ingestion-gateway to require at least one of multiple alternative backend components (e.g., redpanda or pubsub), each with its own SemVer version constraint.

Motivation & Context

Previously, ComponentDependencyRule.Requires in pkg/components/linter evaluated all listed DependencyRequirement entries as a strict logical AND. When a component supports pluggable backends (such as redpanda vs. pubsub), there was no way to express a required "at least one of" dependency in rules.yaml without making both optional: true (which fails to catch deployments where both backends are missing/disabled). Adding a flat or list to DependencyRequirement enables static compatibility enforcement for alternative dependencies while remaining 100% backward-compatible with existing component rules.

Key Changes

  • pkg/components/linter/rules.go:
    • Added Or []DependencyRequirement (yaml:"or,omitempty" json:"or,omitempty") to DependencyRequirement.
    • Added validateRulesConfig, validateDependencyRequirement, and validateOrRequirement in ParseRules to enforce flat 1-level or rules (rejecting entries that specify both component and or, top-level version alongside or, neither component nor or, nested or blocks, or or alternatives with an empty component).
  • pkg/components/linter/matrix.go:
    • Extended evaluateDependencyRequirement with evaluateOrDependencyRequirement, validateOrConstraints, checkOrAlternatives, allOrAlternativesOptional, and reportMissingOrComponents.
    • Implemented pure logical OR evaluation: satisfied when at least one enabled alternative satisfies its SemVer constraint; reports VERSION_INCOMPATIBILITY only when $\ge 1$ alternative is enabled and all enabled alternatives fail their version constraints; reports REQUIRED_COMPONENT_MISSING when all alternatives are missing/disabled (unless optional: true is set on the parent requirement or on all alternatives).
  • pkg/components/linter/rules_test.go & pkg/components/linter/matrix_test.go:
    • Added table-driven tests (TestParseRules_OrRequirements and TestMatrix_OrRequirements) covering schema validation errors and all matrix evaluation paths.
  • cmd/component-linter/README.md:
    • Documented or: syntax and evaluation semantics under Section 8 (Compatibility Matrix Configuration (rules.yaml)).

Assumptions

  • Suppressing cascading VERSION_INCOMPATIBILITY / REQUIRED_COMPONENT_MISSING when an enabled or alternative has an unparseable spec.version — assumed to match existing single-dependency behavior in evaluateDependencyRequirement (where validateSchema already emits INVALID_SEMVER for the malformed manifest) — if wrong, a malformed version on an enabled alternative would emit both INVALID_SEMVER and a secondary compatibility error.

Verification & Testing

  • Commands Executed:
    • bazel test //pkg/components/linter/... //cmd/component-linter/...
    • bazel coverage --combined_report=lcov //pkg/components/linter/...
    • ./.githooks/pre-commit
  • Coverage & Test Status: All unit tests and pre-commit checks pass with 100% line coverage on pkg/components/linter/rules.go and all new/modified lines in pkg/components/linter/matrix.go.

Related Issues / Bugs

N/A

TAG=agy
CONV=22bf6868-8f46-4b28-8b7d-e36b1dfd7dcc

…ments in linter rules

Add flat 1-level `or` support to `DependencyRequirement` in `pkg/components/linter` so components in `compatibilityMatrix.componentDependencies` (e.g., `metrics` or `ingestion-gateway`) can declare alternative backend requirements (such as `redpanda` or `pubsub`) with independent SemVer constraints.

Key changes:
- Extend `DependencyRequirement` in `pkg/components/linter/rules.go` with `Or []DependencyRequirement` (`yaml:"or,omitempty" json:"or,omitempty"`).
- Add strict schema validation in `ParseRules` to reject mutually exclusive fields (`component` or top-level `version` combined with `or`), empty requirements, nested `or` blocks, or `or` alternatives missing `component`.
- Update `evaluateDependencyRequirement` in `pkg/components/linter/matrix.go` to evaluate `or` blocks with pure logical OR semantics: satisfied if at least one enabled alternative meets its SemVer constraint; emits `VERSION_INCOMPATIBILITY` only when enabled alternatives exist and all fail their version constraints; emits `REQUIRED_COMPONENT_MISSING` when all alternatives are missing/disabled (unless `optional: true`).
- Add comprehensive table-driven unit tests in `rules_test.go` and `matrix_test.go` and update `cmd/component-linter/README.md`.

TAG=agy
CONV=22bf6868-8f46-4b28-8b7d-e36b1dfd7dcc
@VLukiantsev
Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for disjunctive requirements ("or") in the component linter's compatibility matrix. It updates the configuration parser to validate and support flat 1-level "or" lists of alternative requirements, implements the corresponding evaluation logic in the linter matrix, and adds comprehensive unit tests. Feedback on the changes suggests simplifying a loop in reportMissingOrComponents by replacing an if block containing a continue with a standard if/else block to improve readability.

Comment thread pkg/components/linter/matrix.go Resolved
Simplify the loop in `reportMissingOrComponents` by initializing the quoted component name first and conditionally appending the version constraint before a single `parts = append(parts, part)` call, eliminating the `continue` statement while keeping control flow strictly linear.

Comment link: #1341 (comment)

TAG=agy
CONV=22bf6868-8f46-4b28-8b7d-e36b1dfd7dcc
@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for disjunctive requirements (or) in the component linter, allowing a dependency requirement to be satisfied by any of a list of alternative components. The changes include updates to the documentation, parser validation to prevent nested or invalid or structures, evaluation logic in the linter matrix, and comprehensive unit tests. The review feedback suggests a minor improvement in checkOrAlternatives to copy the loop variable before modifying its fields, which prevents potential bugs if the slice is refactored to pointers in the future.

Comment thread pkg/components/linter/matrix.go Resolved
@VLukiantsev
VLukiantsev marked this pull request as ready for review October 20, 2026 15:50
@github-actions
github-actions Bot requested a review from andrzejfudro October 20, 2026 15:50
@VLukiantsev
VLukiantsev enabled auto-merge October 20, 2026 15:51
@VLukiantsev
VLukiantsev added this pull request to the merge queue Oct 21, 2026
Merged via the queue into main with commit a964f3b Oct 21, 2026
15 checks passed
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

0