mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-26 23:56:37 +09:00
3875db1974
Adds a read-only Actions job queue: running jobs first, then waiting jobs in the order a runner picks them up. It is shown instance-wide in the admin Actions section with owner, repository and status filters, and per repository in the Actions tab. Both lists refresh in place. Pending work is currently only visible per repository and newest-first, so nothing shows what is queued, in which order, or what occupies the runners. Reordering the queue will be proposed separately. A migration adds indexes for the runner pickup query and repository-scoped status lookups. * Fix #34198 <img width="1345" height="451" alt="image" src="https://github.com/user-attachments/assets/7d52ff76-81b4-44e8-b583-d7d89c9dffcd" /> <img width="1809" height="1134" alt="image" src="https://github.com/user-attachments/assets/4d56c0cb-bae7-4ce2-8f3c-75163b2bc7f4" /> --------- Co-authored-by: Zettat123 <zettat123@gmail.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
113 lines
3.2 KiB
Go
113 lines
3.2 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package actions
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"gitea.dev/models/db"
|
|
"gitea.dev/models/unittest"
|
|
"gitea.dev/modules/timeutil"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestActionJobList_SortMatrixGroupsByName(t *testing.T) {
|
|
mk := func(jobID, name string) *ActionRunJob {
|
|
return &ActionRunJob{JobID: jobID, Name: name}
|
|
}
|
|
names := func(jobs ActionJobList) []string {
|
|
out := make([]string, len(jobs))
|
|
for i, j := range jobs {
|
|
out[i] = j.Name
|
|
}
|
|
return out
|
|
}
|
|
|
|
t.Run("matrix group sorted naturally", func(t *testing.T) {
|
|
jobs := ActionJobList{
|
|
mk("build", "build"),
|
|
mk("test", "test (10)"),
|
|
mk("test", "test (2)"),
|
|
mk("test", "test (1)"),
|
|
mk("deploy", "deploy"),
|
|
}
|
|
jobs.SortMatrixGroupsByName()
|
|
assert.Equal(t, []string{"build", "test (1)", "test (2)", "test (10)", "deploy"}, names(jobs))
|
|
})
|
|
|
|
t.Run("non-adjacent same JobID stays in input order", func(t *testing.T) {
|
|
jobs := ActionJobList{
|
|
mk("test", "test (10)"),
|
|
mk("build", "build"),
|
|
mk("test", "test (1)"),
|
|
}
|
|
jobs.SortMatrixGroupsByName()
|
|
assert.Equal(t, []string{"test (10)", "build", "test (1)"}, names(jobs))
|
|
})
|
|
|
|
t.Run("groups stay in input order", func(t *testing.T) {
|
|
jobs := ActionJobList{
|
|
mk("z", "z"),
|
|
mk("a", "a"),
|
|
}
|
|
jobs.SortMatrixGroupsByName()
|
|
assert.Equal(t, []string{"z", "a"}, names(jobs))
|
|
})
|
|
|
|
t.Run("empty and singleton", func(t *testing.T) {
|
|
ActionJobList(nil).SortMatrixGroupsByName()
|
|
jobs := ActionJobList{mk("only", "only")}
|
|
jobs.SortMatrixGroupsByName()
|
|
assert.Equal(t, []string{"only"}, names(jobs))
|
|
})
|
|
}
|
|
|
|
func TestFindJobQueueJobs(t *testing.T) {
|
|
require.NoError(t, unittest.PrepareTestDatabase())
|
|
ctx := t.Context()
|
|
const repoID int64 = 987654
|
|
|
|
insert := func(status Status, taskID int64, reusable bool, updated timeutil.TimeStamp) int64 {
|
|
job := &ActionRunJob{RepoID: repoID, Status: status, TaskID: taskID, IsReusableCaller: reusable, Updated: updated}
|
|
_, err := db.GetEngine(ctx).NoAutoTime().Insert(job)
|
|
require.NoError(t, err)
|
|
return job.ID
|
|
}
|
|
queuedA := insert(StatusWaiting, 0, false, 200)
|
|
queuedB := insert(StatusWaiting, 0, false, 300)
|
|
queuedC := insert(StatusWaiting, 0, false, 100)
|
|
running := insert(StatusRunning, 998, false, 0)
|
|
cancelling := insert(StatusCancelling, 999, false, 0)
|
|
insert(StatusWaiting, 999, false, 0)
|
|
insert(StatusWaiting, 0, true, 0)
|
|
|
|
find := func(status Status, page, pageSize int) (ids []int64, total int64) {
|
|
jobs, total, err := FindJobQueueJobs(ctx, JobQueueOptions{RepoID: repoID, Status: status}, page, pageSize)
|
|
require.NoError(t, err)
|
|
for _, job := range jobs {
|
|
ids = append(ids, job.ID)
|
|
}
|
|
return ids, total
|
|
}
|
|
|
|
ids, total := find(StatusUnknown, 1, 10)
|
|
assert.EqualValues(t, 5, total)
|
|
assert.Equal(t, []int64{running, cancelling, queuedC, queuedA, queuedB}, ids)
|
|
|
|
ids, _ = find(StatusWaiting, 1, 10)
|
|
assert.Equal(t, []int64{queuedC, queuedA, queuedB}, ids)
|
|
|
|
ids, _ = find(StatusRunning, 1, 10)
|
|
assert.Equal(t, []int64{running, cancelling}, ids)
|
|
|
|
ids, _ = find(StatusUnknown, 99, 3)
|
|
assert.Equal(t, []int64{queuedA, queuedB}, ids)
|
|
|
|
repoIDs, err := JobQueueFilterRepoIDs(ctx, 1000)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, repoIDs, repoID)
|
|
}
|