Skip to content

Commit

Permalink
ensure link to workflow url always present (#1892)
Browse files Browse the repository at this point in the history
* async update of workflow urls
  • Loading branch information
motatoes authored Mar 5, 2025
1 parent 1f15455 commit 84f1c0e
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 16 deletions.
1 change: 1 addition & 0 deletions backend/ci_backends/ci_backends.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

type CiBackend interface {
TriggerWorkflow(spec spec.Spec, runName string, vcsToken string) error
GetWorkflowUrl(spec spec.Spec) (string, error)
}

type JenkinsCi struct{}
Expand Down
17 changes: 17 additions & 0 deletions backend/ci_backends/github_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package ci_backends
import (
"context"
"encoding/json"
"fmt"
"github.com/diggerhq/digger/backend/utils"
orchestrator_scheduler "github.com/diggerhq/digger/libs/scheduler"
"github.com/diggerhq/digger/libs/spec"
"github.com/google/go-github/v61/github"
Expand Down Expand Up @@ -30,3 +32,18 @@ func (g GithubActionCi) TriggerWorkflow(spec spec.Spec, runName string, vcsToken

return err
}

func (g GithubActionCi) GetWorkflowUrl(spec spec.Spec) (string, error) {
if spec.JobId == "" {
log.Printf("Cannot get workflow URL: JobId is empty")
return "", fmt.Errorf("job ID is required to fetch workflow URL")
}

_, workflowRunUrl, err := utils.GetWorkflowIdAndUrlFromDiggerJobId(g.Client, spec.VCS.RepoOwner, spec.VCS.RepoName, spec.JobId)
if err != nil {
log.Printf("Error getting workflow ID from job: %v", err)
return "", err
} else {
return workflowRunUrl, nil
}
}
33 changes: 18 additions & 15 deletions backend/controllers/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,21 +364,6 @@ func (d DiggerController) SetJobStatusForProject(c *gin.Context) {
return
}

client, _, err := utils.GetGithubClient(d.GithubClientProvider, job.Batch.GithubInstallationId, job.Batch.RepoFullName)
if err != nil {
log.Printf("Error Creating github client: %v", err)
} else {
_, workflowRunUrl, err := utils.GetWorkflowIdAndUrlFromDiggerJobId(client, job.Batch.RepoOwner, job.Batch.RepoName, job.DiggerJobID)
if err != nil {
log.Printf("Error getting workflow ID from job: %v", err)
} else {
job.WorkflowRunUrl = &workflowRunUrl
err = models.DB.UpdateDiggerJob(job)
if err != nil {
log.Printf("Error updating digger job: %v", err)
}
}
}
case "succeeded":
job.Status = orchestrator_scheduler.DiggerJobSucceeded
job.TerraformOutput = request.TerraformOutput
Expand Down Expand Up @@ -463,6 +448,24 @@ func (d DiggerController) SetJobStatusForProject(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Error saving job"})
return
}

// attempt to update workflow run url
client, _, err := utils.GetGithubClient(d.GithubClientProvider, job.Batch.GithubInstallationId, job.Batch.RepoFullName)
if err != nil {
log.Printf("Error Creating github client: %v", err)
} else {
_, workflowRunUrl, err := utils.GetWorkflowIdAndUrlFromDiggerJobId(client, job.Batch.RepoOwner, job.Batch.RepoName, job.DiggerJobID)
if err != nil {
log.Printf("Error getting workflow ID from job: %v", err)
} else if workflowRunUrl != "#" && workflowRunUrl != "" {
job.WorkflowRunUrl = &workflowRunUrl
err = models.DB.UpdateDiggerJob(job)
if err != nil {
log.Printf("Error updating digger job: %v", err)
}
}
}

job.StatusUpdatedAt = request.Timestamp
err = models.DB.GormDB.Save(&job).Error
if err != nil {
Expand Down
48 changes: 48 additions & 0 deletions backend/services/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import (
"github.com/diggerhq/digger/backend/models"
"github.com/diggerhq/digger/backend/utils"
orchestrator_scheduler "github.com/diggerhq/digger/libs/scheduler"
"github.com/diggerhq/digger/libs/spec"
"github.com/google/go-github/v61/github"
"github.com/google/uuid"
"log"
"runtime/debug"
"time"
)

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

go UpdateWorkflowUrlForJob(job, ciBackend, spec)

return nil
}

// This is meant to run asyncronously since it queries for job url
func UpdateWorkflowUrlForJob(job *models.DiggerJob, ciBackend ci_backends.CiBackend, spec *spec.Spec) {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from panic in UpdateWorkflowUrlForJob handler: %v", r)
log.Printf("\n=== PANIC RECOVERED ===\n")
log.Printf("Error: %v\n", r)
log.Printf("Stack Trace:\n%s", string(debug.Stack()))
log.Printf("=== END PANIC ===\n")
}
}()

batch := job.Batch
// for now we only perform this update for github
if batch.VCS != models.DiggerVCSGithub {
return
}
for n := 0; n < 30; n++ {
time.Sleep(1 * time.Second)
workflowUrl, err := ciBackend.GetWorkflowUrl(*spec)
if err != nil {
log.Printf("DiggerJobId %v: error while attempting to fetch workflow url: %v", job.DiggerJobID, err)
} else {
if workflowUrl == "#" || workflowUrl == "" {
log.Printf("DiggerJobId %v: got blank workflow url as response, ignoring", job.DiggerJobID)
} else {
job.WorkflowRunUrl = &workflowUrl
err = models.DB.UpdateDiggerJob(job)
if err != nil {
log.Printf("DiggerJobId %v: Error updating digger job: %v", job.DiggerJobID, err)
continue
} else {
log.Printf("DiggerJobId %v: successfully updated workflow run url to: %v for DiggerJobID: %v", job.DiggerJobID, workflowUrl, job.DiggerJobID)
}

return
}
}
}

// if we get to here its highly likely that the workflow job entirely failed to start for some reason
}
4 changes: 4 additions & 0 deletions backend/tasks/runs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ func (m MockCiBackend) TriggerWorkflow(spec spec.Spec, runName string, vcsToken
return nil
}

