diff --git a/modules/structs/repo_actions.go b/modules/structs/repo_actions.go index af75bbd669..1dea877f19 100644 --- a/modules/structs/repo_actions.go +++ b/modules/structs/repo_actions.go @@ -33,18 +33,19 @@ type ActionTaskResponse struct { TotalCount int64 `json:"total_count"` } -// CreateActionWorkflowDispatch represents the data structure for dispatching a workflow action. -// -// swagger:model CreateActionWorkflowDispatch +// CreateActionWorkflowDispatch represents the payload for triggering a workflow dispatch event +// swagger:model type CreateActionWorkflowDispatch struct { // required: true - Ref string `json:"ref"` - Inputs map[string]interface{} `json:"inputs"` + // example: refs/heads/main + Ref string `json:"ref" binding:"Required"` + // required: false + Inputs map[string]any `json:"inputs,omitempty"` } // ActionWorkflow represents a ActionWorkflow type ActionWorkflow struct { - ID int64 `json:"id"` + ID string `json:"id"` NodeID string `json:"node_id"` Name string `json:"name"` Path string `json:"path"` diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 31a94c57b5..a2cae73bee 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -873,7 +873,9 @@ func Routes() *web.Router { m.Group("/workflows", func() { m.Get("", reqToken(), reqChecker, actw.ListRepositoryWorkflows) m.Get("/{workflow_id}", reqToken(), reqChecker, actw.GetWorkflow) + m.Put("/{workflow_id}/disable", reqToken(), reqChecker, actw.DisableWorkflow) m.Post("/{workflow_id}/dispatches", reqToken(), reqChecker, bind(api.CreateActionWorkflowDispatch{}), actw.DispatchWorkflow) + m.Put("/{workflow_id}/enable", reqToken(), reqChecker, actw.EnableWorkflow) }, context.ReferencesGitRepo(), reqRepoWriter(unit.TypeCode)) }) } diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 905748bf80..a113b77859 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -4,17 +4,8 @@ package repo import ( - "code.gitea.io/gitea/models/perm" - access_model "code.gitea.io/gitea/models/perm/access" - "code.gitea.io/gitea/models/unit" - "code.gitea.io/gitea/modules/actions" - "code.gitea.io/gitea/modules/git" "errors" - "github.com/nektos/act/pkg/jobparser" - "github.com/nektos/act/pkg/model" "net/http" - "strconv" - "strings" actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" @@ -629,7 +620,20 @@ func (a ActionWorkflow) ListRepositoryWorkflows(ctx *context.APIContext) { // "$ref": "#/responses/conflict" // "422": // "$ref": "#/responses/validationError" - panic("implement me") + // "500": + // "$ref": "#/responses/error" + + workflows, err := actions_service.ListActionWorkflows(ctx) + if err != nil { + return + } + + if len(workflows) == 0 { + ctx.JSON(http.StatusNotFound, nil) + } + + ctx.SetTotalCountHeader(int64(len(workflows))) + ctx.JSON(http.StatusOK, workflows) } func (a ActionWorkflow) GetWorkflow(ctx *context.APIContext) { @@ -667,7 +671,75 @@ func (a ActionWorkflow) GetWorkflow(ctx *context.APIContext) { // "$ref": "#/responses/conflict" // "422": // "$ref": "#/responses/validationError" - panic("implement me") + // "500": + // "$ref": "#/responses/error" + + workflowID := ctx.PathParam("workflow_id") + if len(workflowID) == 0 { + ctx.Error(http.StatusUnprocessableEntity, "MissingWorkflowParameter", util.NewInvalidArgumentErrorf("workflow_id is required parameter")) + return + } + + workflow, err := actions_service.GetActionWorkflow(ctx, workflowID) + if err != nil { + return + } + + if workflow == nil { + ctx.JSON(http.StatusNotFound, nil) + } + + ctx.JSON(http.StatusOK, workflow) +} + +func (a ActionWorkflow) DisableWorkflow(ctx *context.APIContext) { + // swagger:operation PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/disable repository DisableWorkflow + // --- + // summary: Disable a workflow + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: workflow_id + // in: path + // description: id of the workflow + // type: string + // required: true + // responses: + // "204": + // description: No Content + // "400": + // "$ref": "#/responses/error" + // "403": + // "$ref": "#/responses/forbidden" + // "404": + // "$ref": "#/responses/notFound" + // "409": + // "$ref": "#/responses/conflict" + // "422": + // "$ref": "#/responses/validationError" + + workflowID := ctx.PathParam("workflow_id") + if len(workflowID) == 0 { + ctx.Error(http.StatusUnprocessableEntity, "MissingWorkflowParameter", util.NewInvalidArgumentErrorf("workflow_id is required parameter")) + return + } + + err := actions_service.DisableActionWorkflow(ctx, workflowID) + if err != nil { + ctx.Error(http.StatusInternalServerError, "DisableActionWorkflow", err) + } + + ctx.Status(http.StatusNoContent) } func (a ActionWorkflow) DispatchWorkflow(ctx *context.APIContext) { @@ -724,137 +796,57 @@ func (a ActionWorkflow) DispatchWorkflow(ctx *context.APIContext) { return } - // can not rerun job when workflow is disabled - cfgUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions) - cfg := cfgUnit.ActionsConfig() - if cfg.IsWorkflowDisabled(workflowID) { - ctx.Error(http.StatusInternalServerError, "WorkflowDisabled", ctx.Tr("actions.workflow.disabled")) - return - } - - // get target commit of run from specified ref - refName := git.RefName(ref) - var runTargetCommit *git.Commit - var err error - if refName.IsTag() { - runTargetCommit, err = ctx.Repo.GitRepo.GetTagCommit(refName.TagName()) - } else if refName.IsBranch() { - // [E] PANIC: runtime error: invalid memory address or nil pointer dereference - runTargetCommit, err = ctx.Repo.GitRepo.GetBranchCommit(refName.BranchName()) - } else { - ctx.Error(http.StatusInternalServerError, "WorkflowRefNameError", ctx.Tr("form.git_ref_name_error", ref)) - return - } - if err != nil { - ctx.Error(http.StatusNotFound, "WorkflowRefNotFound", ctx.Tr("form.target_ref_not_exist", ref)) - return - } - - // get workflow entry from default branch commit - defaultBranchCommit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) - if err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowDefaultBranchError", err.Error()) - return - } - entries, err := actions.ListWorkflows(defaultBranchCommit) - if err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowListError", err.Error()) - } - - // find workflow from commit - var workflows []*jobparser.SingleWorkflow - for _, entry := range entries { - if entry.Name() == workflowID { - content, err := actions.GetContentFromEntry(entry) - if err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowGetContentError", err.Error()) - return - } - workflows, err = jobparser.Parse(content) - if err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowParseError", err.Error()) - return - } - break - } - } - - if len(workflows) == 0 { - ctx.Error(http.StatusNotFound, "WorkflowNotFound", ctx.Tr("actions.workflow.not_found", workflowID)) - return - } - - workflow := &model.Workflow{ - RawOn: workflows[0].RawOn, - } - inputs := make(map[string]any) - if workflowDispatch := workflow.WorkflowDispatchConfig(); workflowDispatch != nil { - for name, config := range workflowDispatch.Inputs { - value, exists := opt.Inputs[name] - if !exists { - continue - } - if config.Type == "boolean" { - inputs[name] = strconv.FormatBool(value == "on") - } else if value != "" { - inputs[name] = value.(string) - } else { - inputs[name] = config.Default - } - } - } - - workflowDispatchPayload := &api.WorkflowDispatchPayload{ - Workflow: workflowID, - Ref: ref, - Repository: convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}), - Inputs: inputs, - Sender: convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone), - } - var eventPayload []byte - if eventPayload, err = workflowDispatchPayload.JSONPayload(); err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowDispatchJSONParseError", err.Error()) - return - } - - run := &actions_model.ActionRun{ - Title: strings.SplitN(runTargetCommit.CommitMessage, "\n", 2)[0], - RepoID: ctx.Repo.Repository.ID, - OwnerID: ctx.Repo.Repository.Owner.ID, - WorkflowID: workflowID, - TriggerUserID: ctx.Doer.ID, - Ref: ref, - CommitSHA: runTargetCommit.ID.String(), - IsForkPullRequest: false, - Event: "workflow_dispatch", - TriggerEvent: "workflow_dispatch", - EventPayload: string(eventPayload), - Status: actions_model.StatusWaiting, - } - - // cancel running jobs of the same workflow - if err := actions_model.CancelPreviousJobs( - ctx, - run.RepoID, - run.Ref, - run.WorkflowID, - run.Event, - ); err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowCancelPreviousJobsError", err.Error()) - return - } - - if err := actions_model.InsertRun(ctx, run, workflows); err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowInsertRunError", err.Error()) - return - } - - alljobs, err := db.Find[actions_model.ActionRunJob](ctx, actions_model.FindRunJobOptions{RunID: run.ID}) - if err != nil { - ctx.Error(http.StatusInternalServerError, "WorkflowFindRunJobError", err.Error()) - return - } - actions_service.CreateCommitStatus(ctx, alljobs...) + actions_service.DispatchActionWorkflow(ctx, workflowID, opt) + + ctx.Status(http.StatusNoContent) +} + +func (a ActionWorkflow) EnableWorkflow(ctx *context.APIContext) { + // swagger:operation PUT /repos/{owner}/{repo}/actions/workflows/{workflow_id}/enable repository EnableWorkflow + // --- + // summary: Enable a workflow + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: workflow_id + // in: path + // description: id of the workflow + // type: string + // required: true + // responses: + // "204": + // description: No Content + // "400": + // "$ref": "#/responses/error" + // "403": + // "$ref": "#/responses/forbidden" + // "404": + // "$ref": "#/responses/notFound" + // "409": + // "$ref": "#/responses/conflict" + // "422": + // "$ref": "#/responses/validationError" + + workflowID := ctx.PathParam("workflow_id") + if len(workflowID) == 0 { + ctx.Error(http.StatusUnprocessableEntity, "MissingWorkflowParameter", util.NewInvalidArgumentErrorf("workflow_id is required parameter")) + return + } + + err := actions_service.EnableActionWorkflow(ctx, workflowID) + if err != nil { + ctx.Error(http.StatusInternalServerError, "EnableActionWorkflow", err) + } ctx.Status(http.StatusNoContent) } diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go index 1de58632d5..1c61e11a12 100644 --- a/routers/api/v1/swagger/options.go +++ b/routers/api/v1/swagger/options.go @@ -203,6 +203,9 @@ type swaggerParameterBodies struct { // in:body CreateVariableOption api.CreateVariableOption + // in:body + CreateActionWorkflowDispatch api.CreateActionWorkflowDispatch + // in:body UpdateVariableOption api.UpdateVariableOption } diff --git a/services/actions/workflow.go b/services/actions/workflow.go new file mode 100644 index 0000000000..eecfff008a --- /dev/null +++ b/services/actions/workflow.go @@ -0,0 +1,245 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "fmt" + "net/http" + "strconv" + "strings" + + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/modules/actions" + "code.gitea.io/gitea/modules/git" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/convert" + + "github.com/nektos/act/pkg/jobparser" + "github.com/nektos/act/pkg/model" +) + +func getActionWorkflowEntry(ctx *context.APIContext, entry *git.TreeEntry, commit *git.Commit) (*api.ActionWorkflow, error) { + cfgUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions) + cfg := cfgUnit.ActionsConfig() + + URL := fmt.Sprintf("%s/actions/workflows/%s", ctx.Repo.Repository.APIURL(), entry.Name()) + badgeURL := fmt.Sprintf("%s/actions/workflows/%s/badge.svg?branch=%s", ctx.Repo.Repository.HTMLURL(ctx), entry.Name(), ctx.Repo.Repository.DefaultBranch) + + // See https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#get-a-workflow + // State types: + // - active + // - deleted + // - disabled_fork + // - disabled_inactivity + // - disabled_manually + state := "active" + if cfg.IsWorkflowDisabled(entry.Name()) { + state = "disabled_manually" + } + + // TODO: NodeID + // TODO: CreatedAt + // TODO: UpdatedAt + // TODO: HTMLURL + // TODO: DeletedAt + + return &api.ActionWorkflow{ + ID: entry.Name(), + Name: entry.Name(), + Path: entry.Name(), + State: state, + URL: URL, + BadgeURL: badgeURL, + }, nil +} + +func disableOrEnableWorkflow(ctx *context.APIContext, workflowID string, isEnable bool) error { + cfgUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions) + cfg := cfgUnit.ActionsConfig() + + if isEnable { + cfg.EnableWorkflow(workflowID) + } else { + cfg.DisableWorkflow(workflowID) + } + + return repo_model.UpdateRepoUnit(ctx, cfgUnit) +} + +func ListActionWorkflows(ctx *context.APIContext) ([]*api.ActionWorkflow, error) { + defaultBranchCommit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) + if err != nil { + ctx.Error(http.StatusInternalServerError, "WorkflowDefaultBranchError", err.Error()) + return nil, err + } + + entries, err := actions.ListWorkflows(defaultBranchCommit) + if err != nil { + ctx.Error(http.StatusNotFound, "WorkflowListNotFound", err.Error()) + return nil, err + } + + workflows := make([]*api.ActionWorkflow, len(entries)) + for i, entry := range entries { + workflows[i], err = getActionWorkflowEntry(ctx, entry, defaultBranchCommit) + if err != nil { + ctx.Error(http.StatusInternalServerError, "WorkflowGetError", err.Error()) + return nil, err + } + } + + return workflows, nil +} + +func GetActionWorkflow(ctx *context.APIContext, workflowID string) (*api.ActionWorkflow, error) { + entries, err := ListActionWorkflows(ctx) + if err != nil { + return nil, err + } + + workflows := make([]*api.ActionWorkflow, len(entries)) + for i, entry := range entries { + if entry.Name == workflowID { + workflows[i] = entry + break + } + } + + return workflows[len(workflows)-1], nil +} + +func DisableActionWorkflow(ctx *context.APIContext, workflowID string) error { + return disableOrEnableWorkflow(ctx, workflowID, false) +} + +func DispatchActionWorkflow(ctx *context.APIContext, workflowID string, opt *api.CreateActionWorkflowDispatch) { + // can not run job when workflow is disabled + cfgUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeActions) + cfg := cfgUnit.ActionsConfig() + if cfg.IsWorkflowDisabled(workflowID) { + ctx.Error(http.StatusInternalServerError, "WorkflowDisabled", ctx.Tr("actions.workflow.disabled")) + return + } + + // get target commit of run from specified ref + refName := git.RefName(opt.Ref) + var runTargetCommit *git.Commit + var err error + if refName.IsTag() { + runTargetCommit, err = ctx.Repo.GitRepo.GetTagCommit(refName.TagName()) + } else if refName.IsBranch() { + runTargetCommit, err = ctx.Repo.GitRepo.GetBranchCommit(refName.BranchName()) + } else { + ctx.Error(http.StatusInternalServerError, "WorkflowRefNameError", ctx.Tr("form.git_ref_name_error", opt.Ref)) + return + } + if err != nil { + ctx.Error(http.StatusNotFound, "WorkflowRefNotFound", ctx.Tr("form.target_ref_not_exist", opt.Ref)) + return + } + + // get workflow entry from default branch commit + defaultBranchCommit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) + if err != nil { + ctx.Error(http.StatusInternalServerError, "WorkflowDefaultBranchError", err.Error()) + return + } + entries, err := actions.ListWorkflows(defaultBranchCommit) + if err != nil { + ctx.Error(http.StatusNotFound, "WorkflowListNotFound", err.Error()) + } + + // find workflow from commit + var workflows []*jobparser.SingleWorkflow + for _, entry := range entries { + if entry.Name() == workflowID { + content, err := actions.GetContentFromEntry(entry) + if err != nil { + ctx.Error(http.StatusInternalServerError, "WorkflowGetContentError", err.Error()) + return + } + workflows, err = jobparser.Parse(content) + if err != nil { + ctx.Error(http.StatusInternalServerError, "WorkflowParseError", err.Error()) + return + } + break + } + } + + if len(workflows) == 0 { + ctx.Error(http.StatusNotFound, "WorkflowNotFound", ctx.Tr("actions.workflow.not_found", workflowID)) + return + } + + workflow := &model.Workflow{ + RawOn: workflows[0].RawOn, + } + inputs := make(map[string]any) + if workflowDispatch := workflow.WorkflowDispatchConfig(); workflowDispatch != nil { + for name, config := range workflowDispatch.Inputs { + value, exists := opt.Inputs[name] + if !exists { + continue + } + if config.Type == "boolean" { + inputs[name] = strconv.FormatBool(value == "on") + } else if value != "" { + inputs[name] = value + } else { + inputs[name] = config.Default + } + } + } + + workflowDispatchPayload := &api.WorkflowDispatchPayload{ + Workflow: workflowID, + Ref: opt.Ref, + Repository: convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}), + Inputs: inputs, + Sender: convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone), + } + var eventPayload []byte + if eventPayload, err = workflowDispatchPayload.JSONPayload(); err != nil { + ctx.Error(http.StatusInternalServerError, "WorkflowDispatchJSONParseError", err.Error()) + return + } + + run := &actions_model.ActionRun{ + Title: strings.SplitN(runTargetCommit.CommitMessage, "\n", 2)[0], + RepoID: ctx.Repo.Repository.ID, + OwnerID: ctx.Repo.Repository.Owner.ID, + WorkflowID: workflowID, + TriggerUserID: ctx.Doer.ID, + Ref: opt.Ref, + CommitSHA: runTargetCommit.ID.String(), + IsForkPullRequest: false, + Event: "workflow_dispatch", + TriggerEvent: "workflow_dispatch", + EventPayload: string(eventPayload), + Status: actions_model.StatusWaiting, + } + + if err := actions_model.InsertRun(ctx, run, workflows); err != nil { + ctx.Error(http.StatusInternalServerError, "WorkflowInsertRunError", err.Error()) + return + } + + alljobs, err := db.Find[actions_model.ActionRunJob](ctx, actions_model.FindRunJobOptions{RunID: run.ID}) + if err != nil { + ctx.Error(http.StatusInternalServerError, "WorkflowFindRunJobError", err.Error()) + return + } + CreateCommitStatus(ctx, alljobs...) +} + +func EnableActionWorkflow(ctx *context.APIContext, workflowID string) error { + return disableOrEnableWorkflow(ctx, workflowID, true) +} diff --git a/services/actions/workflow_interface.go b/services/actions/workflow_interface.go index dfb108e024..43fa92bdf8 100644 --- a/services/actions/workflow_interface.go +++ b/services/actions/workflow_interface.go @@ -11,6 +11,10 @@ type WorkflowAPI interface { ListRepositoryWorkflows(*context.APIContext) // GetWorkflow get a workflow GetWorkflow(*context.APIContext) + // DisableWorkflow disable a workflow + DisableWorkflow(*context.APIContext) // DispatchWorkflow create a workflow dispatch event DispatchWorkflow(*context.APIContext) + // EnableWorkflow enable a workflow + EnableWorkflow(*context.APIContext) } diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 43967b9fd1..ae4384f723 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -4389,6 +4389,9 @@ }, "422": { "$ref": "#/responses/validationError" + }, + "500": { + "$ref": "#/responses/error" } } } @@ -4442,6 +4445,64 @@ "409": { "$ref": "#/responses/conflict" }, + "422": { + "$ref": "#/responses/validationError" + }, + "500": { + "$ref": "#/responses/error" + } + } + } + }, + "/repos/{owner}/{repo}/actions/workflows/{workflow_id}/disable": { + "put": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Disable a workflow", + "operationId": "DisableWorkflow", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "id of the workflow", + "name": "workflow_id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "$ref": "#/responses/error" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "404": { + "$ref": "#/responses/notFound" + }, + "409": { + "$ref": "#/responses/conflict" + }, "422": { "$ref": "#/responses/validationError" } @@ -4510,6 +4571,61 @@ } } }, + "/repos/{owner}/{repo}/actions/workflows/{workflow_id}/enable": { + "put": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "Enable a workflow", + "operationId": "EnableWorkflow", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "id of the workflow", + "name": "workflow_id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "$ref": "#/responses/error" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "404": { + "$ref": "#/responses/notFound" + }, + "409": { + "$ref": "#/responses/conflict" + }, + "422": { + "$ref": "#/responses/validationError" + } + } + } + }, "/repos/{owner}/{repo}/activities/feeds": { "get": { "produces": [ @@ -18564,8 +18680,7 @@ "x-go-name": "HTMLURL" }, "id": { - "type": "integer", - "format": "int64", + "type": "string", "x-go-name": "ID" }, "name": { @@ -19595,6 +19710,26 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "CreateActionWorkflowDispatch": { + "description": "CreateActionWorkflowDispatch represents the payload for triggering a workflow dispatch event", + "type": "object", + "required": [ + "ref" + ], + "properties": { + "inputs": { + "type": "object", + "additionalProperties": {}, + "x-go-name": "Inputs" + }, + "ref": { + "type": "string", + "x-go-name": "Ref", + "example": "refs/heads/main" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "CreateBranchProtectionOption": { "description": "CreateBranchProtectionOption options for creating a branch protection", "type": "object",