mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-03-26 23:13:06 -04:00
Some checks are pending
/ release (push) Waiting to run
testing-integration / test-unit (push) Waiting to run
testing-integration / test-sqlite (push) Waiting to run
testing-integration / test-mariadb (v10.6) (push) Waiting to run
testing-integration / test-mariadb (v11.8) (push) Waiting to run
testing / backend-checks (push) Waiting to run
testing / frontend-checks (push) Waiting to run
testing / test-unit (push) Blocked by required conditions
testing / test-e2e (push) Blocked by required conditions
testing / test-remote-cacher (redis) (push) Blocked by required conditions
testing / test-remote-cacher (valkey) (push) Blocked by required conditions
testing / test-remote-cacher (garnet) (push) Blocked by required conditions
testing / test-remote-cacher (redict) (push) Blocked by required conditions
testing / test-mysql (push) Blocked by required conditions
testing / test-pgsql (push) Blocked by required conditions
testing / test-sqlite (push) Blocked by required conditions
testing / security-check (push) Blocked by required conditions
Follow-up to #10525; adds support for `on.workflow_call.inputs` to expanded reusable workflows (when no `runs-on` is specified in a job that `uses: ...` another workflow).
The majority of the work for this is done by the `jobparser` library which evaluates inputs automatically when the job is being parsed and stores those inputs on the expanded jobs as the "default" value in `on.workflow_call.inputs`. Forgejo's role here is just to to ensure that `forgejo.event_name` is set to `"workflow_call"` when a job is dispatched, which causes the runner to use the inputs that are stored -- 34c20aa50f/act/runner/expression.go (L452-L467).
## 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/1323
### 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/1664
- [ ] 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.
<!--start release-notes-assistant-->
## Release notes
<!--URL:https://codeberg.org/forgejo/forgejo-->
- Features
- [PR](https://codeberg.org/forgejo/forgejo/pulls/10614): <!--number 10614 --><!--line 0 --><!--description c3VwcG9ydCB3b3JrZmxvdyBpbnB1dHMgb24gZXhwYW5kZWQgcmV1c2FibGUgd29ya2Zsb3dz-->support workflow inputs on expanded reusable workflows<!--description-->
<!--end release-notes-assistant-->
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10614
Reviewed-by: Andreas Ahlenstorf <aahlenst@noreply.codeberg.org>
Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Co-committed-by: Mathieu Fenniak <mathieu@fenniak.net>
397 lines
13 KiB
Go
397 lines
13 KiB
Go
// Copyright 2024 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package actions
|
|
|
|
import (
|
|
"testing"
|
|
|
|
actions_model "forgejo.org/models/actions"
|
|
"forgejo.org/models/repo"
|
|
"forgejo.org/models/unittest"
|
|
"forgejo.org/models/user"
|
|
actions_module "forgejo.org/modules/actions"
|
|
"forgejo.org/modules/json"
|
|
"forgejo.org/modules/setting"
|
|
webhook_module "forgejo.org/modules/webhook"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestFindTaskNeeds(t *testing.T) {
|
|
require.NoError(t, unittest.PrepareTestDatabase())
|
|
|
|
task := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: 51})
|
|
job := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: task.JobID})
|
|
|
|
ret, err := FindTaskNeeds(t.Context(), job)
|
|
require.NoError(t, err)
|
|
assert.Len(t, ret, 1)
|
|
assert.Contains(t, ret, "job1")
|
|
assert.Len(t, ret["job1"].Outputs, 2)
|
|
assert.Equal(t, "abc", ret["job1"].Outputs["output_a"])
|
|
assert.Equal(t, "bbb", ret["job1"].Outputs["output_b"])
|
|
}
|
|
|
|
func TestGenerateGiteaContext(t *testing.T) {
|
|
testUser := &user.User{
|
|
ID: 1,
|
|
Name: "testuser",
|
|
}
|
|
|
|
testRepo := &repo.Repository{
|
|
ID: 1,
|
|
OwnerName: "testowner",
|
|
Name: "testrepo",
|
|
}
|
|
|
|
emptyField := func(t *testing.T, context map[string]any, field string) {
|
|
v, ok := context[field]
|
|
assert.True(t, ok, "expected field %q to be present", field)
|
|
assert.Empty(t, v)
|
|
}
|
|
|
|
t.Run("Basic workflow run without job", func(t *testing.T) {
|
|
run := &actions_model.ActionRun{
|
|
ID: 1,
|
|
Index: 42,
|
|
TriggerUser: testUser,
|
|
Repo: testRepo,
|
|
TriggerEvent: "push",
|
|
Ref: "refs/heads/main",
|
|
CommitSHA: "abc123def456",
|
|
WorkflowID: "test-workflow.yaml",
|
|
WorkflowDirectory: ".forgejo/workflows",
|
|
EventPayload: `{"repository": {"name": "testrepo"}}`,
|
|
}
|
|
|
|
context, err := GenerateGiteaContext(run, nil)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "testuser", context["actor"])
|
|
assert.Equal(t, setting.AppURL+"api/v1", context["api_url"])
|
|
assert.Equal(t, "push", context["event_name"])
|
|
assert.Equal(t, "refs/heads/main", context["ref"])
|
|
assert.Equal(t, "main", context["ref_name"])
|
|
assert.Equal(t, "branch", context["ref_type"])
|
|
assert.Equal(t, "testowner/testrepo", context["repository"])
|
|
assert.Equal(t, "testowner", context["repository_owner"])
|
|
assert.Equal(t, "abc123def456", context["sha"])
|
|
assert.Equal(t, "42", context["run_number"])
|
|
assert.Equal(t, "test-workflow.yaml", context["workflow"])
|
|
assert.Equal(t, "testowner/testrepo/.forgejo/workflows/test-workflow.yaml@refs/heads/main", context["workflow_ref"])
|
|
assert.Equal(t, false, context["ref_protected"])
|
|
assert.Equal(t, "Actions", context["secret_source"])
|
|
assert.Equal(t, setting.AppURL, context["server_url"])
|
|
|
|
event, ok := context["event"].(map[string]any)
|
|
require.True(t, ok)
|
|
assert.Equal(t, "testrepo", event["repository"].(map[string]any)["name"])
|
|
|
|
emptyField(t, context, "action_path")
|
|
emptyField(t, context, "action_ref")
|
|
emptyField(t, context, "action_repository")
|
|
emptyField(t, context, "action_status")
|
|
emptyField(t, context, "action")
|
|
emptyField(t, context, "base_ref")
|
|
emptyField(t, context, "env")
|
|
emptyField(t, context, "event_path")
|
|
emptyField(t, context, "graphql_url")
|
|
emptyField(t, context, "head_ref")
|
|
emptyField(t, context, "job")
|
|
emptyField(t, context, "path")
|
|
emptyField(t, context, "retention_days")
|
|
emptyField(t, context, "run_attempt")
|
|
emptyField(t, context, "run_id")
|
|
emptyField(t, context, "triggering_actor")
|
|
emptyField(t, context, "workspace")
|
|
})
|
|
|
|
t.Run("Workflow run with job", func(t *testing.T) {
|
|
run := &actions_model.ActionRun{
|
|
ID: 1,
|
|
Index: 42,
|
|
TriggerUser: testUser,
|
|
Repo: testRepo,
|
|
TriggerEvent: "push",
|
|
Ref: "refs/heads/main",
|
|
CommitSHA: "abc123def456",
|
|
WorkflowID: "test-workflow",
|
|
EventPayload: `{}`,
|
|
}
|
|
|
|
job := &actions_model.ActionRunJob{
|
|
ID: 100,
|
|
RunID: 1,
|
|
JobID: "test-job",
|
|
Attempt: 1,
|
|
WorkflowPayload: []byte("on: [push]"),
|
|
}
|
|
|
|
context, err := GenerateGiteaContext(run, job)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "test-job", context["job"])
|
|
assert.Equal(t, "1", context["run_id"])
|
|
assert.Equal(t, "1", context["run_attempt"])
|
|
})
|
|
|
|
t.Run("Pull request event", func(t *testing.T) {
|
|
pullRequestPayload := map[string]any{
|
|
"pull_request": map[string]any{
|
|
"base": map[string]any{
|
|
"ref": "main",
|
|
"label": "main",
|
|
"sha": "base123sha",
|
|
},
|
|
"head": map[string]any{
|
|
"ref": "feature-branch",
|
|
"label": "feature-branch",
|
|
"sha": "head456sha",
|
|
},
|
|
},
|
|
}
|
|
|
|
payloadBytes, _ := json.Marshal(pullRequestPayload)
|
|
|
|
run := &actions_model.ActionRun{
|
|
ID: 1,
|
|
Index: 42,
|
|
TriggerUser: testUser,
|
|
Repo: testRepo,
|
|
TriggerEvent: "pull_request",
|
|
Ref: "refs/pull/1/merge",
|
|
CommitSHA: "merge789sha",
|
|
WorkflowID: "test-workflow.yaml",
|
|
WorkflowDirectory: ".forgejo/workflows",
|
|
Event: webhook_module.HookEventPullRequest,
|
|
EventPayload: string(payloadBytes),
|
|
}
|
|
|
|
context, err := GenerateGiteaContext(run, nil)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "main", context["base_ref"])
|
|
assert.Equal(t, "feature-branch", context["head_ref"])
|
|
assert.Equal(t, "refs/pull/1/merge", context["ref"])
|
|
assert.Equal(t, "merge789sha", context["sha"])
|
|
assert.Equal(t, "testowner/testrepo/.forgejo/workflows/test-workflow.yaml@refs/pull/1/merge", context["workflow_ref"])
|
|
})
|
|
|
|
t.Run("Pull request target event", func(t *testing.T) {
|
|
pullRequestPayload := map[string]any{
|
|
"pull_request": map[string]any{
|
|
"base": map[string]any{
|
|
"ref": "main",
|
|
"label": "main",
|
|
"sha": "base123sha",
|
|
},
|
|
"head": map[string]any{
|
|
"ref": "feature-branch",
|
|
"label": "feature-branch",
|
|
"sha": "head456sha",
|
|
},
|
|
},
|
|
}
|
|
|
|
payloadBytes, _ := json.Marshal(pullRequestPayload)
|
|
|
|
run := &actions_model.ActionRun{
|
|
ID: 1,
|
|
Index: 42,
|
|
TriggerUser: testUser,
|
|
Repo: testRepo,
|
|
TriggerEvent: actions_module.GithubEventPullRequestTarget,
|
|
Ref: "refs/pull/1/merge",
|
|
CommitSHA: "merge789sha",
|
|
WorkflowID: "test-workflow.yml",
|
|
WorkflowDirectory: ".github/workflows",
|
|
Event: webhook_module.HookEventPullRequest,
|
|
EventPayload: string(payloadBytes),
|
|
}
|
|
|
|
context, err := GenerateGiteaContext(run, nil)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "main", context["base_ref"])
|
|
assert.Equal(t, "feature-branch", context["head_ref"])
|
|
// For pull_request_target, ref and sha should be from base
|
|
assert.Equal(t, "refs/heads/main", context["ref"])
|
|
assert.Equal(t, "base123sha", context["sha"])
|
|
assert.Equal(t, "main", context["ref_name"])
|
|
assert.Equal(t, "branch", context["ref_type"])
|
|
assert.Equal(t, "testowner/testrepo/.github/workflows/test-workflow.yml@refs/heads/main", context["workflow_ref"])
|
|
})
|
|
|
|
t.Run("workflow_call job", func(t *testing.T) {
|
|
run := &actions_model.ActionRun{
|
|
ID: 1,
|
|
Index: 42,
|
|
TriggerUser: testUser,
|
|
Repo: testRepo,
|
|
TriggerEvent: "push",
|
|
Ref: "refs/heads/main",
|
|
CommitSHA: "abc123def456",
|
|
WorkflowID: "test-workflow",
|
|
EventPayload: `{}`,
|
|
}
|
|
|
|
job := &actions_model.ActionRunJob{
|
|
ID: 100,
|
|
RunID: 1,
|
|
JobID: "test-job",
|
|
Attempt: 1,
|
|
WorkflowPayload: []byte("on: { workflow_call: { inputs: {} } }\n__metadata:\n workflow_call_parent: b5a9f46f1f2513d7777fde50b169d323a6519e349cc175484c947ac315a209ed\n"),
|
|
}
|
|
|
|
context, err := GenerateGiteaContext(run, job)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "workflow_call", context["event_name"])
|
|
})
|
|
}
|
|
|
|
func TestGenerateGiteaContextForRun(t *testing.T) {
|
|
testUser := &user.User{
|
|
ID: 1,
|
|
Name: "testuser",
|
|
}
|
|
|
|
testRepo := &repo.Repository{
|
|
ID: 1,
|
|
OwnerName: "testowner",
|
|
Name: "testrepo",
|
|
}
|
|
|
|
t.Run("Basic workflow run", func(t *testing.T) {
|
|
run := &actions_model.ActionRun{
|
|
ID: 1,
|
|
Index: 42,
|
|
TriggerUser: testUser,
|
|
Repo: testRepo,
|
|
TriggerEvent: "push",
|
|
Ref: "refs/heads/main",
|
|
CommitSHA: "abc123def456",
|
|
WorkflowID: "test-workflow.yaml",
|
|
WorkflowDirectory: ".forgejo/workflows",
|
|
EventPayload: `{"repository": {"name": "testrepo"}}`,
|
|
}
|
|
|
|
gitContextObj := generateGiteaContextForRun(run)
|
|
|
|
assert.Equal(t, "testuser", gitContextObj.Actor)
|
|
assert.Equal(t, setting.AppURL+"api/v1", gitContextObj.APIURL)
|
|
assert.Equal(t, "push", gitContextObj.EventName)
|
|
assert.Equal(t, "refs/heads/main", gitContextObj.Ref)
|
|
assert.Equal(t, "main", gitContextObj.RefName)
|
|
assert.Equal(t, "branch", gitContextObj.RefType)
|
|
assert.Equal(t, "testowner/testrepo", gitContextObj.Repository)
|
|
assert.Equal(t, "testowner", gitContextObj.RepositoryOwner)
|
|
assert.Equal(t, "abc123def456", gitContextObj.Sha)
|
|
assert.Equal(t, "42", gitContextObj.RunNumber)
|
|
assert.Equal(t, "test-workflow.yaml", gitContextObj.Workflow)
|
|
assert.Equal(t, "testowner/testrepo/.forgejo/workflows/test-workflow.yaml@refs/heads/main", gitContextObj.WorkflowRef)
|
|
|
|
assert.Equal(t, "testrepo", gitContextObj.Event["repository"].(map[string]any)["name"])
|
|
|
|
assert.Empty(t, gitContextObj.ActionPath)
|
|
assert.Empty(t, gitContextObj.ActionRef)
|
|
assert.Empty(t, gitContextObj.ActionRepository)
|
|
assert.Empty(t, gitContextObj.Action)
|
|
assert.Empty(t, gitContextObj.BaseRef)
|
|
assert.Empty(t, gitContextObj.EventPath)
|
|
assert.Empty(t, gitContextObj.GraphQLURL)
|
|
assert.Empty(t, gitContextObj.HeadRef)
|
|
assert.Empty(t, gitContextObj.Job)
|
|
assert.Empty(t, gitContextObj.RetentionDays)
|
|
assert.Empty(t, gitContextObj.RunAttempt)
|
|
assert.Empty(t, gitContextObj.RunID)
|
|
assert.Empty(t, gitContextObj.Workspace)
|
|
})
|
|
|
|
t.Run("Pull request event", func(t *testing.T) {
|
|
pullRequestPayload := map[string]any{
|
|
"pull_request": map[string]any{
|
|
"base": map[string]any{
|
|
"ref": "main",
|
|
"label": "main",
|
|
"sha": "base123sha",
|
|
},
|
|
"head": map[string]any{
|
|
"ref": "feature-branch",
|
|
"label": "feature-branch",
|
|
"sha": "head456sha",
|
|
},
|
|
},
|
|
}
|
|
|
|
payloadBytes, _ := json.Marshal(pullRequestPayload)
|
|
|
|
run := &actions_model.ActionRun{
|
|
ID: 1,
|
|
Index: 42,
|
|
TriggerUser: testUser,
|
|
Repo: testRepo,
|
|
TriggerEvent: "pull_request",
|
|
Ref: "refs/pull/1/merge",
|
|
CommitSHA: "merge789sha",
|
|
WorkflowID: "test-workflow.yaml",
|
|
WorkflowDirectory: ".forgejo/workflows",
|
|
Event: webhook_module.HookEventPullRequest,
|
|
EventPayload: string(payloadBytes),
|
|
}
|
|
|
|
gitContextObj := generateGiteaContextForRun(run)
|
|
|
|
assert.Equal(t, "main", gitContextObj.BaseRef)
|
|
assert.Equal(t, "feature-branch", gitContextObj.HeadRef)
|
|
assert.Equal(t, "refs/pull/1/merge", gitContextObj.Ref)
|
|
assert.Equal(t, "merge789sha", gitContextObj.Sha)
|
|
assert.Equal(t, "testowner/testrepo/.forgejo/workflows/test-workflow.yaml@refs/pull/1/merge", gitContextObj.WorkflowRef)
|
|
})
|
|
|
|
t.Run("Pull request target event", func(t *testing.T) {
|
|
pullRequestPayload := map[string]any{
|
|
"pull_request": map[string]any{
|
|
"base": map[string]any{
|
|
"ref": "main",
|
|
"label": "main",
|
|
"sha": "base123sha",
|
|
},
|
|
"head": map[string]any{
|
|
"ref": "feature-branch",
|
|
"label": "feature-branch",
|
|
"sha": "head456sha",
|
|
},
|
|
},
|
|
}
|
|
|
|
payloadBytes, _ := json.Marshal(pullRequestPayload)
|
|
|
|
run := &actions_model.ActionRun{
|
|
ID: 1,
|
|
Index: 42,
|
|
TriggerUser: testUser,
|
|
Repo: testRepo,
|
|
TriggerEvent: actions_module.GithubEventPullRequestTarget,
|
|
Ref: "refs/pull/1/merge",
|
|
CommitSHA: "merge789sha",
|
|
WorkflowID: "test-workflow.yml",
|
|
WorkflowDirectory: ".github/workflows",
|
|
Event: webhook_module.HookEventPullRequest,
|
|
EventPayload: string(payloadBytes),
|
|
}
|
|
|
|
gitContextObj := generateGiteaContextForRun(run)
|
|
|
|
assert.Equal(t, "main", gitContextObj.BaseRef)
|
|
assert.Equal(t, "feature-branch", gitContextObj.HeadRef)
|
|
// For pull_request_target, ref and sha should be from base
|
|
assert.Equal(t, "refs/heads/main", gitContextObj.Ref)
|
|
assert.Equal(t, "base123sha", gitContextObj.Sha)
|
|
assert.Equal(t, "main", gitContextObj.RefName)
|
|
assert.Equal(t, "branch", gitContextObj.RefType)
|
|
assert.Equal(t, "testowner/testrepo/.github/workflows/test-workflow.yml@refs/heads/main", gitContextObj.WorkflowRef)
|
|
})
|
|
}
|