Skip to content

Commit cc703a9

Browse files
authored
send workflow url from cli (#2048)
* send workflow url from cli
1 parent bdf5316 commit cc703a9

File tree

3 files changed

+86
-98
lines changed

3 files changed

+86
-98
lines changed

backend/controllers/projects.go

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ type SetJobStatusRequest struct {
621621
PrCommentUrl string `json:"pr_comment_url"`
622622
PrCommentId string `json:"pr_comment_id"`
623623
TerraformOutput string `json:"terraform_output"`
624+
WorkflowUrl string `json:"workflow_url,omitempty"`
624625
}
625626

626627
func (d DiggerController) SetJobStatusForProject(c *gin.Context) {
@@ -664,6 +665,10 @@ func (d DiggerController) SetJobStatusForProject(c *gin.Context) {
664665
switch request.Status {
665666
case "started":
666667
job.Status = orchestrator_scheduler.DiggerJobStarted
668+
if request.WorkflowUrl != "" {
669+
slog.Debug("Adding workflow url to job", "jobId", jobId, "workflowUrl", request.WorkflowUrl)
670+
job.WorkflowRunUrl = &request.WorkflowUrl
671+
}
667672
err := models.DB.UpdateDiggerJob(job)
668673
if err != nil {
669674
slog.Error("Error updating job status",
@@ -862,44 +867,13 @@ func (d DiggerController) SetJobStatusForProject(c *gin.Context) {
862867
return
863868
}
864869

865-
// attempt to update workflow run url
870+
// attempt to update workflow run url, note we only have this for backwards compatibility with
871+
// older digger cli versions, newer cli versions after v0.6.110 will send the workflow url so
872+
// we don't need to pull API, saving us rate limit exceeded errors
866873
slog.Debug("Attempting to update workflow run URL", "jobId", jobId)
867-
868-
client, _, err := utils.GetGithubClient(d.GithubClientProvider, job.Batch.GithubInstallationId, job.Batch.RepoFullName)
874+
err = updateWorkflowUrlForJob(d.GithubClientProvider, job)
869875
if err != nil {
870-
slog.Warn("Error creating GitHub client for workflow URL update",
871-
"jobId", jobId,
872-
"repoFullName", job.Batch.RepoFullName,
873-
"error", err,
874-
)
875-
} else {
876-
_, workflowRunUrl, err := utils.GetWorkflowIdAndUrlFromDiggerJobId(
877-
client,
878-
job.Batch.RepoOwner,
879-
job.Batch.RepoName,
880-
job.DiggerJobID,
881-
)
882-
if err != nil {
883-
slog.Warn("Error getting workflow ID from job",
884-
"jobId", jobId,
885-
"error", err,
886-
)
887-
} else if workflowRunUrl != "#" && workflowRunUrl != "" {
888-
job.WorkflowRunUrl = &workflowRunUrl
889-
err = models.DB.UpdateDiggerJob(job)
890-
if err != nil {
891-
slog.Error("Error updating job with workflow URL",
892-
"jobId", jobId,
893-
"workflowUrl", workflowRunUrl,
894-
"error", err,
895-
)
896-
} else {
897-
slog.Debug("Updated job with workflow URL",
898-
"jobId", jobId,
899-
"workflowUrl", workflowRunUrl,
900-
)
901-
}
902-
}
876+
slog.Warn("Failed to update workflow run URL", "jobId", jobId, "error", err)
903877
}
904878

905879
job.StatusUpdatedAt = request.Timestamp
@@ -991,6 +965,63 @@ func (d DiggerController) SetJobStatusForProject(c *gin.Context) {
991965
c.JSON(http.StatusOK, res)
992966
}
993967

968+
func updateWorkflowUrlForJob(githubClientProvider utils.GithubClientProvider, job *models.DiggerJob) error {
969+
if job == nil {
970+
return fmt.Errorf("job is nil")
971+
}
972+
if job.WorkflowRunUrl != nil && *job.WorkflowRunUrl != "#" && *job.WorkflowRunUrl != "" {
973+
slog.Debug("Workflow URL already exists", "jobId", job.DiggerJobID)
974+
return nil
975+
}
976+
jobId := job.DiggerJobID
977+
client, _, err := utils.GetGithubClient(githubClientProvider, job.Batch.GithubInstallationId, job.Batch.RepoFullName)
978+
if err != nil {
979+
slog.Warn("Error creating GitHub client for workflow URL update",
980+
"jobId", jobId,
981+
"repoFullName", job.Batch.RepoFullName,
982+
"error", err,
983+
)
984+
return fmt.Errorf("error creating GitHub client for workflow URL update: %v", err)
985+
}
986+
987+
_, workflowRunUrl, err := utils.GetWorkflowIdAndUrlFromDiggerJobId(
988+
client,
989+
job.Batch.RepoOwner,
990+
job.Batch.RepoName,
991+
job.DiggerJobID,
992+
)
993+
if err != nil {
994+
slog.Warn("Error getting workflow ID from job",
995+
"jobId", jobId,
996+
"error", err,
997+
)
998+
return fmt.Errorf("error getting workflow ID from job: %v", err)
999+
}
1000+
1001+
if workflowRunUrl != "#" && workflowRunUrl != "" {
1002+
job.WorkflowRunUrl = &workflowRunUrl
1003+
err = models.DB.UpdateDiggerJob(job)
1004+
if err != nil {
1005+
slog.Error("Error updating job with workflow URL",
1006+
"jobId", jobId,
1007+
"workflowUrl", workflowRunUrl,
1008+
"error", err,
1009+
)
1010+
return fmt.Errorf("error updating job with workflow URL: %v", err)
1011+
} else {
1012+
slog.Debug("Updated job with workflow URL",
1013+
"jobId", jobId,
1014+
"workflowUrl", workflowRunUrl,
1015+
)
1016+
}
1017+
} else {
1018+
slog.Debug("Workflow URL not found for job",
1019+
"jobId", jobId)
1020+
return fmt.Errorf("workflow URL not found for job (workflowUrl returned: %v)", workflowRunUrl)
1021+
}
1022+
return nil
1023+
}
1024+
9941025
type CreateProjectRunRequest struct {
9951026
StartedAt time.Time `json:"startedAt"`
9961027
EndedAt time.Time `json:"endedAt"`

backend/services/scheduler.go

Lines changed: 1 addition & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,14 @@ package services
22

33
import (
44
"fmt"
5-
"log/slog"
6-
"runtime/debug"
7-
"time"
8-
95
"github.com/diggerhq/digger/backend/ci_backends"
106
"github.com/diggerhq/digger/backend/config"
117
"github.com/diggerhq/digger/backend/models"
128
"github.com/diggerhq/digger/backend/utils"
139
orchestrator_scheduler "github.com/diggerhq/digger/libs/scheduler"
14-
"github.com/diggerhq/digger/libs/spec"
1510
"github.com/google/go-github/v61/github"
1611
"github.com/google/uuid"
12+
"log/slog"
1713
)
1814

1915
func DiggerJobCompleted(client *github.Client, batchId *uuid.UUID, parentJob *models.DiggerJob, repoFullName string, repoOwner string, repoName string, workflowFileName string, gh utils.GithubClientProvider) error {
@@ -168,63 +164,6 @@ func TriggerJob(gh utils.GithubClientProvider, ciBackend ci_backends.CiBackend,
168164
}
169165

170166
slog.Info("Job successfully triggered", "jobId", job.DiggerJobID, "status", job.Status)
171-
go UpdateWorkflowUrlForJob(job, ciBackend, spec)
172167

173168
return nil
174169
}
175-
176-
// This is meant to run asynchronously since it queries for job url
177-
func UpdateWorkflowUrlForJob(job *models.DiggerJob, ciBackend ci_backends.CiBackend, spec *spec.Spec) {
178-
defer func() {
179-
if r := recover(); r != nil {
180-
stack := string(debug.Stack())
181-
slog.Error("Recovered from panic in UpdateWorkflowUrlForJob",
182-
"jobId", job.DiggerJobID,
183-
"error", r,
184-
"stackTrace", stack,
185-
)
186-
}
187-
}()
188-
189-
batch := job.Batch
190-
// for now we only perform this update for github
191-
if batch.VCS != models.DiggerVCSGithub {
192-
slog.Debug("Skipping workflow URL update for non-GitHub VCS", "jobId", job.DiggerJobID, "vcs", batch.VCS)
193-
return
194-
}
195-
196-
slog.Info("Starting workflow URL update", "jobId", job.DiggerJobID)
197-
198-
for n := 0; n < 30; n++ {
199-
time.Sleep(1 * time.Second)
200-
workflowUrl, err := ciBackend.GetWorkflowUrl(*spec)
201-
if err != nil {
202-
slog.Debug("Error fetching workflow URL",
203-
"jobId", job.DiggerJobID,
204-
"attempt", n+1,
205-
"error", err)
206-
} else {
207-
if workflowUrl == "#" || workflowUrl == "" {
208-
slog.Debug("Received blank workflow URL", "jobId", job.DiggerJobID, "attempt", n+1)
209-
} else {
210-
job.WorkflowRunUrl = &workflowUrl
211-
err = models.DB.UpdateDiggerJob(job)
212-
if err != nil {
213-
slog.Error("Failed to update job with workflow URL",
214-
"jobId", job.DiggerJobID,
215-
"url", workflowUrl,
216-
"error", err)
217-
continue
218-
} else {
219-
slog.Info("Successfully updated workflow URL",
220-
"jobId", job.DiggerJobID,
221-
"url", workflowUrl)
222-
}
223-
return
224-
}
225-
}
226-
}
227-
228-
slog.Warn("Failed to obtain workflow URL after multiple attempts", "jobId", job.DiggerJobID)
229-
// if we get to here its highly likely that the workflow job entirely failed to start for some reason
230-
}

libs/backendapi/diggerapi.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,22 @@ func (d DiggerApi) ReportProjectRun(namespace string, projectName string, starte
135135
return nil
136136
}
137137

138+
func isGitHubActions() bool {
139+
return os.Getenv("GITHUB_ACTIONS") == "true"
140+
}
141+
142+
func getWorkflowUrl() string {
143+
if isGitHubActions() {
144+
githubServerURL := os.Getenv("GITHUB_SERVER_URL") // e.g., https://github.com
145+
githubRepository := os.Getenv("GITHUB_REPOSITORY") // e.g., diggerhq/demo-opentofu
146+
githubRunID := os.Getenv("GITHUB_RUN_ID") // numeric run ID
147+
workflowURL := fmt.Sprintf("%s/%s/actions/runs/%s", githubServerURL, githubRepository, githubRunID)
148+
return workflowURL
149+
} else {
150+
return "#"
151+
}
152+
}
153+
138154
func (d DiggerApi) ReportProjectJobStatus(repo string, projectName string, jobId string, status string, timestamp time.Time, summary *iac_utils.IacSummary, planJson string, PrCommentUrl string, PrCommentId string, terraformOutput string, iacUtils iac_utils.IacUtils) (*scheduler.SerializedBatch, error) {
139155
repoNameForBackendReporting := strings.ReplaceAll(repo, "/", "-")
140156
u, err := url.Parse(d.DiggerHost)
@@ -160,6 +176,7 @@ func (d DiggerApi) ReportProjectJobStatus(repo string, projectName string, jobId
160176
}
161177
}
162178

179+
workflowUrl := getWorkflowUrl()
163180
u.Path = filepath.Join(u.Path, "repos", repoNameForBackendReporting, "projects", projectName, "jobs", jobId, "set-status")
164181
request := map[string]interface{}{
165182
"status": status,
@@ -169,6 +186,7 @@ func (d DiggerApi) ReportProjectJobStatus(repo string, projectName string, jobId
169186
"pr_comment_url": PrCommentUrl,
170187
"pr_comment_id": PrCommentId,
171188
"terraform_output": terraformOutput,
189+
"workflow_url": workflowUrl,
172190
}
173191

174192
jsonData, err := json.Marshal(request)

0 commit comments

Comments
 (0)