Skip to content

Commit 651ef66

Browse files
Add workflow_job webhook (go-gitea#33694)
Provide external Integration information about the Queue lossly based on https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=completed#workflow_job Naming conflicts between GitHub & Gitea are here, Blocked => Waiting, Waiting => Queued Rationale Enhancement for ephemeral runners management go-gitea#33570
1 parent f61f301 commit 651ef66

33 files changed

+520
-7
lines changed

models/webhook/webhook_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestWebhook_EventsArray(t *testing.T) {
7373
"pull_request", "pull_request_assign", "pull_request_label", "pull_request_milestone",
7474
"pull_request_comment", "pull_request_review_approved", "pull_request_review_rejected",
7575
"pull_request_review_comment", "pull_request_sync", "pull_request_review_request", "wiki", "repository", "release",
76-
"package", "status",
76+
"package", "status", "workflow_job",
7777
},
7878
(&Webhook{
7979
HookEvent: &webhook_module.HookEvent{SendEverything: true},

modules/structs/hook.go

+15
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,18 @@ type CommitStatusPayload struct {
469469
func (p *CommitStatusPayload) JSONPayload() ([]byte, error) {
470470
return json.MarshalIndent(p, "", " ")
471471
}
472+
473+
// WorkflowJobPayload represents a payload information of workflow job event.
474+
type WorkflowJobPayload struct {
475+
Action string `json:"action"`
476+
WorkflowJob *ActionWorkflowJob `json:"workflow_job"`
477+
PullRequest *PullRequest `json:"pull_request,omitempty"`
478+
Organization *Organization `json:"organization,omitempty"`
479+
Repo *Repository `json:"repository"`
480+
Sender *User `json:"sender"`
481+
}
482+
483+
// JSONPayload implements Payload
484+
func (p *WorkflowJobPayload) JSONPayload() ([]byte, error) {
485+
return json.MarshalIndent(p, "", " ")
486+
}

modules/structs/repo_actions.go

+37
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,40 @@ type ActionArtifactsResponse struct {
9696
Entries []*ActionArtifact `json:"artifacts"`
9797
TotalCount int64 `json:"total_count"`
9898
}
99+
100+
// ActionWorkflowStep represents a step of a WorkflowJob
101+
type ActionWorkflowStep struct {
102+
Name string `json:"name"`
103+
Number int64 `json:"number"`
104+
Status string `json:"status"`
105+
Conclusion string `json:"conclusion,omitempty"`
106+
// swagger:strfmt date-time
107+
StartedAt time.Time `json:"started_at,omitempty"`
108+
// swagger:strfmt date-time
109+
CompletedAt time.Time `json:"completed_at,omitempty"`
110+
}
111+
112+
// ActionWorkflowJob represents a WorkflowJob
113+
type ActionWorkflowJob struct {
114+
ID int64 `json:"id"`
115+
URL string `json:"url"`
116+
HTMLURL string `json:"html_url"`
117+
RunID int64 `json:"run_id"`
118+
RunURL string `json:"run_url"`
119+
Name string `json:"name"`
120+
Labels []string `json:"labels"`
121+
RunAttempt int64 `json:"run_attempt"`
122+
HeadSha string `json:"head_sha"`
123+
HeadBranch string `json:"head_branch,omitempty"`
124+
Status string `json:"status"`
125+
Conclusion string `json:"conclusion,omitempty"`
126+
RunnerID int64 `json:"runner_id,omitempty"`
127+
RunnerName string `json:"runner_name,omitempty"`
128+
Steps []*ActionWorkflowStep `json:"steps"`
129+
// swagger:strfmt date-time
130+
CreatedAt time.Time `json:"created_at"`
131+
// swagger:strfmt date-time
132+
StartedAt time.Time `json:"started_at,omitempty"`
133+
// swagger:strfmt date-time
134+
CompletedAt time.Time `json:"completed_at,omitempty"`
135+
}

modules/webhook/type.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ const (
3737
// FIXME: This event should be a group of pull_request_review_xxx events
3838
HookEventPullRequestReview HookEventType = "pull_request_review"
3939
// Actions event only
40-
HookEventSchedule HookEventType = "schedule"
40+
HookEventSchedule HookEventType = "schedule"
41+
HookEventWorkflowJob HookEventType = "workflow_job"
4142
)
4243

4344
func AllEvents() []HookEventType {
@@ -66,6 +67,7 @@ func AllEvents() []HookEventType {
6667
HookEventRelease,
6768
HookEventPackage,
6869
HookEventStatus,
70+
HookEventWorkflowJob,
6971
}
7072
}
7173

options/locale/locale_en-US.ini

+3
Original file line numberDiff line numberDiff line change
@@ -2380,6 +2380,9 @@ settings.event_pull_request_review_request = Pull Request Review Requested
23802380
settings.event_pull_request_review_request_desc = Pull request review requested or review request removed.
23812381
settings.event_pull_request_approvals = Pull Request Approvals
23822382
settings.event_pull_request_merge = Pull Request Merge
2383+
settings.event_header_workflow = Workflow Events
2384+
settings.event_workflow_job = Workflow Jobs
2385+
settings.event_workflow_job_desc = Gitea Actions Workflow job queued, waiting, in progress, or completed.
23832386
settings.event_package = Package
23842387
settings.event_package_desc = Package created or deleted in a repository.
23852388
settings.branch_filter = Branch filter

routers/api/actions/runner/runner.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"code.gitea.io/gitea/modules/log"
1616
"code.gitea.io/gitea/modules/util"
1717
actions_service "code.gitea.io/gitea/services/actions"
18+
notify_service "code.gitea.io/gitea/services/notify"
1819

1920
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
2021
"code.gitea.io/actions-proto-go/runner/v1/runnerv1connect"
@@ -210,7 +211,7 @@ func (s *Service) UpdateTask(
210211
if err := task.LoadJob(ctx); err != nil {
211212
return nil, status.Errorf(codes.Internal, "load job: %v", err)
212213
}
213-
if err := task.Job.LoadRun(ctx); err != nil {
214+
if err := task.Job.LoadAttributes(ctx); err != nil {
214215
return nil, status.Errorf(codes.Internal, "load run: %v", err)
215216
}
216217

@@ -219,6 +220,10 @@ func (s *Service) UpdateTask(
219220
actions_service.CreateCommitStatus(ctx, task.Job)
220221
}
221222

223+
if task.Status.IsDone() {
224+
notify_service.WorkflowJobStatusUpdate(ctx, task.Job.Run.Repo, task.Job.Run.TriggerUser, task.Job, task)
225+
}
226+
222227
if req.Msg.State.Result != runnerv1.Result_RESULT_UNSPECIFIED {
223228
if err := actions_service.EmitJobsIfReady(task.Job.RunID); err != nil {
224229
log.Error("Emit ready jobs of run %d: %v", task.Job.RunID, err)

routers/api/v1/utils/hook.go

+1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI
207207
webhook_module.HookEventRelease: util.SliceContainsString(form.Events, string(webhook_module.HookEventRelease), true),
208208
webhook_module.HookEventPackage: util.SliceContainsString(form.Events, string(webhook_module.HookEventPackage), true),
209209
webhook_module.HookEventStatus: util.SliceContainsString(form.Events, string(webhook_module.HookEventStatus), true),
210+
webhook_module.HookEventWorkflowJob: util.SliceContainsString(form.Events, string(webhook_module.HookEventWorkflowJob), true),
210211
},
211212
BranchFilter: form.BranchFilter,
212213
},

routers/web/repo/actions/view.go

+25-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"code.gitea.io/gitea/modules/web"
3434
actions_service "code.gitea.io/gitea/services/actions"
3535
context_module "code.gitea.io/gitea/services/context"
36+
notify_service "code.gitea.io/gitea/services/notify"
3637

3738
"github.com/nektos/act/pkg/model"
3839
"xorm.io/builder"
@@ -458,6 +459,9 @@ func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob, shou
458459
}
459460

460461
actions_service.CreateCommitStatus(ctx, job)
462+
_ = job.LoadAttributes(ctx)
463+
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
464+
461465
return nil
462466
}
463467

@@ -518,6 +522,8 @@ func Cancel(ctx *context_module.Context) {
518522
return
519523
}
520524

525+
var updatedjobs []*actions_model.ActionRunJob
526+
521527
if err := db.WithTx(ctx, func(ctx context.Context) error {
522528
for _, job := range jobs {
523529
status := job.Status
@@ -534,6 +540,9 @@ func Cancel(ctx *context_module.Context) {
534540
if n == 0 {
535541
return fmt.Errorf("job has changed, try again")
536542
}
543+
if n > 0 {
544+
updatedjobs = append(updatedjobs, job)
545+
}
537546
continue
538547
}
539548
if err := actions_model.StopTask(ctx, job.TaskID, actions_model.StatusCancelled); err != nil {
@@ -548,6 +557,11 @@ func Cancel(ctx *context_module.Context) {
548557

549558
actions_service.CreateCommitStatus(ctx, jobs...)
550559

560+
for _, job := range updatedjobs {
561+
_ = job.LoadAttributes(ctx)
562+
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
563+
}
564+
551565
ctx.JSON(http.StatusOK, struct{}{})
552566
}
553567

@@ -561,6 +575,8 @@ func Approve(ctx *context_module.Context) {
561575
run := current.Run
562576
doer := ctx.Doer
563577

578+
var updatedjobs []*actions_model.ActionRunJob
579+
564580
if err := db.WithTx(ctx, func(ctx context.Context) error {
565581
run.NeedApproval = false
566582
run.ApprovedBy = doer.ID
@@ -570,10 +586,13 @@ func Approve(ctx *context_module.Context) {
570586
for _, job := range jobs {
571587
if len(job.Needs) == 0 && job.Status.IsBlocked() {
572588
job.Status = actions_model.StatusWaiting
573-
_, err := actions_model.UpdateRunJob(ctx, job, nil, "status")
589+
n, err := actions_model.UpdateRunJob(ctx, job, nil, "status")
574590
if err != nil {
575591
return err
576592
}
593+
if n > 0 {
594+
updatedjobs = append(updatedjobs, job)
595+
}
577596
}
578597
}
579598
return nil
@@ -584,6 +603,11 @@ func Approve(ctx *context_module.Context) {
584603

585604
actions_service.CreateCommitStatus(ctx, jobs...)
586605

606+
for _, job := range updatedjobs {
607+
_ = job.LoadAttributes(ctx)
608+
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
609+
}
610+
587611
ctx.JSON(http.StatusOK, struct{}{})
588612
}
589613

routers/web/repo/setting/webhook.go

+1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ func ParseHookEvent(form forms.WebhookForm) *webhook_module.HookEvent {
185185
webhook_module.HookEventRepository: form.Repository,
186186
webhook_module.HookEventPackage: form.Package,
187187
webhook_module.HookEventStatus: form.Status,
188+
webhook_module.HookEventWorkflowJob: form.WorkflowJob,
188189
},
189190
BranchFilter: form.BranchFilter,
190191
}

services/actions/clear_tasks.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"code.gitea.io/gitea/modules/setting"
1717
"code.gitea.io/gitea/modules/timeutil"
1818
webhook_module "code.gitea.io/gitea/modules/webhook"
19+
notify_service "code.gitea.io/gitea/services/notify"
1920
)
2021

2122
// StopZombieTasks stops the task which have running status, but haven't been updated for a long time
@@ -37,6 +38,10 @@ func StopEndlessTasks(ctx context.Context) error {
3738
func notifyWorkflowJobStatusUpdate(ctx context.Context, jobs []*actions_model.ActionRunJob) {
3839
if len(jobs) > 0 {
3940
CreateCommitStatus(ctx, jobs...)
41+
for _, job := range jobs {
42+
_ = job.LoadAttributes(ctx)
43+
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
44+
}
4045
}
4146
}
4247

@@ -107,14 +112,20 @@ func CancelAbandonedJobs(ctx context.Context) error {
107112
for _, job := range jobs {
108113
job.Status = actions_model.StatusCancelled
109114
job.Stopped = now
115+
updated := false
110116
if err := db.WithTx(ctx, func(ctx context.Context) error {
111-
_, err := actions_model.UpdateRunJob(ctx, job, nil, "status", "stopped")
117+
n, err := actions_model.UpdateRunJob(ctx, job, nil, "status", "stopped")
118+
updated = err == nil && n > 0
112119
return err
113120
}); err != nil {
114121
log.Warn("cancel abandoned job %v: %v", job.ID, err)
115122
// go on
116123
}
117124
CreateCommitStatus(ctx, job)
125+
if updated {
126+
_ = job.LoadAttributes(ctx)
127+
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
128+
}
118129
}
119130

120131
return nil

services/actions/job_emitter.go

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"code.gitea.io/gitea/models/db"
1313
"code.gitea.io/gitea/modules/graceful"
1414
"code.gitea.io/gitea/modules/queue"
15+
notify_service "code.gitea.io/gitea/services/notify"
1516

1617
"github.com/nektos/act/pkg/jobparser"
1718
"xorm.io/builder"
@@ -49,6 +50,7 @@ func checkJobsOfRun(ctx context.Context, runID int64) error {
4950
if err != nil {
5051
return err
5152
}
53+
var updatedjobs []*actions_model.ActionRunJob
5254
if err := db.WithTx(ctx, func(ctx context.Context) error {
5355
idToJobs := make(map[string][]*actions_model.ActionRunJob, len(jobs))
5456
for _, job := range jobs {
@@ -64,13 +66,18 @@ func checkJobsOfRun(ctx context.Context, runID int64) error {
6466
} else if n != 1 {
6567
return fmt.Errorf("no affected for updating blocked job %v", job.ID)
6668
}
69+
updatedjobs = append(updatedjobs, job)
6770
}
6871
}
6972
return nil
7073
}); err != nil {
7174
return err
7275
}
7376
CreateCommitStatus(ctx, jobs...)
77+
for _, job := range updatedjobs {
78+
_ = job.LoadAttributes(ctx)
79+
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
80+
}
7481
return nil
7582
}
7683

services/actions/notifier_helper.go

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
api "code.gitea.io/gitea/modules/structs"
2828
webhook_module "code.gitea.io/gitea/modules/webhook"
2929
"code.gitea.io/gitea/services/convert"
30+
notify_service "code.gitea.io/gitea/services/notify"
3031

3132
"github.com/nektos/act/pkg/jobparser"
3233
"github.com/nektos/act/pkg/model"
@@ -363,6 +364,9 @@ func handleWorkflows(
363364
continue
364365
}
365366
CreateCommitStatus(ctx, alljobs...)
367+
for _, job := range alljobs {
368+
notify_service.WorkflowJobStatusUpdate(ctx, input.Repo, input.Doer, job, nil)
369+
}
366370
}
367371
return nil
368372
}

services/actions/schedule_tasks.go

+12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"code.gitea.io/gitea/modules/log"
1616
"code.gitea.io/gitea/modules/timeutil"
1717
webhook_module "code.gitea.io/gitea/modules/webhook"
18+
notify_service "code.gitea.io/gitea/services/notify"
1819

1920
"github.com/nektos/act/pkg/jobparser"
2021
)
@@ -148,6 +149,17 @@ func CreateScheduleTask(ctx context.Context, cron *actions_model.ActionSchedule)
148149
if err := actions_model.InsertRun(ctx, run, workflows); err != nil {
149150
return err
150151
}
152+
allJobs, err := db.Find[actions_model.ActionRunJob](ctx, actions_model.FindRunJobOptions{RunID: run.ID})
153+
if err != nil {
154+
log.Error("FindRunJobs: %v", err)
155+
}
156+
err = run.LoadAttributes(ctx)
157+
if err != nil {
158+
log.Error("LoadAttributes: %v", err)
159+
}
160+
for _, job := range allJobs {
161+
notify_service.WorkflowJobStatusUpdate(ctx, run.Repo, run.TriggerUser, job, nil)
162+
}
151163

152164
// Return nil if no errors occurred
153165
return nil

services/actions/task.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ import (
1010
actions_model "code.gitea.io/gitea/models/actions"
1111
"code.gitea.io/gitea/models/db"
1212
secret_model "code.gitea.io/gitea/models/secret"
13+
notify_service "code.gitea.io/gitea/services/notify"
1314

1415
runnerv1 "code.gitea.io/actions-proto-go/runner/v1"
1516
"google.golang.org/protobuf/types/known/structpb"
1617
)
1718

1819
func PickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv1.Task, bool, error) {
1920
var (
20-
task *runnerv1.Task
21-
job *actions_model.ActionRunJob
21+
task *runnerv1.Task
22+
job *actions_model.ActionRunJob
23+
actionTask *actions_model.ActionTask
2224
)
2325

2426
if err := db.WithTx(ctx, func(ctx context.Context) error {
@@ -34,6 +36,7 @@ func PickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
3436
return fmt.Errorf("task LoadAttributes: %w", err)
3537
}
3638
job = t.Job
39+
actionTask = t
3740

3841
secrets, err := secret_model.GetSecretsOfTask(ctx, t)
3942
if err != nil {
@@ -74,6 +77,7 @@ func PickTask(ctx context.Context, runner *actions_model.ActionRunner) (*runnerv
7477
}
7578

7679
CreateCommitStatus(ctx, job)
80+
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, actionTask)
7781

7882
return task, true, nil
7983
}

services/actions/workflow.go

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"code.gitea.io/gitea/modules/util"
2626
"code.gitea.io/gitea/services/context"
2727
"code.gitea.io/gitea/services/convert"
28+
notify_service "code.gitea.io/gitea/services/notify"
2829

2930
"github.com/nektos/act/pkg/jobparser"
3031
"github.com/nektos/act/pkg/model"
@@ -276,6 +277,9 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
276277
log.Error("FindRunJobs: %v", err)
277278
}
278279
CreateCommitStatus(ctx, allJobs...)
280+
for _, job := range allJobs {
281+
notify_service.WorkflowJobStatusUpdate(ctx, repo, doer, job, nil)
282+
}
279283

280284
return nil
281285
}

0 commit comments

Comments
 (0)