Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions modules/structs/repo_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,10 @@ type ActionRunnersResponse struct {
Entries []*ActionRunner `json:"runners"`
TotalCount int64 `json:"total_count"`
}

// RunDetails returns workflow_dispatch runid and url
type RunDetails struct {
WorkflowRunID int64 `json:"workflow_run_id"`
RunURL string `json:"run_url"`
HTMLURL string `json:"html_url"`
}
27 changes: 24 additions & 3 deletions routers/api/v1/repo/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -1004,9 +1004,15 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) {
// in: body
// schema:
// "$ref": "#/definitions/CreateActionWorkflowDispatch"
// - name: return_run_details
// description: Whether the response should include the workflow run ID and URLs.
// in: query
// type: boolean
// responses:
// "200":
// "$ref": "#/responses/RunDetails"
// "204":
// description: No Content
// description: No Content, if return_run_details is missing or false
// "400":
// "$ref": "#/responses/error"
// "403":
Expand All @@ -1023,7 +1029,7 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) {
return
}

err := actions_service.DispatchActionWorkflow(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, workflowID, opt.Ref, func(workflowDispatch *model.WorkflowDispatch, inputs map[string]any) error {
runID, err := actions_service.DispatchActionWorkflow(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, workflowID, opt.Ref, func(workflowDispatch *model.WorkflowDispatch, inputs map[string]any) error {
if strings.Contains(ctx.Req.Header.Get("Content-Type"), "form-urlencoded") {
// The chi framework's "Binding" doesn't support to bind the form map values into a map[string]string
// So we have to manually read the `inputs[key]` from the form
Expand Down Expand Up @@ -1054,7 +1060,22 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) {
return
}

ctx.Status(http.StatusNoContent)
if !ctx.FormBool("return_run_details") {
ctx.Status(http.StatusNoContent)
return
}

workflowRun, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID)
if err != nil {
ctx.APIErrorInternal(err)
return
}

ctx.JSON(http.StatusOK, &api.RunDetails{
WorkflowRunID: runID,
HTMLURL: fmt.Sprintf("%s/actions/runs/%d", ctx.Repo.Repository.HTMLURL(ctx), workflowRun.Index),
RunURL: fmt.Sprintf("%s/actions/runs/%d", ctx.Repo.Repository.APIURL(), runID),
})
}

func ActionsEnableWorkflow(ctx *context.APIContext) {
Expand Down
7 changes: 7 additions & 0 deletions routers/api/v1/swagger/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,10 @@ type swaggerResponseActionWorkflowList struct {
// in:body
Body api.ActionWorkflowResponse `json:"body"`
}

// RunDetails
// swagger:response RunDetails
type swaggerResponseRunDetails struct {
// in:body
Body api.RunDetails `json:"body"`
}
2 changes: 1 addition & 1 deletion routers/web/repo/actions/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ func Run(ctx *context_module.Context) {
ctx.ServerError("ref", nil)
return
}
err := actions_service.DispatchActionWorkflow(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, workflowID, ref, func(workflowDispatch *model.WorkflowDispatch, inputs map[string]any) error {
_, err := actions_service.DispatchActionWorkflow(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, workflowID, ref, func(workflowDispatch *model.WorkflowDispatch, inputs map[string]any) error {
for name, config := range workflowDispatch.Inputs {
value := ctx.Req.PostFormValue(name)
if config.Type == "boolean" {
Expand Down
26 changes: 13 additions & 13 deletions services/actions/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ func EnableOrDisableWorkflow(ctx *context.APIContext, workflowID string, isEnabl
return repo_model.UpdateRepoUnit(ctx, cfgUnit)
}

func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, workflowID, ref string, processInputs func(model *model.WorkflowDispatch, inputs map[string]any) error) error {
func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, workflowID, ref string, processInputs func(model *model.WorkflowDispatch, inputs map[string]any) error) (runID int64, _ error) {
if workflowID == "" {
return util.ErrorWrapTranslatable(
return 0, util.ErrorWrapTranslatable(
util.NewNotExistErrorf("workflowID is empty"),
"actions.workflow.not_found", workflowID,
)
}

if ref == "" {
return util.ErrorWrapTranslatable(
return 0, util.ErrorWrapTranslatable(
util.NewNotExistErrorf("ref is empty"),
"form.target_ref_not_exist", ref,
)
Expand All @@ -63,7 +63,7 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
cfgUnit := repo.MustGetUnit(ctx, unit.TypeActions)
cfg := cfgUnit.ActionsConfig()
if cfg.IsWorkflowDisabled(workflowID) {
return util.ErrorWrapTranslatable(
return 0, util.ErrorWrapTranslatable(
util.NewPermissionDeniedErrorf("workflow is disabled"),
"actions.workflow.disabled",
)
Expand All @@ -82,7 +82,7 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
runTargetCommit, err = gitRepo.GetBranchCommit(ref)
}
if err != nil {
return util.ErrorWrapTranslatable(
return 0, util.ErrorWrapTranslatable(
util.NewNotExistErrorf("ref %q doesn't exist", ref),
"form.target_ref_not_exist", ref,
)
Expand All @@ -91,7 +91,7 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
// get workflow entry from runTargetCommit
_, entries, err := actions.ListWorkflows(runTargetCommit)
if err != nil {
return err
return 0, err
}

// find workflow from commit
Expand Down Expand Up @@ -122,20 +122,20 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
}

if entry == nil {
return util.ErrorWrapTranslatable(
return 0, util.ErrorWrapTranslatable(
util.NewNotExistErrorf("workflow %q doesn't exist", workflowID),
"actions.workflow.not_found", workflowID,
)
}

content, err := actions.GetContentFromEntry(entry)
if err != nil {
return err
return 0, err
}

singleWorkflow := &jobparser.SingleWorkflow{}
if err := yaml.Unmarshal(content, singleWorkflow); err != nil {
return fmt.Errorf("failed to unmarshal workflow content: %w", err)
return 0, fmt.Errorf("failed to unmarshal workflow content: %w", err)
}
// get inputs from post
workflow := &model.Workflow{
Expand All @@ -144,7 +144,7 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
inputsWithDefaults := make(map[string]any)
if workflowDispatch := workflow.WorkflowDispatchConfig(); workflowDispatch != nil {
if err = processInputs(workflowDispatch, inputsWithDefaults); err != nil {
return err
return 0, err
}
}

Expand All @@ -161,13 +161,13 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re

var eventPayload []byte
if eventPayload, err = workflowDispatchPayload.JSONPayload(); err != nil {
return fmt.Errorf("JSONPayload: %w", err)
return 0, fmt.Errorf("JSONPayload: %w", err)
}
run.EventPayload = string(eventPayload)

// Insert the action run and its associated jobs into the database
if err := PrepareRunAndInsert(ctx, content, run, inputsWithDefaults); err != nil {
return fmt.Errorf("PrepareRun: %w", err)
return 0, fmt.Errorf("PrepareRun: %w", err)
}
return nil
return run.ID, nil
}
37 changes: 36 additions & 1 deletion templates/swagger/v1_json.tmpl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions tests/integration/actions_trigger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
files_service "code.gitea.io/gitea/services/repository/files"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestPullRequestTargetEvent(t *testing.T) {
Expand Down Expand Up @@ -906,6 +907,27 @@ jobs:
CommitSHA: branch.CommitID,
})
assert.NotNil(t, run)

// Now trigger with rundetails
values.Set("return_run_details", "true")

req = NewRequestWithURLValues(t, "POST", fmt.Sprintf("/api/v1/repos/%s/actions/workflows/dispatch.yml/dispatches", repo.FullName()), values).
AddTokenAuth(token)
resp := MakeRequest(t, req, http.StatusOK)
runDetails := &api.RunDetails{}
require.NoError(t, json.NewDecoder(resp.Body).Decode(runDetails))
assert.NotEqual(t, 0, runDetails.WorkflowRunID)

run = unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{
ID: runDetails.WorkflowRunID,
Title: "add workflow",
RepoID: repo.ID,
Event: "workflow_dispatch",
Ref: "refs/heads/main",
WorkflowID: "dispatch.yml",
CommitSHA: branch.CommitID,
})
assert.NotNil(t, run)
})
}

Expand Down