Skip to content
5 changes: 1 addition & 4 deletions routers/api/actions/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,7 @@ func (s *Service) UpdateTask(
return nil, status.Errorf(codes.Internal, "load run: %v", err)
}

// don't create commit status for cron job
if task.Job.Run.ScheduleID == 0 {
actions_service.CreateCommitStatus(ctx, task.Job)
}
actions_service.CreateCommitStatusForRunJobs(ctx, task.Job.Run, task.Job)

if task.Status.IsDone() {
notify_service.WorkflowJobStatusUpdate(ctx, task.Job.Run.Repo, task.Job.Run.TriggerUser, task.Job, task)
Expand Down
8 changes: 4 additions & 4 deletions routers/web/repo/actions/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob, shou
return err
}

actions_service.CreateCommitStatus(ctx, job)
actions_service.CreateCommitStatusForRunJobs(ctx, job.Run, job)
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)

return nil
Expand Down Expand Up @@ -569,7 +569,7 @@ func Logs(ctx *context_module.Context) {
func Cancel(ctx *context_module.Context) {
runIndex := getRunIndex(ctx)

_, jobs := getRunJobs(ctx, runIndex, -1)
firstJob, jobs := getRunJobs(ctx, runIndex, -1)
if ctx.Written() {
return
}
Expand All @@ -588,7 +588,7 @@ func Cancel(ctx *context_module.Context) {
return
}

actions_service.CreateCommitStatus(ctx, jobs...)
actions_service.CreateCommitStatusForRunJobs(ctx, firstJob.Run, jobs...)
actions_service.EmitJobsIfReadyByJobs(updatedJobs)

for _, job := range updatedJobs {
Expand Down Expand Up @@ -642,7 +642,7 @@ func Approve(ctx *context_module.Context) {
return
}

actions_service.CreateCommitStatus(ctx, jobs...)
actions_service.CreateCommitStatusForRunJobs(ctx, current.Run, jobs...)

if len(updatedJobs) > 0 {
job := updatedJobs[0]
Expand Down
23 changes: 16 additions & 7 deletions services/actions/clear_tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,19 @@ func StopEndlessTasks(ctx context.Context) error {
}

func notifyWorkflowJobStatusUpdate(ctx context.Context, jobs []*actions_model.ActionRunJob) {
if len(jobs) > 0 {
CreateCommitStatus(ctx, jobs...)
for _, job := range jobs {
_ = job.LoadAttributes(ctx)
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
if len(jobs) == 0 {
return
}
for _, job := range jobs {
if err := job.LoadAttributes(ctx); err != nil {
log.Error("Failed to load job attributes: %v", err)
continue
}
job := jobs[0]
CreateCommitStatusForRunJobs(ctx, job.Run, job)
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
}

if job := jobs[0]; job.Run != nil && job.Run.Repo != nil {
notify_service.WorkflowRunStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job.Run)
}
}
Expand Down Expand Up @@ -208,7 +214,10 @@ func CancelAbandonedJobs(ctx context.Context) error {
log.Warn("cancel abandoned job %v: %v", job.ID, err)
// go on
}
CreateCommitStatus(ctx, job)
if job.Run == nil || job.Run.Repo == nil {
continue // error occurs during loading attributes, the following code that depends on "Run.Repo" will fail, so ignore and skip
}
CreateCommitStatusForRunJobs(ctx, job.Run, job)
if updated {
updatedJobs = append(updatedJobs, job)
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
Expand Down
82 changes: 45 additions & 37 deletions services/actions/commit_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,62 @@ import (
"errors"
"fmt"
"path"
"strconv"

actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
actions_module "code.gitea.io/gitea/modules/actions"
"code.gitea.io/gitea/modules/commitstatus"
git "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
webhook_module "code.gitea.io/gitea/modules/webhook"
commitstatus_service "code.gitea.io/gitea/services/repository/commitstatus"

"github.com/nektos/act/pkg/jobparser"
)

// CreateCommitStatus creates a commit status for the given job.
// CreateCommitStatusForRunJobs creates a commit status for the given job if it has a supported event and related commit.
// It won't return an error failed, but will log it, because it's not critical.
func CreateCommitStatus(ctx context.Context, jobs ...*actions_model.ActionRunJob) {
func CreateCommitStatusForRunJobs(ctx context.Context, run *actions_model.ActionRun, jobs ...*actions_model.ActionRunJob) {
// don't create commit status for cron job
if run.ScheduleID != 0 {
return
}

event, commitID, err := getCommitStatusEventNameAndCommitID(run)
if err != nil {
log.Error("GetCommitStatusEventNameAndSHA: %v", err)
}
if event == "" || commitID == "" {
return // unsupported event, or no commit id, or error occurs, do nothing
}

if err = run.LoadAttributes(ctx); err != nil {
log.Error("run.LoadAttributes: %v", err)
return
}

for _, job := range jobs {
if err := createCommitStatus(ctx, job); err != nil {
if err = createCommitStatus(ctx, run.Repo, event, commitID, run, job); err != nil {
log.Error("Failed to create commit status for job %d: %v", job.ID, err)
}
}
}

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
event string
)
func getCommitStatusEventNameAndCommitID(run *actions_model.ActionRun) (event, commitID string, _ error) {
switch run.Event {
case webhook_module.HookEventPush:
event = "push"
payload, err := run.GetPushEventPayload()
if err != nil {
return fmt.Errorf("GetPushEventPayload: %w", err)
return "", "", fmt.Errorf("GetPushEventPayload: %w", err)
}
if payload.HeadCommit == nil {
return errors.New("head commit is missing in event payload")
return "", "", errors.New("head commit is missing in event payload")
}
sha = payload.HeadCommit.ID
commitID = payload.HeadCommit.ID
case // pull_request
webhook_module.HookEventPullRequest,
webhook_module.HookEventPullRequestSync,
Expand All @@ -69,32 +78,33 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
}
payload, err := run.GetPullRequestEventPayload()
if err != nil {
return fmt.Errorf("GetPullRequestEventPayload: %w", err)
return "", "", fmt.Errorf("GetPullRequestEventPayload: %w", err)
}
if payload.PullRequest == nil {
return errors.New("pull request is missing in event payload")
return "", "", errors.New("pull request is missing in event payload")
} else if payload.PullRequest.Head == nil {
return errors.New("head of pull request is missing in event payload")
return "", "", errors.New("head of pull request is missing in event payload")
}
sha = payload.PullRequest.Head.Sha
commitID = payload.PullRequest.Head.Sha
case webhook_module.HookEventRelease:
event = string(run.Event)
sha = run.CommitSHA
default:
return nil
commitID = run.CommitSHA
default: // do nothing, return empty
}
return event, commitID, nil
}

repo := run.Repo
func createCommitStatus(ctx context.Context, repo *repo_model.Repository, event, commitID string, run *actions_model.ActionRun, job *actions_model.ActionRunJob) error {
// TODO: store workflow name as a field in ActionRun to avoid parsing
runName := path.Base(run.WorkflowID)
if wfs, err := jobparser.Parse(job.WorkflowPayload); err == nil && len(wfs) > 0 {
runName = wfs[0].Name
}
ctxname := fmt.Sprintf("%s / %s (%s)", runName, job.Name, event)
ctxName := fmt.Sprintf("%s / %s (%s)", runName, job.Name, event)
state := toCommitStatus(job.Status)
if statuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptionsAll); err == nil {
if statuses, err := git_model.GetLatestCommitStatus(ctx, repo.ID, commitID, db.ListOptionsAll); err == nil {
for _, v := range statuses {
if v.Context == ctxname {
if v.Context == ctxName {
if v.State == state {
// no need to update
return nil
Expand All @@ -106,7 +116,7 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
return fmt.Errorf("GetLatestCommitStatus: %w", err)
}

description := ""
var description string
switch job.Status {
// TODO: if we want support description in different languages, we need to support i18n placeholders in it
case actions_model.StatusSuccess:
Expand All @@ -123,6 +133,8 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
description = "Waiting to run"
case actions_model.StatusBlocked:
description = "Blocked by required conditions"
default:
description = "Unknown status: " + strconv.Itoa(int(job.Status))
}

index, err := getIndexOfJob(ctx, job)
Expand All @@ -131,20 +143,16 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
}

creator := user_model.NewActionsUser()
commitID, err := git.NewIDFromString(sha)
if err != nil {
return fmt.Errorf("HashTypeInterfaceFromHashString: %w", err)
}
status := git_model.CommitStatus{
SHA: sha,
SHA: commitID,
TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), index),
Description: description,
Context: ctxname,
Context: ctxName,
CreatorID: creator.ID,
State: state,
}

return commitstatus_service.CreateCommitStatus(ctx, repo, creator, commitID.String(), &status)
return commitstatus_service.CreateCommitStatus(ctx, repo, creator, commitID, &status)
}

func toCommitStatus(status actions_model.Status) commitstatus.CommitStatusState {
Expand Down
2 changes: 1 addition & 1 deletion services/actions/job_emitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func checkJobsByRunID(ctx context.Context, runID int64) error {
}); err != nil {
return err
}
CreateCommitStatus(ctx, jobs...)
CreateCommitStatusForRunJobs(ctx, run, jobs...)
for _, job := range updatedJobs {
_ = job.LoadAttributes(ctx)
notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
Expand Down
79 changes: 2 additions & 77 deletions services/actions/notifier_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ import (
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"
"code.gitea.io/gitea/services/convert"
notify_service "code.gitea.io/gitea/services/notify"

"github.com/nektos/act/pkg/jobparser"
"github.com/nektos/act/pkg/model"
)

Expand Down Expand Up @@ -346,65 +344,10 @@ func handleWorkflows(

run.NeedApproval = need

if err := run.LoadAttributes(ctx); err != nil {
log.Error("LoadAttributes: %v", err)
if err := PrepareRunAndInsert(ctx, dwf.Content, run, nil); err != nil {
log.Error("PrepareRunAndInsert: %v", err)
continue
}

vars, err := actions_model.GetVariablesOfRun(ctx, run)
if err != nil {
log.Error("GetVariablesOfRun: %v", err)
continue
}

wfRawConcurrency, err := jobparser.ReadWorkflowRawConcurrency(dwf.Content)
if err != nil {
log.Error("ReadWorkflowRawConcurrency: %v", err)
continue
}
if wfRawConcurrency != nil {
err = EvaluateRunConcurrencyFillModel(ctx, run, wfRawConcurrency, vars)
if err != nil {
log.Error("EvaluateRunConcurrencyFillModel: %v", err)
continue
}
}

giteaCtx := GenerateGiteaContext(run, nil)

jobs, err := jobparser.Parse(dwf.Content, jobparser.WithVars(vars), jobparser.WithGitContext(giteaCtx.ToGitHubContext()))
if err != nil {
log.Error("jobparser.Parse: %v", err)
continue
}

if len(jobs) > 0 && jobs[0].RunName != "" {
run.Title = jobs[0].RunName
}

if err := InsertRun(ctx, run, jobs); err != nil {
log.Error("InsertRun: %v", err)
continue
}

alljobs, err := db.Find[actions_model.ActionRunJob](ctx, actions_model.FindRunJobOptions{RunID: run.ID})
if err != nil {
log.Error("FindRunJobs: %v", err)
continue
}
CreateCommitStatus(ctx, alljobs...)
if len(alljobs) > 0 {
job := alljobs[0]
err := job.LoadRun(ctx)
if err != nil {
log.Error("LoadRun: %v", err)
continue
}
notify_service.WorkflowRunStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job.Run)
}
for _, job := range alljobs {
notify_service.WorkflowJobStatusUpdate(ctx, input.Repo, input.Doer, job, nil)
}
}
return nil
}
Expand Down Expand Up @@ -559,24 +502,6 @@ func handleSchedules(
Content: dwf.Content,
}

vars, err := actions_model.GetVariablesOfRun(ctx, run.ToActionRun())
if err != nil {
log.Error("GetVariablesOfRun: %v", err)
continue
}

giteaCtx := GenerateGiteaContext(run.ToActionRun(), nil)

jobs, err := jobparser.Parse(dwf.Content, jobparser.WithVars(vars), jobparser.WithGitContext(giteaCtx.ToGitHubContext()))
if err != nil {
log.Error("jobparser.Parse: %v", err)
continue
}

if len(jobs) > 0 && jobs[0].RunName != "" {
run.Title = jobs[0].RunName
}

crons = append(crons, run)
}

Expand Down
Loading