Skip to content

Commit 84f1c0e

Browse files
authored
ensure link to workflow url always present (#1892)
* async update of workflow urls
1 parent 1f15455 commit 84f1c0e

File tree

12 files changed

+119
-16
lines changed

12 files changed

+119
-16
lines changed

backend/ci_backends/ci_backends.go

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
type CiBackend interface {
99
TriggerWorkflow(spec spec.Spec, runName string, vcsToken string) error
10+
GetWorkflowUrl(spec spec.Spec) (string, error)
1011
}
1112

1213
type JenkinsCi struct{}

backend/ci_backends/github_actions.go

+17
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package ci_backends
33
import (
44
"context"
55
"encoding/json"
6+
"fmt"
7+
"github.com/diggerhq/digger/backend/utils"
68
orchestrator_scheduler "github.com/diggerhq/digger/libs/scheduler"
79
"github.com/diggerhq/digger/libs/spec"
810
"github.com/google/go-github/v61/github"
@@ -30,3 +32,18 @@ func (g GithubActionCi) TriggerWorkflow(spec spec.Spec, runName string, vcsToken
3032

3133
return err
3234
}
35+
36+
func (g GithubActionCi) GetWorkflowUrl(spec spec.Spec) (string, error) {
37+
if spec.JobId == "" {
38+
log.Printf("Cannot get workflow URL: JobId is empty")
39+
return "", fmt.Errorf("job ID is required to fetch workflow URL")
40+
}
41+
42+
_, workflowRunUrl, err := utils.GetWorkflowIdAndUrlFromDiggerJobId(g.Client, spec.VCS.RepoOwner, spec.VCS.RepoName, spec.JobId)
43+
if err != nil {
44+
log.Printf("Error getting workflow ID from job: %v", err)
45+
return "", err
46+
} else {
47+
return workflowRunUrl, nil
48+
}
49+
}

backend/controllers/projects.go

+18-15
Original file line numberDiff line numberDiff line change
@@ -364,21 +364,6 @@ func (d DiggerController) SetJobStatusForProject(c *gin.Context) {
364364
return
365365
}
366366

367-
client, _, err := utils.GetGithubClient(d.GithubClientProvider, job.Batch.GithubInstallationId, job.Batch.RepoFullName)
368-
if err != nil {
369-
log.Printf("Error Creating github client: %v", err)
370-
} else {
371-
_, workflowRunUrl, err := utils.GetWorkflowIdAndUrlFromDiggerJobId(client, job.Batch.RepoOwner, job.Batch.RepoName, job.DiggerJobID)
372-
if err != nil {
373-
log.Printf("Error getting workflow ID from job: %v", err)
374-
} else {
375-
job.WorkflowRunUrl = &workflowRunUrl
376-
err = models.DB.UpdateDiggerJob(job)
377-
if err != nil {
378-
log.Printf("Error updating digger job: %v", err)
379-
}
380-
}
381-
}
382367
case "succeeded":
383368
job.Status = orchestrator_scheduler.DiggerJobSucceeded
384369
job.TerraformOutput = request.TerraformOutput
@@ -463,6 +448,24 @@ func (d DiggerController) SetJobStatusForProject(c *gin.Context) {
463448
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error saving job"})
464449
return
465450
}
451+
452+
// attempt to update workflow run url
453+
client, _, err := utils.GetGithubClient(d.GithubClientProvider, job.Batch.GithubInstallationId, job.Batch.RepoFullName)
454+
if err != nil {
455+
log.Printf("Error Creating github client: %v", err)
456+
} else {
457+
_, workflowRunUrl, err := utils.GetWorkflowIdAndUrlFromDiggerJobId(client, job.Batch.RepoOwner, job.Batch.RepoName, job.DiggerJobID)
458+
if err != nil {
459+
log.Printf("Error getting workflow ID from job: %v", err)
460+
} else if workflowRunUrl != "#" && workflowRunUrl != "" {
461+
job.WorkflowRunUrl = &workflowRunUrl
462+
err = models.DB.UpdateDiggerJob(job)
463+
if err != nil {
464+
log.Printf("Error updating digger job: %v", err)
465+
}
466+
}
467+
}
468+
466469
job.StatusUpdatedAt = request.Timestamp
467470
err = models.DB.GormDB.Save(&job).Error
468471
if err != nil {

backend/services/scheduler.go

+48
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import (
77
"github.com/diggerhq/digger/backend/models"
88
"github.com/diggerhq/digger/backend/utils"
99
orchestrator_scheduler "github.com/diggerhq/digger/libs/scheduler"
10+
"github.com/diggerhq/digger/libs/spec"
1011
"github.com/google/go-github/v61/github"
1112
"github.com/google/uuid"
1213
"log"
14+
"runtime/debug"
15+
"time"
1316
)
1417

1518
func DiggerJobCompleted(client *github.Client, batchId *uuid.UUID, parentJob *models.DiggerJob, repoFullName string, repoOwner string, repoName string, workflowFileName string, gh utils.GithubClientProvider) error {
@@ -131,5 +134,50 @@ func TriggerJob(gh utils.GithubClientProvider, ciBackend ci_backends.CiBackend,
131134
return err
132135
}
133136

137+
go UpdateWorkflowUrlForJob(job, ciBackend, spec)
138+
134139
return nil
135140
}
141+
142+
// This is meant to run asyncronously since it queries for job url
143+
func UpdateWorkflowUrlForJob(job *models.DiggerJob, ciBackend ci_backends.CiBackend, spec *spec.Spec) {
144+
defer func() {
145+
if r := recover(); r != nil {
146+
log.Printf("Recovered from panic in UpdateWorkflowUrlForJob handler: %v", r)
147+
log.Printf("\n=== PANIC RECOVERED ===\n")
148+
log.Printf("Error: %v\n", r)
149+
log.Printf("Stack Trace:\n%s", string(debug.Stack()))
150+
log.Printf("=== END PANIC ===\n")
151+
}
152+
}()
153+
154+
batch := job.Batch
155+
// for now we only perform this update for github
156+
if batch.VCS != models.DiggerVCSGithub {
157+
return
158+
}
159+
for n := 0; n < 30; n++ {
160+
time.Sleep(1 * time.Second)
161+
workflowUrl, err := ciBackend.GetWorkflowUrl(*spec)
162+
if err != nil {
163+
log.Printf("DiggerJobId %v: error while attempting to fetch workflow url: %v", job.DiggerJobID, err)
164+
} else {
165+
if workflowUrl == "#" || workflowUrl == "" {
166+
log.Printf("DiggerJobId %v: got blank workflow url as response, ignoring", job.DiggerJobID)
167+
} else {
168+
job.WorkflowRunUrl = &workflowUrl
169+
err = models.DB.UpdateDiggerJob(job)
170+
if err != nil {
171+
log.Printf("DiggerJobId %v: Error updating digger job: %v", job.DiggerJobID, err)
172+
continue
173+
} else {
174+
log.Printf("DiggerJobId %v: successfully updated workflow run url to: %v for DiggerJobID: %v", job.DiggerJobID, workflowUrl, job.DiggerJobID)
175+
}
176+
177+
return
178+
}
179+
}
180+
}
181+
182+
// if we get to here its highly likely that the workflow job entirely failed to start for some reason
183+
}

backend/tasks/runs_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ func (m MockCiBackend) TriggerWorkflow(spec spec.Spec, runName string, vcsToken
2828
return nil
2929
}
3030

31+
func (m MockCiBackend) GetWorkflowUrl(spec spec.Spec) (string, error) {
32+
return "", nil
33+
}
34+
3135
func setupSuite(tb testing.TB) (func(tb testing.TB), *models.Database) {
3236
log.Println("setup suite")
3337

backend/utils/github.go

-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,6 @@ func GetWorkflowIdAndUrlFromDiggerJobId(client *github.Client, repoOwner string,
231231
}
232232

233233
for _, workflowRun := range runs.WorkflowRuns {
234-
println(*workflowRun.ID)
235234
workflowjobs, _, err := client.Actions.ListWorkflowJobs(context.Background(), repoOwner, repoName, *workflowRun.ID, nil)
236235
if err != nil {
237236
return 0, "#", fmt.Errorf("error listing workflow jobs for run %v %v", workflowRun.ID, err)

ee/backend/ci_backends/bitbucket_pipeline.go

+7
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,10 @@ func (bbp BitbucketPipelineCI) TriggerWorkflow(spec spec.Spec, runName string, v
3737
_, err = bbp.Client.TriggerPipeline(bbp.Branch, variables)
3838
return err
3939
}
40+
41+
// GetWorkflowUrl fetch workflow url after triggering a job
42+
// since some CI don't return url automatically we split it out to become a
43+
// followup method
44+
func (bbp BitbucketPipelineCI) GetWorkflowUrl(spec spec.Spec) (string, error) {
45+
return "", nil
46+
}

ee/backend/ci_backends/buildkite.go

+4
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ func (b BuildkiteCi) TriggerWorkflow(spec spec.Spec, runName string, vcsToken st
3131
return err
3232

3333
}
34+
35+
func (b BuildkiteCi) GetWorkflowUrl(spec spec.Spec) (string, error) {
36+
return "", nil
37+
}

ee/backend/ci_backends/gitlab_pipeline.go

+4
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,7 @@ func (gl GitlabPipelineCI) TriggerWorkflow(spec spec.Spec, runName string, vcsTo
5959

6060
return err
6161
}
62+
63+
func (g GitlabPipelineCI) GetWorkflowUrl(spec spec.Spec) (string, error) {
64+
return "", nil
65+
}

ee/backend/controllers/bitbucket.go

+11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"log"
2525
"net/http"
2626
"os"
27+
"runtime/debug"
2728
"strconv"
2829
"strings"
2930
)
@@ -139,6 +140,16 @@ func (ee DiggerEEController) BitbucketWebhookHandler(c *gin.Context) {
139140
}
140141

141142
func handleIssueCommentEventBB(bitbucketProvider utils.BitbucketProvider, payload *BitbucketCommentCreatedEvent, ciBackendProvider ci_backends.CiBackendProvider, organisationId uint, vcsConnectionId *uint, bbAccessToken string) error {
143+
defer func() {
144+
if r := recover(); r != nil {
145+
log.Printf("Recovered from panic in handleIssueCommentEventBB handler: %v", r)
146+
log.Printf("\n=== PANIC RECOVERED ===\n")
147+
log.Printf("Error: %v\n", r)
148+
log.Printf("Stack Trace:\n%s", string(debug.Stack()))
149+
log.Printf("=== END PANIC ===\n")
150+
}
151+
}()
152+
142153
repoFullName := payload.Repository.FullName
143154
repoOwner := payload.Repository.Owner.Username
144155
repoName := payload.Repository.Name

next/ci_backends/ci_backends.go

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
type CiBackend interface {
99
TriggerWorkflow(spec spec.Spec, runName string, vcsToken string) error
10+
GetWorkflowUrl(spec spec.Spec) (string, error)
1011
}
1112

1213
type JenkinsCi struct{}

next/ci_backends/github_actions.go

+4
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,7 @@ func (g GithubActionCi) TriggerWorkflow(spec spec.Spec, runName string, vcsToken
3030

3131
return err
3232
}
33+
34+
func (g GithubActionCi) GetWorkflowUrl(spec spec.Spec) (string, error) {
35+
return "", nil
36+
}

0 commit comments

Comments
 (0)