- fgj logins {list,default}: complementary UI to 'fgj auth'. 'list'
shows all configured hosts (hostname, user, protocol, default flag,
match_dirs) with --json. 'default [hostname]' gets or sets which
host wins in resolution when no other signal is present.
Adds 'Default bool' field to HostConfig; GetHost consults it between
match_dirs and the codeberg.org fallback. Multiple defaults tolerated
with a stderr warning; alphabetical-first wins.
- fgj actions run delete: delete a completed workflow run via raw
DELETE (SDK v0.23.2 has no DeleteRepoActionRun). Fetches run first
and refuses to delete non-terminal states unless --force; suggests
'actions run cancel' for those. Confirmation prompt unless --yes.
- pr list / issue list gain --since and --before date filter flags.
Accepts YYYY-MM-DD, RFC 3339, YYYY-MM-DD HH:MM:SS, and relative
deltas (7d, 24h, 2w, 1m — months=30 days). Issues use server-side
filter via ListIssueOption.Since/Before; PRs fall back to client-side
(SDK lacks Since/Before on ListPullRequestsOptions).
- fgj label update added as alias for 'fgj label edit' (tea-compat).
All changes:
cmd/logins.go (new, 140 LOC)
cmd/actions_run_delete.go (new, ~85 LOC)
cmd/pr.go, cmd/issue.go (+parseDateArg helper, filter wiring)
cmd/label.go (1-line alias)
internal/config/config.go (Default field + DefaultHost method)
CHANGELOG.md
Built in parallel by three sub-agents; plus the label alias done
serially. go build / go vet / go test -race all clean.
99 lines
2.9 KiB
Go
99 lines
2.9 KiB
Go
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 <run-id>",
|
|
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
|
|
}
|