-
Notifications
You must be signed in to change notification settings - Fork 561
feat/support layers #2061
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat/support layers #2061
Changes from all commits
02654a0
3565598
f109ffe
f804758
ad28469
3f2a1b6
1b2c37b
9654f9f
e9b99fe
e02affe
e3da663
914b30b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -720,17 +720,6 @@ func handlePullRequestEvent(gh utils.GithubClientProvider, payload *github.PullR | |||||
return fmt.Errorf("error initializing comment reporter") | ||||||
} | ||||||
|
||||||
err = utils.ReportInitialJobsStatus(commentReporter, jobsForImpactedProjects) | ||||||
if err != nil { | ||||||
slog.Error("Failed to comment initial status for jobs", | ||||||
"prNumber", prNumber, | ||||||
"jobCount", len(jobsForImpactedProjects), | ||||||
"error", err, | ||||||
) | ||||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Failed to comment initial status for jobs: %v", err)) | ||||||
return fmt.Errorf("failed to comment initial status for jobs") | ||||||
} | ||||||
|
||||||
err = utils.SetPRStatusForJobs(ghService, prNumber, jobsForImpactedProjects) | ||||||
if err != nil { | ||||||
slog.Error("Error setting status for PR", | ||||||
|
@@ -741,6 +730,40 @@ func handlePullRequestEvent(gh utils.GithubClientProvider, payload *github.PullR | |||||
return fmt.Errorf("error setting status for PR: %v", err) | ||||||
} | ||||||
|
||||||
nLayers, _ := orchestrator_scheduler.CountUniqueLayers(jobsForImpactedProjects) | ||||||
slog.Debug("Number of layers", | ||||||
"prNumber", prNumber, | ||||||
"nLayers", nLayers, | ||||||
"respectLayers", config.RespectLayers, | ||||||
) | ||||||
if config.RespectLayers && nLayers > 1 { | ||||||
slog.Debug("Respecting layers", | ||||||
"prNumber", prNumber) | ||||||
err = utils.ReportLayersTableForJobs(commentReporter, jobsForImpactedProjects) | ||||||
if err != nil { | ||||||
slog.Error("Failed to comment initial status for jobs", | ||||||
"prNumber", prNumber, | ||||||
"jobCount", len(jobsForImpactedProjects), | ||||||
"error", err, | ||||||
) | ||||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Failed to comment initial status for jobs: %v", err)) | ||||||
return fmt.Errorf("failed to comment initial status for jobs") | ||||||
} | ||||||
slog.Debug("not performing plan since there are multiple layers and respect_layers is enabled") | ||||||
return nil | ||||||
} else { | ||||||
err = utils.ReportInitialJobsStatus(commentReporter, jobsForImpactedProjects) | ||||||
if err != nil { | ||||||
slog.Error("Failed to comment initial status for jobs", | ||||||
"prNumber", prNumber, | ||||||
"jobCount", len(jobsForImpactedProjects), | ||||||
"error", err, | ||||||
) | ||||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Failed to comment initial status for jobs: %v", err)) | ||||||
return fmt.Errorf("failed to comment initial status for jobs") | ||||||
} | ||||||
} | ||||||
|
||||||
slog.Debug("Preparing job and project maps", | ||||||
"prNumber", prNumber, | ||||||
"projectCount", len(impactedProjects), | ||||||
|
@@ -788,6 +811,9 @@ func handlePullRequestEvent(gh utils.GithubClientProvider, payload *github.PullR | |||||
"jobCount", len(impactedJobsMap), | ||||||
) | ||||||
|
||||||
if config.RespectLayers { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's an empty if block at line 814 that appears to be incomplete code. The condition
Suggested change
|
||||||
|
||||||
} | ||||||
Comment on lines
+814
to
+816
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Empty conditional block - this appears to be unfinished code that should be removed or completed |
||||||
batchId, _, err := utils.ConvertJobsToDiggerJobs( | ||||||
*diggerCommand, | ||||||
models.DiggerVCSGithub, | ||||||
|
@@ -1427,7 +1453,7 @@ func handleIssueCommentEvent(gh utils.GithubClientProvider, payload *github.Issu | |||||
"branchName", prBranchName, | ||||||
) | ||||||
|
||||||
impactedProjects, impactedProjectsSourceMapping, requestedProject, _, err := generic.ProcessIssueCommentEvent(issueNumber, commentBody, config, projectsGraph, ghService) | ||||||
processEventResult, err := generic.ProcessIssueCommentEvent(issueNumber, commentBody, config, projectsGraph, ghService) | ||||||
if err != nil { | ||||||
slog.Error("Error processing issue comment event", | ||||||
"issueNumber", issueNumber, | ||||||
|
@@ -1436,45 +1462,49 @@ func handleIssueCommentEvent(gh utils.GithubClientProvider, payload *github.Issu | |||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Error processing event: %v", err)) | ||||||
return fmt.Errorf("error processing event") | ||||||
} | ||||||
impactedProjectsForComment := processEventResult.ImpactedProjectsForComment | ||||||
impactedProjectsSourceMapping := processEventResult.ImpactedProjectsSourceMapping | ||||||
allImpactedProjects := processEventResult.AllImpactedProjects | ||||||
|
||||||
slog.Info("Issue comment event processed successfully", | ||||||
"issueNumber", issueNumber, | ||||||
"impactedProjectCount", len(impactedProjects), | ||||||
"requestedProject", requestedProject, | ||||||
"impactedProjectCount", len(impactedProjectsForComment), | ||||||
"allImpactedProjectsCount", len(allImpactedProjects), | ||||||
|
||||||
) | ||||||
|
||||||
jobs, coverAllImpactedProjects, err := generic.ConvertIssueCommentEventToJobs(repoFullName, actor, issueNumber, commentBody, impactedProjects, requestedProject, config.Workflows, prBranchName, defaultBranch) | ||||||
jobs, coverAllImpactedProjects, err := generic.ConvertIssueCommentEventToJobs(repoFullName, actor, issueNumber, commentBody, impactedProjectsForComment, allImpactedProjects, config.Workflows, prBranchName, defaultBranch) | ||||||
if err != nil { | ||||||
slog.Error("Error converting event to jobs", | ||||||
"issueNumber", issueNumber, | ||||||
"impactedProjectCount", len(impactedProjects), | ||||||
"impactedProjectCount", len(impactedProjectsForComment), | ||||||
"error", err, | ||||||
) | ||||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Error converting event to jobs: %v", err)) | ||||||
return fmt.Errorf("error converting event to jobs") | ||||||
} | ||||||
|
||||||
slog.Info("Issue comment event converted to jobs successfully", | ||||||
"issueNumber", issueNumber, | ||||||
"jobCount", len(jobs), | ||||||
) | ||||||
|
||||||
// if flag set we dont allow more projects impacted than the number of changed files in PR (safety check) | ||||||
if config2.LimitByNumOfFilesChanged() { | ||||||
if len(impactedProjects) > len(changedFiles) { | ||||||
if len(impactedProjectsForComment) > len(changedFiles) { | ||||||
slog.Error("Number of impacted projects exceeds number of changed files", | ||||||
"issueNumber", issueNumber, | ||||||
"impactedProjectCount", len(impactedProjects), | ||||||
"impactedProjectCount", len(impactedProjectsForComment), | ||||||
"changedFileCount", len(changedFiles), | ||||||
) | ||||||
|
||||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Error the number impacted projects %v exceeds number of changed files: %v", len(impactedProjects), len(changedFiles))) | ||||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Error the number impacted projects %v exceeds number of changed files: %v", len(impactedProjectsForComment), len(changedFiles))) | ||||||
|
||||||
slog.Debug("Detailed event information", | ||||||
slog.Group("details", | ||||||
slog.Any("changedFiles", changedFiles), | ||||||
slog.Int("configLength", len(diggerYmlStr)), | ||||||
slog.Int("impactedProjectCount", len(impactedProjects)), | ||||||
slog.Int("impactedProjectCount", len(impactedProjectsForComment)), | ||||||
), | ||||||
) | ||||||
|
||||||
|
@@ -1483,20 +1513,20 @@ func handleIssueCommentEvent(gh utils.GithubClientProvider, payload *github.Issu | |||||
} | ||||||
|
||||||
maxImpactedProjectsPerChange := config2.MaxImpactedProjectsPerChange() | ||||||
if len(impactedProjects) > maxImpactedProjectsPerChange { | ||||||
if len(impactedProjectsForComment) > maxImpactedProjectsPerChange { | ||||||
slog.Error("Number of impacted projects exceeds number of changed files", | ||||||
"prNumber", issueNumber, | ||||||
"impactedProjectCount", len(impactedProjects), | ||||||
"impactedProjectCount", len(impactedProjectsForComment), | ||||||
"changedFileCount", len(changedFiles), | ||||||
) | ||||||
|
||||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Error the number impacted projects %v exceeds Max allowed ImpactedProjectsPerChange: %v, we set this limit to protect against hitting github API limits", len(impactedProjects), maxImpactedProjectsPerChange)) | ||||||
commentReporterManager.UpdateComment(fmt.Sprintf(":x: Error the number impacted projects %v exceeds Max allowed ImpactedProjectsPerChange: %v, we set this limit to protect against hitting github API limits", len(impactedProjectsForComment), maxImpactedProjectsPerChange)) | ||||||
|
||||||
slog.Debug("Detailed event information", | ||||||
slog.Group("details", | ||||||
slog.Any("changedFiles", changedFiles), | ||||||
slog.Int("configLength", len(diggerYmlStr)), | ||||||
slog.Int("impactedProjectCount", len(impactedProjects)), | ||||||
slog.Int("impactedProjectCount", len(impactedProjectsForComment)), | ||||||
), | ||||||
) | ||||||
return fmt.Errorf("error processing event") | ||||||
|
@@ -1506,11 +1536,11 @@ func handleIssueCommentEvent(gh utils.GithubClientProvider, payload *github.Issu | |||||
if config.PrLocks { | ||||||
slog.Info("Processing PR locks for impacted projects", | ||||||
"issueNumber", issueNumber, | ||||||
"projectCount", len(impactedProjects), | ||||||
"projectCount", len(impactedProjectsForComment), | ||||||
"command", *diggerCommand, | ||||||
) | ||||||
|
||||||
for _, project := range impactedProjects { | ||||||
for _, project := range impactedProjectsForComment { | ||||||
prLock := dg_locking.PullRequestLock{ | ||||||
InternalLock: locking.BackendDBLock{ | ||||||
OrgId: orgId, | ||||||
|
@@ -1580,12 +1610,12 @@ func handleIssueCommentEvent(gh utils.GithubClientProvider, payload *github.Issu | |||||
|
||||||
slog.Debug("Preparing job and project maps", | ||||||
"issueNumber", issueNumber, | ||||||
"projectCount", len(impactedProjects), | ||||||
"projectCount", len(impactedProjectsForComment), | ||||||
"jobCount", len(jobs), | ||||||
) | ||||||
|
||||||
impactedProjectsMap := make(map[string]dg_configuration.Project) | ||||||
for _, p := range impactedProjects { | ||||||
for _, p := range impactedProjectsForComment { | ||||||
impactedProjectsMap[p.Name] = p | ||||||
} | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-- Modify "digger_batches" table | ||
ALTER TABLE "public"."digger_batches" ADD COLUMN "layer" bigint NULL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Consider using |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -3,6 +3,7 @@ package utils | |||||
import ( | ||||||
"fmt" | ||||||
"log/slog" | ||||||
"sort" | ||||||
|
||||||
"github.com/diggerhq/digger/libs/ci" | ||||||
"github.com/diggerhq/digger/libs/scheduler" | ||||||
|
@@ -135,6 +136,28 @@ func UpdateCRComment(cr *CommentReporter, comment string) error { | |||||
return nil | ||||||
} | ||||||
|
||||||
func trimMessageIfExceedsMaxLength(message string) string { | ||||||
|
||||||
const GithubCommentMaxLength = 65536 | ||||||
|
||||||
if len(message) > GithubCommentMaxLength { | ||||||
slog.Warn("Comment message is too long, trimming", | ||||||
"originalLength", len(message), | ||||||
"maxLength", GithubCommentMaxLength, | ||||||
) | ||||||
|
||||||
const footer = "[trimmed]" | ||||||
trimLength := len(message) - GithubCommentMaxLength + len(footer) | ||||||
message = message[:len(message)-trimLength] + footer | ||||||
|
||||||
slog.Debug("Trimmed comment message", | ||||||
"newLength", len(message), | ||||||
"trimmedBytes", trimLength, | ||||||
) | ||||||
} | ||||||
return message | ||||||
} | ||||||
|
||||||
func ReportInitialJobsStatus(cr *CommentReporter, jobs []scheduler.Job) error { | ||||||
prNumber := cr.PrNumber | ||||||
prService := cr.PrService | ||||||
|
@@ -158,24 +181,7 @@ func ReportInitialJobsStatus(cr *CommentReporter, jobs []scheduler.Job) error { | |||||
} | ||||||
} | ||||||
|
||||||
const GithubCommentMaxLength = 65536 | ||||||
|
||||||
if len(message) > GithubCommentMaxLength { | ||||||
slog.Warn("Comment message is too long, trimming", | ||||||
"originalLength", len(message), | ||||||
"maxLength", GithubCommentMaxLength, | ||||||
) | ||||||
|
||||||
const footer = "[trimmed]" | ||||||
trimLength := len(message) - GithubCommentMaxLength + len(footer) | ||||||
message = message[:len(message)-trimLength] + footer | ||||||
|
||||||
slog.Debug("Trimmed comment message", | ||||||
"newLength", len(message), | ||||||
"trimmedBytes", trimLength, | ||||||
) | ||||||
} | ||||||
|
||||||
message = trimMessageIfExceedsMaxLength(message) | ||||||
err := prService.EditComment(prNumber, commentId, message) | ||||||
if err != nil { | ||||||
slog.Error("Failed to update comment with initial jobs status", | ||||||
|
@@ -190,39 +196,61 @@ func ReportInitialJobsStatus(cr *CommentReporter, jobs []scheduler.Job) error { | |||||
return nil | ||||||
} | ||||||
|
||||||
func ReportNoProjectsImpacted(cr *CommentReporter, jobs []scheduler.Job) error { | ||||||
func ReportLayersTableForJobs(cr *CommentReporter, jobs []scheduler.Job) error { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Function name suggests it reports layers table but the log message still says 'Reporting initial jobs status' - should be updated for consistency |
||||||
prNumber := cr.PrNumber | ||||||
prService := cr.PrService | ||||||
commentId := cr.CommentId | ||||||
|
||||||
slog.Info("Reporting no projects impacted", | ||||||
// sort jobs by layer for better display (sort by name too) | ||||||
sort.Slice(jobs, func(i, j int) bool { | ||||||
if jobs[i].Layer == jobs[j].Layer { | ||||||
return jobs[i].ProjectName < jobs[j].ProjectName | ||||||
} | ||||||
return jobs[i].Layer < jobs[j].Layer | ||||||
}) | ||||||
|
||||||
slog.Info("Reporting initial jobs status", | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Log message is inconsistent with function purpose - should say 'Reporting layers table' instead of 'initial jobs status'
Suggested change
Context Used: 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) |
||||||
"prNumber", prNumber, | ||||||
"commentId", commentId, | ||||||
"jobCount", len(jobs), | ||||||
) | ||||||
|
||||||
message := "" + | ||||||
":construction_worker: The following projects are impacted\n\n" | ||||||
for _, job := range jobs { | ||||||
message = message + fmt.Sprintf(""+ | ||||||
"<!-- PROJECTHOLDER %v -->\n"+ | ||||||
":clock11: **%v**: pending...\n"+ | ||||||
"<!-- PROJECTHOLDEREND %v -->\n"+ | ||||||
"", job.ProjectName, job.ProjectName, job.ProjectName) | ||||||
|
||||||
slog.Debug("Added project placeholder to message", "projectName", job.ProjectName) | ||||||
message := "" | ||||||
if len(jobs) == 0 { | ||||||
message = message + ":construction_worker: No projects impacted" | ||||||
} else { | ||||||
message = message + fmt.Sprintf("| Project | Layer |\n") | ||||||
message = message + fmt.Sprintf("|---------|--------|\n") | ||||||
for _, job := range jobs { | ||||||
message = message + fmt.Sprintf(""+ | ||||||
"|:clock11: **%v**|%v|\n", job.ProjectName, job.Layer) | ||||||
} | ||||||
} | ||||||
|
||||||
message += "----------------\n\n" | ||||||
message += ` | ||||||
<details> | ||||||
<summary>Instructions</summary> | ||||||
|
||||||
Since you enabled layers in your configuration, you can proceed to perform a layer-by-layer deployment. | ||||||
To start planning the first layer you can run "digger plan --layer 0". To apply the first layer, run "digger apply --layer 0". | ||||||
|
||||||
To deploy the next layer, run "digger plan --layer 1". To apply the next layer, run "digger apply --layer 1". | ||||||
|
||||||
And so on. A new commit on the branch will restart this deployment process. | ||||||
</details> | ||||||
` | ||||||
message = trimMessageIfExceedsMaxLength(message) | ||||||
err := prService.EditComment(prNumber, commentId, message) | ||||||
if err != nil { | ||||||
slog.Error("Failed to update comment with no projects impacted message", | ||||||
slog.Error("Failed to update comment with initial jobs status", | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Error log message is generic 'initial jobs status' but should reflect the layers table context
Suggested change
Context Used: Context - Enrich debug logs with relevant context. Always include identifiers like 'prNumber' in logs to facilitate easier tracing and troubleshooting. (link) |
||||||
"prNumber", prNumber, | ||||||
"commentId", commentId, | ||||||
"error", err, | ||||||
) | ||||||
return err | ||||||
} | ||||||
|
||||||
slog.Debug("Successfully reported no projects impacted", "prNumber", prNumber, "commentId", commentId) | ||||||
slog.Debug("Successfully reported initial jobs status", "prNumber", prNumber, "commentId", commentId) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Success log message should reflect the actual operation being performed (layers table) rather than generic 'initial jobs status'
Suggested change
Context Used: 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) |
||||||
return nil | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation of the
respect_layers
feature silently returns early when multiple layers are detected, without providing clear feedback to the user about why no jobs are being triggered. This can be confusing for users who expect automatic job triggering.The bug is that while the code does report a layers table with instructions in a collapsible details section, it doesn't explicitly inform users that no automatic job triggering will occur. This significant change in behavior should be prominently communicated.
The fix adds a more visible message explaining that when
respect_layers
is enabled with multiple layers, jobs aren't automatically triggered, and directs users to the instructions for manually triggering jobs by layer. It also improves the logging from debug to info level for better visibility in logs.