package cmd import ( "fmt" "net/http" "strconv" "github.com/spf13/cobra" "forgejo.zerova.net/public/fgj-sid/internal/api" "forgejo.zerova.net/public/fgj-sid/internal/config" ) var runDeleteCmd = &cobra.Command{ Use: "delete ", Aliases: []string{"rm"}, Short: "Delete a workflow run", Long: `Delete a completed workflow run. By default, the run is fetched first and deletion is refused if the run is still pending, running, or waiting. Use --force to override this and delete a non-terminal run. To stop an in-progress run, use 'fgj actions run cancel' instead.`, Example: ` # Delete a completed run (with confirmation) fgj actions run delete 123 # Delete without confirmation fgj actions run delete 123 -y # Force delete a non-terminal run fgj actions run delete 123 --force -y`, Args: cobra.ExactArgs(1), RunE: runRunDelete, } func init() { runCmd.AddCommand(runDeleteCmd) addRepoFlags(runDeleteCmd) runDeleteCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt") runDeleteCmd.Flags().Bool("force", false, "Allow deleting a non-terminal (pending/running/waiting) run") } func runRunDelete(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(), getCwd()) 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) } skipConfirm, _ := cmd.Flags().GetBool("yes") force, _ := cmd.Flags().GetBool("force") // Fetch the run to check state and to display status in the confirmation prompt. runEndpoint := fmt.Sprintf("/api/v1/repos/%s/%s/actions/runs/%d", owner, name, runID) var run ActionRun if err := client.GetJSON(runEndpoint, &run); err != nil { return fmt.Errorf("failed to get run: %w", err) } if !isRunComplete(run.Status) && !force { return fmt.Errorf("run %d is %s; refusing to delete a non-terminal run. Use 'fgj actions run cancel %d' to stop it, or pass --force to delete anyway", runID, run.Status, runID) } if !skipConfirm && ios.IsStdinTTY() { answer, err := promptLine(fmt.Sprintf("Delete run %d (%s) in %s/%s? [y/N]: ", runID, run.Status, owner, name)) if err != nil { return err } if answer != "y" && answer != "Y" && answer != "yes" { fmt.Fprintln(ios.ErrOut, "Cancelled.") return nil } } deleteEndpoint := fmt.Sprintf("/api/v1/repos/%s/%s/actions/runs/%d", owner, name, runID) if _, err := client.DoJSON(http.MethodDelete, deleteEndpoint, nil, nil); err != nil { return fmt.Errorf("failed to delete run %d: %w", runID, err) } cs := ios.ColorScheme() fmt.Fprintf(ios.Out, "%s Deleted run %d\n", cs.SuccessIcon(), runID) return nil }