mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 19:06:18 +01:00 
			
		
		
		
	Backport #35590 by @Zettat123 Depends on [gitea/act#143](https://gitea.com/gitea/act/pulls/143) The [`inputs` context](https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#inputs-context) is used when parsing workflows so that `run-name` like `run-name: Deploy to ${{ inputs.deploy_target }}` can be parsed correctly. Co-authored-by: Zettat123 <zettat123@gmail.com>
This commit is contained in:
		
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @@ -295,7 +295,7 @@ replace github.com/jaytaylor/html2text => github.com/Necoro/html2text v0.0.0-202 | ||||
|  | ||||
| replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 | ||||
|  | ||||
| replace github.com/nektos/act => gitea.com/gitea/act v0.261.6 | ||||
| replace github.com/nektos/act => gitea.com/gitea/act v0.261.7-0.20251003180512-ac6e4b751763 | ||||
|  | ||||
| // TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why | ||||
| replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 | ||||
|   | ||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @@ -31,8 +31,8 @@ dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= | ||||
| dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= | ||||
| filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= | ||||
| filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= | ||||
| gitea.com/gitea/act v0.261.6 h1:CjZwKOyejonNFDmsXOw3wGm5Vet573hHM6VMLsxtvPY= | ||||
| gitea.com/gitea/act v0.261.6/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= | ||||
| gitea.com/gitea/act v0.261.7-0.20251003180512-ac6e4b751763 h1:ohdxegvslDEllZmRNDqpKun6L4Oq81jNdEDtGgHEV2c= | ||||
| gitea.com/gitea/act v0.261.7-0.20251003180512-ac6e4b751763/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= | ||||
| gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40= | ||||
| gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits= | ||||
| gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4= | ||||
|   | ||||
| @@ -26,6 +26,7 @@ import ( | ||||
|  | ||||
| 	"github.com/nektos/act/pkg/jobparser" | ||||
| 	"github.com/nektos/act/pkg/model" | ||||
| 	"gopkg.in/yaml.v3" | ||||
| ) | ||||
|  | ||||
| func EnableOrDisableWorkflow(ctx *context.APIContext, workflowID string, isEnable bool) error { | ||||
| @@ -136,9 +137,24 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	singleWorkflow := &jobparser.SingleWorkflow{} | ||||
| 	if err := yaml.Unmarshal(content, singleWorkflow); err != nil { | ||||
| 		return fmt.Errorf("failed to unmarshal workflow content: %w", err) | ||||
| 	} | ||||
| 	// get inputs from post | ||||
| 	workflow := &model.Workflow{ | ||||
| 		RawOn: singleWorkflow.RawOn, | ||||
| 	} | ||||
| 	inputsWithDefaults := make(map[string]any) | ||||
| 	if workflowDispatch := workflow.WorkflowDispatchConfig(); workflowDispatch != nil { | ||||
| 		if err = processInputs(workflowDispatch, inputsWithDefaults); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	giteaCtx := GenerateGiteaContext(run, nil) | ||||
|  | ||||
| 	workflows, err = jobparser.Parse(content, jobparser.WithGitContext(giteaCtx.ToGitHubContext())) | ||||
| 	workflows, err = jobparser.Parse(content, jobparser.WithGitContext(giteaCtx.ToGitHubContext()), jobparser.WithInputs(inputsWithDefaults)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -154,17 +170,6 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re | ||||
| 		) | ||||
| 	} | ||||
|  | ||||
| 	// get inputs from post | ||||
| 	workflow := &model.Workflow{ | ||||
| 		RawOn: workflows[0].RawOn, | ||||
| 	} | ||||
| 	inputsWithDefaults := make(map[string]any) | ||||
| 	if workflowDispatch := workflow.WorkflowDispatchConfig(); workflowDispatch != nil { | ||||
| 		if err = processInputs(workflowDispatch, inputsWithDefaults); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// ctx.Req.PostForm -> WorkflowDispatchPayload.Inputs -> ActionRun.EventPayload -> runner: ghc.Event | ||||
| 	// https://docs.github.com/en/actions/learn-github-actions/contexts#github-context | ||||
| 	// https://docs.github.com/en/webhooks/webhook-events-and-payloads#workflow_dispatch | ||||
|   | ||||
							
								
								
									
										85
									
								
								tests/integration/actions_inputs_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								tests/integration/actions_inputs_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| // Copyright 2025 The Gitea Authors. All rights reserved. | ||||
| // SPDX-License-Identifier: MIT | ||||
|  | ||||
| package integration | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"testing" | ||||
|  | ||||
| 	actions_model "code.gitea.io/gitea/models/actions" | ||||
| 	auth_model "code.gitea.io/gitea/models/auth" | ||||
| 	repo_model "code.gitea.io/gitea/models/repo" | ||||
| 	"code.gitea.io/gitea/models/unittest" | ||||
| 	user_model "code.gitea.io/gitea/models/user" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestWorkflowWithInputsContext(t *testing.T) { | ||||
| 	onGiteaRun(t, func(t *testing.T, u *url.URL) { | ||||
| 		user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) | ||||
| 		session := loginUser(t, user2.Name) | ||||
| 		token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser) | ||||
|  | ||||
| 		apiRepo := createActionsTestRepo(t, token, "actions-inputs-context", false) | ||||
| 		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}) | ||||
| 		httpContext := NewAPITestContext(t, user2.Name, repo.Name, auth_model.AccessTokenScopeWriteRepository) | ||||
| 		defer doAPIDeleteRepository(httpContext)(t) | ||||
|  | ||||
| 		wRunner := newMockRunner() | ||||
| 		wRunner.registerAsRepoRunner(t, user2.Name, repo.Name, "windows-runner", []string{"windows-runner"}, false) | ||||
| 		lRunner := newMockRunner() | ||||
| 		lRunner.registerAsRepoRunner(t, user2.Name, repo.Name, "linux-runner", []string{"linux-runner"}, false) | ||||
|  | ||||
| 		wf1TreePath := ".gitea/workflows/test-inputs-context.yml" | ||||
| 		wf1FileContent := `name: Test Inputs Context | ||||
| on: | ||||
|   workflow_dispatch: | ||||
|     inputs: | ||||
|       os: | ||||
|         description: 'OS' | ||||
|         required: true | ||||
|         type: choice | ||||
|         options: | ||||
|         - linux | ||||
|         - windows | ||||
|  | ||||
| run-name: Build APP on ${{ inputs.os }} | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: ${{ inputs.os }}-runner | ||||
|     steps: | ||||
|       - run: echo 'Start building APP' | ||||
| ` | ||||
|  | ||||
| 		opts1 := getWorkflowCreateFileOptions(user2, repo.DefaultBranch, "create %s"+wf1TreePath, wf1FileContent) | ||||
| 		createWorkflowFile(t, token, user2.Name, repo.Name, wf1TreePath, opts1) | ||||
|  | ||||
| 		// run the workflow with os=windows | ||||
| 		urlStr := fmt.Sprintf("/%s/%s/actions/run?workflow=%s", user2.Name, repo.Name, "test-inputs-context.yml") | ||||
| 		req := NewRequestWithValues(t, "POST", urlStr, map[string]string{ | ||||
| 			"_csrf": GetUserCSRFToken(t, session), | ||||
| 			"ref":   "refs/heads/main", | ||||
| 			"os":    "windows", | ||||
| 		}) | ||||
| 		session.MakeRequest(t, req, http.StatusSeeOther) | ||||
|  | ||||
| 		// linux-runner cannot fetch the task | ||||
| 		lRunner.fetchNoTask(t) | ||||
|  | ||||
| 		task := wRunner.fetchTask(t) | ||||
| 		_, _, run := getTaskAndJobAndRunByTaskID(t, task.Id) | ||||
| 		assert.Equal(t, "Build APP on windows", run.Title) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func getTaskAndJobAndRunByTaskID(t *testing.T, taskID int64) (*actions_model.ActionTask, *actions_model.ActionRunJob, *actions_model.ActionRun) { | ||||
| 	actionTask := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionTask{ID: taskID}) | ||||
| 	actionRunJob := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRunJob{ID: actionTask.JobID}) | ||||
| 	actionRun := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: actionRunJob.RunID}) | ||||
| 	return actionTask, actionRunJob, actionRun | ||||
| } | ||||
| @@ -93,7 +93,20 @@ func (r *mockRunner) registerAsRepoRunner(t *testing.T, ownerName, repoName, run | ||||
| } | ||||
|  | ||||
| func (r *mockRunner) fetchTask(t *testing.T, timeout ...time.Duration) *runnerv1.Task { | ||||
| 	fetchTimeout := 10 * time.Second | ||||
| 	task := r.tryFetchTask(t, timeout...) | ||||
| 	assert.NotNil(t, task, "failed to fetch a task") | ||||
| 	return task | ||||
| } | ||||
|  | ||||
| func (r *mockRunner) fetchNoTask(t *testing.T, timeout ...time.Duration) { | ||||
| 	task := r.tryFetchTask(t, timeout...) | ||||
| 	assert.Nil(t, task, "a task is fetched") | ||||
| } | ||||
|  | ||||
| const defaultFetchTaskTimeout = 1 * time.Second | ||||
|  | ||||
| func (r *mockRunner) tryFetchTask(t *testing.T, timeout ...time.Duration) *runnerv1.Task { | ||||
| 	fetchTimeout := defaultFetchTaskTimeout | ||||
| 	if len(timeout) > 0 { | ||||
| 		fetchTimeout = timeout[0] | ||||
| 	} | ||||
| @@ -108,9 +121,9 @@ func (r *mockRunner) fetchTask(t *testing.T, timeout ...time.Duration) *runnerv1 | ||||
| 			task = resp.Msg.Task | ||||
| 			break | ||||
| 		} | ||||
| 		time.Sleep(time.Second) | ||||
| 		time.Sleep(200 * time.Millisecond) | ||||
| 	} | ||||
| 	assert.NotNil(t, task, "failed to fetch a task") | ||||
|  | ||||
| 	return task | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user