mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-16 00:35:10 +00:00
fix(actions): correctness and hardening fixes (#38518)
Various fixes to actions 1. **Cap total jobs per run in reusable-workflow expansion** — only nesting depth was capped, so fan-out + nested reusable workflows could explode job-row inserts and exhaust the DB from a single push. Now enforces `MaxJobNumPerRun` in the insert path. 2. **Reject rerun-failed when a run has no failed jobs** — an empty job list meant "re-run everything", so `rerun-failed` on a green run re-ran all jobs. Now errors (web + API). 3. **Don't adopt external commit statuses into the legacy hash** — the pre-#35699 Context-only hash matched API-posted statuses too, collapsing two same-named workflows into one check. Now limited to Actions-user rows. 4. **Don't cut post-cancel cleanup short in `StopEndlessTasks`** — the sweep force-stopped just-cancelled jobs mid-cleanup. Now targets `StatusRunning` only; stalled cancels stay covered by `StopZombieTasks`. 5. **Avoid redundant run reload in `GenerateGiteaContext`** — resolving `github.triggering_actor` reloaded the run already passed in. Now loads only the trigger user via new `ActionRunAttempt.LoadTriggerUser`. --------- Co-authored-by: Zettat123 <zettat123@gmail.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
@@ -566,9 +566,6 @@ func ViewPost(ctx *context_module.Context) {
|
||||
}
|
||||
|
||||
func fillViewRunResponseSummary(ctx *context_module.Context, resp *ViewResponse, run *actions_model.ActionRun, attempt *actions_model.ActionRunAttempt, jobs []*actions_model.ActionRunJob) {
|
||||
// Latest when the run has no attempts yet (legacy) or the viewed attempt is the run's latest.
|
||||
isLatestAttempt := run.LatestAttemptID == 0 || (attempt != nil && attempt.ID == run.LatestAttemptID)
|
||||
|
||||
resp.State.Run.RepoID = ctx.Repo.Repository.ID
|
||||
resp.State.Run.Index = run.Index
|
||||
// the title for the "run" is from the commit message
|
||||
@@ -577,8 +574,12 @@ func fillViewRunResponseSummary(ctx *context_module.Context, resp *ViewResponse,
|
||||
resp.State.Run.Link = run.Link()
|
||||
resp.State.Run.ViewLink = getRunViewLink(run, attempt)
|
||||
resp.State.Run.Attempts = make([]*ViewRunAttempt, 0)
|
||||
// Legacy runs (LatestAttemptID == 0) have no attempt; their artifacts and summaries all
|
||||
// share run_attempt_id=0, so passing 0 here scopes to this run's legacy rows only.
|
||||
var runAttemptID int64
|
||||
var effectiveStatus actions_model.Status
|
||||
if attempt != nil {
|
||||
runAttemptID = attempt.ID
|
||||
effectiveStatus = attempt.Status
|
||||
resp.State.Run.RunAttempt = attempt.Attempt
|
||||
resp.State.Run.Duration = attempt.Duration().String()
|
||||
@@ -588,6 +589,9 @@ func fillViewRunResponseSummary(ctx *context_module.Context, resp *ViewResponse,
|
||||
resp.State.Run.Duration = run.Duration().String()
|
||||
resp.State.Run.TriggeredAt = run.Created.AsTime().Unix()
|
||||
}
|
||||
// Latest when the run has no attempts yet (legacy) or the viewed attempt is the run's latest.
|
||||
isLatestAttempt := run.LatestAttemptID == 0 || runAttemptID == run.LatestAttemptID
|
||||
|
||||
resp.State.Run.Status = effectiveStatus.String()
|
||||
resp.State.Run.Done = effectiveStatus.IsDone()
|
||||
|
||||
@@ -647,7 +651,7 @@ func fillViewRunResponseSummary(ctx *context_module.Context, resp *ViewResponse,
|
||||
Status: runAttempt.Status.String(),
|
||||
Done: runAttempt.Status.IsDone(),
|
||||
Link: getRunViewLink(run, runAttempt),
|
||||
Current: runAttempt.ID == attempt.ID,
|
||||
Current: runAttempt.ID == runAttemptID,
|
||||
Latest: runAttempt.ID == run.LatestAttemptID,
|
||||
TriggeredAt: runAttempt.Created.AsTime().Unix(),
|
||||
TriggerUserName: runAttempt.TriggerUser.GetDisplayName(),
|
||||
@@ -672,13 +676,6 @@ func fillViewRunResponseSummary(ctx *context_module.Context, resp *ViewResponse,
|
||||
resp.State.Run.PullRequest = refInfo.PullRequest
|
||||
resp.State.Run.TriggerEvent = run.TriggerEvent
|
||||
|
||||
// Legacy runs (LatestAttemptID == 0) have no attempt; their artifacts and summaries all
|
||||
// share run_attempt_id=0, so passing 0 here scopes to this run's legacy rows only.
|
||||
var runAttemptID int64
|
||||
if attempt != nil {
|
||||
runAttemptID = attempt.ID
|
||||
}
|
||||
|
||||
// Each step's markdown is rendered independently so an unclosed construct
|
||||
// in one step can't bleed into the next.
|
||||
// On a single-job view only that job's summaries are needed; the run view shows all.
|
||||
@@ -1006,7 +1003,15 @@ func RerunFailed(ctx *context_module.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := actions_service.RerunWorkflowRunJobs(ctx, ctx.Repo.Repository, run, ctx.Doer, actions_service.GetFailedJobsForRerun(jobs)); err != nil {
|
||||
// An empty job list means "re-run the whole run" to RerunWorkflowRunJobs, which is right for the plain
|
||||
// rerun button but wrong here, so a direct POST on a fully successful run cannot re-run everything.
|
||||
failedJobs := actions_service.GetFailedJobsForRerun(jobs)
|
||||
if len(failedJobs) == 0 {
|
||||
ctx.JSONError(ctx.Locale.Tr("actions.runs.no_failed_jobs"))
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := actions_service.RerunWorkflowRunJobs(ctx, ctx.Repo.Repository, run, ctx.Doer, failedJobs); err != nil {
|
||||
handleWorkflowRerunError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user