mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-12 22:10:25 +00:00
feat: allow runners to request a particular job (#11676)
Forgejo Runner can optionally ask for a particular job. Example: `forgejo-runner one-job --handle 9d52c7d8-aebe-426b-b015-dd453aacaada`. This change adds the necessary job filtering to Forgejo. See https://code.forgejo.org/forgejo/forgejo-actions-feature-requests/issues/76 for the motivation and design considerations. PR for the extension of the runner protocol: https://code.forgejo.org/forgejo/actions-proto/pulls/18 Related change in Forgejo Runner with usage example: https://code.forgejo.org/forgejo/runner/pulls/1443 ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests for Go changes (can be removed for JavaScript changes) - I added test coverage for Go changes... - [x] in their respective `*_test.go` for unit tests. - [x] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I ran... - [x] `make pr-go` before pushing ### Tests for JavaScript changes (can be removed for Go changes) - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [x] I did not document these changes and I do not expect someone else to do it. ### Release notes - [x] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change. - [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change. *The decision if the pull request will be shown in the release notes is up to the mergers / release team.* The content of the `release-notes/<pull request number>.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead. <!--start release-notes-assistant--> ## Release notes <!--URL:https://codeberg.org/forgejo/forgejo--> - Features - [PR](https://codeberg.org/forgejo/forgejo/pulls/11676): <!--number 11676 --><!--line 0 --><!--description YWxsb3cgcnVubmVycyB0byByZXF1ZXN0IGEgcGFydGljdWxhciBqb2I=-->allow runners to request a particular job<!--description--> <!--end release-notes-assistant--> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11676 Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org> Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch> Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
This commit is contained in:
parent
30ee20582e
commit
5e1c13f50e
17 changed files with 278 additions and 36 deletions
|
|
@ -191,3 +191,89 @@ jobs:
|
|||
assert.NotEqual(t, task1.Id, task2.Id)
|
||||
})
|
||||
}
|
||||
|
||||
func TestActionFetchTask_RequestedJob(t *testing.T) {
|
||||
if !setting.Database.Type.IsSQLite3() {
|
||||
// mock repo runner only supported on SQLite testing
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
onApplicationRun(t, func(t *testing.T, u *url.URL) {
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
// create the repo
|
||||
repo, _, f := tests.CreateDeclarativeRepo(t, user2, "repo-many-tasks",
|
||||
[]unit_model.Type{unit_model.TypeActions}, nil,
|
||||
[]*files_service.ChangeRepoFile{
|
||||
{
|
||||
Operation: "create",
|
||||
TreePath: ".forgejo/workflows/simple.yml",
|
||||
ContentReader: strings.NewReader(`
|
||||
on:
|
||||
push:
|
||||
jobs:
|
||||
job1:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo OK
|
||||
job2:
|
||||
runs-on: debian
|
||||
steps:
|
||||
- run: echo OK
|
||||
job3:
|
||||
runs-on: debian
|
||||
steps:
|
||||
- run: echo OK
|
||||
`),
|
||||
},
|
||||
},
|
||||
)
|
||||
defer f()
|
||||
|
||||
debianRunner := newMockRunner()
|
||||
debianRunner.registerAsRepoRunner(t, user2.Name, repo.Name, "debian-runner", []string{"debian"})
|
||||
|
||||
ubuntuRunner := newMockRunner()
|
||||
ubuntuRunner.registerAsRepoRunner(t, user2.Name, repo.Name, "ubuntu-runner", []string{"ubuntu-latest"})
|
||||
|
||||
job1 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{RepoID: repo.ID, Name: "job1"})
|
||||
job2 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{RepoID: repo.ID, Name: "job2"})
|
||||
job3 := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{RepoID: repo.ID, Name: "job3"})
|
||||
|
||||
assert.NotEmpty(t, job1.Handle)
|
||||
assert.NotEmpty(t, job2.Handle)
|
||||
assert.NotEmpty(t, job3.Handle)
|
||||
|
||||
nonExistingHandle := "does-not-exist"
|
||||
emptyHandle := ""
|
||||
|
||||
// The runner's labels do not match. Therefore, it does not receive the job despite explicitly asking for it.
|
||||
task := debianRunner.maybeFetchSingleTask(t, &job1.Handle)
|
||||
require.Nil(t, task)
|
||||
|
||||
// If the requested job does not exist or is not ready, the runner does not receive any job.
|
||||
task = ubuntuRunner.maybeFetchSingleTask(t, &nonExistingHandle)
|
||||
require.Nil(t, task)
|
||||
|
||||
ubuntuRunner.lastTasksVersion = 0
|
||||
debianRunner.lastTasksVersion = 0
|
||||
|
||||
// The next job waiting in line for the debian-runner is job2. But because the runner explicitly asks for job3,
|
||||
// it receives job3 instead.
|
||||
task = debianRunner.maybeFetchSingleTask(t, &job3.Handle)
|
||||
require.NotNil(t, task)
|
||||
assert.Contains(t, string(task.GetWorkflowPayload()), "name: job3")
|
||||
|
||||
ubuntuRunner.lastTasksVersion = 0
|
||||
debianRunner.lastTasksVersion = 0
|
||||
|
||||
// Without explicitly asking for a job, the runners receives the next job waiting in line.
|
||||
task = debianRunner.maybeFetchSingleTask(t, nil)
|
||||
require.NotNil(t, task)
|
||||
assert.Contains(t, string(task.GetWorkflowPayload()), "name: job2")
|
||||
|
||||
task = ubuntuRunner.maybeFetchSingleTask(t, &emptyHandle)
|
||||
require.NotNil(t, task)
|
||||
assert.Contains(t, string(task.GetWorkflowPayload()), "name: job1")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,16 @@ func (r *mockRunner) maybeFetchTask(t *testing.T) *runnerv1.Task {
|
|||
return resp.Msg.Task
|
||||
}
|
||||
|
||||
func (r *mockRunner) maybeFetchSingleTask(t *testing.T, handle *string) *runnerv1.Task {
|
||||
resp, err := r.client.runnerServiceClient.FetchSingleTask(t.Context(), connect.NewRequest(&runnerv1.FetchSingleTaskRequest{
|
||||
TasksVersion: r.lastTasksVersion,
|
||||
Handle: handle,
|
||||
}))
|
||||
require.NoError(t, err)
|
||||
r.lastTasksVersion = resp.Msg.TasksVersion
|
||||
return resp.Msg.Task
|
||||
}
|
||||
|
||||
func (r *mockRunner) fetchTask(t *testing.T, timeout ...time.Duration) *runnerv1.Task {
|
||||
fetchTimeout := 10 * time.Second
|
||||
if len(timeout) > 0 {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ func TestAPIAdminActionsGetJobs(t *testing.T) {
|
|||
expected := api.ActionRunJob{
|
||||
ID: 393,
|
||||
Attempt: 1,
|
||||
Handle: "18e9cf40-c2f6-409f-b832-b945ea7dc79b",
|
||||
RepoID: 1,
|
||||
OwnerID: 1,
|
||||
Name: "job_2",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ func TestActionsAPISearchActionJobs_OrgRunner(t *testing.T) {
|
|||
job395 := api.ActionRunJob{
|
||||
ID: 395,
|
||||
Attempt: 1,
|
||||
Handle: "40317a2f-2f00-4a82-8cc4-57347989a493",
|
||||
RepoID: 1,
|
||||
OwnerID: 3,
|
||||
Name: "job_2",
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ func TestActionsAPISearchActionJobs_RepoRunner(t *testing.T) {
|
|||
job393 := api.ActionRunJob{
|
||||
ID: 393,
|
||||
Attempt: 1,
|
||||
Handle: "18e9cf40-c2f6-409f-b832-b945ea7dc79b",
|
||||
RepoID: 1,
|
||||
OwnerID: 1,
|
||||
Name: "job_2",
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ func TestActionsAPISearchActionJobs_UserRunner(t *testing.T) {
|
|||
job394 := api.ActionRunJob{
|
||||
ID: 394,
|
||||
Attempt: 2,
|
||||
Handle: "a723d3e3-49a1-4e6b-947f-e987e60bfbd6",
|
||||
RepoID: 1,
|
||||
OwnerID: 2,
|
||||
Name: "job_2",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue