Skip to content

Commit c562b35

Browse files
committed
temp commit
1 parent 2a37cc1 commit c562b35

File tree

2 files changed

+362
-6
lines changed

2 files changed

+362
-6
lines changed

ee/backend/controllers/gitlab.go

Lines changed: 212 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/diggerhq/digger/backend/utils"
1212
"github.com/diggerhq/digger/libs/ci/generic"
1313
dg_github "github.com/diggerhq/digger/libs/ci/github"
14+
gitlab2 "github.com/diggerhq/digger/libs/ci/gitlab"
1415
comment_updater "github.com/diggerhq/digger/libs/comment_utils/reporting"
1516
dg_configuration "github.com/diggerhq/digger/libs/digger_config"
1617
dg_locking "github.com/diggerhq/digger/libs/locking"
@@ -78,12 +79,12 @@ func (d DiggerEEController) GitlabWebHookHandler(c *gin.Context) {
7879
}
7980
case *gitlab.MergeEvent:
8081
log.Printf("Got pull request event for %d", event.Project.ID)
81-
//err := handlePullRequestEvent(gh, event, d.CiBackendProvider)
82-
//if err != nil {
83-
// log.Printf("handlePullRequestEvent error: %v", err)
84-
// c.String(http.StatusInternalServerError, err.Error())
85-
// return
86-
//}
82+
err := handlePullRequestEvent(d.GitlabProvider, event, d.CiBackendProvider, organisationId)
83+
if err != nil {
84+
log.Printf("handlePullRequestEvent error: %v", err)
85+
c.String(http.StatusInternalServerError, err.Error())
86+
return
87+
}
8788
case *gitlab.PushEvent:
8889
log.Printf("Got push event for %v %v", event.Project.URL, event.Ref)
8990
//err := handlePushEvent(gh, event)
@@ -99,6 +100,211 @@ func (d DiggerEEController) GitlabWebHookHandler(c *gin.Context) {
99100
c.JSON(200, "ok")
100101
}
101102

103+
func handlePullRequestEvent(gitlabProvider utils.GitlabProvider, payload *gitlab.MergeEvent, ciBackendProvider ci_backends.CiBackendProvider, organisationId uint) error {
104+
projectId := payload.Project.ID
105+
repoFullName := payload.Project.PathWithNamespace
106+
repoOwner, repoName, _ := strings.Cut(repoFullName, "/")
107+
cloneURL := payload.Project.GitHTTPURL
108+
prNumber := payload.ObjectAttributes.IID
109+
isDraft := payload.ObjectAttributes.WorkInProgress
110+
branch := payload.ObjectAttributes.SourceBranch
111+
commitSha := payload.ObjectAttributes.MergeCommitSHA
112+
//defaultBranch := payload.Repository.DefaultBranch
113+
//actor := payload.User.Username
114+
discussionId := ""
115+
//action := payload.ObjectAttributes.Action
116+
117+
glService, glerr := utils.GetGitlabService(gitlabProvider, projectId, repoName, repoFullName, prNumber, discussionId)
118+
if glerr != nil {
119+
log.Printf("GetGithubService error: %v", glerr)
120+
return fmt.Errorf("error getting ghService to post error comment")
121+
}
122+
123+
diggerYmlStr, config, projectsGraph, err := utils.GetDiggerConfigForBranch(gitlabProvider, projectId, repoFullName, repoOwner, repoName, cloneURL, branch, prNumber, discussionId)
124+
if err != nil {
125+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: Could not load digger config, error: %v", err))
126+
log.Printf("getDiggerConfigForPR error: %v", err)
127+
return fmt.Errorf("error getting digger config")
128+
}
129+
130+
if !config.AllowDraftPRs && isDraft {
131+
log.Printf("AllowDraftPRs is disabled, skipping PR: %v", prNumber)
132+
return nil
133+
}
134+
135+
impactedProjects, impactedProjectsSourceMapping, _, err := gitlab2.ProcessGitlabPullRequestEvent(payload, config, projectsGraph, glService)
136+
if err != nil {
137+
log.Printf("Error processing event: %v", err)
138+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: Error processing event: %v", err))
139+
return fmt.Errorf("error processing event")
140+
}
141+
142+
jobsForImpactedProjects, _, err := gitlab2.ConvertGithubPullRequestEventToJobs(payload, impactedProjects, nil, *config)
143+
if err != nil {
144+
log.Printf("Error converting event to jobsForImpactedProjects: %v", err)
145+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: Error converting event to jobsForImpactedProjects: %v", err))
146+
return fmt.Errorf("error converting event to jobsForImpactedProjects")
147+
}
148+
149+
if len(jobsForImpactedProjects) == 0 {
150+
// do not report if no projects are impacted to minimise noise in the PR thread
151+
// TODO use status checks instead: https://github.com/diggerhq/digger/issues/1135
152+
log.Printf("No projects impacted; not starting any jobs")
153+
// This one is for aggregate reporting
154+
err = utils.SetPRStatusForJobs(glService, prNumber, jobsForImpactedProjects)
155+
return nil
156+
}
157+
158+
diggerCommand, err := scheduler.GetCommandFromJob(jobsForImpactedProjects[0])
159+
if err != nil {
160+
log.Printf("could not determine digger command from job: %v", jobsForImpactedProjects[0].Commands)
161+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: could not determine digger command from job: %v", err))
162+
return fmt.Errorf("unkown digger command in comment %v", err)
163+
}
164+
165+
if *diggerCommand == scheduler.DiggerCommandNoop {
166+
log.Printf("job is of type noop, no actions top perform")
167+
return nil
168+
}
169+
170+
// perform locking/unlocking in backend
171+
if config.PrLocks {
172+
for _, project := range impactedProjects {
173+
prLock := dg_locking.PullRequestLock{
174+
InternalLock: locking.BackendDBLock{
175+
OrgId: organisationId,
176+
},
177+
CIService: glService,
178+
Reporter: comment_updater.NoopReporter{},
179+
ProjectName: project.Name,
180+
ProjectNamespace: repoFullName,
181+
PrNumber: prNumber,
182+
}
183+
err = dg_locking.PerformLockingActionFromCommand(prLock, *diggerCommand)
184+
if err != nil {
185+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: Failed perform lock action on project: %v %v", project.Name, err))
186+
return fmt.Errorf("failed to perform lock action on project: %v, %v", project.Name, err)
187+
}
188+
}
189+
}
190+
191+
// if commands are locking or unlocking we don't need to trigger any jobs
192+
if *diggerCommand == scheduler.DiggerCommandUnlock ||
193+
*diggerCommand == scheduler.DiggerCommandLock {
194+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":white_check_mark: Command %v completed successfully", *diggerCommand))
195+
return nil
196+
}
197+
198+
if !config.AllowDraftPRs && isDraft {
199+
log.Printf("Draft PRs are disabled, skipping PR: %v", prNumber)
200+
return nil
201+
}
202+
203+
commentReporter, err := utils.InitCommentReporter(glService, prNumber, ":construction_worker: Digger starting...")
204+
if err != nil {
205+
log.Printf("Error initializing comment reporter: %v", err)
206+
return fmt.Errorf("error initializing comment reporter")
207+
}
208+
209+
err = utils.ReportInitialJobsStatus(commentReporter, jobsForImpactedProjects)
210+
if err != nil {
211+
log.Printf("Failed to comment initial status for jobs: %v", err)
212+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: Failed to comment initial status for jobs: %v", err))
213+
return fmt.Errorf("failed to comment initial status for jobs")
214+
}
215+
216+
err = utils.SetPRStatusForJobs(glService, prNumber, jobsForImpactedProjects)
217+
if err != nil {
218+
log.Printf("error setting status for PR: %v", err)
219+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: error setting status for PR: %v", err))
220+
fmt.Errorf("error setting status for PR: %v", err)
221+
}
222+
223+
impactedProjectsMap := make(map[string]dg_configuration.Project)
224+
for _, p := range impactedProjects {
225+
impactedProjectsMap[p.Name] = p
226+
}
227+
228+
impactedJobsMap := make(map[string]scheduler.Job)
229+
for _, j := range jobsForImpactedProjects {
230+
impactedJobsMap[j.ProjectName] = j
231+
}
232+
233+
commentId, err := strconv.ParseInt(commentReporter.CommentId, 10, 64)
234+
if err != nil {
235+
log.Printf("strconv.ParseInt error: %v", err)
236+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: could not handle commentId: %v", err))
237+
}
238+
batchId, _, err := utils.ConvertJobsToDiggerJobs(*diggerCommand, models.DiggerVCSGitlab, organisationId, impactedJobsMap, impactedProjectsMap, projectsGraph, 0, branch, prNumber, repoOwner, repoName, repoFullName, commitSha, commentId, diggerYmlStr)
239+
if err != nil {
240+
log.Printf("ConvertJobsToDiggerJobs error: %v", err)
241+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: ConvertJobsToDiggerJobs error: %v", err))
242+
return fmt.Errorf("error converting jobs")
243+
}
244+
245+
if config.CommentRenderMode == dg_configuration.CommentRenderModeGroupByModule {
246+
sourceDetails, err := comment_updater.PostInitialSourceComments(glService, prNumber, impactedProjectsSourceMapping)
247+
if err != nil {
248+
log.Printf("PostInitialSourceComments error: %v", err)
249+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: PostInitialSourceComments error: %v", err))
250+
return fmt.Errorf("error posting initial comments")
251+
}
252+
batch, err := models.DB.GetDiggerBatch(batchId)
253+
if err != nil {
254+
log.Printf("GetDiggerBatch error: %v", err)
255+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: PostInitialSourceComments error: %v", err))
256+
return fmt.Errorf("error getting digger batch")
257+
}
258+
batch.SourceDetails, err = json.Marshal(sourceDetails)
259+
if err != nil {
260+
log.Printf("sourceDetails, json Marshal error: %v", err)
261+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: json Marshal error: %v", err))
262+
return fmt.Errorf("error marshalling sourceDetails")
263+
}
264+
err = models.DB.UpdateDiggerBatch(batch)
265+
if err != nil {
266+
log.Printf("UpdateDiggerBatch error: %v", err)
267+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: UpdateDiggerBatch error: %v", err))
268+
return fmt.Errorf("error updating digger batch")
269+
}
270+
}
271+
272+
segment.Track(strconv.Itoa(int(organisationId)), "backend_trigger_job")
273+
274+
ciBackend, err := ciBackendProvider.GetCiBackend(
275+
ci_backends.CiBackendOptions{
276+
RepoName: repoName,
277+
RepoOwner: repoOwner,
278+
RepoFullName: repoFullName,
279+
GitlabProjectId: projectId,
280+
GitlabCIMergeRequestID: payload.ObjectAttributes.ID,
281+
GitlabCIMergeRequestIID: payload.ObjectAttributes.IID,
282+
GitlabciprojectId: payload.Project.ID,
283+
GitlabciprojectNamespace: payload.Project.Namespace,
284+
//GitlabciprojectNamespaceId: 0,
285+
GitlabmergeRequestEventName: payload.EventType,
286+
//GitlabCIPipelineID: ,
287+
//GitlabCIPipelineIID: "",
288+
GitlabCIProjectName: payload.Project.Name,
289+
GitlabDiscussionId: discussionId,
290+
},
291+
)
292+
if err != nil {
293+
log.Printf("GetCiBackend error: %v", err)
294+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: GetCiBackend error: %v", err))
295+
return fmt.Errorf("error fetching ci backed %v", err)
296+
}
297+
298+
err = controllers.TriggerDiggerJobs(ciBackend, repoFullName, repoOwner, repoName, batchId, prNumber, glService)
299+
if err != nil {
300+
log.Printf("TriggerDiggerJobs error: %v", err)
301+
utils.InitCommentReporter(glService, prNumber, fmt.Sprintf(":x: TriggerDiggerJobs error: %v", err))
302+
return fmt.Errorf("error triggerring Digger Jobs")
303+
}
304+
305+
return nil
306+
}
307+
102308
func handleIssueCommentEvent(gitlabProvider utils.GitlabProvider, payload *gitlab.MergeCommentEvent, ciBackendProvider ci_backends.CiBackendProvider, organisationId uint) error {
103309
projectId := payload.ProjectID
104310
repoFullName := payload.Project.PathWithNamespace

libs/ci/gitlab/webhooks.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package gitlab
2+
3+
import (
4+
"fmt"
5+
"github.com/diggerhq/digger/libs/ci"
6+
"github.com/diggerhq/digger/libs/ci/generic"
7+
"github.com/diggerhq/digger/libs/digger_config"
8+
"github.com/diggerhq/digger/libs/scheduler"
9+
"github.com/dominikbraun/graph"
10+
"github.com/xanzy/go-gitlab"
11+
)
12+
13+
func ProcessGitlabPullRequestEvent(payload *gitlab.MergeEvent, diggerConfig *digger_config.DiggerConfig, dependencyGraph graph.Graph[string, digger_config.Project], ciService ci.PullRequestService) ([]digger_config.Project, map[string]digger_config.ProjectToSourceMapping, int, error) {
14+
var impactedProjects []digger_config.Project
15+
var prNumber int
16+
prNumber = payload.ObjectAttributes.IID
17+
changedFiles, err := ciService.GetChangedFiles(prNumber)
18+
19+
if err != nil {
20+
return nil, nil, prNumber, fmt.Errorf("could not get changed files")
21+
}
22+
impactedProjects, impactedProjectsSourceLocations := diggerConfig.GetModifiedProjects(changedFiles)
23+
24+
if diggerConfig.DependencyConfiguration.Mode == digger_config.DependencyConfigurationHard {
25+
impactedProjects, err = generic.FindAllProjectsDependantOnImpactedProjects(impactedProjects, dependencyGraph)
26+
if err != nil {
27+
return nil, nil, prNumber, fmt.Errorf("failed to find all projects dependant on impacted projects")
28+
}
29+
}
30+
31+
return impactedProjects, impactedProjectsSourceLocations, prNumber, nil
32+
}
33+
34+
func ConvertGithubPullRequestEventToJobs(payload *gitlab.MergeEvent, impactedProjects []digger_config.Project, requestedProject *digger_config.Project, config digger_config.DiggerConfig) ([]scheduler.Job, bool, error) {
35+
workflows := config.Workflows
36+
jobs := make([]scheduler.Job, 0)
37+
38+
defaultBranch := payload.Repository.DefaultBranch
39+
prBranch := payload.ObjectAttributes.SourceBranch
40+
41+
for _, project := range impactedProjects {
42+
workflow, ok := workflows[project.Workflow]
43+
if !ok {
44+
return nil, false, fmt.Errorf("failed to find workflow config '%s' for project '%s'", project.Workflow, project.Name)
45+
}
46+
47+
runEnvVars := generic.GetRunEnvVars(defaultBranch, prBranch, project.Name, project.Dir)
48+
49+
stateEnvVars, commandEnvVars := digger_config.CollectTerraformEnvConfig(workflow.EnvVars)
50+
pullRequestNumber := payload.ObjectAttributes.IID
51+
namespace := payload.Repository.PathWithNamespace
52+
sender := payload.User.Username
53+
54+
StateEnvProvider, CommandEnvProvider := scheduler.GetStateAndCommandProviders(project)
55+
if payload.ObjectAttributes.Action == "merge" && payload.ObjectAttributes.TargetBranch == defaultBranch {
56+
jobs = append(jobs, scheduler.Job{
57+
ProjectName: project.Name,
58+
ProjectDir: project.Dir,
59+
ProjectWorkspace: project.Workspace,
60+
ProjectWorkflow: project.Workflow,
61+
Terragrunt: project.Terragrunt,
62+
Commands: workflow.Configuration.OnCommitToDefault,
63+
ApplyStage: scheduler.ToConfigStage(workflow.Apply),
64+
PlanStage: scheduler.ToConfigStage(workflow.Plan),
65+
RunEnvVars: runEnvVars,
66+
CommandEnvVars: commandEnvVars,
67+
StateEnvVars: stateEnvVars,
68+
PullRequestNumber: &pullRequestNumber,
69+
EventName: "pull_request",
70+
Namespace: namespace,
71+
RequestedBy: sender,
72+
CommandEnvProvider: CommandEnvProvider,
73+
StateEnvProvider: StateEnvProvider,
74+
})
75+
} else if payload.ObjectAttributes.Action == "open" || payload.ObjectAttributes.Action == "reopen" || payload.ObjectAttributes.Action == "synchronize" {
76+
jobs = append(jobs, scheduler.Job{
77+
ProjectName: project.Name,
78+
ProjectDir: project.Dir,
79+
ProjectWorkspace: project.Workspace,
80+
ProjectWorkflow: project.Workflow,
81+
Terragrunt: project.Terragrunt,
82+
OpenTofu: project.OpenTofu,
83+
Commands: workflow.Configuration.OnPullRequestPushed,
84+
ApplyStage: scheduler.ToConfigStage(workflow.Apply),
85+
PlanStage: scheduler.ToConfigStage(workflow.Plan),
86+
RunEnvVars: runEnvVars,
87+
CommandEnvVars: commandEnvVars,
88+
StateEnvVars: stateEnvVars,
89+
PullRequestNumber: &pullRequestNumber,
90+
EventName: "pull_request",
91+
Namespace: namespace,
92+
RequestedBy: sender,
93+
CommandEnvProvider: CommandEnvProvider,
94+
StateEnvProvider: StateEnvProvider,
95+
})
96+
} else if payload.ObjectAttributes.Action == "close" {
97+
jobs = append(jobs, scheduler.Job{
98+
ProjectName: project.Name,
99+
ProjectDir: project.Dir,
100+
ProjectWorkspace: project.Workspace,
101+
ProjectWorkflow: project.Workflow,
102+
Terragrunt: project.Terragrunt,
103+
OpenTofu: project.OpenTofu,
104+
Commands: workflow.Configuration.OnPullRequestClosed,
105+
ApplyStage: scheduler.ToConfigStage(workflow.Apply),
106+
PlanStage: scheduler.ToConfigStage(workflow.Plan),
107+
RunEnvVars: runEnvVars,
108+
CommandEnvVars: commandEnvVars,
109+
StateEnvVars: stateEnvVars,
110+
PullRequestNumber: &pullRequestNumber,
111+
EventName: "pull_request",
112+
Namespace: namespace,
113+
RequestedBy: sender,
114+
CommandEnvProvider: CommandEnvProvider,
115+
StateEnvProvider: StateEnvProvider,
116+
})
117+
// TODO: Figure how to detect gitlab's "PR converted to draft" event
118+
} else if payload.ObjectAttributes.Action == "converted_to_draft" {
119+
var commands []string
120+
if config.AllowDraftPRs == false && len(workflow.Configuration.OnPullRequestConvertedToDraft) == 0 {
121+
commands = []string{"digger unlock"}
122+
} else {
123+
commands = workflow.Configuration.OnPullRequestConvertedToDraft
124+
}
125+
126+
jobs = append(jobs, scheduler.Job{
127+
ProjectName: project.Name,
128+
ProjectDir: project.Dir,
129+
ProjectWorkspace: project.Workspace,
130+
ProjectWorkflow: project.Workflow,
131+
Terragrunt: project.Terragrunt,
132+
OpenTofu: project.OpenTofu,
133+
Commands: commands,
134+
ApplyStage: scheduler.ToConfigStage(workflow.Apply),
135+
PlanStage: scheduler.ToConfigStage(workflow.Plan),
136+
RunEnvVars: runEnvVars,
137+
CommandEnvVars: commandEnvVars,
138+
StateEnvVars: stateEnvVars,
139+
PullRequestNumber: &pullRequestNumber,
140+
EventName: "pull_request_converted_to_draft",
141+
Namespace: namespace,
142+
RequestedBy: sender,
143+
CommandEnvProvider: CommandEnvProvider,
144+
StateEnvProvider: StateEnvProvider,
145+
})
146+
}
147+
148+
}
149+
return jobs, true, nil
150+
}

0 commit comments

Comments
 (0)