f55fe989a4
Backport #24023. A commit status is bound to a job, not a run.
142 lines
3.9 KiB
Go
142 lines
3.9 KiB
Go
// Copyright 2023 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package actions
|
|
|
|
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"
|
|
user_model "code.gitea.io/gitea/models/user"
|
|
api "code.gitea.io/gitea/modules/structs"
|
|
webhook_module "code.gitea.io/gitea/modules/webhook"
|
|
)
|
|
|
|
func CreateCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) error {
|
|
if err := job.LoadAttributes(ctx); err != nil {
|
|
return fmt.Errorf("load run: %w", err)
|
|
}
|
|
|
|
run := job.Run
|
|
var (
|
|
sha string
|
|
creatorID int64
|
|
)
|
|
|
|
switch run.Event {
|
|
case webhook_module.HookEventPush:
|
|
payload, err := run.GetPushEventPayload()
|
|
if err != nil {
|
|
return fmt.Errorf("GetPushEventPayload: %w", err)
|
|
}
|
|
|
|
// Since the payload comes from json data, we should check if it's broken, or it will cause panic
|
|
switch {
|
|
case payload.Repo == nil:
|
|
return fmt.Errorf("repo is missing in event payload")
|
|
case payload.Pusher == nil:
|
|
return fmt.Errorf("pusher is missing in event payload")
|
|
case payload.HeadCommit == nil:
|
|
return fmt.Errorf("head commit is missing in event payload")
|
|
}
|
|
|
|
sha = payload.HeadCommit.ID
|
|
creatorID = payload.Pusher.ID
|
|
case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestSync:
|
|
payload, err := run.GetPullRequestEventPayload()
|
|
if err != nil {
|
|
return fmt.Errorf("GetPullRequestEventPayload: %w", err)
|
|
}
|
|
|
|
switch {
|
|
case payload.PullRequest == nil:
|
|
return fmt.Errorf("pull request is missing in event payload")
|
|
case payload.PullRequest.Head == nil:
|
|
return fmt.Errorf("head of pull request is missing in event payload")
|
|
case payload.PullRequest.Head.Repository == nil:
|
|
return fmt.Errorf("head repository of pull request is missing in event payload")
|
|
case payload.PullRequest.Head.Repository.Owner == nil:
|
|
return fmt.Errorf("owner of head repository of pull request is missing in evnt payload")
|
|
}
|
|
|
|
sha = payload.PullRequest.Head.Sha
|
|
creatorID = payload.PullRequest.Head.Repository.Owner.ID
|
|
default:
|
|
return nil
|
|
}
|
|
|
|
repo := run.Repo
|
|
ctxname := job.Name
|
|
state := toCommitStatus(job.Status)
|
|
creator, err := user_model.GetUserByID(ctx, creatorID)
|
|
if err != nil {
|
|
return fmt.Errorf("GetUserByID: %w", err)
|
|
}
|
|
if statuses, _, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{}); err == nil {
|
|
for _, v := range statuses {
|
|
if v.Context == ctxname {
|
|
if v.State == state {
|
|
return nil
|
|
}
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
return fmt.Errorf("GetLatestCommitStatus: %w", err)
|
|
}
|
|
|
|
index, err := getIndexOfJob(ctx, job)
|
|
if err != nil {
|
|
return fmt.Errorf("getIndexOfJob: %w", err)
|
|
}
|
|
|
|
if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
|
|
Repo: repo,
|
|
SHA: sha,
|
|
Creator: creator,
|
|
CommitStatus: &git_model.CommitStatus{
|
|
SHA: sha,
|
|
TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index),
|
|
Description: "",
|
|
Context: ctxname,
|
|
CreatorID: creatorID,
|
|
State: state,
|
|
},
|
|
}); err != nil {
|
|
return fmt.Errorf("NewCommitStatus: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func toCommitStatus(status actions_model.Status) api.CommitStatusState {
|
|
switch status {
|
|
case actions_model.StatusSuccess:
|
|
return api.CommitStatusSuccess
|
|
case actions_model.StatusFailure, actions_model.StatusCancelled, actions_model.StatusSkipped:
|
|
return api.CommitStatusFailure
|
|
case actions_model.StatusWaiting, actions_model.StatusBlocked:
|
|
return api.CommitStatusPending
|
|
case actions_model.StatusRunning:
|
|
return api.CommitStatusRunning
|
|
default:
|
|
return api.CommitStatusError
|
|
}
|
|
}
|
|
|
|
func getIndexOfJob(ctx context.Context, job *actions_model.ActionRunJob) (int, error) {
|
|
// TODO: store job index as a field in ActionRunJob to avoid this
|
|
jobs, err := actions_model.GetRunJobsByRunID(ctx, job.RunID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
for i, v := range jobs {
|
|
if v.ID == job.ID {
|
|
return i, nil
|
|
}
|
|
}
|
|
return 0, nil
|
|
}
|