Skip to content

Conversation

@adityachoudhari26
Copy link
Contributor

@adityachoudhari26 adityachoudhari26 commented Oct 21, 2025

Summary by CodeRabbit

  • Bug Fixes
    • Fixed deployment policy to consider all previous job statuses, including failed and cancelled states, when evaluating redeployment eligibility.
    • Redeployments for releases with prior failed or cancelled deployments are now correctly denied.
    • Updated job recency detection to use creation time instead of completion time.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 21, 2025

Walkthrough

The skipdeployed evaluator's job status filtering has been removed. Previously, the evaluator only considered jobs in Pending, InProgress, or Successful states when determining deployment eligibility. The evaluator now considers all job statuses, including Failed, Cancelled, and Skipped, when checking if a release can be redeployed.

Changes

Cohort / File(s) Summary
Implementation
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeployed.go
Removed slices import and deleted validJobStatuses filter logic. Evaluator now accepts any job status (not just Pending/InProgress/Successful) when identifying the most recent job for a release target.
Tests
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeployed_test.go
Updated test expectations to reflect all statuses now being considered. Renamed test cases from IgnoresInvalidJobStatuses to ConsidersAllJobStatuses. Tests now verify that retries after failed/cancelled/skipped jobs are denied with existing_job_id and job_status details. Some tests changed from using CompletedAt to CreatedAt for recent job detection.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

The change is straightforward: removal of a filtering condition and corresponding test updates. The scope is limited to two related files with consistent, repetitive patterns across tests reflecting the new behavior.

Poem

🐰 The filter's gone, hop hooray!
All statuses now have their say,
Failed or cancelled, none ignored—
The evaluator keeps its word!
bounces excitedly

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The PR title states "only taint target on successful job," which suggests limiting some action to successful job outcomes. However, the actual changes do the opposite: the PR removes the validJobStatuses filter that previously ignored failed, cancelled, and skipped job statuses, and now considers all job statuses when determining whether to prevent redeployment. This means the system now DENIES retries after failed/cancelled/skipped jobs (treating them as blocking conditions), rather than limiting blocking behavior to only successful jobs. The title's semantic meaning contradicts the actual implementation, making it misleading about what the changeset accomplishes. The title should be revised to accurately reflect that the PR now considers all job statuses (including unsuccessful ones) when preventing redeployment, rather than suggesting a restriction to successful jobs. A more accurate title might be something like "Consider all job statuses when determining if deployment should be skipped" or similar phrasing that captures the actual behavior change.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch only-taint-on-success

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.

@github-actions
Copy link

📊 DB Package Test Coverage

pkg/db coverage: 55.7%

View detailed coverage report in artifacts

Copy link
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: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b4796d6 and 0dff190.

📒 Files selected for processing (1)
  • apps/workspace-engine/pkg/workspace/releasemanager/targets/taint.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
apps/workspace-engine/**/*.go

📄 CodeRabbit inference engine (apps/workspace-engine/CLAUDE.md)

apps/workspace-engine/**/*.go: Do not add extraneous inline comments that state the obvious
Do not add comments that simply restate what the code does
Do not add comments for standard Go patterns (e.g., noting WaitGroup or semaphore usage)
Write comments that explain why, document complex logic/algorithms, provide non-obvious context, include TODO/FIXME, and document exported functions/types/methods

Files:

  • apps/workspace-engine/pkg/workspace/releasemanager/targets/taint.go
🧬 Code graph analysis (1)
apps/workspace-engine/pkg/workspace/releasemanager/targets/taint.go (2)
apps/workspace-engine/pkg/oapi/type_conversion.go (1)
  • ConvertToOapiJob (43-49)
apps/workspace-engine/pkg/oapi/oapi.gen.go (2)
  • Status (57-57)
  • Successful (43-43)

Comment on lines 93 to 100
oapiJob, ok := oapi.ConvertToOapiJob(entity)
if !ok {
continue
}

if oapiJob.Status != oapi.Successful {
continue
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove redundant type conversion; status check logic is correct.

The ConvertToOapiJob call on line 93 is unnecessary because the case *oapi.Job: statement on line 92 already guarantees that entity is of type *oapi.Job. The conversion will always succeed, making the check on lines 94-96 dead code that can never execute.

The status check on lines 98-100 correctly implements the PR objective to only taint targets for successful jobs.

Apply this diff to remove the redundant conversion:

 	case *oapi.Job:
-		oapiJob, ok := oapi.ConvertToOapiJob(entity)
-		if !ok {
-			continue
-		}
-
-		if oapiJob.Status != oapi.Successful {
+		if entity.Status != oapi.Successful {
 			continue
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
oapiJob, ok := oapi.ConvertToOapiJob(entity)
if !ok {
continue
}
if oapiJob.Status != oapi.Successful {
continue
}
if entity.Status != oapi.Successful {
continue
}
🤖 Prompt for AI Agents
In apps/workspace-engine/pkg/workspace/releasemanager/targets/taint.go around
lines 93 to 100, remove the redundant call to oapi.ConvertToOapiJob and its
associated ok check (the lines that perform the conversion and continue on !ok)
because the preceding case *oapi.Job: already guarantees the type; instead, use
the entity value asserted as the job (or the existing variable from the case)
and keep the existing status check for oapi.Successful unchanged.

@github-actions
Copy link

📊 Code Coverage Report

workspace-engine coverage: 45.9%

View detailed coverage report in artifacts

@github-actions
Copy link

📊 DB Package Test Coverage

pkg/db coverage: 55.7%

View detailed coverage report in artifacts

Copy link
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: 0

🧹 Nitpick comments (5)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeployed_test.go (5)

104-119: Policy check: should failures block same‑release retry? Also avoid impl-coupled comment.

This test now denies retry after a failed job and mentions “validJobStatuses filter removed.” That couples the test to an internal detail and, more importantly, changes behavior that could prevent remediation. Please confirm the product policy: do failed jobs block re‑deploy of the same release, or should only pending/inProgress/successful block? The PR title (“only taint target on successful job”) suggests the latter.

If the intent is “only successful blocks; failures/cancellations allow retry,” update the assertions accordingly and drop the impl note.

Example adjustment if retries after failure should be allowed:

-  // Assert: Should DENY retry because failed jobs are now considered (validJobStatuses filter removed)
+  // Assert: Should ALLOW retry; previous failure should not block re-deploy of the same release

-  if result.Allowed {
-    t.Errorf("expected denied for retry after failure (failed jobs are now tracked), got allowed: %s", result.Message)
-  }
+  if !result.Allowed {
+    t.Errorf("expected allowed for retry after failure, got denied: %s", result.Message)
+  }

As per coding guidelines.


334-349: Same concern for cancellations: confirm whether cancelled should block retry; remove impl detail in comment.

This test now denies retry after a cancelled job and references “validJobStatuses filter removed.” Please verify policy. Typically, cancellation shouldn’t permanently block redeploy of the same release.

If the policy is to permit retry after cancellation, flip the assertion and remove the impl-coupled comment.

Example if cancellation should allow retry:

-  // Assert: Should DENY retry because cancelled jobs are now considered (validJobStatuses filter removed)
+  // Assert: Should ALLOW retry; cancellation should not block re-deploy of the same release

-  if result.Allowed {
-    t.Errorf("expected denied for retry after cancellation (cancelled jobs are now tracked), got allowed: %s", result.Message)
-  }
+  if !result.Allowed {
+    t.Errorf("expected allowed for retry after cancellation, got denied: %s", result.Message)
+  }

As per coding guidelines.


675-699: Stabilize time ordering with a fixed base time.

Multiple time.Now() calls can introduce flakiness if execution spans a clock tick. Use a single base time and derive relative times for CreatedAt/CompletedAt.

Example:

- completedAt := time.Now()
+ base := time.Date(2025, 1, 1, 10, 0, 0, 0, time.UTC)
+ completedAt := base

 st.Jobs.Upsert(ctx, &oapi.Job{
   Id:        "job-failed",
   ReleaseId: oldRelease.ID(),
   Status:    oapi.Failure,
-  CreatedAt: time.Now().Add(-3 * time.Hour),
+  CreatedAt: base.Add(-3 * time.Hour),
   CompletedAt: &completedAt,
 })
...
 st.Jobs.Upsert(ctx, &oapi.Job{
   Id:        "job-skipped",
   ReleaseId: oldRelease.ID(),
   Status:    oapi.Skipped,
-  CreatedAt: time.Now().Add(-1 * time.Hour), // Most recent
+  CreatedAt: base.Add(-1 * time.Hour), // Most recent
   CompletedAt: &completedAt,
 })
``` <!-- review_comment_end -->

---

`715-719`: **Strengthen assertion: also assert most recent job status.**

We assert previous_release_id but not the status of that most recent job. Add a check to ensure we actually selected the skipped job.


```diff
 if result.Details["previous_release_id"] != oldRelease.ID() {
   t.Errorf("expected previous_release_id=%s (from most recent job), got %v", oldRelease.ID(), result.Details["previous_release_id"])
 }
+if result.Details["job_status"] != string(oapi.Skipped) {
+  t.Errorf("expected job_status=%s, got %v", oapi.Skipped, result.Details["job_status"])
+}
``` <!-- review_comment_end -->

---

`721-791`: **Broad “all statuses block” may hinder remediation; consider scoping blockers.**

This parametrized test asserts that ANY status prevents re‑deploying the same release. That would block recovery from failure/cancelled/skipped/misconfig states. Please confirm intended contract. A common policy is:
- Blockers: pending, inProgress (to prevent duplicates), successful (to avoid redeploying identical release).
- Non‑blockers (allow retry): failure, cancelled, skipped, invalidIntegration, invalidJobAgent, actionRequired, externalRunNotFound.

If that policy is desired, split the slice into two sets and invert the expectations for the non‑blockers.



Illustrative refactor:

```diff
- statuses := []oapi.JobStatus{
-   oapi.Pending, oapi.InProgress, oapi.Successful, oapi.Failure, oapi.Cancelled, oapi.Skipped,
-   oapi.ActionRequired, oapi.ExternalRunNotFound, oapi.InvalidIntegration, oapi.InvalidJobAgent,
- }
+ blockers := []oapi.JobStatus{oapi.Pending, oapi.InProgress, oapi.Successful}
+ nonBlockers := []oapi.JobStatus{
+   oapi.Failure, oapi.Cancelled, oapi.Skipped, oapi.ActionRequired,
+   oapi.ExternalRunNotFound, oapi.InvalidIntegration, oapi.InvalidJobAgent,
+ }

- for _, status := range statuses {
+ for _, status := range blockers {
    t.Run(string(status), func(t *testing.T) {
      ...
-     // Assert: Should DENY regardless of job status
+     // Assert: Should DENY for blocker statuses
      if err != nil { ... }
      if result.Allowed { ... }
      ...
    })
  }
+
+ for _, status := range nonBlockers {
+   t.Run("nonBlocker_"+string(status), func(t *testing.T) {
+     ...
+     // Assert: Should ALLOW for non‑blocker statuses
+     if err != nil { ... }
+     if !result.Allowed {
+       t.Errorf("expected allowed for retry with status %s, got denied: %s", status, result.Message)
+     }
+   })
+ }

As per coding guidelines.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0dff190 and 06ed6be.

📒 Files selected for processing (2)
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeployed_test.go (7 hunks)
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeplyed.go (0 hunks)
💤 Files with no reviewable changes (1)
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeplyed.go
🧰 Additional context used
📓 Path-based instructions (2)
apps/workspace-engine/**/*.go

📄 CodeRabbit inference engine (apps/workspace-engine/CLAUDE.md)

apps/workspace-engine/**/*.go: Do not add extraneous inline comments that state the obvious
Do not add comments that simply restate what the code does
Do not add comments for standard Go patterns (e.g., noting WaitGroup or semaphore usage)
Write comments that explain why, document complex logic/algorithms, provide non-obvious context, include TODO/FIXME, and document exported functions/types/methods

Files:

  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeployed_test.go
apps/workspace-engine/**/*_test.go

📄 CodeRabbit inference engine (apps/workspace-engine/CLAUDE.md)

Follow the existing test structure used in *_test.go files

Files:

  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeployed_test.go
🧬 Code graph analysis (1)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeployed_test.go (4)
apps/workspace-engine/pkg/oapi/oapi.gen.go (20)
  • Failure (37-37)
  • Cancelled (35-35)
  • CreatedAt (49-49)
  • JobStatus (237-237)
  • Pending (41-41)
  • InProgress (38-38)
  • Successful (43-43)
  • Skipped (42-42)
  • ActionRequired (34-34)
  • ExternalRunNotFound (36-36)
  • InvalidIntegration (39-39)
  • InvalidJobAgent (40-40)
  • ReleaseTarget (388-392)
  • Release (379-385)
  • DeploymentVersion (152-162)
  • Id (51-51)
  • Job (213-225)
  • ReleaseId (55-55)
  • Status (57-57)
  • CompletedAt (48-48)
apps/workspace-engine/pkg/workspace/store/releases.go (1)
  • Releases (16-18)
apps/workspace-engine/pkg/workspace/store/jobs.go (1)
  • Jobs (16-18)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/skipdeployed/skipdeplyed.go (1)
  • NewSkipDeployedEvaluator (21-25)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Typecheck
  • GitHub Check: Lint
  • GitHub Check: build (linux/amd64)
  • GitHub Check: workspace-engine-tests

@adityachoudhari26 adityachoudhari26 merged commit dd6117b into main Oct 21, 2025
7 of 8 checks passed
@adityachoudhari26 adityachoudhari26 deleted the only-taint-on-success branch October 21, 2025 03:49
This was referenced Oct 31, 2025
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