Skip to content

Conversation

motatoes
Copy link
Contributor

  • update status check to use new api
  • moving to modern checked status

This comment has been minimized.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Summary

This PR modernizes Digger's GitHub status check system by migrating from GitHub's legacy Status API to the newer Check Runs API. The changes encompass several key improvements:

Core API Migration: The GitHub integration in libs/ci/github/github.go has been completely rewritten to use GitHub's Check Runs API instead of the deprecated Status API. This removes the 140-character description limit and provides better UI integration with GitHub's pull request interface.

Status Mapping Improvements: Critical fixes were made to status mappings in libs/scheduler/models.go, where BatchJobFailed was incorrectly returning 'success' instead of 'failure', and BatchJobInvalidated now returns 'cancelled' instead of 'failure' for better semantic accuracy.

Enhanced Status Granularity: The new system introduces more nuanced status states like 'neutral' and 'skipped' that better represent different job scenarios. When only plan jobs are running, the apply status is set to 'neutral', and when no jobs are present, both plan and apply are marked as 'skipped' rather than 'success'.

Centralized Status Management: Status check logic has been moved from individual CLI components to centralized backend functions (UpdateCheckStatusForBatch and UpdateCheckStatusForJob), providing better consistency and control over status reporting.

Database Persistence Fix: A critical bug was fixed in backend/models/storage.go where batch status updates were being set in memory but not persisted to the database, potentially causing inconsistencies in job tracking.

Legacy Code Cleanup: Individual project-level status checks in the CLI have been commented out as the system transitions to the new centralized approach, reducing status check clutter in the GitHub PR interface.

The changes maintain backward compatibility while providing a foundation for more sophisticated status reporting that aligns with modern GitHub integration best practices.

Confidence score: 3/5

  • This PR has potential breaking changes and incomplete implementation that could impact production status reporting
  • Score reflects concerns about commented-out error handling, missing status mappings, and potential race conditions in concurrent scenarios
  • Pay close attention to GitHub integration files and status check logic for proper error handling and complete status coverage

Context used:

Context - Enrich debug logs with relevant context. Always include identifiers like 'prNumber' in logs to facilitate easier tracing and troubleshooting. (link)
Context - Use consistent and descriptive keys for debug logging. For example, prefer 'prBatchCount' over 'len(prBatches)' to maintain clarity and adhere to naming conventions. (link)

9 files reviewed, 7 comments

Edit Code Review Bot Settings | Greptile

@@ -856,6 +856,7 @@ func (db *Database) UpdateBatchStatus(batch *DiggerBatch) error {
}
if allJobsSucceeded == true {
batch.Status = scheduler.BatchJobSucceeded
db.GormDB.Save(batch)
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Consider adding error handling for the save operation to log any potential database errors.

Suggested change
db.GormDB.Save(batch)
if err := db.GormDB.Save(batch).Error; err != nil {
slog.Error("failed to update batch status to succeeded",
"batchId", batchId,
"error", err)
return err
}

case orchestrator_scheduler.DiggerJobFailed:
return "failed", nil
}
return "", fmt.Errorf("unknown job status: %s", job.Status)
Copy link
Contributor

Choose a reason for hiding this comment

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

syntax: The error message uses %s format specifier but job.Status is an int8, should use %d instead for proper formatting.

Suggested change
return "", fmt.Errorf("unknown job status: %s", job.Status)
return "", fmt.Errorf("unknown job status: %d", job.Status)

Name: statusContext, // similar to "Context" in Status API
HeadSHA: pr.GetHead().GetSHA(),
Status: github.String(checkStatus), // required when setting a conclusion
//Conclusion: github.String(conclusion),
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Commented-out conclusion suggests incomplete implementation - should this be removed or is there a reason it's commented?

@@ -210,6 +210,7 @@ func SetPRStatusForJobs(prService ci.PullRequestService, prNumber int, jobs []sc
if scheduler.IsPlanJobs(jobs) {
slog.Debug("Setting aggregate plan status", "prNumber", prNumber)
err = prService.SetStatus(prNumber, "pending", "digger/plan")
err = prService.SetStatus(prNumber, "neutral", "digger/apply")
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: Error handling issue: the error from setting 'digger/apply' status overwrites the error from setting 'digger/plan' status. If the first call succeeds but the second fails, the original error is lost.

@@ -224,13 +225,13 @@ func SetPRStatusForJobs(prService ci.PullRequestService, prNumber int, jobs []sc
} else {
slog.Debug("Setting success status for empty job list", "prNumber", prNumber)

err := prService.SetStatus(prNumber, "success", "digger/plan")
err := prService.SetStatus(prNumber, "skipped", "digger/plan")
if err != nil {
slog.Error("Failed to set success plan status", "prNumber", prNumber, "error", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Log message still says 'success plan status' but now setting 'skipped' status - should update message to match

Suggested change
slog.Error("Failed to set success plan status", "prNumber", prNumber, "error", err)
slog.Error("Failed to set skipped plan status", "prNumber", prNumber, "error", err)

if err != nil {
slog.Error("Failed to set success plan status", "prNumber", prNumber, "error", err)
return fmt.Errorf("error setting pr status: %v", err)
}

err = prService.SetStatus(prNumber, "success", "digger/apply")
err = prService.SetStatus(prNumber, "skipped", "digger/apply")
if err != nil {
slog.Error("Failed to set success apply status", "prNumber", prNumber, "error", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

style: Log message still says 'success apply status' but now setting 'skipped' status - should update message to match

Suggested change
slog.Error("Failed to set success apply status", "prNumber", prNumber, "error", err)
slog.Error("Failed to set skipped apply status", "prNumber", prNumber, "error", err)

@@ -275,7 +275,7 @@ func run(command string, job orchestrator.Job, policyChecker policy.Checker, org
if err != nil {
msg := fmt.Sprintf("Failed to Run digger plan command. %v", err)
slog.Error("Failed to Run digger plan command", "error", err)
err := prService.SetStatus(*job.PullRequestNumber, "failure", job.GetProjectAlias()+"/plan")
//err := prService.SetStatus(*job.PullRequestNumber, "failure", job.GetProjectAlias()+"/plan")
Copy link
Contributor

Choose a reason for hiding this comment

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

syntax: Same issue - error handling logic remains for commented status check call, creating unreachable code.

Suggested change
//err := prService.SetStatus(*job.PullRequestNumber, "failure", job.GetProjectAlias()+"/plan")
//err := prService.SetStatus(*job.PullRequestNumber, "failure", job.GetProjectAlias()+"/plan")
if err != nil {
msg := fmt.Sprintf("Failed to set PR status. %v", err)
return nil, msg, fmt.Errorf("%s", msg)
}

Comment on lines +188 to +202
func GetStatusCheckForJob(job *DiggerJob) (string, error) {
switch job.Status {
case orchestrator_scheduler.DiggerJobStarted:
return "pending", nil
case orchestrator_scheduler.DiggerJobTriggered:
return "pending", nil
case orchestrator_scheduler.DiggerJobCreated:
return "pending", nil
case orchestrator_scheduler.DiggerJobSucceeded:
return "success", nil
case orchestrator_scheduler.DiggerJobFailed:
return "failed", nil
}
return "", fmt.Errorf("unknown job status: %s", job.Status)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The GetStatusCheckForJob function in backend/models/scheduler.go is missing a case for the DiggerJobQueuedForRun status that is defined in libs/scheduler/models.go. Additionally, it doesn't have a proper default case to handle any future job statuses that might be added.

The current implementation has a fallback return statement outside the switch statement, but this is not as clear as having an explicit default case within the switch. If a new job status is added in the future, the function will return an error rather than providing a sensible default behavior.

I've added the missing case for DiggerJobQueuedForRun and converted the fallback to a proper default case within the switch statement to make the code more maintainable and future-proof.

Suggested change
func GetStatusCheckForJob(job *DiggerJob) (string, error) {
switch job.Status {
case orchestrator_scheduler.DiggerJobStarted:
return "pending", nil
case orchestrator_scheduler.DiggerJobTriggered:
return "pending", nil
case orchestrator_scheduler.DiggerJobCreated:
return "pending", nil
case orchestrator_scheduler.DiggerJobSucceeded:
return "success", nil
case orchestrator_scheduler.DiggerJobFailed:
return "failed", nil
}
return "", fmt.Errorf("unknown job status: %s", job.Status)
}
func GetStatusCheckForJob(job *DiggerJob) (string, error) {
switch job.Status {
case orchestrator_scheduler.DiggerJobStarted:
return "pending", nil
case orchestrator_scheduler.DiggerJobTriggered:
return "pending", nil
case orchestrator_scheduler.DiggerJobCreated:
return "pending", nil
case orchestrator_scheduler.DiggerJobSucceeded:
return "success", nil
case orchestrator_scheduler.DiggerJobFailed:
return "failed", nil
case orchestrator_scheduler.DiggerJobQueuedForRun:
return "pending", nil
default:
return "", fmt.Errorf("unknown job status: %s", job.Status)
}
}

Comment on lines +198 to +199
case orchestrator_scheduler.DiggerJobFailed:
return "failed", nil
Copy link
Contributor

Choose a reason for hiding this comment

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

The GetStatusCheckForJob function in backend/models/scheduler.go returns "failed" for failed jobs, but GitHub's status API expects "failure" as the status value.

This is confirmed by examining the GitHub implementation in libs/ci/github/github.go where the SetStatus method maps status values to GitHub's check run API. The interface in libs/ci/ci.go also documents that the status should be one of "pending", "failure", or "success".

This mismatch could cause issues when reporting job statuses to GitHub, as the status value "failed" is not properly handled by GitHub's API.

Suggested change
case orchestrator_scheduler.DiggerJobFailed:
return "failed", nil
case orchestrator_scheduler.DiggerJobFailed:
return "failure", nil

Comment on lines +424 to 428
//err := prService.SetStatus(*job.PullRequestNumber, "failure", job.GetProjectAlias()+"/apply")
if err != nil {
msg := fmt.Sprintf("Failed to set PR status. %v", err)
return nil, msg, fmt.Errorf("%s", msg)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is another instance of the same issue in the file. The call to prService.SetStatus() on line 424 is commented out, but the error check for this call is still active. This creates a logical inconsistency since err is being checked but never set by the commented-out function call.

This is part of the same pattern of issues where status setting calls have been commented out but their error handling remains active. This could lead to confusion during maintenance and potentially cause runtime issues if the variable err happens to have a non-nil value from a previous operation.

Suggested change
//err := prService.SetStatus(*job.PullRequestNumber, "failure", job.GetProjectAlias()+"/apply")
if err != nil {
msg := fmt.Sprintf("Failed to set PR status. %v", err)
return nil, msg, fmt.Errorf("%s", msg)
}
// SetStatus calls have been commented out but error checks remain
// Commenting out the error check as well since there's no error to check
// if err != nil {
// msg := fmt.Sprintf("Failed to set PR status. %v", err)
// return nil, msg, fmt.Errorf("%s", msg)
// }

Comment on lines +301 to +308
var conclusion string
if status == "pending" {
checkStatus = "in_progress"
conclusion = ""
} else {
checkStatus = "completed"
conclusion = status
}
Copy link
Contributor

Choose a reason for hiding this comment

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

The GitHub Checks API doesn't directly support the "skipped" status value that was previously used with the Status API. In the current implementation, when the status is "skipped", it's being mapped to the same conclusion value, which isn't a valid conclusion for the Checks API.

According to GitHub's documentation, the valid conclusion values for the Checks API are: "action_required", "cancelled", "failure", "neutral", "success", "skipped", "stale", or "timed_out".

While "skipped" is a valid conclusion value, the code is directly using the status value as the conclusion, which could lead to issues if other non-standard status values are used. For the "neutral" status, it should also be mapped to the "neutral" conclusion.

This fix ensures that both "neutral" and "skipped" status values are properly mapped to valid conclusion values in the GitHub Checks API.

Suggested change
var conclusion string
if status == "pending" {
checkStatus = "in_progress"
conclusion = ""
} else {
checkStatus = "completed"
conclusion = status
}
var conclusion string
if status == "pending" {
checkStatus = "in_progress"
conclusion = ""
} else if status == "neutral" || status == "skipped" {
checkStatus = "completed"
conclusion = "neutral"
} else {
checkStatus = "completed"
conclusion = status
}

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