Skip to content

feat: deployment dependency can also filter by versions#964

Merged
adityachoudhari26 merged 4 commits intomainfrom
deployment-dependency-can-select-version
Apr 10, 2026
Merged

feat: deployment dependency can also filter by versions#964
adityachoudhari26 merged 4 commits intomainfrom
deployment-dependency-can-select-version

Conversation

@adityachoudhari26
Copy link
Copy Markdown
Member

@adityachoudhari26 adityachoudhari26 commented Apr 10, 2026

Resolves #743

Summary by CodeRabbit

  • New Features

    • Dependency rules can reference currently deployed upstream version properties (tag, name, status, metadata, createdAt) and now evaluate selectors against those versions; a dependency is satisfied when at least one upstream release target matches.
  • Documentation

    • Updated docs and API schema with version-scoped selector examples and a full list of available CEL context variables.

Copilot AI review requested due to automatic review settings April 10, 2026 00:08
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 10, 2026

Warning

Rate limit exceeded

@adityachoudhari26 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 37 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 37 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command 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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c80d2add-c5ee-451e-b7db-e1b4393cea14

📥 Commits

Reviewing files that changed from the base of the PR and between b52eab1 and d5b700e.

📒 Files selected for processing (1)
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/deployment_dependency.go
📝 Walkthrough

Walkthrough

Refactors deployment dependency evaluation from job-based checks to evaluating currently deployed versions via CEL. Adds a top-level version CEL context, updates getters/DB queries to return DeploymentVersion, changes evaluator control flow to evaluate dependsOn against upstream release targets' deployed versions, and updates schemas, docs, and tests.

Changes

Cohort / File(s) Summary
OpenAPI / Schema docs & generated types
apps/api/openapi/openapi.json, apps/api/openapi/schemas/policies.jsonnet, apps/api/src/types/openapi.ts, apps/workspace-engine/oapi/openapi.json, apps/workspace-engine/oapi/spec/schemas/policy.jsonnet, packages/workspace-engine-sdk/src/schema.ts, apps/workspace-engine/pkg/oapi/oapi.gen.go
Extended DeploymentDependencyRule.dependsOn description across schemas, generated types, and docs to document available CEL context (deployment.* and new version.* fields) and added example expressions. No shape/type changes.
CEL environment & helpers
apps/workspace-engine/pkg/selector/langs/cel/cel.go, apps/workspace-engine/pkg/selector/langs/cel/cel_test.go
Added top-level version map to CEL context, added DeploymentVersionToMap (exported) and internal deploymentVersionToMap, and updated struct-to-map conversion and tests to include version.
Evaluator logic
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/deployment_dependency.go, .../deployment_dependency_test.go
Replaced job-status-based dependency checks with CEL evaluation against currently deployed DeploymentVersion per upstream release target. Evaluator now compiles dependsOn, iterates release targets, fetches deployed versions, injects version into context, and allows on first true match; denial aggregates CEL errors when present. Tests rewritten for version/tag/metadata scenarios.
Getter interfaces & DB implementation
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/getter.go, apps/workspace-engine/svc/controllers/desiredrelease/policyeval/getter_postgres.go
Replaced GetLatestCompletedJobForReleaseTarget(*oapi.ReleaseTarget) *oapi.Job with GetCurrentlyDeployedVersion(ctx context.Context, *oapi.ReleaseTarget) *oapi.DeploymentVersion. DB query now reads current release/version and maps nullable fields into DeploymentVersion.
Controller mocks & tests
apps/workspace-engine/svc/controllers/desiredrelease/policyeval/policyeval_test.go, apps/workspace-engine/svc/controllers/desiredrelease/reconcile_test.go, apps/workspace-engine/test/controllers/harness/mocks.go, apps/workspace-engine/test/controllers/policy_combined_test.go, apps/workspace-engine/test/controllers/policy_deployment_dependency_test.go
Updated mocks and tests to use CurrentlyDeployedVersions / GetCurrentlyDeployedVersion(ctx, rt) and to assert version-based dependency semantics (tags, metadata, missing versions, multi-upstream "at least one" matching). Removed prior job-based scenarios.
Documentation
docs/policies/deployment-dependency.mdx
Expanded docs to clarify dependsOn matches release targets, list deployment.* and version.* CEL variables, describe new evaluation flow, and add examples for version.tag and version.metadata selectors.

Sequence Diagram

sequenceDiagram
    participant Eval as Deployment Dependency Evaluator
    participant RTG as ReleaseTarget Getter
    participant DB as Postgres DB
    participant CEL as CEL Engine

    Note over Eval,CEL: Version-based dependency evaluation

    Eval->>Eval: Compile `dependsOn` as CEL program
    Eval->>RTG: GetReleaseTargetsForResource(resource)
    RTG-->>Eval: [releaseTarget1, releaseTarget2, ...]

    loop for each release target
        Eval->>RTG: GetCurrentlyDeployedVersion(ctx, releaseTarget)
        RTG->>DB: Query current release/version by ids
        DB-->>RTG: row with version fields
        RTG-->>Eval: DeploymentVersion {id, tag, name, status, metadata, createdAt}

        Eval->>Eval: Build context { deployment: {...}, version: {...} }
        Eval->>CEL: Evaluate `dependsOn` with context
        CEL-->>Eval: true / false / error

        alt true
            Eval-->>Eval: Return AllowedResult (first match)
        else false or error
            Note over Eval: Continue to next release target (collect errors)
        end
    end

    alt at least one matched
        Eval-->>Eval: Allow deployment
    else none matched
        Eval-->>Eval: Deny deployment (include aggregated CEL errors if any)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • jsbroks

Poem

🐰 I nibble docs and tweak the CEL,
I hop through versions where deployments dwell.
From jobs of old to versions true,
Now version.* guides what we do.
Hooray — one match and the release hops through! 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: adding version filtering to deployment dependencies via CEL selectors.
Linked Issues check ✅ Passed The PR implements all core requirements from issue #743: CEL-based version selection for dependencies, version property context (tag, name, status, metadata, createdAt), dependency evaluation logic against currently deployed versions, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #743 objectives: schema updates, OpenAPI generation, CEL context extensions, evaluator implementation, getter contract changes, and test updates. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deployment-dependency-can-select-version

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds version-aware evaluation to deployment dependency policies by exposing the currently deployed upstream version to the CEL selector, and updates generated OpenAPI/SDK artifacts, docs, and tests accordingly.

Changes:

  • Extend CEL selector context with version.* and document available variables for dependsOn.
  • Update deployment dependency evaluator to resolve each same-resource release target’s currently deployed version (latest successful job) and evaluate dependsOn against {deployment, version}.
  • Update workspace-engine tests, mocks, and generated OpenAPI/SDK types to match the new behavior.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/workspace-engine-sdk/src/schema.ts Updates SDK schema docstring for dependsOn to include version.* fields.
docs/policies/deployment-dependency.mdx Documents new version.* variables and adds version-scoped dependency examples.
apps/workspace-engine/test/controllers/policy_deployment_dependency_test.go Updates controller tests to use “currently deployed version” instead of “latest completed job” and adds version selector cases.
apps/workspace-engine/test/controllers/policy_combined_test.go Updates combined-policy test harness data to use deployed versions.
apps/workspace-engine/test/controllers/harness/mocks.go Renames mock storage from latest jobs to deployed versions and updates getter signature.
apps/workspace-engine/svc/controllers/desiredrelease/reconcile_test.go Updates reconcile test mock getter signature.
apps/workspace-engine/svc/controllers/desiredrelease/policyeval/policyeval_test.go Updates policy eval test mock getter signature.
apps/workspace-engine/svc/controllers/desiredrelease/policyeval/getter_postgres.go Wires postgres policyeval getter to the new deployed-version getter.
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/getter.go Implements GetCurrentlyDeployedVersion using GetCurrentReleaseByReleaseTarget.
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/deployment_dependency.go Evaluates dependency selector against {deployment, version} for each same-resource release target.
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/deployment_dependency_test.go Updates evaluator unit tests for version-aware selectors and “any match” semantics.
apps/workspace-engine/pkg/selector/langs/cel/cel.go Adds version as a CEL variable and mapping for DeploymentVersion.
apps/workspace-engine/pkg/selector/langs/cel/cel_test.go Updates selector context tests to include version.
apps/workspace-engine/pkg/oapi/oapi.gen.go Updates generated model comment for DeploymentDependencyRule.dependsOn.
apps/workspace-engine/oapi/spec/schemas/policy.jsonnet Updates OpenAPI schema description for dependsOn.
apps/workspace-engine/oapi/openapi.json Regenerates OpenAPI JSON with updated dependsOn description.
apps/api/src/types/openapi.ts Updates API OpenAPI-generated TS types with updated dependsOn description.
apps/api/openapi/schemas/policies.jsonnet Updates API OpenAPI schema description for dependsOn.
apps/api/openapi/openapi.json Regenerates API OpenAPI JSON with updated dependsOn description.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +68 to 84
row, err := p.queries.GetCurrentReleaseByReleaseTarget(
ctx,
db.GetCurrentReleaseByReleaseTargetParams{
ResourceID: uuid.MustParse(rt.ResourceId),
EnvironmentID: uuid.MustParse(rt.EnvironmentId),
DeploymentID: uuid.MustParse(rt.DeploymentId),
},
)
if err != nil {
slog.Error(
"failed to get latest completed job for release target",
"failed to get current release for release target",
"releaseTarget",
releaseTarget.Key(),
rt.Key(),
"error",
err,
)
return nil
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

GetCurrentReleaseByReleaseTarget will return pgx.ErrNoRows when a release target has no successful completed job yet, which is an expected/normal state for dependency evaluation. Logging this at error level will likely be noisy and can mask real errors. Consider treating ErrNoRows as a nil deployed version (no log, or debug-level) and only logging unexpected errors.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +94
for _, rt := range releaseTargets {
deployment, err := e.getters.GetDeployment(ctx, rt.DeploymentId)
if err != nil || deployment == nil {
continue
}

version := e.getters.GetCurrentlyDeployedVersion(ctx, rt)
if version == nil {
continue
}

for _, upstreamReleaseTarget := range upstreamReleaseTargets {
if !e.checkUpstreamTargetHasSuccessfulRelease(upstreamReleaseTarget) {
return results.NewDeniedResult(
celCtx := cel.BuildEntityContext(nil, deployment, nil)
celCtx["version"] = cel.DeploymentVersionToMap(version)
matched, err := celutil.EvalBool(program, celCtx)
if err != nil {
continue
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

Errors from GetDeployment / GetCurrentlyDeployedVersion / CEL evaluation are silently ignored via continue. When the selector is invalid for the provided context (e.g., missing fields) or the DB call fails, the final denied message becomes misleading (“no upstream…matches”) and makes debugging difficult. Consider recording these errors (span/log) and/or returning a denied result that includes the first evaluation error and the release target key.

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +83
releaseTargets := e.getters.GetReleaseTargetsForResource(ctx, scope.Resource.Id)

for _, rt := range releaseTargets {
deployment, err := e.getters.GetDeployment(ctx, rt.DeploymentId)
if err != nil || deployment == nil {
continue
}

Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

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

This implementation does two DB lookups per release target (GetDeployment + GetCurrentlyDeployedVersion). If a resource has many release targets, this can become an N+1 query pattern during policy evaluation. Consider fetching deployments in bulk (e.g., GetAllDeployments once per workspace) and/or adding a batch query that returns {deployment, currentVersion} for all release targets on a resource.

Suggested change
releaseTargets := e.getters.GetReleaseTargetsForResource(ctx, scope.Resource.Id)
for _, rt := range releaseTargets {
deployment, err := e.getters.GetDeployment(ctx, rt.DeploymentId)
if err != nil || deployment == nil {
continue
}
releaseTargets := e.getters.GetReleaseTargetsForResource(ctx, scope.Resource.Id)
deploymentsByID := make(map[string]*oapi.Deployment, len(releaseTargets))
for _, rt := range releaseTargets {
if _, ok := deploymentsByID[rt.DeploymentId]; ok {
continue
}
deployment, err := e.getters.GetDeployment(ctx, rt.DeploymentId)
if err != nil || deployment == nil {
continue
}
deploymentsByID[rt.DeploymentId] = deployment
}
for _, rt := range releaseTargets {
deployment, ok := deploymentsByID[rt.DeploymentId]
if !ok || deployment == nil {
continue
}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/workspace-engine/pkg/selector/langs/cel/cel.go`:
- Line 14: CelSelector.Matches currently omits the "version" variable from the
activation even though the CEL environment and structToMap now support
oapi.DeploymentVersion; update CelSelector.Matches to include "version" in the
activation construction and populate it when a deployment version entity is
provided (use structToMap(oapi.DeploymentVersion) or equivalent conversion), so
that WithMapVariables("resource","deployment","environment","version") can
evaluate selectors using the version field consistently with Compile and
structToMap.

In
`@apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/deployment_dependency.go`:
- Around line 76-84: The loop over releaseTargets returned by
e.getters.GetReleaseTargetsForResource(ctx, scope.Resource.Id) must skip the
release target that's currently being evaluated to avoid self-satisfaction;
inside the for _, rt := range releaseTargets loop (before calling
e.getters.GetDeployment or e.getters.GetCurrentlyDeployedVersion) add a guard
that continues when rt identifies the current target (e.g., compare rt.Id to
scope.Target.Id or otherwise the unique identifier you use for the evaluated
release target) so the current release target is not considered as an upstream
dependency.

In
`@apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/getter.go`:
- Around line 76-84: GetCurrentReleaseByReleaseTarget currently logs
pgx.ErrNoRows as an error for empty deployments; update the error handling in
the function (the block that checks err after calling the DB) to first detect
the sentinel with if errors.Is(err, pgx.ErrNoRows) { return nil } and only call
slog.Error("failed to get current release for release target", "releaseTarget",
rt.Key(), "error", err) for other errors so expected empty state does not
produce error logs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 279422d7-21ca-4156-9ecb-e3df0e6a30a5

📥 Commits

Reviewing files that changed from the base of the PR and between d05d8bb and d579b52.

📒 Files selected for processing (19)
  • apps/api/openapi/openapi.json
  • apps/api/openapi/schemas/policies.jsonnet
  • apps/api/src/types/openapi.ts
  • apps/workspace-engine/oapi/openapi.json
  • apps/workspace-engine/oapi/spec/schemas/policy.jsonnet
  • apps/workspace-engine/pkg/oapi/oapi.gen.go
  • apps/workspace-engine/pkg/selector/langs/cel/cel.go
  • apps/workspace-engine/pkg/selector/langs/cel/cel_test.go
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/deployment_dependency.go
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/deployment_dependency_test.go
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/getter.go
  • apps/workspace-engine/svc/controllers/desiredrelease/policyeval/getter_postgres.go
  • apps/workspace-engine/svc/controllers/desiredrelease/policyeval/policyeval_test.go
  • apps/workspace-engine/svc/controllers/desiredrelease/reconcile_test.go
  • apps/workspace-engine/test/controllers/harness/mocks.go
  • apps/workspace-engine/test/controllers/policy_combined_test.go
  • apps/workspace-engine/test/controllers/policy_deployment_dependency_test.go
  • docs/policies/deployment-dependency.mdx
  • packages/workspace-engine-sdk/src/schema.ts

@adityachoudhari26 adityachoudhari26 merged commit 33ebbed into main Apr 10, 2026
13 checks passed
@adityachoudhari26 adityachoudhari26 deleted the deployment-dependency-can-select-version branch April 10, 2026 00:46
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.

Deployment Version Dependencies - Allow versions to depend on specific versions of other deployments

2 participants