2025-01-14 11:17:42 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
|
|
package actions
|
|
|
|
|
|
|
|
|
|
import (
|
2025-09-04 22:46:22 +02:00
|
|
|
"fmt"
|
2025-01-14 11:17:42 +00:00
|
|
|
"testing"
|
|
|
|
|
|
2025-09-04 22:46:22 +02:00
|
|
|
"forgejo.org/models/db"
|
|
|
|
|
"forgejo.org/models/unittest"
|
fix: prevent jobs with unknown needs from running (#12046)
If Forgejo encounters an Actions workflow with unknown jobs in a needs definition, Forgejo will ignore those and run the job anyway. That is bad. For example, releases could be published without any testing because the name of the testing job was misspelt.
Workflow that demonstrates the problem:
```yaml
on:
push:
workflow_dispatch:
jobs:
build:
runs-on: debian
steps:
- run: |
echo "OK"
test:
runs-on: debian
needs: [does-not-exist]
steps:
- run: |
echo "OK"
```
Now, before a workflow is run, Forgejo will check whether all jobs referenced in `needs` exist. If any of them does not, it raises a pre-execution error which fails the workflow immediately. It also displays an appropriate error to the user, for example:
```
Workflow was not executed due to an error that blocked the execution attempt.
Job with ID test references unknown jobs in `needs`: does-not-exist.
```
Futhermore, workflows with pre-execution errors can no longer be rerun, which was previously possible.
Original issue: https://code.forgejo.org/forgejo/runner/issues/977.
## Checklist
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). 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.
- [ ] 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.
- [ ] 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/12046
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-04-10 15:40:08 +02:00
|
|
|
"forgejo.org/modules/container"
|
fix: set attempt number of action run jobs eagerly (#11750)
A Forgejo Action job should be uniquely identifiable by its `ID` and `Attempt` number. Each time a particular job is (re-)run, its `Attempt` number is incremented while its `ID` remains static. Unfortunately, `Attempt` is not incremented when the (re-)run is triggered, but right when Forgejo Runner requests the job. That makes identifying a particular run much harder, because the attempt number is changed in the midst of an attempt. Furthermore, it requires taking the job's `Status` into account. This is fixed by setting the correct attempt number right when a (re-)run is triggered. That means that the `Attempt` number remains static for the duration of a single attempt.
## 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.
- [ ] 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.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] 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.
- [x] 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/11750
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-03-20 17:23:09 +01:00
|
|
|
"forgejo.org/modules/timeutil"
|
2025-09-04 22:46:22 +02:00
|
|
|
|
2025-12-05 17:17:37 +01:00
|
|
|
"code.forgejo.org/forgejo/runner/v12/act/jobparser"
|
2025-01-14 11:17:42 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2025-09-04 22:46:22 +02:00
|
|
|
"github.com/stretchr/testify/require"
|
2025-01-14 11:17:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestActionRunJob_ItRunsOn(t *testing.T) {
|
|
|
|
|
actionJob := ActionRunJob{RunsOn: []string{"ubuntu"}}
|
|
|
|
|
agentLabels := []string{"ubuntu", "node-20"}
|
|
|
|
|
|
|
|
|
|
assert.True(t, actionJob.ItRunsOn(agentLabels))
|
|
|
|
|
assert.False(t, actionJob.ItRunsOn([]string{}))
|
|
|
|
|
|
|
|
|
|
actionJob.RunsOn = append(actionJob.RunsOn, "node-20")
|
|
|
|
|
|
|
|
|
|
assert.True(t, actionJob.ItRunsOn(agentLabels))
|
|
|
|
|
|
|
|
|
|
agentLabels = []string{"ubuntu"}
|
|
|
|
|
|
|
|
|
|
assert.False(t, actionJob.ItRunsOn(agentLabels))
|
|
|
|
|
|
|
|
|
|
actionJob.RunsOn = []string{}
|
|
|
|
|
|
|
|
|
|
assert.False(t, actionJob.ItRunsOn(agentLabels))
|
|
|
|
|
}
|
2025-09-04 22:46:22 +02:00
|
|
|
|
|
|
|
|
func TestActionRunJob_HTMLURL(t *testing.T) {
|
|
|
|
|
require.NoError(t, unittest.PrepareTestDatabase())
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
id int64
|
|
|
|
|
expected string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
id: 192,
|
|
|
|
|
expected: "https://try.gitea.io/user5/repo4/actions/runs/187/jobs/0/attempt/1",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 393,
|
|
|
|
|
expected: "https://try.gitea.io/user2/repo1/actions/runs/187/jobs/1/attempt/1",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 394,
|
|
|
|
|
expected: "https://try.gitea.io/user2/repo1/actions/runs/187/jobs/2/attempt/2",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(fmt.Sprintf("id=%d", tt.id), func(t *testing.T) {
|
|
|
|
|
var job ActionRunJob
|
|
|
|
|
has, err := db.GetEngine(t.Context()).Where("id=?", tt.id).Get(&job)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.True(t, has, "load ActionRunJob from fixture")
|
|
|
|
|
|
|
|
|
|
err = job.LoadAttributes(t.Context())
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
url, err := job.HTMLURL(t.Context())
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Equal(t, tt.expected, url)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-11 04:39:02 +01:00
|
|
|
|
feat: support reusable workflow expansion when `with` or `strategy.matrix` contains ${{ needs... }} (#10647)
This change allows the `with:` field of a reusable workflow to reference a previous job, such as `with: { some-input: "${{ needs.other-job.outputs.other-output }}" }`. `strategy.matrix` can also reference `${{ needs... }}`.
When a job is parsed and encounters this situation, the outer job of the workflow is marked with a field `incomplete_with` (or `incomplete_matrix`), indicating to Forgejo that it can't be executed as-is and the other jobs in its `needs` list need to be completed first. And then in `job_emitter.go` when one job is completed, it checks if other jobs had a `needs` reference to it and unblocks those jobs -- but if they're marked with `incomplete_with` then they can be sent back through the job parser, with the now-available job outputs, to be expanded into the correct definition of the job.
The core functionality for this already exists to allow `runs-on` and `strategy.matrix` to reference the outputs of other jobs, but it is expanded upon here to include `with` for reusable workflows.
There is one known defect in this implementation, but it has a limited scope -- if this code path is used to expand a nested reusable workflow, then the `${{ input.... }}` context will be incorrect. This will require an update to the jobparser in runner version 12.4.0, and so it is out-of-scope of this PR.
## 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
- I added test coverage for Go changes...
- [x] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- 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)).
- **end-to-end test:** will require the noted "known defect" to be resolved, but tests are authored at https://code.forgejo.org/forgejo/end-to-end/compare/main...mfenniak:expand-reusable-workflows-needs
### 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
- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10647
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
2025-12-31 19:04:35 +01:00
|
|
|
func TestActionRunJob_HasIncompleteMatrix(t *testing.T) {
|
2025-11-29 17:49:04 +01:00
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
job ActionRunJob
|
|
|
|
|
isIncomplete bool
|
2025-12-05 17:17:37 +01:00
|
|
|
needs *jobparser.IncompleteNeeds
|
2025-11-29 17:49:04 +01:00
|
|
|
errContains string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "normal workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow")},
|
|
|
|
|
isIncomplete: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "incomplete_matrix workflow",
|
2025-12-05 17:17:37 +01:00
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow\nincomplete_matrix: true\nincomplete_matrix_needs: { job: abc }")},
|
|
|
|
|
needs: &jobparser.IncompleteNeeds{Job: "abc"},
|
2025-11-29 17:49:04 +01:00
|
|
|
isIncomplete: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "unparseable workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: []\nincomplete_matrix: true")},
|
|
|
|
|
errContains: "failure unmarshaling WorkflowPayload to SingleWorkflow: yaml: unmarshal errors",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
feat: support reusable workflow expansion when `with` or `strategy.matrix` contains ${{ needs... }} (#10647)
This change allows the `with:` field of a reusable workflow to reference a previous job, such as `with: { some-input: "${{ needs.other-job.outputs.other-output }}" }`. `strategy.matrix` can also reference `${{ needs... }}`.
When a job is parsed and encounters this situation, the outer job of the workflow is marked with a field `incomplete_with` (or `incomplete_matrix`), indicating to Forgejo that it can't be executed as-is and the other jobs in its `needs` list need to be completed first. And then in `job_emitter.go` when one job is completed, it checks if other jobs had a `needs` reference to it and unblocks those jobs -- but if they're marked with `incomplete_with` then they can be sent back through the job parser, with the now-available job outputs, to be expanded into the correct definition of the job.
The core functionality for this already exists to allow `runs-on` and `strategy.matrix` to reference the outputs of other jobs, but it is expanded upon here to include `with` for reusable workflows.
There is one known defect in this implementation, but it has a limited scope -- if this code path is used to expand a nested reusable workflow, then the `${{ input.... }}` context will be incorrect. This will require an update to the jobparser in runner version 12.4.0, and so it is out-of-scope of this PR.
## 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
- I added test coverage for Go changes...
- [x] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- 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)).
- **end-to-end test:** will require the noted "known defect" to be resolved, but tests are authored at https://code.forgejo.org/forgejo/end-to-end/compare/main...mfenniak:expand-reusable-workflows-needs
### 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
- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10647
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
2025-12-31 19:04:35 +01:00
|
|
|
isIncomplete, needs, err := tt.job.HasIncompleteMatrix()
|
2025-11-29 17:49:04 +01:00
|
|
|
if tt.errContains != "" {
|
|
|
|
|
assert.ErrorContains(t, err, tt.errContains)
|
|
|
|
|
} else {
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Equal(t, tt.isIncomplete, isIncomplete)
|
2025-12-05 17:17:37 +01:00
|
|
|
assert.Equal(t, tt.needs, needs)
|
2025-11-29 17:49:04 +01:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-05 18:14:43 +01:00
|
|
|
|
feat: support reusable workflow expansion when `with` or `strategy.matrix` contains ${{ needs... }} (#10647)
This change allows the `with:` field of a reusable workflow to reference a previous job, such as `with: { some-input: "${{ needs.other-job.outputs.other-output }}" }`. `strategy.matrix` can also reference `${{ needs... }}`.
When a job is parsed and encounters this situation, the outer job of the workflow is marked with a field `incomplete_with` (or `incomplete_matrix`), indicating to Forgejo that it can't be executed as-is and the other jobs in its `needs` list need to be completed first. And then in `job_emitter.go` when one job is completed, it checks if other jobs had a `needs` reference to it and unblocks those jobs -- but if they're marked with `incomplete_with` then they can be sent back through the job parser, with the now-available job outputs, to be expanded into the correct definition of the job.
The core functionality for this already exists to allow `runs-on` and `strategy.matrix` to reference the outputs of other jobs, but it is expanded upon here to include `with` for reusable workflows.
There is one known defect in this implementation, but it has a limited scope -- if this code path is used to expand a nested reusable workflow, then the `${{ input.... }}` context will be incorrect. This will require an update to the jobparser in runner version 12.4.0, and so it is out-of-scope of this PR.
## 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
- I added test coverage for Go changes...
- [x] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- 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)).
- **end-to-end test:** will require the noted "known defect" to be resolved, but tests are authored at https://code.forgejo.org/forgejo/end-to-end/compare/main...mfenniak:expand-reusable-workflows-needs
### 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
- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10647
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
2025-12-31 19:04:35 +01:00
|
|
|
func TestActionRunJob_HasIncompleteRunsOn(t *testing.T) {
|
2025-12-05 18:14:43 +01:00
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
job ActionRunJob
|
|
|
|
|
isIncomplete bool
|
|
|
|
|
needs *jobparser.IncompleteNeeds
|
|
|
|
|
matrix *jobparser.IncompleteMatrix
|
|
|
|
|
errContains string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "normal workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow")},
|
|
|
|
|
isIncomplete: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "nincomplete_runs_on workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow\nincomplete_runs_on: true\nincomplete_runs_on_needs: { job: abc }")},
|
|
|
|
|
needs: &jobparser.IncompleteNeeds{Job: "abc"},
|
|
|
|
|
isIncomplete: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "nincomplete_runs_on workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow\nincomplete_runs_on: true\nincomplete_runs_on_matrix: { dimension: abc }")},
|
|
|
|
|
matrix: &jobparser.IncompleteMatrix{Dimension: "abc"},
|
|
|
|
|
isIncomplete: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "unparseable workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: []\nincomplete_runs_on: true")},
|
|
|
|
|
errContains: "failure unmarshaling WorkflowPayload to SingleWorkflow: yaml: unmarshal errors",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
feat: support reusable workflow expansion when `with` or `strategy.matrix` contains ${{ needs... }} (#10647)
This change allows the `with:` field of a reusable workflow to reference a previous job, such as `with: { some-input: "${{ needs.other-job.outputs.other-output }}" }`. `strategy.matrix` can also reference `${{ needs... }}`.
When a job is parsed and encounters this situation, the outer job of the workflow is marked with a field `incomplete_with` (or `incomplete_matrix`), indicating to Forgejo that it can't be executed as-is and the other jobs in its `needs` list need to be completed first. And then in `job_emitter.go` when one job is completed, it checks if other jobs had a `needs` reference to it and unblocks those jobs -- but if they're marked with `incomplete_with` then they can be sent back through the job parser, with the now-available job outputs, to be expanded into the correct definition of the job.
The core functionality for this already exists to allow `runs-on` and `strategy.matrix` to reference the outputs of other jobs, but it is expanded upon here to include `with` for reusable workflows.
There is one known defect in this implementation, but it has a limited scope -- if this code path is used to expand a nested reusable workflow, then the `${{ input.... }}` context will be incorrect. This will require an update to the jobparser in runner version 12.4.0, and so it is out-of-scope of this PR.
## 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
- I added test coverage for Go changes...
- [x] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- 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)).
- **end-to-end test:** will require the noted "known defect" to be resolved, but tests are authored at https://code.forgejo.org/forgejo/end-to-end/compare/main...mfenniak:expand-reusable-workflows-needs
### 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
- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10647
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
2025-12-31 19:04:35 +01:00
|
|
|
isIncomplete, needs, matrix, err := tt.job.HasIncompleteRunsOn()
|
2025-12-05 18:14:43 +01:00
|
|
|
if tt.errContains != "" {
|
|
|
|
|
assert.ErrorContains(t, err, tt.errContains)
|
|
|
|
|
} else {
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Equal(t, tt.isIncomplete, isIncomplete)
|
|
|
|
|
assert.Equal(t, tt.needs, needs)
|
|
|
|
|
assert.Equal(t, tt.matrix, matrix)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
feat: expand reusable workflow calls into their inner jobs (#10525)
Previously, Forgejo's behaviour for an Actions reusable workflow was to send the entire job to one specific Forgejo Runner based upon its required `runs-on` label, and that single Runner would then read the workflow file and perform all the jobs inside simultaneously, merging their log output into one output (#9768).
This PR begins an implementation of expanding reusable workflows into their internal jobs.
In this PR, the most basic support is implemented for expanding reusable workflows:
- If a `runs-on` field is provided on the workflow, then the legacy behaviour of sending the reusable workflow to a runner is maintained.
- If the `runs-on` field is omitted, then the job may be expanded, if:
- If the `uses:` is a local path within the repo -- expanded
- If the `uses:` is a path to another repo that is on the same Forgejo server -- expanded
- If the `uses:` is a fully-qualified URL -- not expanded
Because this is an "opt-in" implementation by omitting `runs-on`, and all existing capability is retained, I've **omitted some features** from this PR to make the scope small and manageable for review and testing. These features will be implemented after the initial support is landed:
- Workflow input variables
- Workflow secrets
- Workflow output variables
- "Incomplete" workflows which require multiple passes to evaluate -- any job within a reusable workflow where the `with`, `runs-on`, or `strategy.matrix` fields contain an output from another job with `${{ needs... }}`
Although this implementation has restrictions with missing features, it is intended to fix #9768.
Replaces PR #10448.
## 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
- I added test coverage for Go changes...
- [x] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- 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)).
- end-to-end testing: https://code.forgejo.org/forgejo/end-to-end/pulls/1316
### Documentation
- [x] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- https://codeberg.org/forgejo/docs/pulls/1648
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10525
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
2025-12-24 20:47:21 +01:00
|
|
|
|
|
|
|
|
func TestActionRunJob_IsWorkflowCallOuterJob(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
job ActionRunJob
|
|
|
|
|
isWorkflowCallOuterJob bool
|
|
|
|
|
errContains string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "normal workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow")},
|
|
|
|
|
isWorkflowCallOuterJob: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "workflow_call outer job",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: test\njobs:\n job:\n if: false\n__metadata:\n workflow_call_id: b5a9f46f1f2513d7777fde50b169d323a6519e349cc175484c947ac315a209ed\n")},
|
|
|
|
|
isWorkflowCallOuterJob: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "unparseable workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: []\nincomplete_runs_on: true")},
|
|
|
|
|
errContains: "failure unmarshaling WorkflowPayload to SingleWorkflow: yaml: unmarshal errors",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
isWorkflowCallOuterJob, err := tt.job.IsWorkflowCallOuterJob()
|
|
|
|
|
if tt.errContains != "" {
|
|
|
|
|
assert.ErrorContains(t, err, tt.errContains)
|
|
|
|
|
} else {
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Equal(t, tt.isWorkflowCallOuterJob, isWorkflowCallOuterJob)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-29 15:37:44 +01:00
|
|
|
|
|
|
|
|
func TestActionRunJob_IsWorkflowCallInnerJob(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
job ActionRunJob
|
|
|
|
|
isWorkflowCallInnerJob bool
|
|
|
|
|
errContains string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "normal workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("on: [workflow_dispatch]\nname: workflow")},
|
|
|
|
|
isWorkflowCallInnerJob: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "inner job",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("on:\n workflow_call:\nname: workflow\n__metadata:\n workflow_call_parent: b5a9f46f1f2513d7777fde50b169d323a6519e349cc175484c947ac315a209ed\n")},
|
|
|
|
|
isWorkflowCallInnerJob: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "unparseable workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: []\nincomplete_runs_on: true")},
|
|
|
|
|
errContains: "failure unmarshaling WorkflowPayload to SingleWorkflow: yaml: unmarshal errors",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
isWorkflowCallInnerJob, err := tt.job.IsWorkflowCallInnerJob()
|
|
|
|
|
if tt.errContains != "" {
|
|
|
|
|
assert.ErrorContains(t, err, tt.errContains)
|
|
|
|
|
} else {
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Equal(t, tt.isWorkflowCallInnerJob, isWorkflowCallInnerJob)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
feat: support reusable workflow expansion when `with` or `strategy.matrix` contains ${{ needs... }} (#10647)
This change allows the `with:` field of a reusable workflow to reference a previous job, such as `with: { some-input: "${{ needs.other-job.outputs.other-output }}" }`. `strategy.matrix` can also reference `${{ needs... }}`.
When a job is parsed and encounters this situation, the outer job of the workflow is marked with a field `incomplete_with` (or `incomplete_matrix`), indicating to Forgejo that it can't be executed as-is and the other jobs in its `needs` list need to be completed first. And then in `job_emitter.go` when one job is completed, it checks if other jobs had a `needs` reference to it and unblocks those jobs -- but if they're marked with `incomplete_with` then they can be sent back through the job parser, with the now-available job outputs, to be expanded into the correct definition of the job.
The core functionality for this already exists to allow `runs-on` and `strategy.matrix` to reference the outputs of other jobs, but it is expanded upon here to include `with` for reusable workflows.
There is one known defect in this implementation, but it has a limited scope -- if this code path is used to expand a nested reusable workflow, then the `${{ input.... }}` context will be incorrect. This will require an update to the jobparser in runner version 12.4.0, and so it is out-of-scope of this PR.
## 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
- I added test coverage for Go changes...
- [x] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- 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)).
- **end-to-end test:** will require the noted "known defect" to be resolved, but tests are authored at https://code.forgejo.org/forgejo/end-to-end/compare/main...mfenniak:expand-reusable-workflows-needs
### 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
- [ ] I do not want this change to show in the release notes.
- [x] I want the title to show in the release notes with a link to this pull request.
- [ ] I want the content of the `release-notes/<pull request number>.md` to be be used for the release notes instead of the title.
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10647
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
2025-12-31 19:04:35 +01:00
|
|
|
|
|
|
|
|
func TestActionRunJob_HasIncompleteWith(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
job ActionRunJob
|
|
|
|
|
isIncomplete bool
|
|
|
|
|
needs *jobparser.IncompleteNeeds
|
|
|
|
|
matrix *jobparser.IncompleteMatrix
|
|
|
|
|
errContains string
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "normal workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow")},
|
|
|
|
|
isIncomplete: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "incomplete_with workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow\nincomplete_with: true\nincomplete_with_needs: { job: abc }")},
|
|
|
|
|
needs: &jobparser.IncompleteNeeds{Job: "abc"},
|
|
|
|
|
isIncomplete: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "incomplete_with workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: workflow\nincomplete_with: true\nincomplete_with_matrix: { dimension: abc }")},
|
|
|
|
|
matrix: &jobparser.IncompleteMatrix{Dimension: "abc"},
|
|
|
|
|
isIncomplete: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "unparseable workflow",
|
|
|
|
|
job: ActionRunJob{WorkflowPayload: []byte("name: []\nincomplete_with: true")},
|
|
|
|
|
errContains: "failure unmarshaling WorkflowPayload to SingleWorkflow: yaml: unmarshal errors",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
isIncomplete, needs, matrix, err := tt.job.HasIncompleteWith()
|
|
|
|
|
if tt.errContains != "" {
|
|
|
|
|
assert.ErrorContains(t, err, tt.errContains)
|
|
|
|
|
} else {
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Equal(t, tt.isIncomplete, isIncomplete)
|
|
|
|
|
assert.Equal(t, tt.needs, needs)
|
|
|
|
|
assert.Equal(t, tt.matrix, matrix)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
fix: newly expanded dynamic matrix jobs can become stuck in a 'blocked' state (#11184)
The end-to-end tests are currently failing on v15: https://code.forgejo.org/forgejo/end-to-end/actions/runs/4900/jobs/8/attempt/1#jobstep-4-356 This is a regression from #11164.
The cause of this regression is:
- When the job emitter emits new jobs, it *now* sets their `Needs` field correctly, fixed in #11164.
- If a job has `needs` set to a non-empty array, it will start as status **blocked**: https://codeberg.org/forgejo/forgejo/src/commit/db037fca507178feb2bd05e0bf59df7c7534116d/models/actions/run.go#L369-L370
This got past manual testing and the end-to-end test run in #11164 because it is intermittent. If the runner invokes `UpdateTask` multiple times once the status of the job is settled, then the API will invoke the job emitter multiple times -- a second run would unblock the newly blocked jobs. Podman-based runners do this often due to a long cleanup time, and Docker-based runners (like the end-to-end test) can do it randomly depending on a race condition.
https://codeberg.org/forgejo/forgejo/src/commit/db037fca507178feb2bd05e0bf59df7c7534116d/routers/api/actions/runner/runner.go#L241-L244
The fix for this is to reinvoke the job emitter's logic whenever new jobs are created, so that their new blocked state can be reevaluated to see if it is correct or not. This is treated cautiously by examining if new jobs are present.
## 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
- I added test coverage for Go changes...
- [x] in their respective `*_test.go` for unit tests.
- [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server.
- 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
- [ ] 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.
- [x] 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.
- This will be a fix to an unreleased regression within the milestone, and so won't be user-facing.
*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/11184
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
2026-02-07 14:36:49 +01:00
|
|
|
|
|
|
|
|
func TestRunHasOtherJobs(t *testing.T) {
|
|
|
|
|
require.NoError(t, unittest.PrepareTestDatabase())
|
|
|
|
|
|
|
|
|
|
jobs, err := GetRunJobsByRunID(t.Context(), 791)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.Len(t, jobs, 1)
|
|
|
|
|
|
|
|
|
|
has, err := RunHasOtherJobs(t.Context(), 791, nil)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.True(t, has)
|
|
|
|
|
|
|
|
|
|
has, err = RunHasOtherJobs(t.Context(), 791, []*ActionRunJob{})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.True(t, has)
|
|
|
|
|
|
|
|
|
|
has, err = RunHasOtherJobs(t.Context(), 791, jobs)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.False(t, has)
|
|
|
|
|
}
|
fix: set attempt number of action run jobs eagerly (#11750)
A Forgejo Action job should be uniquely identifiable by its `ID` and `Attempt` number. Each time a particular job is (re-)run, its `Attempt` number is incremented while its `ID` remains static. Unfortunately, `Attempt` is not incremented when the (re-)run is triggered, but right when Forgejo Runner requests the job. That makes identifying a particular run much harder, because the attempt number is changed in the midst of an attempt. Furthermore, it requires taking the job's `Status` into account. This is fixed by setting the correct attempt number right when a (re-)run is triggered. That means that the `Attempt` number remains static for the duration of a single attempt.
## 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.
- [ ] 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.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] 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.
- [x] 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/11750
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-03-20 17:23:09 +01:00
|
|
|
|
|
|
|
|
func TestActionRunJobPrepareNextAttempt(t *testing.T) {
|
2026-03-25 17:27:05 +01:00
|
|
|
lastHandle := "original-handle"
|
|
|
|
|
job := ActionRunJob{ID: 46, Handle: lastHandle}
|
|
|
|
|
|
fix: set attempt number of action run jobs eagerly (#11750)
A Forgejo Action job should be uniquely identifiable by its `ID` and `Attempt` number. Each time a particular job is (re-)run, its `Attempt` number is incremented while its `ID` remains static. Unfortunately, `Attempt` is not incremented when the (re-)run is triggered, but right when Forgejo Runner requests the job. That makes identifying a particular run much harder, because the attempt number is changed in the midst of an attempt. Furthermore, it requires taking the job's `Status` into account. This is fixed by setting the correct attempt number right when a (re-)run is triggered. That means that the `Attempt` number remains static for the duration of a single attempt.
## 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.
- [ ] 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.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] 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.
- [x] 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/11750
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-03-20 17:23:09 +01:00
|
|
|
err := job.PrepareNextAttempt(StatusWaiting)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
2026-03-25 17:27:05 +01:00
|
|
|
assert.NotEqual(t, lastHandle, job.Handle)
|
|
|
|
|
assert.NotEmpty(t, job.Handle)
|
fix: set attempt number of action run jobs eagerly (#11750)
A Forgejo Action job should be uniquely identifiable by its `ID` and `Attempt` number. Each time a particular job is (re-)run, its `Attempt` number is incremented while its `ID` remains static. Unfortunately, `Attempt` is not incremented when the (re-)run is triggered, but right when Forgejo Runner requests the job. That makes identifying a particular run much harder, because the attempt number is changed in the midst of an attempt. Furthermore, it requires taking the job's `Status` into account. This is fixed by setting the correct attempt number right when a (re-)run is triggered. That means that the `Attempt` number remains static for the duration of a single attempt.
## 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.
- [ ] 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.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] 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.
- [x] 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/11750
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-03-20 17:23:09 +01:00
|
|
|
assert.Equal(t, int64(1), job.Attempt)
|
|
|
|
|
assert.Zero(t, job.Started)
|
|
|
|
|
assert.Zero(t, job.Stopped)
|
|
|
|
|
assert.Zero(t, job.TaskID)
|
|
|
|
|
assert.Equal(t, StatusWaiting, job.Status)
|
|
|
|
|
|
2026-03-25 17:27:05 +01:00
|
|
|
lastHandle = job.Handle
|
fix: set attempt number of action run jobs eagerly (#11750)
A Forgejo Action job should be uniquely identifiable by its `ID` and `Attempt` number. Each time a particular job is (re-)run, its `Attempt` number is incremented while its `ID` remains static. Unfortunately, `Attempt` is not incremented when the (re-)run is triggered, but right when Forgejo Runner requests the job. That makes identifying a particular run much harder, because the attempt number is changed in the midst of an attempt. Furthermore, it requires taking the job's `Status` into account. This is fixed by setting the correct attempt number right when a (re-)run is triggered. That means that the `Attempt` number remains static for the duration of a single attempt.
## 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.
- [ ] 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.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] 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.
- [x] 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/11750
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-03-20 17:23:09 +01:00
|
|
|
job.Started = timeutil.TimeStampNow()
|
|
|
|
|
job.Stopped = timeutil.TimeStampNow()
|
|
|
|
|
job.TaskID = int64(59)
|
|
|
|
|
job.Status = StatusFailure
|
|
|
|
|
|
|
|
|
|
err = job.PrepareNextAttempt(StatusBlocked)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
2026-03-25 17:27:05 +01:00
|
|
|
assert.NotEqual(t, lastHandle, job.Handle)
|
|
|
|
|
assert.NotEmpty(t, job.Handle)
|
fix: set attempt number of action run jobs eagerly (#11750)
A Forgejo Action job should be uniquely identifiable by its `ID` and `Attempt` number. Each time a particular job is (re-)run, its `Attempt` number is incremented while its `ID` remains static. Unfortunately, `Attempt` is not incremented when the (re-)run is triggered, but right when Forgejo Runner requests the job. That makes identifying a particular run much harder, because the attempt number is changed in the midst of an attempt. Furthermore, it requires taking the job's `Status` into account. This is fixed by setting the correct attempt number right when a (re-)run is triggered. That means that the `Attempt` number remains static for the duration of a single attempt.
## 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.
- [ ] 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.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] 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.
- [x] 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/11750
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-03-20 17:23:09 +01:00
|
|
|
assert.Equal(t, int64(2), job.Attempt)
|
|
|
|
|
assert.Zero(t, job.Started)
|
|
|
|
|
assert.Zero(t, job.Stopped)
|
|
|
|
|
assert.Zero(t, job.TaskID)
|
|
|
|
|
assert.Equal(t, StatusBlocked, job.Status)
|
|
|
|
|
|
2026-03-25 17:27:05 +01:00
|
|
|
lastHandle = job.Handle
|
|
|
|
|
|
fix: set attempt number of action run jobs eagerly (#11750)
A Forgejo Action job should be uniquely identifiable by its `ID` and `Attempt` number. Each time a particular job is (re-)run, its `Attempt` number is incremented while its `ID` remains static. Unfortunately, `Attempt` is not incremented when the (re-)run is triggered, but right when Forgejo Runner requests the job. That makes identifying a particular run much harder, because the attempt number is changed in the midst of an attempt. Furthermore, it requires taking the job's `Status` into account. This is fixed by setting the correct attempt number right when a (re-)run is triggered. That means that the `Attempt` number remains static for the duration of a single attempt.
## 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.
- [ ] 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.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] 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.
- [x] 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/11750
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-03-20 17:23:09 +01:00
|
|
|
// The job hasn't finished yet. Preparing a next attempt should not be possible. It should be left untouched.
|
|
|
|
|
err = job.PrepareNextAttempt(StatusWaiting)
|
|
|
|
|
require.ErrorContains(t, err, "cannot prepare next attempt because job 46 is active: blocked")
|
|
|
|
|
|
2026-03-25 17:27:05 +01:00
|
|
|
assert.Equal(t, lastHandle, job.Handle)
|
fix: set attempt number of action run jobs eagerly (#11750)
A Forgejo Action job should be uniquely identifiable by its `ID` and `Attempt` number. Each time a particular job is (re-)run, its `Attempt` number is incremented while its `ID` remains static. Unfortunately, `Attempt` is not incremented when the (re-)run is triggered, but right when Forgejo Runner requests the job. That makes identifying a particular run much harder, because the attempt number is changed in the midst of an attempt. Furthermore, it requires taking the job's `Status` into account. This is fixed by setting the correct attempt number right when a (re-)run is triggered. That means that the `Attempt` number remains static for the duration of a single attempt.
## 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.
- [ ] 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.
- [ ] I did not document these changes and I do not expect someone else to do it.
### Release notes
- [ ] 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.
- [x] 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/11750
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-03-20 17:23:09 +01:00
|
|
|
assert.Equal(t, int64(2), job.Attempt)
|
|
|
|
|
assert.Zero(t, job.Started)
|
|
|
|
|
assert.Zero(t, job.Stopped)
|
|
|
|
|
assert.Zero(t, job.TaskID)
|
|
|
|
|
assert.Equal(t, StatusBlocked, job.Status)
|
|
|
|
|
}
|
2026-03-25 17:27:05 +01:00
|
|
|
|
|
|
|
|
func TestIsRequestedByRunner(t *testing.T) {
|
|
|
|
|
sameHandle := "4a1ca0be-4470-486d-8504-89b4a5ac00cf"
|
|
|
|
|
differentHandle := "88423da3-67af-4f2d-9a92-a0db822697e9"
|
|
|
|
|
emptyHandle := ""
|
|
|
|
|
|
|
|
|
|
job := &ActionRunJob{ID: 422, Attempt: 5, Handle: sameHandle}
|
|
|
|
|
|
|
|
|
|
assert.True(t, job.IsRequestedByRunner(nil))
|
|
|
|
|
assert.True(t, job.IsRequestedByRunner(&sameHandle))
|
|
|
|
|
assert.False(t, job.IsRequestedByRunner(&differentHandle))
|
|
|
|
|
assert.False(t, job.IsRequestedByRunner(&emptyHandle))
|
|
|
|
|
|
|
|
|
|
// Old jobs that were created before the introduction of Handle do not have one.
|
|
|
|
|
emptyHandleJob := &ActionRunJob{ID: 422, Attempt: 5, Handle: ""}
|
|
|
|
|
|
|
|
|
|
assert.True(t, emptyHandleJob.IsRequestedByRunner(nil))
|
|
|
|
|
assert.True(t, emptyHandleJob.IsRequestedByRunner(&emptyHandle))
|
|
|
|
|
|
|
|
|
|
assert.False(t, emptyHandleJob.IsRequestedByRunner(&differentHandle))
|
|
|
|
|
}
|
fix: prevent jobs with unknown needs from running (#12046)
If Forgejo encounters an Actions workflow with unknown jobs in a needs definition, Forgejo will ignore those and run the job anyway. That is bad. For example, releases could be published without any testing because the name of the testing job was misspelt.
Workflow that demonstrates the problem:
```yaml
on:
push:
workflow_dispatch:
jobs:
build:
runs-on: debian
steps:
- run: |
echo "OK"
test:
runs-on: debian
needs: [does-not-exist]
steps:
- run: |
echo "OK"
```
Now, before a workflow is run, Forgejo will check whether all jobs referenced in `needs` exist. If any of them does not, it raises a pre-execution error which fails the workflow immediately. It also displays an appropriate error to the user, for example:
```
Workflow was not executed due to an error that blocked the execution attempt.
Job with ID test references unknown jobs in `needs`: does-not-exist.
```
Futhermore, workflows with pre-execution errors can no longer be rerun, which was previously possible.
Original issue: https://code.forgejo.org/forgejo/runner/issues/977.
## Checklist
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). 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.
- [ ] 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.
- [ ] 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/12046
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-04-10 15:40:08 +02:00
|
|
|
|
|
|
|
|
func TestAllNeedsExist(t *testing.T) {
|
|
|
|
|
testCases := []struct {
|
|
|
|
|
name string
|
|
|
|
|
job ActionRunJob
|
|
|
|
|
existingJobIDs container.Set[string]
|
|
|
|
|
expectedUnknownIDs []string
|
|
|
|
|
ok bool
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "no needs",
|
|
|
|
|
job: ActionRunJob{Needs: nil},
|
|
|
|
|
existingJobIDs: container.Set[string]{},
|
|
|
|
|
expectedUnknownIDs: []string{},
|
|
|
|
|
ok: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "empty needs",
|
|
|
|
|
job: ActionRunJob{Needs: []string{}},
|
|
|
|
|
existingJobIDs: container.Set[string]{},
|
|
|
|
|
expectedUnknownIDs: []string{},
|
|
|
|
|
ok: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "satisfied needs",
|
|
|
|
|
job: ActionRunJob{Needs: []string{"job1", "job2"}},
|
|
|
|
|
existingJobIDs: container.SetOf("job2", "job1"),
|
|
|
|
|
expectedUnknownIDs: []string{},
|
|
|
|
|
ok: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "unsatisfied needs",
|
|
|
|
|
job: ActionRunJob{Needs: []string{"unknown", "job2"}},
|
|
|
|
|
existingJobIDs: container.SetOf("job2", "job1"),
|
|
|
|
|
expectedUnknownIDs: []string{"unknown"},
|
|
|
|
|
ok: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "comparison is case-sensitive",
|
|
|
|
|
job: ActionRunJob{Needs: []string{"Job1", "job2"}},
|
|
|
|
|
existingJobIDs: container.SetOf("job2", "job1"),
|
|
|
|
|
expectedUnknownIDs: []string{"Job1"},
|
|
|
|
|
ok: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, testCase := range testCases {
|
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
|
|
|
unknownIDs, ok := testCase.job.AllNeedsExist(testCase.existingJobIDs)
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, testCase.ok, ok)
|
|
|
|
|
assert.Equal(t, testCase.expectedUnknownIDs, unknownIDs)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestActionRunJob_CanBeRerun(t *testing.T) {
|
|
|
|
|
testCases := []struct {
|
2026-04-19 22:08:00 +02:00
|
|
|
name string
|
|
|
|
|
job ActionRunJob
|
|
|
|
|
canBeRerun bool
|
|
|
|
|
expectedError string
|
fix: prevent jobs with unknown needs from running (#12046)
If Forgejo encounters an Actions workflow with unknown jobs in a needs definition, Forgejo will ignore those and run the job anyway. That is bad. For example, releases could be published without any testing because the name of the testing job was misspelt.
Workflow that demonstrates the problem:
```yaml
on:
push:
workflow_dispatch:
jobs:
build:
runs-on: debian
steps:
- run: |
echo "OK"
test:
runs-on: debian
needs: [does-not-exist]
steps:
- run: |
echo "OK"
```
Now, before a workflow is run, Forgejo will check whether all jobs referenced in `needs` exist. If any of them does not, it raises a pre-execution error which fails the workflow immediately. It also displays an appropriate error to the user, for example:
```
Workflow was not executed due to an error that blocked the execution attempt.
Job with ID test references unknown jobs in `needs`: does-not-exist.
```
Futhermore, workflows with pre-execution errors can no longer be rerun, which was previously possible.
Original issue: https://code.forgejo.org/forgejo/runner/issues/977.
## Checklist
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). 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.
- [ ] 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.
- [ ] 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/12046
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-04-10 15:40:08 +02:00
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "job with unknown status",
|
|
|
|
|
job: ActionRunJob{Run: &ActionRun{Status: StatusSuccess}, Status: StatusUnknown},
|
|
|
|
|
canBeRerun: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "successful job",
|
|
|
|
|
job: ActionRunJob{Run: &ActionRun{Status: StatusSuccess}, Status: StatusSuccess},
|
|
|
|
|
canBeRerun: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "failed job",
|
|
|
|
|
job: ActionRunJob{Run: &ActionRun{Status: StatusSuccess}, Status: StatusFailure},
|
|
|
|
|
canBeRerun: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "cancelled job",
|
|
|
|
|
job: ActionRunJob{Run: &ActionRun{Status: StatusSuccess}, Status: StatusCancelled},
|
|
|
|
|
canBeRerun: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "skipped job",
|
|
|
|
|
job: ActionRunJob{Run: &ActionRun{Status: StatusSuccess}, Status: StatusSkipped},
|
|
|
|
|
canBeRerun: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "waiting job",
|
|
|
|
|
job: ActionRunJob{Run: &ActionRun{Status: StatusSuccess}, Status: StatusWaiting},
|
|
|
|
|
canBeRerun: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "blocked job",
|
|
|
|
|
job: ActionRunJob{Run: &ActionRun{Status: StatusSuccess}, Status: StatusBlocked},
|
|
|
|
|
canBeRerun: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
2026-04-19 22:08:00 +02:00
|
|
|
name: "ActionRun is nil",
|
|
|
|
|
job: ActionRunJob{ID: 12, Run: nil, Status: StatusSuccess},
|
|
|
|
|
expectedError: "cannot load run 0 of job 12",
|
fix: prevent jobs with unknown needs from running (#12046)
If Forgejo encounters an Actions workflow with unknown jobs in a needs definition, Forgejo will ignore those and run the job anyway. That is bad. For example, releases could be published without any testing because the name of the testing job was misspelt.
Workflow that demonstrates the problem:
```yaml
on:
push:
workflow_dispatch:
jobs:
build:
runs-on: debian
steps:
- run: |
echo "OK"
test:
runs-on: debian
needs: [does-not-exist]
steps:
- run: |
echo "OK"
```
Now, before a workflow is run, Forgejo will check whether all jobs referenced in `needs` exist. If any of them does not, it raises a pre-execution error which fails the workflow immediately. It also displays an appropriate error to the user, for example:
```
Workflow was not executed due to an error that blocked the execution attempt.
Job with ID test references unknown jobs in `needs`: does-not-exist.
```
Futhermore, workflows with pre-execution errors can no longer be rerun, which was previously possible.
Original issue: https://code.forgejo.org/forgejo/runner/issues/977.
## Checklist
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). 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.
- [ ] 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.
- [ ] 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/12046
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-04-10 15:40:08 +02:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "with busy run but completed job",
|
|
|
|
|
job: ActionRunJob{Run: &ActionRun{Status: StatusRunning}, Status: StatusSuccess},
|
|
|
|
|
canBeRerun: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "with run that cannot be run",
|
|
|
|
|
job: ActionRunJob{
|
|
|
|
|
Run: &ActionRun{Status: StatusRunning, PreExecutionErrorCode: ErrorCodeEventDetectionError},
|
|
|
|
|
Status: StatusSuccess,
|
|
|
|
|
},
|
|
|
|
|
canBeRerun: false,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, testCase := range testCases {
|
|
|
|
|
t.Run(testCase.name, func(t *testing.T) {
|
2026-04-19 22:08:00 +02:00
|
|
|
result, err := testCase.job.CanBeRerun(t.Context())
|
|
|
|
|
|
|
|
|
|
if testCase.expectedError == "" {
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
} else {
|
|
|
|
|
require.ErrorContains(t, err, testCase.expectedError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, testCase.canBeRerun, result)
|
fix: prevent jobs with unknown needs from running (#12046)
If Forgejo encounters an Actions workflow with unknown jobs in a needs definition, Forgejo will ignore those and run the job anyway. That is bad. For example, releases could be published without any testing because the name of the testing job was misspelt.
Workflow that demonstrates the problem:
```yaml
on:
push:
workflow_dispatch:
jobs:
build:
runs-on: debian
steps:
- run: |
echo "OK"
test:
runs-on: debian
needs: [does-not-exist]
steps:
- run: |
echo "OK"
```
Now, before a workflow is run, Forgejo will check whether all jobs referenced in `needs` exist. If any of them does not, it raises a pre-execution error which fails the workflow immediately. It also displays an appropriate error to the user, for example:
```
Workflow was not executed due to an error that blocked the execution attempt.
Job with ID test references unknown jobs in `needs`: does-not-exist.
```
Futhermore, workflows with pre-execution errors can no longer be rerun, which was previously possible.
Original issue: https://code.forgejo.org/forgejo/runner/issues/977.
## Checklist
The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. All work and communication must conform to Forgejo's [AI Agreement](https://codeberg.org/forgejo/governance/src/branch/main/AIAgreement.md). 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.
- [ ] 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.
- [ ] 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/12046
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
Co-authored-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
Co-committed-by: Andreas Ahlenstorf <andreas@ahlenstorf.ch>
2026-04-10 15:40:08 +02:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|