refactor(cmd): unify actions/aliases command trees via factory functions
The remaining audit finding: cmd/aliases.go rebuilt parallel `run *` and
`workflow *` command subtrees by hand to expose them at top level
(matching gh CLI's `gh run list` ergonomics). That duplication is what
let the `--json` Bool/string mismatch fixed in 0c181df slip in — the
flag was registered correctly under `actions run list` but Bool-typed
under the top-level `run list`, and `wantJSON` silently swallowed the
type-error return.
Switch each `run *` and `workflow *` command from a package-level
`var xxxCmd = &cobra.Command{...}` declaration to a factory function
`newXxxCmd() *cobra.Command` that returns a fully-configured Command
(struct, examples, args, RunE, AND its own flag registrations).
Each parent factory (newRunCmd, newWorkflowCmd) takes a `parentLabel`
string that's appended to the parent's Short/Long, so the alias-tree
variant says "(alias for 'actions run')" without the children diverging.
actions.go init() now does:
actionsCmd.AddCommand(newRunCmd(""))
actionsCmd.AddCommand(newWorkflowCmd(""))
aliases.go shrinks from 142 lines to 17 lines:
rootCmd.AddCommand(newRunCmd(" (alias for 'actions run')"))
rootCmd.AddCommand(newWorkflowCmd(" (alias for 'actions workflow')"))
Verified: `diff` of `fj run list --help` flags vs `fj actions run list
--help` flags is empty. Both trees produce IDENTICAL surfaces. Future
flag changes touch one factory and propagate to both paths.
Note: secret/variable subcommands aren't aliased so they keep the
package-level var pattern. Only the run/workflow subtrees moved.
This commit is contained in:
parent
155ddb97ba
commit
373c769d2c
2 changed files with 171 additions and 258 deletions
281
cmd/actions.go
281
cmd/actions.go
|
|
@ -87,18 +87,34 @@ var actionsCmd = &cobra.Command{
|
|||
Long: "View and manage workflows, runs, secrets, and variables for Forgejo Actions in your repositories.",
|
||||
}
|
||||
|
||||
// Run commands (compatible with gh run)
|
||||
var runCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "View and manage workflow runs",
|
||||
Long: "List, view, and manage workflow runs.",
|
||||
// Run and Workflow command trees are built via factory functions
|
||||
// (newRunCmd / newWorkflowCmd) so cmd/aliases.go can build an identical
|
||||
// top-level tree under rootCmd without duplicating Use/Short/Long/Example/
|
||||
// flag declarations. Single source of truth — drift impossible.
|
||||
|
||||
// newRunCmd builds the `run` subtree. parentLabel is interpolated into the
|
||||
// parent's Short/Long so the alias-tree variant can advertise itself as
|
||||
// "alias for 'actions run'" without diverging on the children.
|
||||
func newRunCmd(parentLabel string) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "View and manage workflow runs" + parentLabel,
|
||||
Long: "List, view, and manage workflow runs." + parentLabel,
|
||||
}
|
||||
cmd.AddCommand(newRunListCmd())
|
||||
cmd.AddCommand(newRunViewCmd())
|
||||
cmd.AddCommand(newRunWatchCmd())
|
||||
cmd.AddCommand(newRunRerunCmd())
|
||||
cmd.AddCommand(newRunCancelCmd())
|
||||
return cmd
|
||||
}
|
||||
|
||||
var runListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List recent workflow runs",
|
||||
Long: "List recent workflow runs for a repository.",
|
||||
Example: ` # List recent workflow runs
|
||||
func newRunListCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List recent workflow runs",
|
||||
Long: "List recent workflow runs for a repository.",
|
||||
Example: ` # List recent workflow runs
|
||||
fj actions run list
|
||||
|
||||
# List runs with a custom limit
|
||||
|
|
@ -106,14 +122,20 @@ var runListCmd = &cobra.Command{
|
|||
|
||||
# Output as JSON
|
||||
fj actions run list --json`,
|
||||
RunE: runRunList,
|
||||
RunE: runRunList,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
c.Flags().IntP("limit", "L", 20, "Maximum number of runs to list")
|
||||
addJSONFlags(c, "Output workflow runs as JSON")
|
||||
return c
|
||||
}
|
||||
|
||||
var runViewCmd = &cobra.Command{
|
||||
Use: "view <run-id>",
|
||||
Short: "View a workflow run",
|
||||
Long: "View details about a specific workflow run.",
|
||||
Example: ` # View a workflow run
|
||||
func newRunViewCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "view <run-id>",
|
||||
Short: "View a workflow run",
|
||||
Long: "View details about a specific workflow run.",
|
||||
Example: ` # View a workflow run
|
||||
fj actions run view 123
|
||||
|
||||
# View with job details
|
||||
|
|
@ -124,55 +146,86 @@ var runViewCmd = &cobra.Command{
|
|||
|
||||
# View only failed logs
|
||||
fj actions run view 123 --log-failed`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunView,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunView,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
c.Flags().BoolP("verbose", "v", false, "Show job steps")
|
||||
c.Flags().BoolP("log", "", false, "View full log for either a run or specific job")
|
||||
c.Flags().StringP("job", "j", "", "View a specific job ID from a run")
|
||||
c.Flags().BoolP("log-failed", "", false, "View the log for any failed steps in a run or specific job")
|
||||
addJSONFlags(c, "Output workflow run as JSON")
|
||||
return c
|
||||
}
|
||||
|
||||
var runWatchCmd = &cobra.Command{
|
||||
Use: "watch <run-id>",
|
||||
Short: "Watch a workflow run",
|
||||
Long: "Poll a workflow run until it completes.",
|
||||
Example: ` # Watch a run until it completes
|
||||
func newRunWatchCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "watch <run-id>",
|
||||
Short: "Watch a workflow run",
|
||||
Long: "Poll a workflow run until it completes.",
|
||||
Example: ` # Watch a run until it completes
|
||||
fj actions run watch 123
|
||||
|
||||
# Watch with a custom polling interval
|
||||
fj actions run watch 123 -i 10s`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunWatch,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunWatch,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
c.Flags().DurationP("interval", "i", 5*time.Second, "Polling interval")
|
||||
return c
|
||||
}
|
||||
|
||||
var runRerunCmd = &cobra.Command{
|
||||
Use: "rerun <run-id>",
|
||||
Short: "Rerun a workflow run",
|
||||
Long: "Trigger a rerun for a specific workflow run.",
|
||||
Example: ` # Rerun a failed workflow run
|
||||
func newRunRerunCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "rerun <run-id>",
|
||||
Short: "Rerun a workflow run",
|
||||
Long: "Trigger a rerun for a specific workflow run.",
|
||||
Example: ` # Rerun a failed workflow run
|
||||
fj actions run rerun 123`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunRerun,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunRerun,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
return c
|
||||
}
|
||||
|
||||
var runCancelCmd = &cobra.Command{
|
||||
Use: "cancel <run-id>",
|
||||
Short: "Cancel a workflow run",
|
||||
Long: "Cancel a running workflow run.",
|
||||
Example: ` # Cancel a running workflow
|
||||
func newRunCancelCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "cancel <run-id>",
|
||||
Short: "Cancel a workflow run",
|
||||
Long: "Cancel a running workflow run.",
|
||||
Example: ` # Cancel a running workflow
|
||||
fj actions run cancel 123`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunCancel,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunCancel,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
return c
|
||||
}
|
||||
|
||||
// Workflow commands
|
||||
var workflowCmd = &cobra.Command{
|
||||
Use: "workflow",
|
||||
Short: "Manage workflows",
|
||||
Long: "List, view, and run workflows.",
|
||||
// newWorkflowCmd builds the `workflow` subtree. parentLabel is interpolated
|
||||
// the same way as newRunCmd's, so the alias variant can self-identify.
|
||||
func newWorkflowCmd(parentLabel string) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "workflow",
|
||||
Short: "Manage workflows" + parentLabel,
|
||||
Long: "List, view, and run workflows." + parentLabel,
|
||||
}
|
||||
cmd.AddCommand(newWorkflowListCmd())
|
||||
cmd.AddCommand(newWorkflowViewCmd())
|
||||
cmd.AddCommand(newWorkflowRunCmd())
|
||||
cmd.AddCommand(newWorkflowEnableCmd())
|
||||
cmd.AddCommand(newWorkflowDisableCmd())
|
||||
return cmd
|
||||
}
|
||||
|
||||
var workflowListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List workflows",
|
||||
Long: "List all workflows in a repository.",
|
||||
Example: ` # List all workflows
|
||||
func newWorkflowListCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List workflows",
|
||||
Long: "List all workflows in a repository.",
|
||||
Example: ` # List all workflows
|
||||
fj actions workflow list
|
||||
|
||||
# List workflows as JSON
|
||||
|
|
@ -180,53 +233,78 @@ var workflowListCmd = &cobra.Command{
|
|||
|
||||
# List workflows for a specific repo
|
||||
fj actions workflow list -R owner/repo`,
|
||||
RunE: runWorkflowList,
|
||||
RunE: runWorkflowList,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
c.Flags().IntP("limit", "L", 20, "Maximum number of workflows to list")
|
||||
addJSONFlags(c, "Output workflows as JSON")
|
||||
return c
|
||||
}
|
||||
|
||||
var workflowViewCmd = &cobra.Command{
|
||||
Use: "view <workflow>",
|
||||
Short: "View a workflow",
|
||||
Long: "View details about a specific workflow. You can specify the workflow by name or filename.",
|
||||
Example: ` # View a workflow by filename
|
||||
func newWorkflowViewCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "view <workflow>",
|
||||
Short: "View a workflow",
|
||||
Long: "View details about a specific workflow. You can specify the workflow by name or filename.",
|
||||
Example: ` # View a workflow by filename
|
||||
fj actions workflow view ci.yml
|
||||
|
||||
# View as JSON
|
||||
fj actions workflow view ci.yml --json`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runWorkflowView,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runWorkflowView,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
addJSONFlags(c, "Output workflow as JSON")
|
||||
return c
|
||||
}
|
||||
|
||||
var workflowRunCmd = &cobra.Command{
|
||||
Use: "run <workflow>",
|
||||
Short: "Run a workflow",
|
||||
Long: "Trigger a workflow_dispatch event for a workflow. The workflow must support the workflow_dispatch trigger.",
|
||||
Example: ` # Trigger a workflow on the default branch
|
||||
func newWorkflowRunCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "run <workflow>",
|
||||
Short: "Run a workflow",
|
||||
Long: "Trigger a workflow_dispatch event for a workflow. The workflow must support the workflow_dispatch trigger.",
|
||||
Example: ` # Trigger a workflow on the default branch
|
||||
fj actions workflow run deploy.yml
|
||||
|
||||
# Trigger on a specific branch with input parameters
|
||||
fj actions workflow run deploy.yml -r staging -f environment=staging -f version=1.2.3`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runWorkflowRun,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runWorkflowRun,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
c.Flags().StringP("ref", "r", "", "Branch or tag name to run the workflow on (defaults to repository's default branch)")
|
||||
c.Flags().StringSliceP("field", "f", nil, "Add a string parameter in key=value format (can be used multiple times)")
|
||||
c.Flags().StringSliceP("raw-field", "F", nil, "Add a string parameter in key=value format, reading from file if value starts with @ (can be used multiple times)")
|
||||
return c
|
||||
}
|
||||
|
||||
var workflowEnableCmd = &cobra.Command{
|
||||
Use: "enable <workflow>",
|
||||
Short: "Enable a workflow",
|
||||
Long: "Enable a workflow so it can be triggered.\n\nNote: This feature requires Forgejo 15.0+ or Gitea 1.24+.\nFor older versions, use the web UI to enable workflows.",
|
||||
Example: ` # Enable a workflow
|
||||
func newWorkflowEnableCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "enable <workflow>",
|
||||
Short: "Enable a workflow",
|
||||
Long: "Enable a workflow so it can be triggered.\n\nNote: This feature requires Forgejo 15.0+ or Gitea 1.24+.\nFor older versions, use the web UI to enable workflows.",
|
||||
Example: ` # Enable a workflow
|
||||
fj actions workflow enable ci.yml`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runWorkflowEnable,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runWorkflowEnable,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
return c
|
||||
}
|
||||
|
||||
var workflowDisableCmd = &cobra.Command{
|
||||
Use: "disable <workflow>",
|
||||
Short: "Disable a workflow",
|
||||
Long: "Disable a workflow so it cannot be triggered.\n\nNote: This feature requires Forgejo 15.0+ or Gitea 1.24+.\nFor older versions, use the web UI to disable workflows.",
|
||||
Example: ` # Disable a workflow
|
||||
func newWorkflowDisableCmd() *cobra.Command {
|
||||
c := &cobra.Command{
|
||||
Use: "disable <workflow>",
|
||||
Short: "Disable a workflow",
|
||||
Long: "Disable a workflow so it cannot be triggered.\n\nNote: This feature requires Forgejo 15.0+ or Gitea 1.24+.\nFor older versions, use the web UI to disable workflows.",
|
||||
Example: ` # Disable a workflow
|
||||
fj actions workflow disable ci.yml`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runWorkflowDisable,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runWorkflowDisable,
|
||||
}
|
||||
addRepoFlags(c)
|
||||
return c
|
||||
}
|
||||
|
||||
// Secret commands
|
||||
|
|
@ -336,21 +414,10 @@ var actionsVariableDeleteCmd = &cobra.Command{
|
|||
func init() {
|
||||
rootCmd.AddCommand(actionsCmd)
|
||||
|
||||
// Add run commands (gh run compatible)
|
||||
actionsCmd.AddCommand(runCmd)
|
||||
runCmd.AddCommand(runListCmd)
|
||||
runCmd.AddCommand(runViewCmd)
|
||||
runCmd.AddCommand(runWatchCmd)
|
||||
runCmd.AddCommand(runRerunCmd)
|
||||
runCmd.AddCommand(runCancelCmd)
|
||||
|
||||
// Add workflow commands (gh workflow compatible)
|
||||
actionsCmd.AddCommand(workflowCmd)
|
||||
workflowCmd.AddCommand(workflowListCmd)
|
||||
workflowCmd.AddCommand(workflowViewCmd)
|
||||
workflowCmd.AddCommand(workflowRunCmd)
|
||||
workflowCmd.AddCommand(workflowEnableCmd)
|
||||
workflowCmd.AddCommand(workflowDisableCmd)
|
||||
// Run and Workflow trees come from the factory functions defined above
|
||||
// so cmd/aliases.go can build identical top-level trees under rootCmd.
|
||||
actionsCmd.AddCommand(newRunCmd(""))
|
||||
actionsCmd.AddCommand(newWorkflowCmd(""))
|
||||
|
||||
// Add secret commands
|
||||
actionsCmd.AddCommand(actionsSecretCmd)
|
||||
|
|
@ -366,34 +433,6 @@ func init() {
|
|||
actionsVariableCmd.AddCommand(actionsVariableUpdateCmd)
|
||||
actionsVariableCmd.AddCommand(actionsVariableDeleteCmd)
|
||||
|
||||
// Add flags for run commands
|
||||
addRepoFlags(runListCmd)
|
||||
runListCmd.Flags().IntP("limit", "L", 20, "Maximum number of runs to list")
|
||||
addJSONFlags(runListCmd, "Output workflow runs as JSON")
|
||||
addRepoFlags(runViewCmd)
|
||||
runViewCmd.Flags().BoolP("verbose", "v", false, "Show job steps")
|
||||
runViewCmd.Flags().BoolP("log", "", false, "View full log for either a run or specific job")
|
||||
runViewCmd.Flags().StringP("job", "j", "", "View a specific job ID from a run")
|
||||
runViewCmd.Flags().BoolP("log-failed", "", false, "View the log for any failed steps in a run or specific job")
|
||||
addJSONFlags(runViewCmd, "Output workflow run as JSON")
|
||||
addRepoFlags(runWatchCmd)
|
||||
runWatchCmd.Flags().DurationP("interval", "i", 5*time.Second, "Polling interval")
|
||||
addRepoFlags(runRerunCmd)
|
||||
addRepoFlags(runCancelCmd)
|
||||
|
||||
// Add flags for workflow commands
|
||||
addRepoFlags(workflowListCmd)
|
||||
workflowListCmd.Flags().IntP("limit", "L", 20, "Maximum number of workflows to list")
|
||||
addJSONFlags(workflowListCmd, "Output workflows as JSON")
|
||||
addRepoFlags(workflowViewCmd)
|
||||
addJSONFlags(workflowViewCmd, "Output workflow as JSON")
|
||||
addRepoFlags(workflowRunCmd)
|
||||
addRepoFlags(workflowEnableCmd)
|
||||
addRepoFlags(workflowDisableCmd)
|
||||
workflowRunCmd.Flags().StringP("ref", "r", "", "Branch or tag name to run the workflow on (defaults to repository's default branch)")
|
||||
workflowRunCmd.Flags().StringSliceP("field", "f", nil, "Add a string parameter in key=value format (can be used multiple times)")
|
||||
workflowRunCmd.Flags().StringSliceP("raw-field", "F", nil, "Add a string parameter in key=value format, reading from file if value starts with @ (can be used multiple times)")
|
||||
|
||||
// Add flags for secret commands
|
||||
addRepoFlags(actionsSecretListCmd)
|
||||
addRepoFlags(actionsSecretCreateCmd)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue