feat: add actions run watch rerun and cancel
This commit is contained in:
parent
3ccef4e1c6
commit
c2ee338f1c
1 changed files with 152 additions and 0 deletions
152
cmd/actions.go
152
cmd/actions.go
|
|
@ -109,6 +109,30 @@ var runViewCmd = &cobra.Command{
|
|||
RunE: runRunView,
|
||||
}
|
||||
|
||||
var runWatchCmd = &cobra.Command{
|
||||
Use: "watch <run-id>",
|
||||
Short: "Watch a workflow run",
|
||||
Long: "Poll a workflow run until it completes.",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunWatch,
|
||||
}
|
||||
|
||||
var runRerunCmd = &cobra.Command{
|
||||
Use: "rerun <run-id>",
|
||||
Short: "Rerun a workflow run",
|
||||
Long: "Trigger a rerun for a specific workflow run.",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunRerun,
|
||||
}
|
||||
|
||||
var runCancelCmd = &cobra.Command{
|
||||
Use: "cancel <run-id>",
|
||||
Short: "Cancel a workflow run",
|
||||
Long: "Cancel a running workflow run.",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runRunCancel,
|
||||
}
|
||||
|
||||
// Workflow commands
|
||||
var workflowCmd = &cobra.Command{
|
||||
Use: "workflow",
|
||||
|
|
@ -222,6 +246,9 @@ func init() {
|
|||
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)
|
||||
|
|
@ -253,6 +280,10 @@ func init() {
|
|||
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")
|
||||
runViewCmd.Flags().Bool("json", false, "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)
|
||||
|
|
@ -545,6 +576,118 @@ func runRunView(cmd *cobra.Command, args []string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func runRunWatch(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %w", err)
|
||||
}
|
||||
|
||||
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create client: %w", err)
|
||||
}
|
||||
|
||||
repo, _ := cmd.Flags().GetString("repo")
|
||||
owner, name, err := parseRepo(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runID, err := strconv.ParseInt(args[0], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid run ID: %w", err)
|
||||
}
|
||||
|
||||
interval, _ := cmd.Flags().GetDuration("interval")
|
||||
if interval <= 0 {
|
||||
return fmt.Errorf("interval must be greater than 0")
|
||||
}
|
||||
|
||||
endpoint := fmt.Sprintf("/api/v1/repos/%s/%s/actions/runs/%d", owner, name, runID)
|
||||
|
||||
var lastStatus string
|
||||
for {
|
||||
var run ActionRun
|
||||
if err := client.GetJSON(endpoint, &run); err != nil {
|
||||
return fmt.Errorf("failed to get run: %w", err)
|
||||
}
|
||||
|
||||
if run.Status != lastStatus {
|
||||
fmt.Printf("Status: %s\n", formatStatus(run.Status))
|
||||
lastStatus = run.Status
|
||||
}
|
||||
|
||||
if isRunComplete(run.Status) {
|
||||
fmt.Printf("Run #%d completed with status %s\n", run.IndexInRepo, formatStatus(run.Status))
|
||||
return nil
|
||||
}
|
||||
|
||||
time.Sleep(interval)
|
||||
}
|
||||
}
|
||||
|
||||
func runRunRerun(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %w", err)
|
||||
}
|
||||
|
||||
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create client: %w", err)
|
||||
}
|
||||
|
||||
repo, _ := cmd.Flags().GetString("repo")
|
||||
owner, name, err := parseRepo(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runID, err := strconv.ParseInt(args[0], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid run ID: %w", err)
|
||||
}
|
||||
|
||||
endpoint := fmt.Sprintf("/api/v1/repos/%s/%s/actions/runs/%d/rerun", owner, name, runID)
|
||||
if err := client.PostJSON(endpoint, nil, nil); err != nil {
|
||||
return fmt.Errorf("failed to rerun workflow: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("✓ Rerun requested for run %d\n", runID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runRunCancel(cmd *cobra.Command, args []string) error {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load config: %w", err)
|
||||
}
|
||||
|
||||
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create client: %w", err)
|
||||
}
|
||||
|
||||
repo, _ := cmd.Flags().GetString("repo")
|
||||
owner, name, err := parseRepo(repo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runID, err := strconv.ParseInt(args[0], 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid run ID: %w", err)
|
||||
}
|
||||
|
||||
endpoint := fmt.Sprintf("/api/v1/repos/%s/%s/actions/runs/%d/cancel", owner, name, runID)
|
||||
if err := client.PostJSON(endpoint, nil, nil); err != nil {
|
||||
return fmt.Errorf("failed to cancel workflow run: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("✓ Cancel requested for run %d\n", runID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func showJobLog(client *api.Client, owner, name string, runNumber int64, task ActionTask, logFailed bool) error {
|
||||
// Fetch log from /repos/{owner}/{repo}/actions/runs/{run_number}/jobs/{job_id}/logs
|
||||
logURL := fmt.Sprintf("https://%s/%s/%s/actions/runs/%d/jobs/%d/logs",
|
||||
|
|
@ -594,6 +737,15 @@ func formatStatus(status string) string {
|
|||
}
|
||||
}
|
||||
|
||||
func isRunComplete(status string) bool {
|
||||
switch status {
|
||||
case "success", "failure", "cancelled", "skipped":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func formatTimeSince(t time.Time) string {
|
||||
duration := time.Since(t)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue