Modify the REST endpoint that triggers workflows to provide the data required to track the progress of those workflows.

This commit is contained in:
Mark Turney 2025-03-10 11:52:12 +04:00
commit 69dd7cb15d
7 changed files with 87 additions and 13 deletions

View file

@ -13,3 +13,12 @@ type DispatchWorkflowOption struct {
// Input keys and values configured in the workflow file.
Inputs map[string]string `json:"inputs"`
}
// DispatchWorkflowRun represents a workflow run
// swagger:model
type DispatchWorkflowRun struct {
// the workflow run id
ID int64 `json:"id"`
// the jobs name
Jobs []string `json:"jobs"`
}

View file

@ -639,7 +639,11 @@ func DispatchWorkflow(ctx *context.APIContext) {
// in: body
// schema:
// "$ref": "#/definitions/DispatchWorkflowOption"
// produces:
// - application/json
// responses:
// "201":
// "$ref": "#/responses/DispatchWorkflowRun"
// "204":
// "$ref": "#/responses/empty"
// "404":
@ -670,7 +674,8 @@ func DispatchWorkflow(ctx *context.APIContext) {
return opt.Inputs[key]
}
if err := workflow.Dispatch(ctx, inputGetter, ctx.Repo.Repository, ctx.Doer); err != nil {
run, jobs, err := workflow.Dispatch(ctx, inputGetter, ctx.Repo.Repository, ctx.Doer)
if err != nil {
if actions_service.IsInputRequiredErr(err) {
ctx.Error(http.StatusBadRequest, "workflow.Dispatch", err)
} else {
@ -679,5 +684,10 @@ func DispatchWorkflow(ctx *context.APIContext) {
return
}
ctx.JSON(http.StatusNoContent, nil)
workflowRun := &api.DispatchWorkflowRun{
ID: run.ID,
Jobs: jobs,
}
ctx.JSON(http.StatusCreated, workflowRun)
}

View file

@ -39,3 +39,10 @@ type swaggerRunJobList struct {
// in:body
Body []*api.ActionRunJob `json:"body"`
}
// DispatchWorkflowRun is a Workflow Run after dispatching
// swagger:response DispatchWorkflowRun
type swaggerDispatchWorkflowRun struct {
// in:body
Body *api.DispatchWorkflowRun `json:"body"`
}

View file

@ -46,7 +46,8 @@ func ManualRunWorkflow(ctx *context_module.Context) {
return ctx.Req.PostFormValue(formKey)
}
if err := workflow.Dispatch(ctx, formKeyGetter, ctx.Repo.Repository, ctx.Doer); err != nil {
_, _, err = workflow.Dispatch(ctx, formKeyGetter, ctx.Repo.Repository, ctx.Doer)
if err != nil {
if actions_service.IsInputRequiredErr(err) {
ctx.Flash.Error(ctx.Locale.Tr("actions.workflow.dispatch.input_required", err.(actions_service.InputRequiredErr).Name))
ctx.Redirect(location)

View file

@ -49,15 +49,15 @@ type Workflow struct {
type InputValueGetter func(key string) string
func (entry *Workflow) Dispatch(ctx context.Context, inputGetter InputValueGetter, repo *repo_model.Repository, doer *user.User) error {
func (entry *Workflow) Dispatch(ctx context.Context, inputGetter InputValueGetter, repo *repo_model.Repository, doer *user.User) (r *actions_model.ActionRun, j []string, err error) {
content, err := actions.GetContentFromEntry(entry.GitEntry)
if err != nil {
return err
return nil, nil, err
}
wf, err := act_model.ReadWorkflow(bytes.NewReader(content))
if err != nil {
return err
return nil, nil, err
}
fullWorkflowID := ".forgejo/workflows/" + entry.WorkflowID
@ -79,7 +79,7 @@ func (entry *Workflow) Dispatch(ctx context.Context, inputGetter InputValueGette
if len(name) == 0 {
name = key
}
return InputRequiredErr{Name: name}
return nil, nil, InputRequiredErr{Name: name}
}
continue
}
@ -92,7 +92,12 @@ func (entry *Workflow) Dispatch(ctx context.Context, inputGetter InputValueGette
}
if int64(len(inputs)) > setting.Actions.LimitDispatchInputs {
return errors.New("to many inputs")
return nil, nil, errors.New("to many inputs")
}
var jobNames []string
for jobName, _ := range wf.Jobs {
jobNames = append(jobNames, jobName)
}
payload := &structs.WorkflowDispatchPayload{
@ -105,7 +110,7 @@ func (entry *Workflow) Dispatch(ctx context.Context, inputGetter InputValueGette
p, err := json.Marshal(payload)
if err != nil {
return err
return nil, nil, err
}
run := &actions_model.ActionRun{
@ -126,15 +131,15 @@ func (entry *Workflow) Dispatch(ctx context.Context, inputGetter InputValueGette
vars, err := actions_model.GetVariablesOfRun(ctx, run)
if err != nil {
return err
return nil, nil, err
}
jobs, err := jobparser.Parse(content, jobparser.WithVars(vars))
if err != nil {
return err
return nil, nil, err
}
return actions_model.InsertRun(ctx, run, jobs)
return run, jobNames, actions_model.InsertRun(ctx, run, jobs)
}
func GetWorkflowFromCommit(gitRepo *git.Repository, ref, workflowID string) (*Workflow, error) {

View file

@ -5378,6 +5378,9 @@
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"repository"
],
@ -5414,6 +5417,9 @@
}
],
"responses": {
"201": {
"$ref": "#/responses/DispatchWorkflowRun"
},
"204": {
"$ref": "#/responses/empty"
},
@ -23132,6 +23138,27 @@
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"DispatchWorkflowRun": {
"description": "DispatchWorkflowRun represents a workflow run",
"type": "object",
"properties": {
"id": {
"description": "the workflow run id",
"type": "integer",
"format": "int64",
"x-go-name": "ID"
},
"jobs": {
"description": "the jobs name",
"type": "array",
"items": {
"type": "string"
},
"x-go-name": "Jobs"
}
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"EditAttachmentOptions": {
"description": "EditAttachmentOptions options for editing attachments",
"type": "object",
@ -28511,6 +28538,12 @@
}
}
},
"DispatchWorkflowRun": {
"description": "DispatchWorkflowRun is a Workflow Run after dispatching",
"schema": {
"$ref": "#/definitions/DispatchWorkflowRun"
}
},
"EmailList": {
"description": "EmailList",
"schema": {

View file

@ -752,9 +752,18 @@ func TestWorkflowDispatchEvent(t *testing.T) {
return ""
}
err = workflow.Dispatch(db.DefaultContext, inputGetter, repo, user2)
var r *actions_model.ActionRun
var j []string
r, j, err = workflow.Dispatch(db.DefaultContext, inputGetter, repo, user2)
require.NoError(t, err)
assert.Equal(t, 1, unittest.GetCount(t, &actions_model.ActionRun{RepoID: repo.ID}))
assert.Equal(t, "test", r.Title)
assert.Equal(t, "dispatch.yml", r.WorkflowID)
assert.Equal(t, sha, r.CommitSHA)
assert.Equal(t, actions_module.GithubEventWorkflowDispatch, r.TriggerEvent)
assert.Len(t, j, 1)
assert.Equal(t, "test", j[0])
})
}