feat: v0.3.0d — add PR checks, iostreams, aliases, and broad enhancements

Add PR checks command, iostreams/text packages for colored table output,
top-level run/workflow aliases matching gh CLI structure. Enhance actions,
issues, PRs, releases, repos, labels, milestones, and wiki commands with
improved flags, JSON output, and error handling.
This commit is contained in:
sid 2026-03-23 11:42:44 -06:00
parent 7c0dcc8696
commit 113505de95
29 changed files with 3131 additions and 542 deletions

View file

@ -2,14 +2,11 @@ package cmd
import (
"fmt"
"os"
"strconv"
"strings"
"forgejo.zerova.net/sid/fgj-sid/internal/api"
"forgejo.zerova.net/sid/fgj-sid/internal/config"
"github.com/spf13/cobra"
"golang.org/x/term"
)
var prDiffCmd = &cobra.Command{
@ -46,7 +43,7 @@ func runPRDiff(cmd *cobra.Command, args []string) error {
nameOnly, _ := cmd.Flags().GetBool("name-only")
stat, _ := cmd.Flags().GetBool("stat")
prNumber, err := strconv.ParseInt(args[0], 10, 64)
prNumber, err := parseIssueArg(args[0])
if err != nil {
return fmt.Errorf("invalid pull request number: %w", err)
}
@ -69,7 +66,9 @@ func runPRDiff(cmd *cobra.Command, args []string) error {
diffURL := fmt.Sprintf("https://%s/api/v1/repos/%s/%s/pulls/%d.diff",
client.Hostname(), owner, name, prNumber)
ios.StartSpinner("Fetching diff...")
diff, err := client.GetRawLog(diffURL)
ios.StopSpinner()
if err != nil {
return fmt.Errorf("failed to get pull request diff: %w", err)
}
@ -82,12 +81,18 @@ func runPRDiff(cmd *cobra.Command, args []string) error {
return printDiffStat(diff)
}
// Start pager for diffs
if err := ios.StartPager(); err != nil {
fmt.Fprintf(ios.ErrOut, "warning: failed to start pager: %v\n", err)
}
defer ios.StopPager()
useColor := shouldColorize(colorMode)
if useColor {
return printColorizedDiff(diff)
}
fmt.Print(diff)
fmt.Fprint(ios.Out, diff)
return nil
}
@ -99,7 +104,7 @@ func shouldColorize(mode string) bool {
case "never":
return false
default: // "auto"
return term.IsTerminal(int(os.Stdout.Fd()))
return ios.ColorEnabled()
}
}
@ -111,7 +116,7 @@ func printNameOnly(diff string) error {
name := strings.TrimPrefix(line, "+++ b/")
if name != "" && !seen[name] {
seen[name] = true
fmt.Println(name)
fmt.Fprintln(ios.Out, name)
}
}
}
@ -120,9 +125,9 @@ func printNameOnly(diff string) error {
// fileStat holds per-file diff statistics.
type fileStat struct {
name string
additions int
deletions int
name string
additions int
deletions int
}
// printDiffStat parses the diff and prints a diffstat summary.
@ -165,10 +170,12 @@ func printDiffStat(diff string) error {
}
if len(stats) == 0 {
fmt.Println("0 files changed")
fmt.Fprintln(ios.Out, "0 files changed")
return nil
}
cs := ios.ColorScheme()
// Find the longest file name for alignment
maxNameLen := 0
maxChanges := 0
@ -210,44 +217,36 @@ func printDiffStat(diff string) error {
scaledDel = 1
}
}
bar = strings.Repeat("+", scaledAdd) + strings.Repeat("-", scaledDel)
bar = cs.Green(strings.Repeat("+", scaledAdd)) + cs.Red(strings.Repeat("-", scaledDel))
}
fmt.Printf(" %-*s | %4d %s\n", maxNameLen, s.name, total, bar)
fmt.Fprintf(ios.Out, " %-*s | %4d %s\n", maxNameLen, s.name, total, bar)
}
fmt.Printf(" %d file", len(stats))
fmt.Fprintf(ios.Out, " %d file", len(stats))
if len(stats) != 1 {
fmt.Print("s")
fmt.Fprint(ios.Out, "s")
}
fmt.Printf(" changed, %d insertion", totalAdditions)
fmt.Fprintf(ios.Out, " changed, %d insertion", totalAdditions)
if totalAdditions != 1 {
fmt.Print("s")
fmt.Fprint(ios.Out, "s")
}
fmt.Printf("(+), %d deletion", totalDeletions)
fmt.Fprintf(ios.Out, "(+), %d deletion", totalDeletions)
if totalDeletions != 1 {
fmt.Print("s")
fmt.Fprint(ios.Out, "s")
}
fmt.Println("(-)")
fmt.Fprintln(ios.Out, "(-)")
return nil
}
// ANSI color codes for diff output.
const (
colorReset = "\033[0m"
colorRed = "\033[31m"
colorGreen = "\033[32m"
colorCyan = "\033[36m"
colorBold = "\033[1m"
)
// printColorizedDiff prints the diff with ANSI color codes.
// printColorizedDiff prints the diff with ANSI color codes using ColorScheme.
func printColorizedDiff(diff string) error {
cs := ios.ColorScheme()
for _, line := range strings.Split(diff, "\n") {
switch {
case strings.HasPrefix(line, "diff --git "):
fmt.Println(colorBold + line + colorReset)
fmt.Fprintln(ios.Out, cs.Bold(line))
case strings.HasPrefix(line, "index "),
strings.HasPrefix(line, "--- "),
strings.HasPrefix(line, "+++ "),
@ -256,15 +255,15 @@ func printColorizedDiff(diff string) error {
strings.HasPrefix(line, "similarity index"),
strings.HasPrefix(line, "rename from"),
strings.HasPrefix(line, "rename to"):
fmt.Println(colorBold + line + colorReset)
fmt.Fprintln(ios.Out, cs.Bold(line))
case strings.HasPrefix(line, "@@"):
fmt.Println(colorCyan + line + colorReset)
fmt.Fprintln(ios.Out, cs.Cyan(line))
case strings.HasPrefix(line, "+"):
fmt.Println(colorGreen + line + colorReset)
fmt.Fprintln(ios.Out, cs.Green(line))
case strings.HasPrefix(line, "-"):
fmt.Println(colorRed + line + colorReset)
fmt.Fprintln(ios.Out, cs.Red(line))
default:
fmt.Println(line)
fmt.Fprintln(ios.Out, line)
}
}
return nil