feat(workflows): add dispatch, view, enable and disable subcommands (#952)

## Summary

- Add `tea actions workflows dispatch` to trigger `workflow_dispatch` events with `--ref`, `--input key=value`, and `--follow` for log tailing
- Add `tea actions workflows view` to show workflow details
- Add `tea actions workflows enable` and `disable` to toggle workflow state
- Rewrite `workflows list` to use the Workflow API instead of file listing
- Remove dead `WorkflowsList` print function that used `ContentsResponse`
- Update `CLI.md` and `example-workflows.md` with usage documentation and examples

## Motivation

Enable re-triggering specific workflows from the CLI, which is essential for AI-driven PR flows where a specific workflow needs to be re-run after pushing changes.

Leverages the 5 workflow API endpoints already supported by the Go SDK (v0.24.1) from go-gitea/gitea#33545:
- `ListRepoActionWorkflows`
- `GetRepoActionWorkflow`
- `DispatchRepoActionWorkflow` (with `returnRunDetails` support)
- `EnableRepoActionWorkflow`
- `DisableRepoActionWorkflow`

## New commands

\`\`\`
tea actions workflows
├── list          (rewritten to use Workflow API)
├── view <id>     (new)
├── dispatch <id> (new)
├── enable <id>   (new)
└── disable <id>  (new)
\`\`\`

### Usage examples

\`\`\`bash
# Dispatch workflow on current branch
tea actions workflows dispatch deploy.yml

# Dispatch with specific ref and inputs
tea actions workflows dispatch deploy.yml --ref main --input env=staging --input version=1.2.3

# Dispatch and follow logs
tea actions workflows dispatch ci.yml --ref feature/my-pr --follow

# View workflow details
tea actions workflows view deploy.yml

# Enable/disable workflows
tea actions workflows enable deploy.yml
tea actions workflows disable deploy.yml --confirm
\`\`\`

## Test plan

- [x] `go build ./...` passes
- [x] `go test ./...` passes
- [x] `go vet ./...` passes
- [x] `make lint` — 0 issues
- [x] `make docs-check` — CLI.md is up to date
- [x] Manual test: `tea actions workflows list` shows workflows from API
- [x] Manual test: `tea actions workflows dispatch <workflow> --ref main` triggers a run
- [x] Manual test: `tea actions workflows view <workflow>` shows details

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/gitea/tea/pulls/952
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Bo-Yi Wu <appleboy.tw@gmail.com>
Co-committed-by: Bo-Yi Wu <appleboy.tw@gmail.com>
This commit is contained in:
Bo-Yi Wu
2026-04-09 20:03:33 +00:00
committed by Lunny Xiao
parent 0489d8c275
commit 53e53e1067
10 changed files with 611 additions and 66 deletions

View File

@@ -6,8 +6,6 @@ package workflows
import (
stdctx "context"
"fmt"
"path/filepath"
"strings"
"code.gitea.io/tea/cmd/flags"
"code.gitea.io/tea/modules/context"
@@ -22,15 +20,12 @@ var CmdWorkflowsList = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List repository workflows",
Description: "List workflow files in the repository with active/inactive status",
Description: "List workflows in the repository with their status",
Action: RunWorkflowsList,
Flags: append([]cli.Flag{
&flags.PaginationPageFlag,
&flags.PaginationLimitFlag,
}, flags.AllDefaultFlags...),
Flags: flags.AllDefaultFlags,
}
// RunWorkflowsList lists workflow files in the repository
// RunWorkflowsList lists workflows in the repository using the workflow API
func RunWorkflowsList(ctx stdctx.Context, cmd *cli.Command) error {
c, err := context.InitCommand(cmd)
if err != nil {
@@ -41,51 +36,15 @@ func RunWorkflowsList(ctx stdctx.Context, cmd *cli.Command) error {
}
client := c.Login.Client()
// Try to list workflow files from .gitea/workflows directory
var workflows []*gitea.ContentsResponse
// Try .gitea/workflows first, then .github/workflows
workflowDir := ".gitea/workflows"
contents, _, err := client.ListContents(c.Owner, c.Repo, "", workflowDir)
resp, _, err := client.ListRepoActionWorkflows(c.Owner, c.Repo)
if err != nil {
workflowDir = ".github/workflows"
contents, _, err = client.ListContents(c.Owner, c.Repo, "", workflowDir)
if err != nil {
fmt.Printf("No workflow files found\n")
return nil
}
return fmt.Errorf("failed to list workflows: %w", err)
}
// Filter for workflow files (.yml and .yaml)
for _, content := range contents {
if content.Type == "file" {
ext := strings.ToLower(filepath.Ext(content.Name))
if ext == ".yml" || ext == ".yaml" {
content.Path = workflowDir + "/" + content.Name
workflows = append(workflows, content)
}
}
var workflows []*gitea.ActionWorkflow
if resp != nil {
workflows = resp.Workflows
}
if len(workflows) == 0 {
fmt.Printf("No workflow files found\n")
return nil
}
// Check which workflows have runs to determine active status
workflowStatus := make(map[string]bool)
// Get recent runs to check activity
runs, _, err := client.ListRepoActionRuns(c.Owner, c.Repo, gitea.ListRepoActionRunsOptions{
ListOptions: flags.GetListOptions(cmd),
})
if err == nil && runs != nil {
for _, run := range runs.WorkflowRuns {
// Extract workflow file name from path
workflowFile := filepath.Base(run.Path)
workflowStatus[workflowFile] = true
}
}
return print.WorkflowsList(workflows, workflowStatus, c.Output)
return print.ActionWorkflowsList(workflows, c.Output)
}