func (m MockCiBackend) GetWorkflowUrl(spec spec.Spec) (string, error) {
return "", nil
}

func setupSuite(tb testing.TB) (func(tb testing.TB), *models.Database) {
log.Println("setup suite")

Expand Down
1 change: 0 additions & 1 deletion backend/utils/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ func GetWorkflowIdAndUrlFromDiggerJobId(client *github.Client, repoOwner string,
}

for _, workflowRun := range runs.WorkflowRuns {
println(*workflowRun.ID)
workflowjobs, _, err := client.Actions.ListWorkflowJobs(context.Background(), repoOwner, repoName, *workflowRun.ID, nil)
if err != nil {
return 0, "#", fmt.Errorf("error listing workflow jobs for run %v %v", workflowRun.ID, err)
Expand Down
7 changes: 7 additions & 0 deletions ee/backend/ci_backends/bitbucket_pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,10 @@ func (bbp BitbucketPipelineCI) TriggerWorkflow(spec spec.Spec, runName string, v
_, err = bbp.Client.TriggerPipeline(bbp.Branch, variables)
return err
}

// GetWorkflowUrl fetch workflow url after triggering a job
// since some CI don't return url automatically we split it out to become a
// followup method
func (bbp BitbucketPipelineCI) GetWorkflowUrl(spec spec.Spec) (string, error) {
return "", nil
}
4 changes: 4 additions & 0 deletions ee/backend/ci_backends/buildkite.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ func (b BuildkiteCi) TriggerWorkflow(spec spec.Spec, runName string, vcsToken st
return err

}

func (b BuildkiteCi) GetWorkflowUrl(spec spec.Spec) (string, error) {
return "", nil
}
4 changes: 4 additions & 0 deletions ee/backend/ci_backends/gitlab_pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,7 @@ func (gl GitlabPipelineCI) TriggerWorkflow(spec spec.Spec, runName string, vcsTo

return err
}

func (g GitlabPipelineCI) GetWorkflowUrl(spec spec.Spec) (string, error) {
return "", nil
}
11 changes: 11 additions & 0 deletions ee/backend/controllers/bitbucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"log"
"net/http"
"os"
"runtime/debug"
"strconv"
"strings"
)
Expand Down Expand Up @@ -139,6 +140,16 @@ func (ee DiggerEEController) BitbucketWebhookHandler(c *gin.Context) {
}

func handleIssueCommentEventBB(bitbucketProvider utils.BitbucketProvider, payload *BitbucketCommentCreatedEvent, ciBackendProvider ci_backends.CiBackendProvider, organisationId uint, vcsConnectionId *uint, bbAccessToken string) error {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from panic in handleIssueCommentEventBB handler: %v", r)
log.Printf("\n=== PANIC RECOVERED ===\n")
log.Printf("Error: %v\n", r)
log.Printf("Stack Trace:\n%s", string(debug.Stack()))
log.Printf("=== END PANIC ===\n")
}
}()

repoFullName := payload.Repository.FullName
repoOwner := payload.Repository.Owner.Username
repoName := payload.Repository.Name
Expand Down
1 change: 1 addition & 0 deletions next/ci_backends/ci_backends.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

type CiBackend interface {
TriggerWorkflow(spec spec.Spec, runName string, vcsToken string) error
GetWorkflowUrl(spec spec.Spec) (string, error)
}

type JenkinsCi struct{}
Expand Down
4 changes: 4 additions & 0 deletions next/ci_backends/github_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ func (g GithubActionCi) TriggerWorkflow(spec spec.Spec, runName string, vcsToken

return err
}

func (g GithubActionCi) GetWorkflowUrl(spec spec.Spec) (string, error) {
return "", nil
}

0 comments on commit 84f1c0e

Please sign in to comment.