feat: v0.3.0c — add labels, milestones, wiki, issue dependencies
New commands: - fgj label list/create/edit/delete - fgj milestone list/view/create/edit/delete - fgj wiki list/view/create/edit/delete Enhanced: - fgj issue edit --add-dependency/--remove-dependency
This commit is contained in:
parent
7ee5a61910
commit
95da06c003
7 changed files with 1206 additions and 3 deletions
278
cmd/label.go
Normal file
278
cmd/label.go
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"forgejo.zerova.net/sid/fgj-sid/internal/api"
|
||||
"forgejo.zerova.net/sid/fgj-sid/internal/config"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var labelCmd = &cobra.Command{
|
||||
Use: "label",
|
||||
Short: "Manage labels",
|
||||
Long: "List, create, edit, and delete repository labels.",
|
||||
}
|
||||
|
||||
var labelListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List labels for a repository",
|
||||
Long: "List all labels defined in a repository.",
|
||||
Example: ` # List labels for the current repository
|
||||
fgj label list
|
||||
|
||||
# List labels for a specific repository
|
||||
fgj label list -R owner/repo
|
||||
|
||||
# Output as JSON
|
||||
fgj label list --json`,
|
||||
RunE: runLabelList,
|
||||
}
|
||||
|
||||
var labelCreateCmd = &cobra.Command{
|
||||
Use: "create <name>",
|
||||
Short: "Create a label",
|
||||
Long: "Create a new label in a repository.",
|
||||
Example: ` # Create a label with a color
|
||||
fgj label create bug -c ff0000
|
||||
|
||||
# Create a label with color and description
|
||||
fgj label create feature -c 00ff00 -d "New feature request"
|
||||
|
||||
# Create a label in a specific repository
|
||||
fgj label create urgent -c ff0000 -R owner/repo`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runLabelCreate,
|
||||
}
|
||||
|
||||
var labelEditCmd = &cobra.Command{
|
||||
Use: "edit <name>",
|
||||
Short: "Edit a label",
|
||||
Long: "Edit an existing label in a repository.",
|
||||
Example: ` # Rename a label
|
||||
fgj label edit bug --name bugfix
|
||||
|
||||
# Change the color of a label
|
||||
fgj label edit bug -c 00ff00
|
||||
|
||||
# Update description
|
||||
fgj label edit bug -d "Something is broken"`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runLabelEdit,
|
||||
}
|
||||
|
||||
var labelDeleteCmd = &cobra.Command{
|
||||
Use: "delete <name>",
|
||||
Short: "Delete a label",
|
||||
Long: "Delete a label from a repository.",
|
||||
Example: ` # Delete a label
|
||||
fgj label delete bug
|
||||
|
||||
# Delete a label from a specific repository
|
||||
fgj label delete bug -R owner/repo`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: runLabelDelete,
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(labelCmd)
|
||||
labelCmd.AddCommand(labelListCmd)
|
||||
labelCmd.AddCommand(labelCreateCmd)
|
||||
labelCmd.AddCommand(labelEditCmd)
|
||||
labelCmd.AddCommand(labelDeleteCmd)
|
||||
|
||||
labelListCmd.Flags().StringP("repo", "R", "", "Repository in owner/name format")
|
||||
labelListCmd.Flags().Bool("json", false, "Output as JSON")
|
||||
|
||||
labelCreateCmd.Flags().StringP("repo", "R", "", "Repository in owner/name format")
|
||||
labelCreateCmd.Flags().StringP("color", "c", "", "Label color (hex, e.g. 00ff00)")
|
||||
labelCreateCmd.Flags().StringP("description", "d", "", "Label description")
|
||||
labelCreateCmd.Flags().Bool("json", false, "Output as JSON")
|
||||
|
||||
labelEditCmd.Flags().StringP("repo", "R", "", "Repository in owner/name format")
|
||||
labelEditCmd.Flags().String("name", "", "New name for the label")
|
||||
labelEditCmd.Flags().StringP("color", "c", "", "New color (hex, e.g. 00ff00)")
|
||||
labelEditCmd.Flags().StringP("description", "d", "", "New description")
|
||||
labelEditCmd.Flags().Bool("json", false, "Output as JSON")
|
||||
|
||||
labelDeleteCmd.Flags().StringP("repo", "R", "", "Repository in owner/name format")
|
||||
}
|
||||
|
||||
func newLabelClient(cmd *cobra.Command) (*api.Client, string, string, error) {
|
||||
repo, _ := cmd.Flags().GetString("repo")
|
||||
owner, name, err := parseRepo(repo)
|
||||
if err != nil {
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
client, err := api.NewClientFromConfig(cfg, "", getDetectedHost())
|
||||
if err != nil {
|
||||
return nil, "", "", err
|
||||
}
|
||||
|
||||
return client, owner, name, nil
|
||||
}
|
||||
|
||||
// findLabelByName lists all repo labels and returns the one matching the given name.
|
||||
func findLabelByName(client *api.Client, owner, repo, labelName string) (*gitea.Label, error) {
|
||||
labels, _, err := client.ListRepoLabels(owner, repo, gitea.ListLabelsOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list labels: %w", err)
|
||||
}
|
||||
|
||||
for _, l := range labels {
|
||||
if strings.EqualFold(l.Name, labelName) {
|
||||
return l, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("label not found: %s", labelName)
|
||||
}
|
||||
|
||||
func runLabelList(cmd *cobra.Command, args []string) error {
|
||||
client, owner, name, err := newLabelClient(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
labels, _, err := client.ListRepoLabels(owner, name, gitea.ListLabelsOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list labels: %w", err)
|
||||
}
|
||||
|
||||
jsonFlag, _ := cmd.Flags().GetBool("json")
|
||||
if jsonFlag {
|
||||
return writeJSON(labels)
|
||||
}
|
||||
|
||||
if len(labels) == 0 {
|
||||
fmt.Println("No labels found")
|
||||
return nil
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
_, _ = fmt.Fprintf(w, "NAME\tCOLOR\tDESCRIPTION\n")
|
||||
for _, l := range labels {
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\n", l.Name, l.Color, l.Description)
|
||||
}
|
||||
_ = w.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runLabelCreate(cmd *cobra.Command, args []string) error {
|
||||
labelName := args[0]
|
||||
color, _ := cmd.Flags().GetString("color")
|
||||
description, _ := cmd.Flags().GetString("description")
|
||||
|
||||
client, owner, name, err := newLabelClient(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
label, _, err := client.CreateLabel(owner, name, gitea.CreateLabelOption{
|
||||
Name: labelName,
|
||||
Color: color,
|
||||
Description: description,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create label: %w", err)
|
||||
}
|
||||
|
||||
jsonFlag, _ := cmd.Flags().GetBool("json")
|
||||
if jsonFlag {
|
||||
return writeJSON(label)
|
||||
}
|
||||
|
||||
fmt.Printf("Label created: %s\n", label.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runLabelEdit(cmd *cobra.Command, args []string) error {
|
||||
labelName := args[0]
|
||||
|
||||
client, owner, name, err := newLabelClient(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
existing, err := findLabelByName(client, owner, name, labelName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opt := gitea.EditLabelOption{}
|
||||
changed := false
|
||||
|
||||
if cmd.Flags().Changed("name") {
|
||||
n, _ := cmd.Flags().GetString("name")
|
||||
opt.Name = &n
|
||||
changed = true
|
||||
}
|
||||
if cmd.Flags().Changed("color") {
|
||||
c, _ := cmd.Flags().GetString("color")
|
||||
opt.Color = &c
|
||||
changed = true
|
||||
}
|
||||
if cmd.Flags().Changed("description") {
|
||||
d, _ := cmd.Flags().GetString("description")
|
||||
opt.Description = &d
|
||||
changed = true
|
||||
}
|
||||
|
||||
if !changed {
|
||||
return fmt.Errorf("no changes specified; use flags like --name, --color, or --description")
|
||||
}
|
||||
|
||||
label, _, err := client.EditLabel(owner, name, existing.ID, opt)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to edit label: %w", err)
|
||||
}
|
||||
|
||||
jsonFlag, _ := cmd.Flags().GetBool("json")
|
||||
if jsonFlag {
|
||||
return writeJSON(label)
|
||||
}
|
||||
|
||||
fmt.Printf("Label updated: %s\n", label.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runLabelDelete(cmd *cobra.Command, args []string) error {
|
||||
labelName := args[0]
|
||||
|
||||
client, owner, name, err := newLabelClient(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
existing, err := findLabelByName(client, owner, name, labelName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Are you sure you want to delete label %q? (y/N): ", labelName)
|
||||
var confirm string
|
||||
_, _ = fmt.Scanln(&confirm)
|
||||
if strings.ToLower(confirm) != "y" {
|
||||
fmt.Println("Aborted")
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = client.DeleteLabel(owner, name, existing.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete label: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Label deleted: %s\n", labelName)
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue