mirror of https://github.com/go-gitea/gitea.git
Merge c098a04915 into de69e7f16a
commit
fb9b44f46b
|
|
@ -265,6 +265,13 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin
|
||||||
|
|
||||||
func CancelJobs(ctx context.Context, jobs []*ActionRunJob) ([]*ActionRunJob, error) {
|
func CancelJobs(ctx context.Context, jobs []*ActionRunJob) ([]*ActionRunJob, error) {
|
||||||
cancelledJobs := make([]*ActionRunJob, 0, len(jobs))
|
cancelledJobs := make([]*ActionRunJob, 0, len(jobs))
|
||||||
|
|
||||||
|
// List of runIDs that have no cancelled jobs
|
||||||
|
runsToUpdate := map[int64]*ActionRunJob{}
|
||||||
|
for _, job := range jobs {
|
||||||
|
runsToUpdate[job.RunID] = job
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over each job and attempt to cancel it.
|
// Iterate over each job and attempt to cancel it.
|
||||||
for _, job := range jobs {
|
for _, job := range jobs {
|
||||||
// Skip jobs that are already in a terminal state (completed, cancelled, etc.).
|
// Skip jobs that are already in a terminal state (completed, cancelled, etc.).
|
||||||
|
|
@ -304,6 +311,13 @@ func CancelJobs(ctx context.Context, jobs []*ActionRunJob) ([]*ActionRunJob, err
|
||||||
return cancelledJobs, fmt.Errorf("get job: %w", err)
|
return cancelledJobs, fmt.Errorf("get job: %w", err)
|
||||||
}
|
}
|
||||||
cancelledJobs = append(cancelledJobs, updatedJob)
|
cancelledJobs = append(cancelledJobs, updatedJob)
|
||||||
|
delete(runsToUpdate, job.RunID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for runID, job := range runsToUpdate {
|
||||||
|
if err := UpdateRunStatus(ctx, job.RepoID, runID); err != nil {
|
||||||
|
return cancelledJobs, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return nil to indicate successful cancellation of all running and waiting jobs.
|
// Return nil to indicate successful cancellation of all running and waiting jobs.
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,30 @@ func GetRunJobsByRunID(ctx context.Context, runID int64) (ActionJobList, error)
|
||||||
return jobs, nil
|
return jobs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateRunStatus(ctx context.Context, repoID, runID int64) error {
|
||||||
|
// Other goroutines may aggregate the status of the run and update it too.
|
||||||
|
// So we need load the run and its jobs before updating the run.
|
||||||
|
run, err := GetRunByRepoAndID(ctx, repoID, runID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
jobs, err := GetRunJobsByRunID(ctx, runID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
run.Status = AggregateJobStatus(jobs)
|
||||||
|
if run.Started.IsZero() && run.Status.IsRunning() {
|
||||||
|
run.Started = timeutil.TimeStampNow()
|
||||||
|
}
|
||||||
|
if run.Stopped.IsZero() && run.Status.IsDone() {
|
||||||
|
run.Stopped = timeutil.TimeStampNow()
|
||||||
|
}
|
||||||
|
if err := UpdateRun(ctx, run, "status", "started", "stopped"); err != nil {
|
||||||
|
return fmt.Errorf("update run %d: %w", run.ID, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, cols ...string) (int64, error) {
|
func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, cols ...string) (int64, error) {
|
||||||
e := db.GetEngine(ctx)
|
e := db.GetEngine(ctx)
|
||||||
|
|
||||||
|
|
@ -173,27 +197,8 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if err := UpdateRunStatus(ctx, job.RepoID, job.RunID); err != nil {
|
||||||
// Other goroutines may aggregate the status of the run and update it too.
|
return 0, err
|
||||||
// So we need load the run and its jobs before updating the run.
|
|
||||||
run, err := GetRunByRepoAndID(ctx, job.RepoID, job.RunID)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
jobs, err := GetRunJobsByRunID(ctx, job.RunID)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
run.Status = AggregateJobStatus(jobs)
|
|
||||||
if run.Started.IsZero() && run.Status.IsRunning() {
|
|
||||||
run.Started = timeutil.TimeStampNow()
|
|
||||||
}
|
|
||||||
if run.Stopped.IsZero() && run.Status.IsDone() {
|
|
||||||
run.Stopped = timeutil.TimeStampNow()
|
|
||||||
}
|
|
||||||
if err := UpdateRun(ctx, run, "status", "started", "stopped"); err != nil {
|
|
||||||
return 0, fmt.Errorf("update run %d: %w", run.ID, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return affected, nil
|
return affected, nil
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
|
"code.gitea.io/gitea/models/unittest"
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This verifies that cancelling a run without running jobs (stuck in waiting) is updated to cancelled status
|
||||||
|
func TestActionsCancelStuckWaitingRun(t *testing.T) {
|
||||||
|
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||||
|
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
||||||
|
session := loginUser(t, user5.Name)
|
||||||
|
|
||||||
|
// cancel the run by run index
|
||||||
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/actions/runs/%d/cancel", user5.Name, "repo4", 191), map[string]string{
|
||||||
|
"_csrf": GetUserCSRFToken(t, session),
|
||||||
|
})
|
||||||
|
|
||||||
|
session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
// check if the run is cancelled by id
|
||||||
|
run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
|
||||||
|
ID: 805,
|
||||||
|
})
|
||||||
|
assert.Equal(t, actions_model.StatusCancelled, run.Status)
|
||||||
|
})
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue