mirror of
https://github.com/go-gitea/gitea
synced 2025-07-15 15:07:20 +00:00
Add workflow_run api + webhook (#33964)
Implements - https://docs.github.com/en/rest/actions/workflow-jobs?apiVersion=2022-11-28#list-jobs-for-a-workflow-run--code-samples - https://docs.github.com/en/rest/actions/workflow-jobs?apiVersion=2022-11-28#get-a-job-for-a-workflow-run--code-samples - https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#list-workflow-runs-for-a-repository - https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#get-a-workflow-run - `/actions/runs` for global + user + org (Gitea only) - `/actions/jobs` for global + user + org + repository (Gitea only) - workflow_run webhook + action trigger - limitations - workflow id is assigned to a string, this may result into problems in strongly typed clients Fixes - workflow_job webhook url to no longer contain the `runs/<run>` part to align with api - workflow instance does now use it's name inside the file instead of filename if set Refactoring - Moved a lot of logic from workflows/workflow_job into a shared module used by both webhook and api TODO - [x] Verify Keda Compatibility - [x] Edit Webhook API bug is resolved Closes https://github.com/go-gitea/gitea/issues/23670 Closes https://github.com/go-gitea/gitea/issues/23796 Closes https://github.com/go-gitea/gitea/issues/24898 Replaces https://github.com/go-gitea/gitea/pull/28047 and is much more complete --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@ -5,10 +5,8 @@ package webhook
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
@ -18,6 +16,7 @@ import (
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
@ -956,72 +955,17 @@ func (*webhookNotifier) WorkflowJobStatusUpdate(ctx context.Context, repo *repo_
|
||||
org = convert.ToOrganization(ctx, organization.OrgFromUser(repo.Owner))
|
||||
}
|
||||
|
||||
err := job.LoadAttributes(ctx)
|
||||
status, _ := convert.ToActionsStatus(job.Status)
|
||||
|
||||
convertedJob, err := convert.ToActionWorkflowJob(ctx, repo, task, job)
|
||||
if err != nil {
|
||||
log.Error("Error loading job attributes: %v", err)
|
||||
log.Error("ToActionWorkflowJob: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
jobIndex := 0
|
||||
jobs, err := actions_model.GetRunJobsByRunID(ctx, job.RunID)
|
||||
if err != nil {
|
||||
log.Error("Error loading getting run jobs: %v", err)
|
||||
return
|
||||
}
|
||||
for i, j := range jobs {
|
||||
if j.ID == job.ID {
|
||||
jobIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
status, conclusion := toActionStatus(job.Status)
|
||||
var runnerID int64
|
||||
var runnerName string
|
||||
var steps []*api.ActionWorkflowStep
|
||||
|
||||
if task != nil {
|
||||
runnerID = task.RunnerID
|
||||
if runner, ok, _ := db.GetByID[actions_model.ActionRunner](ctx, runnerID); ok {
|
||||
runnerName = runner.Name
|
||||
}
|
||||
for i, step := range task.Steps {
|
||||
stepStatus, stepConclusion := toActionStatus(job.Status)
|
||||
steps = append(steps, &api.ActionWorkflowStep{
|
||||
Name: step.Name,
|
||||
Number: int64(i),
|
||||
Status: stepStatus,
|
||||
Conclusion: stepConclusion,
|
||||
StartedAt: step.Started.AsTime().UTC(),
|
||||
CompletedAt: step.Stopped.AsTime().UTC(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if err := PrepareWebhooks(ctx, source, webhook_module.HookEventWorkflowJob, &api.WorkflowJobPayload{
|
||||
Action: status,
|
||||
WorkflowJob: &api.ActionWorkflowJob{
|
||||
ID: job.ID,
|
||||
// missing api endpoint for this location
|
||||
URL: fmt.Sprintf("%s/actions/runs/%d/jobs/%d", repo.APIURL(), job.RunID, job.ID),
|
||||
HTMLURL: fmt.Sprintf("%s/jobs/%d", job.Run.HTMLURL(), jobIndex),
|
||||
RunID: job.RunID,
|
||||
// Missing api endpoint for this location, artifacts are available under a nested url
|
||||
RunURL: fmt.Sprintf("%s/actions/runs/%d", repo.APIURL(), job.RunID),
|
||||
Name: job.Name,
|
||||
Labels: job.RunsOn,
|
||||
RunAttempt: job.Attempt,
|
||||
HeadSha: job.Run.CommitSHA,
|
||||
HeadBranch: git.RefName(job.Run.Ref).BranchName(),
|
||||
Status: status,
|
||||
Conclusion: conclusion,
|
||||
RunnerID: runnerID,
|
||||
RunnerName: runnerName,
|
||||
Steps: steps,
|
||||
CreatedAt: job.Created.AsTime().UTC(),
|
||||
StartedAt: job.Started.AsTime().UTC(),
|
||||
CompletedAt: job.Stopped.AsTime().UTC(),
|
||||
},
|
||||
Action: status,
|
||||
WorkflowJob: convertedJob,
|
||||
Organization: org,
|
||||
Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}),
|
||||
Sender: convert.ToUser(ctx, sender, nil),
|
||||
@ -1030,28 +974,46 @@ func (*webhookNotifier) WorkflowJobStatusUpdate(ctx context.Context, repo *repo_
|
||||
}
|
||||
}
|
||||
|
||||
func toActionStatus(status actions_model.Status) (string, string) {
|
||||
var action string
|
||||
var conclusion string
|
||||
switch status {
|
||||
// This is a naming conflict of the webhook between Gitea and GitHub Actions
|
||||
case actions_model.StatusWaiting:
|
||||
action = "queued"
|
||||
case actions_model.StatusBlocked:
|
||||
action = "waiting"
|
||||
case actions_model.StatusRunning:
|
||||
action = "in_progress"
|
||||
func (*webhookNotifier) WorkflowRunStatusUpdate(ctx context.Context, repo *repo_model.Repository, sender *user_model.User, run *actions_model.ActionRun) {
|
||||
source := EventSource{
|
||||
Repository: repo,
|
||||
Owner: repo.Owner,
|
||||
}
|
||||
if status.IsDone() {
|
||||
action = "completed"
|
||||
switch status {
|
||||
case actions_model.StatusSuccess:
|
||||
conclusion = "success"
|
||||
case actions_model.StatusCancelled:
|
||||
conclusion = "cancelled"
|
||||
case actions_model.StatusFailure:
|
||||
conclusion = "failure"
|
||||
}
|
||||
|
||||
var org *api.Organization
|
||||
if repo.Owner.IsOrganization() {
|
||||
org = convert.ToOrganization(ctx, organization.OrgFromUser(repo.Owner))
|
||||
}
|
||||
|
||||
status := convert.ToWorkflowRunAction(run.Status)
|
||||
|
||||
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
|
||||
if err != nil {
|
||||
log.Error("OpenRepository: %v", err)
|
||||
return
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
convertedWorkflow, err := convert.GetActionWorkflow(ctx, gitRepo, repo, run.WorkflowID)
|
||||
if err != nil {
|
||||
log.Error("GetActionWorkflow: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
convertedRun, err := convert.ToActionWorkflowRun(ctx, repo, run)
|
||||
if err != nil {
|
||||
log.Error("ToActionWorkflowRun: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := PrepareWebhooks(ctx, source, webhook_module.HookEventWorkflowRun, &api.WorkflowRunPayload{
|
||||
Action: status,
|
||||
Workflow: convertedWorkflow,
|
||||
WorkflowRun: convertedRun,
|
||||
Organization: org,
|
||||
Repo: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}),
|
||||
Sender: convert.ToUser(ctx, sender, nil),
|
||||
}); err != nil {
|
||||
log.Error("PrepareWebhooks: %v", err)
|
||||
}
|
||||
return action, conclusion
|
||||
}
|
||||
|
Reference in New Issue
Block a user