Batch-load related data in actions run, job, and task API endpoints (#37032)
Avoid per-item DB queries in ListRuns, ListJobs, and ListActionTasks by batch-loading trigger users, repositories, and task attributes before the conversion loop. Remove ReferencesGitRepo from the /actions route group since no task/run endpoints use it. Added tests for these endpoints as well. --------- Signed-off-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Claude (Opus 4.7) <noreply@anthropic.com>
This commit is contained in:
@@ -815,7 +815,8 @@ func (n *actionsNotifier) WorkflowRunStatusUpdate(ctx context.Context, repo *rep
|
||||
log.Error("GetActionWorkflow: %v", err)
|
||||
return
|
||||
}
|
||||
convertedRun, err := convert.ToActionWorkflowRun(ctx, repo, run, nil)
|
||||
run.Repo = repo
|
||||
convertedRun, err := convert.ToActionWorkflowRun(ctx, run, nil)
|
||||
if err != nil {
|
||||
log.Error("ToActionWorkflowRun: %v", err)
|
||||
return
|
||||
|
||||
@@ -115,12 +115,12 @@ func TestToActionWorkflowRun_UsesTriggerEvent(t *testing.T) {
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 803})
|
||||
|
||||
run.Repo = repo
|
||||
// Scheduled runs keep Event as the registration event (push) and use TriggerEvent as the real trigger.
|
||||
run.Event = "push"
|
||||
run.TriggerEvent = "schedule"
|
||||
|
||||
apiRun, err := ToActionWorkflowRun(t.Context(), repo, run, nil)
|
||||
apiRun, err := ToActionWorkflowRun(t.Context(), run, nil)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "schedule", apiRun.Event)
|
||||
}
|
||||
|
||||
+26
-19
@@ -29,6 +29,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/actions"
|
||||
"code.gitea.io/gitea/modules/container"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
@@ -222,14 +223,18 @@ func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag {
|
||||
}
|
||||
}
|
||||
|
||||
// ToActionTask convert a actions_model.ActionTask to an api.ActionTask
|
||||
// ToActionTask convert an actions_model.ActionTask to an api.ActionTask
|
||||
func ToActionTask(ctx context.Context, t *actions_model.ActionTask) (*api.ActionTask, error) {
|
||||
if err := t.LoadAttributes(ctx); err != nil {
|
||||
// don't need Steps here, only need to load job and its run
|
||||
if err := t.LoadJob(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.Job.LoadRun(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := t.Job.Run.LoadRepo(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
url := strings.TrimSuffix(setting.AppURL, "/") + t.GetRunLink()
|
||||
|
||||
return &api.ActionTask{
|
||||
ID: t.ID,
|
||||
Name: t.Job.Name,
|
||||
@@ -240,23 +245,25 @@ func ToActionTask(ctx context.Context, t *actions_model.ActionTask) (*api.Action
|
||||
DisplayTitle: t.Job.Run.Title,
|
||||
Status: t.Status.String(),
|
||||
WorkflowID: t.Job.Run.WorkflowID,
|
||||
URL: url,
|
||||
URL: httplib.MakeAbsoluteURL(ctx, t.Job.Run.Link()),
|
||||
CreatedAt: t.Created.AsLocalTime(),
|
||||
UpdatedAt: t.Updated.AsLocalTime(),
|
||||
RunStartedAt: t.Started.AsLocalTime(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ToActionWorkflowRun(ctx context.Context, repo *repo_model.Repository, run *actions_model.ActionRun, attempt *actions_model.ActionRunAttempt) (*api.ActionWorkflowRun, error) {
|
||||
if err := run.LoadAttributes(ctx); err != nil {
|
||||
func ToActionWorkflowRun(ctx context.Context, run *actions_model.ActionRun, attempt *actions_model.ActionRunAttempt) (_ *api.ActionWorkflowRun, err error) {
|
||||
if err := run.LoadRepo(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := run.LoadTriggerUser(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if attempt == nil {
|
||||
if latestAttempt, has, err := run.GetLatestAttempt(ctx); err != nil {
|
||||
attempt, _, err = run.GetLatestAttempt(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if has {
|
||||
attempt = latestAttempt
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +279,7 @@ func ToActionWorkflowRun(ctx context.Context, repo *repo_model.Repository, run *
|
||||
var previousAttemptURL *string
|
||||
|
||||
if attempt != nil {
|
||||
attempt.Run = run
|
||||
if err := attempt.LoadAttributes(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -281,16 +289,15 @@ func ToActionWorkflowRun(ctx context.Context, repo *repo_model.Repository, run *
|
||||
completedAt = attempt.Stopped.AsLocalTime()
|
||||
triggerUser = attempt.TriggerUser
|
||||
if attempt.Attempt > 1 {
|
||||
url := fmt.Sprintf("%s/actions/runs/%d/attempts/%d", repo.APIURL(), run.ID, attempt.Attempt-1)
|
||||
previousAttemptURL = &url
|
||||
previousAttemptURL = new(fmt.Sprintf("%s/actions/runs/%d/attempts/%d", run.Repo.APIURL(ctx), run.ID, attempt.Attempt-1))
|
||||
}
|
||||
}
|
||||
|
||||
return &api.ActionWorkflowRun{
|
||||
ID: run.ID,
|
||||
URL: fmt.Sprintf("%s/actions/runs/%d", repo.APIURL(), run.ID),
|
||||
URL: fmt.Sprintf("%s/actions/runs/%d", run.Repo.APIURL(ctx), run.ID),
|
||||
PreviousAttemptURL: previousAttemptURL,
|
||||
HTMLURL: run.HTMLURL(),
|
||||
HTMLURL: run.HTMLURL(ctx),
|
||||
RunNumber: run.Index,
|
||||
RunAttempt: runAttempt,
|
||||
StartedAt: startedAt,
|
||||
@@ -302,7 +309,7 @@ func ToActionWorkflowRun(ctx context.Context, repo *repo_model.Repository, run *
|
||||
Status: status,
|
||||
Conclusion: conclusion,
|
||||
Path: fmt.Sprintf("%s@%s", run.WorkflowID, run.Ref),
|
||||
Repository: ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeNone}),
|
||||
Repository: ToRepo(ctx, run.Repo, access_model.Permission{AccessMode: perm.AccessModeNone}),
|
||||
TriggerActor: ToUser(ctx, triggerUser, nil),
|
||||
Actor: ToUser(ctx, actor, nil),
|
||||
}, nil
|
||||
@@ -400,11 +407,11 @@ func ToActionWorkflowJob(ctx context.Context, repo *repo_model.Repository, task
|
||||
return &api.ActionWorkflowJob{
|
||||
ID: job.ID,
|
||||
// missing api endpoint for this location
|
||||
URL: fmt.Sprintf("%s/actions/jobs/%d", repo.APIURL(), job.ID),
|
||||
HTMLURL: fmt.Sprintf("%s/jobs/%d", job.Run.HTMLURL(), job.ID),
|
||||
URL: fmt.Sprintf("%s/actions/jobs/%d", repo.APIURL(ctx), job.ID),
|
||||
HTMLURL: fmt.Sprintf("%s/jobs/%d", job.Run.HTMLURL(ctx), job.ID),
|
||||
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),
|
||||
RunURL: fmt.Sprintf("%s/actions/runs/%d", repo.APIURL(ctx), job.RunID),
|
||||
Name: job.Name,
|
||||
Labels: job.RunsOn,
|
||||
RunAttempt: job.Attempt,
|
||||
|
||||
@@ -1043,7 +1043,8 @@ func (*webhookNotifier) WorkflowRunStatusUpdate(ctx context.Context, repo *repo_
|
||||
return
|
||||
}
|
||||
|
||||
convertedRun, err := convert.ToActionWorkflowRun(ctx, repo, run, nil)
|
||||
run.Repo = repo
|
||||
convertedRun, err := convert.ToActionWorkflowRun(ctx, run, nil)
|
||||
if err != nil {
|
||||
log.Error("ToActionWorkflowRun: %v", err)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user