feat: expose attempt number of ActionRunJob in HTTP API (#11687)

Expose the attempt number of `ActionRunJob` in the HTTP API. It is required to uniquely identify a job run.

Example:

```
$ curl -u andreas --basic http://192.168.178.62:3000/api/v1/repos/andreas/test/actions/runners/jobs
```
```json
[{"id":63,"attempt":2,"repo_id":1,"owner_id":1,"name":"test","needs":null,"runs_on":["debian"],"task_id":0,"status":"waiting"}]
```

## 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...
  - [ ] 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.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11687
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:
Andreas Ahlenstorf 2026-03-17 02:58:34 +01:00 committed by Mathieu Fenniak
parent a32b0da87c
commit 120f97a914
7 changed files with 63 additions and 14 deletions

View file

@ -44,8 +44,19 @@ func TestAPIAdminActionsGetJobs(t *testing.T) {
var jobs []*api.ActionRunJob
DecodeJSON(t, res, &jobs)
assert.Len(t, jobs, 1)
assert.Equal(t, job393.ID, jobs[0].ID)
expected := api.ActionRunJob{
ID: 393,
Attempt: 1,
RepoID: 1,
OwnerID: 1,
Name: "job_2",
Needs: nil,
RunsOn: []string{"ubuntu-latest"},
TaskID: 47,
Status: "waiting",
}
assert.ElementsMatch(t, []*api.ActionRunJob{&expected}, jobs)
})
t.Run("jobs-without-labels", func(t *testing.T) {

View file

@ -27,8 +27,6 @@ func TestActionsAPISearchActionJobs_OrgRunner(t *testing.T) {
session := loginUser(t, "user1")
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization)
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: 395})
req := NewRequest(t, "GET",
fmt.Sprintf("/api/v1/orgs/org3/actions/runners/jobs?labels=%s", "fedora")).
AddTokenAuth(token)
@ -37,8 +35,19 @@ func TestActionsAPISearchActionJobs_OrgRunner(t *testing.T) {
var jobs []*api.ActionRunJob
DecodeJSON(t, res, &jobs)
assert.Len(t, jobs, 1)
assert.Equal(t, job.ID, jobs[0].ID)
job395 := api.ActionRunJob{
ID: 395,
Attempt: 1,
RepoID: 1,
OwnerID: 3,
Name: "job_2",
Needs: nil,
RunsOn: []string{"fedora"},
TaskID: 47,
Status: "waiting",
}
assert.ElementsMatch(t, []*api.ActionRunJob{&job395}, jobs)
}
func TestActionsAPISearchActionJobs_OrgRunnerAllPendingJobsWithoutLabels(t *testing.T) {

View file

@ -36,7 +36,6 @@ func TestActionsAPISearchActionJobs_RepoRunner(t *testing.T) {
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
token := getUserToken(t, user2.LowerName, auth_model.AccessTokenScopeWriteRepository)
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: 393})
req := NewRequestf(
t,
@ -50,8 +49,19 @@ func TestActionsAPISearchActionJobs_RepoRunner(t *testing.T) {
var jobs []*api.ActionRunJob
DecodeJSON(t, res, &jobs)
assert.Len(t, jobs, 1)
assert.Equal(t, job.ID, jobs[0].ID)
job393 := api.ActionRunJob{
ID: 393,
Attempt: 1,
RepoID: 1,
OwnerID: 1,
Name: "job_2",
Needs: nil,
RunsOn: []string{"ubuntu-latest"},
TaskID: 47,
Status: "waiting",
}
assert.ElementsMatch(t, []*api.ActionRunJob{&job393}, jobs)
}
func TestActionsAPISearchActionJobs_RepoRunnerAllPendingJobsWithoutLabels(t *testing.T) {

View file

@ -27,7 +27,6 @@ func TestActionsAPISearchActionJobs_UserRunner(t *testing.T) {
normalUsername := "user2"
session := loginUser(t, normalUsername)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser)
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: 394})
req := NewRequest(t, "GET",
fmt.Sprintf("/api/v1/user/actions/runners/jobs?labels=%s", "debian-latest")).
@ -37,8 +36,19 @@ func TestActionsAPISearchActionJobs_UserRunner(t *testing.T) {
var jobs []*api.ActionRunJob
DecodeJSON(t, res, &jobs)
assert.Len(t, jobs, 1)
assert.Equal(t, job.ID, jobs[0].ID)
job394 := api.ActionRunJob{
ID: 394,
Attempt: 2,
RepoID: 1,
OwnerID: 2,
Name: "job_2",
Needs: nil,
RunsOn: []string{"debian-latest"},
TaskID: 47,
Status: "waiting",
}
assert.ElementsMatch(t, []*api.ActionRunJob{&job394}, jobs)
}
func TestActionsAPISearchActionJobs_UserRunnerAllPendingJobsWithoutLabels(t *testing.T) {