diff --git a/models/bots/run.go b/models/bots/run.go index 4596ddfc21..bd7fab0ad7 100644 --- a/models/bots/run.go +++ b/models/bots/run.go @@ -6,6 +6,7 @@ package bots import ( "context" + "encoding/json" "fmt" "time" @@ -14,8 +15,9 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/timeutil" - "xorm.io/builder" + api "code.gitea.io/gitea/modules/structs" + "xorm.io/builder" "github.com/nektos/act/pkg/jobparser" "golang.org/x/exp/slices" ) @@ -96,6 +98,17 @@ func (run *Run) TakeTime() time.Duration { return time.Since(started).Truncate(time.Second) } +func (run *Run) GetPushEventPayload() (*api.PushPayload, error) { + if run.Event == webhook.HookEventPush { + var payload api.PushPayload + if err := json.Unmarshal([]byte(run.EventPayload), &payload); err != nil { + return nil, err + } + return &payload, nil + } + return nil, fmt.Errorf("event %s is not a push event", run.Event) +} + func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error { _, err := db.GetEngine(ctx).ID(repo.ID). SetExpr("num_runs", diff --git a/models/bots/run_job.go b/models/bots/run_job.go index afc206e7d0..23f70d68b5 100644 --- a/models/bots/run_job.go +++ b/models/bots/run_job.go @@ -43,12 +43,7 @@ func (RunJob) TableName() string { return "bots_run_job" } -// LoadAttributes load Run if not loaded -func (job *RunJob) LoadAttributes(ctx context.Context) error { - if job == nil { - return nil - } - +func (job *RunJob) LoadRun(ctx context.Context) error { if job.Run == nil { run, err := GetRunByID(ctx, job.RunID) if err != nil { @@ -56,6 +51,18 @@ func (job *RunJob) LoadAttributes(ctx context.Context) error { } job.Run = run } + return nil +} + +// LoadAttributes load Run if not loaded +func (job *RunJob) LoadAttributes(ctx context.Context) error { + if job == nil { + return nil + } + + if err := job.LoadRun(ctx);err != nil { + return err + } return job.Run.LoadAttributes(ctx) } diff --git a/models/bots/task.go b/models/bots/task.go index e0bb5425c9..7cabb4ae2b 100644 --- a/models/bots/task.go +++ b/models/bots/task.go @@ -53,12 +53,7 @@ func (Task) TableName() string { return "bots_task" } -// LoadAttributes load Job Steps if not loaded -func (task *Task) LoadAttributes(ctx context.Context) error { - if task == nil { - return nil - } - +func (task *Task) LoadJob(ctx context.Context) error { if task.Job == nil { job, err := GetRunJobByID(ctx, task.JobID) if err != nil { @@ -66,6 +61,18 @@ func (task *Task) LoadAttributes(ctx context.Context) error { } task.Job = job } + return nil +} + +// LoadAttributes load Job Steps if not loaded +func (task *Task) LoadAttributes(ctx context.Context) error { + if task == nil { + return nil + } + if err := task.LoadJob(ctx); err != nil { + return err + } + if err := task.Job.LoadAttributes(ctx); err != nil { return err } @@ -83,7 +90,6 @@ func (task *Task) LoadAttributes(ctx context.Context) error { // FullSteps returns steps with "Set up job" and "Complete job" func (task *Task) FullSteps() []*TaskStep { - // TODO: The logic here is too complex and tricky, may need to be rewritten var firstStep, lastStep *TaskStep @@ -299,7 +305,7 @@ func UpdateTask(ctx context.Context, task *Task, cols ...string) error { return err } -func UpdateTaskByState(state *runnerv1.TaskState) error { +func UpdateTaskByState(state *runnerv1.TaskState) (*Task, error) { stepStates := map[int64]*runnerv1.StepState{} for _, v := range state.Steps { stepStates[v.Id] = v @@ -307,7 +313,7 @@ func UpdateTaskByState(state *runnerv1.TaskState) error { ctx, commiter, err := db.TxContext() if err != nil { - return err + return nil, err } defer commiter.Close() @@ -315,7 +321,7 @@ func UpdateTaskByState(state *runnerv1.TaskState) error { task := &Task{} if _, err := e.ID(state.Id).Get(task); err != nil { - return err + return nil, err } task.Result = state.Result @@ -327,16 +333,16 @@ func UpdateTaskByState(state *runnerv1.TaskState) error { Status: task.Status, Stopped: task.Stopped, }, nil); err != nil { - return err + return nil, err } } if _, err := e.ID(task.ID).Update(task); err != nil { - return err + return nil, err } if err := task.LoadAttributes(ctx); err != nil { - return err + return nil, err } prevStepDone := true @@ -354,15 +360,15 @@ func UpdateTaskByState(state *runnerv1.TaskState) error { prevStepDone = false } if _, err := e.ID(step.ID).Update(step); err != nil { - return err + return nil, err } } if err := commiter.Commit(); err != nil { - return err + return nil, err } - return nil + return task, nil } func isSubset(set, subset []string) bool { diff --git a/modules/structs/commit_status.go b/modules/structs/commit_status.go index 23e0c383b8..1c0e812382 100644 --- a/modules/structs/commit_status.go +++ b/modules/structs/commit_status.go @@ -19,6 +19,8 @@ const ( CommitStatusFailure CommitStatusState = "failure" // CommitStatusWarning is for when the CommitStatus is Warning CommitStatusWarning CommitStatusState = "warning" + // CommitStatusRunning is for when the CommitStatus is Running + CommitStatusRunning CommitStatusState = "running" ) // NoBetterThan returns true if this State is no better than the given State diff --git a/routers/api/bots/runner/runner.go b/routers/api/bots/runner/runner.go index 2a191503ea..d62660ee44 100644 --- a/routers/api/bots/runner/runner.go +++ b/routers/api/bots/runner/runner.go @@ -11,10 +11,13 @@ import ( "time" bots_model "code.gitea.io/gitea/models/bots" + git_model "code.gitea.io/gitea/models/git" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/bots" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" + api "code.gitea.io/gitea/modules/structs" secret_service "code.gitea.io/gitea/services/secrets" runnerv1 "gitea.com/gitea/proto-go/runner/v1" "gitea.com/gitea/proto-go/runner/v1/runnerv1connect" @@ -141,6 +144,21 @@ func (s *Service) FetchTask( return res, nil } +func toCommitStatus(status bots_model.Status) api.CommitStatusState { + switch status { + case bots_model.StatusSuccess: + return api.CommitStatusSuccess + case bots_model.StatusFailure, bots_model.StatusCancelled, bots_model.StatusSkipped: + return api.CommitStatusFailure + case bots_model.StatusWaiting: + return api.CommitStatusPending + case bots_model.StatusRunning: + return api.CommitStatusRunning + default: + return api.CommitStatusError + } +} + // UpdateTask updates the task status. func (s *Service) UpdateTask( ctx context.Context, @@ -148,10 +166,46 @@ func (s *Service) UpdateTask( ) (*connect.Response[runnerv1.UpdateTaskResponse], error) { res := connect.NewResponse(&runnerv1.UpdateTaskResponse{}) - if err := bots_model.UpdateTaskByState(req.Msg.State); err != nil { + task, err := bots_model.UpdateTaskByState(req.Msg.State) + if err != nil { return nil, status.Errorf(codes.Internal, "update task: %v", err) } + if err := task.LoadJob(ctx); err != nil { + return nil, status.Errorf(codes.Internal, "load job: %v", err) + } + if err := task.Job.LoadAttributes(ctx); err != nil { + return nil, status.Errorf(codes.Internal, "load run: %v", err) + } + + if task.Job.Run.Event == webhook.HookEventPush { + payload, err := task.Job.Run.GetPushEventPayload() + if err != nil { + return nil, status.Errorf(codes.Internal, "GetPushEventPayload: %v", err) + } + + creator, err := user_model.GetUserByID(payload.Pusher.ID) + if err != nil { + return nil, status.Errorf(codes.Internal, "GetUserByID: %v", err) + } + + if err := git_model.NewCommitStatus(git_model.NewCommitStatusOptions{ + Repo: task.Job.Run.Repo, + SHA: payload.HeadCommit.ID, + Creator: creator, + CommitStatus: &git_model.CommitStatus{ + SHA: payload.HeadCommit.ID, + TargetURL: fmt.Sprintf("%s/builds/runs/%d", task.Job.Run.Repo.HTMLURL(), task.Job.Run.ID), + Description: "", + Context: task.Job.Name, + CreatorID: payload.Pusher.ID, + State: toCommitStatus(bots_model.Status(req.Msg.State.Result)), + }, + }); err != nil { + log.Error("Update commit status failed: %v", err) + } + } + return res, nil }