package main import ( "context" "errors" "fmt" "io" "log" "net/url" "os" "os/exec" "path/filepath" "strings" "git.sr.ht/~emersion/gqlclient" "github.com/dustin/go-humanize" "github.com/spf13/cobra" "git.sr.ht/~xenrox/hut/srht/gitsrht" "git.sr.ht/~xenrox/hut/termfmt") func newGitCommand() *cobra.Command { cmd := &cobra.Command{ Use: "git", Short: "Use the git API", } cmd.AddCommand(newGitArtifactCommand()) cmd.AddCommand(newGitCreateCommand()) cmd.AddCommand(newGitListCommand()) cmd.AddCommand(newGitDeleteCommand()) cmd.AddCommand(newGitACLCommand()) cmd.AddCommand(newGitShowCommand()) cmd.AddCommand(newGitUserWebhookCommand()) cmd.AddCommand(newGitUpdateCommand()) cmd.PersistentFlags().StringP("repo", "r", "", "name of repository") cmd.RegisterFlagCompletionFunc("repo", completeGitRepo) return cmd} func newGitCreateCommand() *cobra.Command { var visibility, desc, importURL string var clone bool run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() c := createClient("git", cmd) gitVisibility, err := gitsrht.ParseVisibility(visibility) if err != nil { log.Fatal(err) } var importURLPtr *string if importURL != "" { importURLPtr = &importURL } var description *string if desc != "" { description = &desc } repo, err := gitsrht.CreateRepository(c.Client, ctx, args[0], gitVisibility, description, importURLPtr) if err != nil { log.Fatal(err) } log.Printf("Created repository %s\n", repo.Name) ver, err := gitsrht.SshSettings(c.Client, ctx) if err != nil { log.Fatalf("failed to retrieve settings: %v", err) } u, err := url.Parse(c.BaseURL) if err != nil { log.Fatalf("failed to parse base URL: %v", err) } cloneURL := fmt.Sprintf("%s@%s:%s/%s", ver.Settings.SshUser, u.Hostname(), repo.Owner.CanonicalName, repo.Name) if clone { cloneCmd := exec.Command("git", "clone", cloneURL) cloneCmd.Stdin = os.Stdin cloneCmd.Stdout = os.Stdout cloneCmd.Stderr = os.Stderr err = cloneCmd.Run() if err != nil { log.Fatal(err) } } else { fmt.Printf("%s\n", cloneURL) } } cmd := &cobra.Command{ Use: "create <name>", Short: "Create a repository", Args: cobra.ExactArgs(1), ValidArgsFunction: cobra.NoFileCompletions, Run: run, } cmd.Flags().StringVarP(&visibility, "visibility", "v", "public", "repo visibility") cmd.RegisterFlagCompletionFunc("visibility", completeVisibility) cmd.Flags().StringVarP(&desc, "description", "d", "", "repo description") cmd.RegisterFlagCompletionFunc("description", cobra.NoFileCompletions) cmd.Flags().BoolVarP(&clone, "clone", "c", false, "autoclone repo") cmd.Flags().StringVar(&importURL, "import-url", "", "import repo from given URL") cmd.RegisterFlagCompletionFunc("import-url", cobra.NoFileCompletions) return cmd} func newGitListCommand() *cobra.Command { run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() var cursor *gitsrht.Cursor var owner, instance string if len(args) > 0 { owner, instance = parseOwnerName(args[0]) } err := pagerify(func(p pager) error { var repos *gitsrht.RepositoryCursor if len(owner) > 0 { c := createClientWithInstance("git", cmd, instance) username := strings.TrimLeft(owner, ownerPrefixes) user, err := gitsrht.RepositoriesByUser(c.Client, ctx, username, cursor) if err != nil { return err } else if user == nil { return errors.New("no such user") } repos = user.Repositories } else { c := createClient("git", cmd) var err error repos, err = gitsrht.Repositories(c.Client, ctx, cursor) if err != nil { return err } } for _, repo := range repos.Results { printGitRepo(p, &repo) } cursor = repos.Cursor if cursor == nil { return pagerDone } return nil }) if err != nil { log.Fatal(err) } } cmd := &cobra.Command{ Use: "list [user]", Short: "List repos", Args: cobra.MaximumNArgs(1), ValidArgsFunction: cobra.NoFileCompletions, Run: run, } return cmd} func printGitRepo(w io.Writer, repo *gitsrht.Repository) { fmt.Fprintf(w, "%s (%s)\n", termfmt.Bold.String(repo.Name), repo.Visibility.TermString()) if repo.Description != nil && *repo.Description != "" { fmt.Fprintf(w, " %s\n", *repo.Description) } fmt.Fprintln(w)} func newGitDeleteCommand() *cobra.Command { var autoConfirm bool run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() var name, owner, instance string if len(args) > 0 { name, owner, instance = parseResourceName(args[0]) } else { var err error name, owner, instance, err = getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } } c := createClientWithInstance("git", cmd, instance) id := getRepoID(c, ctx, name, owner) if !autoConfirm && !getConfirmation(fmt.Sprintf("Do you really want to delete the repo %s", name)) { log.Println("Aborted") return } repo, err := gitsrht.DeleteRepository(c.Client, ctx, id) if err != nil { log.Fatal(err) } log.Printf("Deleted repository %s\n", repo.Name) } cmd := &cobra.Command{ Use: "delete [repo]", Short: "Delete a repository", Args: cobra.MaximumNArgs(1), ValidArgsFunction: completeGitRepo, Run: run, } cmd.Flags().BoolVarP(&autoConfirm, "yes", "y", false, "auto confirm") return cmd} func newGitArtifactCommand() *cobra.Command { cmd := &cobra.Command{ Use: "artifact", Short: "Manage artifacts", } cmd.AddCommand(newGitArtifactUploadCommand()) cmd.AddCommand(newGitArtifactListCommand()) cmd.AddCommand(newGitArtifactDeleteCommand()) return cmd} func newGitArtifactUploadCommand() *cobra.Command { var rev string run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() repoName, owner, instance, err := getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } c := createClientWithInstance("git", cmd, instance) c.HTTP.Timeout = fileTransferTimeout repoID := getRepoID(c, ctx, repoName, owner) if rev == "" { var err error rev, err = guessRev() if err != nil { log.Fatal(err) } } for _, filename := range args { f, err := os.Open(filename) if err != nil { log.Fatalf("failed to open input file: %v", err) } defer f.Close() file := gqlclient.Upload{Filename: filepath.Base(filename), Body: f} artifact, err := gitsrht.UploadArtifact(c.Client, ctx, repoID, rev, file) if err != nil { log.Fatal(err) } log.Printf("Uploaded %s\n", artifact.Filename) } } cmd := &cobra.Command{ Use: "upload <filename...>", Short: "Upload artifacts", Args: cobra.MinimumNArgs(1), Run: run, } cmd.Flags().StringVar(&rev, "rev", "", "revision tag") cmd.RegisterFlagCompletionFunc("rev", completeRev) return cmd} func newGitArtifactListCommand() *cobra.Command { // TODO: Filter by rev run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() repoName, owner, instance, err := getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } c := createClientWithInstance("git", cmd, instance) var ( username string user *gitsrht.User ) if owner != "" { username = strings.TrimLeft(owner, ownerPrefixes) user, err = gitsrht.ListArtifactsByUser(c.Client, ctx, username, repoName) } else { user, err = gitsrht.ListArtifacts(c.Client, ctx, repoName) } if err != nil { log.Fatal(err) } else if user == nil { log.Fatalf("no such user %q", username) } else if user.Repository == nil { log.Fatalf("no such repository %q", repoName) } for _, ref := range user.Repository.References.Results { if len(ref.Artifacts.Results) == 0 { continue } name := ref.Name[strings.LastIndex(ref.Name, "/")+1:] fmt.Printf("Tag %s:\n", termfmt.Bold.String(name)) for _, artifact := range ref.Artifacts.Results { fmt.Printf(" %s %s\n", termfmt.DarkYellow.Sprintf("#%d", artifact.Id), artifact.Filename) } } } cmd := &cobra.Command{ Use: "list", Short: "List artifacts", Args: cobra.ExactArgs(0), Run: run, } return cmd} func newGitArtifactDeleteCommand() *cobra.Command { run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() c := createClient("git", cmd) id, err := parseInt32(args[0]) if err != nil { log.Fatal(err) } artifact, err := gitsrht.DeleteArtifact(c.Client, ctx, id) if err != nil { log.Fatal(err) } log.Printf("Deleted artifact %s\n", artifact.Filename) } cmd := &cobra.Command{ Use: "delete <ID>", Short: "Delete an artifact", Args: cobra.ExactArgs(1), ValidArgsFunction: completeArtifacts, Run: run, } return cmd} func newGitACLCommand() *cobra.Command { cmd := &cobra.Command{ Use: "acl", Short: "Manage access-control lists", } cmd.AddCommand(newGitACLListCommand()) cmd.AddCommand(newGitACLUpdateCommand()) cmd.AddCommand(newGitACLDeleteCommand()) return cmd} func newGitACLListCommand() *cobra.Command { run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() var name, owner, instance string if len(args) > 0 { name, owner, instance = parseResourceName(args[0]) } else { var err error name, owner, instance, err = getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } } c := createClientWithInstance("git", cmd, instance) var ( cursor *gitsrht.Cursor user *gitsrht.User username string err error ) if owner != "" { username = strings.TrimLeft(owner, ownerPrefixes) } err = pagerify(func(p pager) error { if username != "" { user, err = gitsrht.AclByUser(c.Client, ctx, username, name, cursor) } else { user, err = gitsrht.AclByRepoName(c.Client, ctx, name, cursor) } if err != nil { return err } else if user == nil { return errors.New("no such user") } else if user.Repository == nil { return fmt.Errorf("no such repository %q", name) } for _, acl := range user.Repository.Acls.Results { printGitACLEntry(p, &acl) } cursor = user.Repository.Acls.Cursor if cursor == nil { return pagerDone } return nil }) if err != nil { log.Fatal(err) } } cmd := &cobra.Command{ Use: "list", Short: "List ACL entries", Args: cobra.MaximumNArgs(1), ValidArgsFunction: cobra.NoFileCompletions, Run: run, } return cmd} func printGitACLEntry(w io.Writer, acl *gitsrht.ACL) { var mode string if acl.Mode != nil { mode = string(*acl.Mode) } created := termfmt.Dim.String(humanize.Time(acl.Created.Time)) fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", termfmt.DarkYellow.Sprintf("#%d", acl.Id), acl.Entity.CanonicalName, mode, created)} func newGitACLUpdateCommand() *cobra.Command { var mode string run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() accessMode, err := gitsrht.ParseAccessMode(mode) if err != nil { log.Fatal(err) } if strings.IndexAny(args[0], ownerPrefixes) != 0 { log.Fatal("user must be in canonical form") } name, owner, instance, err := getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } c := createClientWithInstance("git", cmd, instance) id := getRepoID(c, ctx, name, owner) acl, err := gitsrht.UpdateACL(c.Client, ctx, id, accessMode, args[0]) if err != nil { log.Fatal(err) } log.Printf("Updated access rights for %s\n", acl.Entity.CanonicalName) } cmd := &cobra.Command{ Use: "update <user>", Short: "Update/add ACL entries", Args: cobra.ExactArgs(1), ValidArgsFunction: cobra.NoFileCompletions, Run: run, } cmd.Flags().StringVarP(&mode, "mode", "m", "", "access mode") cmd.RegisterFlagCompletionFunc("mode", completeAccessMode) cmd.MarkFlagRequired("mode") return cmd} func newGitACLDeleteCommand() *cobra.Command { run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() c := createClient("git", cmd) id, err := parseInt32(args[0])Lines 1–500 of 1084. Load more
package main import ( "context" "errors" "fmt" "io" "log" "net/url" "os" "os/exec" "path/filepath" "strings" "git.sr.ht/~emersion/gqlclient" "github.com/dustin/go-humanize" "github.com/spf13/cobra" "git.sr.ht/~xenrox/hut/srht/gitsrht" "git.sr.ht/~xenrox/hut/termfmt" ) func newGitCommand() *cobra.Command { cmd := &cobra.Command{ Use: "git", Short: "Use the git API", } cmd.AddCommand(newGitArtifactCommand()) cmd.AddCommand(newGitCreateCommand()) cmd.AddCommand(newGitListCommand()) cmd.AddCommand(newGitDeleteCommand()) cmd.AddCommand(newGitACLCommand()) cmd.AddCommand(newGitShowCommand()) cmd.AddCommand(newGitUserWebhookCommand()) cmd.AddCommand(newGitUpdateCommand()) cmd.PersistentFlags().StringP("repo", "r", "", "name of repository") cmd.RegisterFlagCompletionFunc("repo", completeGitRepo) return cmd } func newGitCreateCommand() *cobra.Command { var visibility, desc, importURL string var clone bool run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() c := createClient("git", cmd) gitVisibility, err := gitsrht.ParseVisibility(visibility) if err != nil { log.Fatal(err) } var importURLPtr *string if importURL != "" { importURLPtr = &importURL } var description *string if desc != "" { description = &desc } repo, err := gitsrht.CreateRepository(c.Client, ctx, args[0], gitVisibility, description, importURLPtr) if err != nil { log.Fatal(err) } log.Printf("Created repository %s\n", repo.Name) ver, err := gitsrht.SshSettings(c.Client, ctx) if err != nil { log.Fatalf("failed to retrieve settings: %v", err) } u, err := url.Parse(c.BaseURL) if err != nil { log.Fatalf("failed to parse base URL: %v", err) } cloneURL := fmt.Sprintf("%s@%s:%s/%s", ver.Settings.SshUser, u.Hostname(), repo.Owner.CanonicalName, repo.Name) if clone { cloneCmd := exec.Command("git", "clone", cloneURL) cloneCmd.Stdin = os.Stdin cloneCmd.Stdout = os.Stdout cloneCmd.Stderr = os.Stderr err = cloneCmd.Run() if err != nil { log.Fatal(err) } } else { fmt.Printf("%s\n", cloneURL) } } cmd := &cobra.Command{ Use: "create <name>", Short: "Create a repository", Args: cobra.ExactArgs(1), ValidArgsFunction: cobra.NoFileCompletions, Run: run, } cmd.Flags().StringVarP(&visibility, "visibility", "v", "public", "repo visibility") cmd.RegisterFlagCompletionFunc("visibility", completeVisibility) cmd.Flags().StringVarP(&desc, "description", "d", "", "repo description") cmd.RegisterFlagCompletionFunc("description", cobra.NoFileCompletions) cmd.Flags().BoolVarP(&clone, "clone", "c", false, "autoclone repo") cmd.Flags().StringVar(&importURL, "import-url", "", "import repo from given URL") cmd.RegisterFlagCompletionFunc("import-url", cobra.NoFileCompletions) return cmd } func newGitListCommand() *cobra.Command { run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() var cursor *gitsrht.Cursor var owner, instance string if len(args) > 0 { owner, instance = parseOwnerName(args[0]) } err := pagerify(func(p pager) error { var repos *gitsrht.RepositoryCursor if len(owner) > 0 { c := createClientWithInstance("git", cmd, instance) username := strings.TrimLeft(owner, ownerPrefixes) user, err := gitsrht.RepositoriesByUser(c.Client, ctx, username, cursor) if err != nil { return err } else if user == nil { return errors.New("no such user") } repos = user.Repositories } else { c := createClient("git", cmd) var err error repos, err = gitsrht.Repositories(c.Client, ctx, cursor) if err != nil { return err } } for _, repo := range repos.Results { printGitRepo(p, &repo) } cursor = repos.Cursor if cursor == nil { return pagerDone } return nil }) if err != nil { log.Fatal(err) } } cmd := &cobra.Command{ Use: "list [user]", Short: "List repos", Args: cobra.MaximumNArgs(1), ValidArgsFunction: cobra.NoFileCompletions, Run: run, } return cmd } func printGitRepo(w io.Writer, repo *gitsrht.Repository) { fmt.Fprintf(w, "%s (%s)\n", termfmt.Bold.String(repo.Name), repo.Visibility.TermString()) if repo.Description != nil && *repo.Description != "" { fmt.Fprintf(w, " %s\n", *repo.Description) } fmt.Fprintln(w) } func newGitDeleteCommand() *cobra.Command { var autoConfirm bool run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() var name, owner, instance string if len(args) > 0 { name, owner, instance = parseResourceName(args[0]) } else { var err error name, owner, instance, err = getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } } c := createClientWithInstance("git", cmd, instance) id := getRepoID(c, ctx, name, owner) if !autoConfirm && !getConfirmation(fmt.Sprintf("Do you really want to delete the repo %s", name)) { log.Println("Aborted") return } repo, err := gitsrht.DeleteRepository(c.Client, ctx, id) if err != nil { log.Fatal(err) } log.Printf("Deleted repository %s\n", repo.Name) } cmd := &cobra.Command{ Use: "delete [repo]", Short: "Delete a repository", Args: cobra.MaximumNArgs(1), ValidArgsFunction: completeGitRepo, Run: run, } cmd.Flags().BoolVarP(&autoConfirm, "yes", "y", false, "auto confirm") return cmd } func newGitArtifactCommand() *cobra.Command { cmd := &cobra.Command{ Use: "artifact", Short: "Manage artifacts", } cmd.AddCommand(newGitArtifactUploadCommand()) cmd.AddCommand(newGitArtifactListCommand()) cmd.AddCommand(newGitArtifactDeleteCommand()) return cmd } func newGitArtifactUploadCommand() *cobra.Command { var rev string run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() repoName, owner, instance, err := getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } c := createClientWithInstance("git", cmd, instance) c.HTTP.Timeout = fileTransferTimeout repoID := getRepoID(c, ctx, repoName, owner) if rev == "" { var err error rev, err = guessRev() if err != nil { log.Fatal(err) } } for _, filename := range args { f, err := os.Open(filename) if err != nil { log.Fatalf("failed to open input file: %v", err) } defer f.Close() file := gqlclient.Upload{Filename: filepath.Base(filename), Body: f} artifact, err := gitsrht.UploadArtifact(c.Client, ctx, repoID, rev, file) if err != nil { log.Fatal(err) } log.Printf("Uploaded %s\n", artifact.Filename) } } cmd := &cobra.Command{ Use: "upload <filename...>", Short: "Upload artifacts", Args: cobra.MinimumNArgs(1), Run: run, } cmd.Flags().StringVar(&rev, "rev", "", "revision tag") cmd.RegisterFlagCompletionFunc("rev", completeRev) return cmd } func newGitArtifactListCommand() *cobra.Command { // TODO: Filter by rev run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() repoName, owner, instance, err := getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } c := createClientWithInstance("git", cmd, instance) var ( username string user *gitsrht.User ) if owner != "" { username = strings.TrimLeft(owner, ownerPrefixes) user, err = gitsrht.ListArtifactsByUser(c.Client, ctx, username, repoName) } else { user, err = gitsrht.ListArtifacts(c.Client, ctx, repoName) } if err != nil { log.Fatal(err) } else if user == nil { log.Fatalf("no such user %q", username) } else if user.Repository == nil { log.Fatalf("no such repository %q", repoName) } for _, ref := range user.Repository.References.Results { if len(ref.Artifacts.Results) == 0 { continue } name := ref.Name[strings.LastIndex(ref.Name, "/")+1:] fmt.Printf("Tag %s:\n", termfmt.Bold.String(name)) for _, artifact := range ref.Artifacts.Results { fmt.Printf(" %s %s\n", termfmt.DarkYellow.Sprintf("#%d", artifact.Id), artifact.Filename) } } } cmd := &cobra.Command{ Use: "list", Short: "List artifacts", Args: cobra.ExactArgs(0), Run: run, } return cmd } func newGitArtifactDeleteCommand() *cobra.Command { run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() c := createClient("git", cmd) id, err := parseInt32(args[0]) if err != nil { log.Fatal(err) } artifact, err := gitsrht.DeleteArtifact(c.Client, ctx, id) if err != nil { log.Fatal(err) } log.Printf("Deleted artifact %s\n", artifact.Filename) } cmd := &cobra.Command{ Use: "delete <ID>", Short: "Delete an artifact", Args: cobra.ExactArgs(1), ValidArgsFunction: completeArtifacts, Run: run, } return cmd } func newGitACLCommand() *cobra.Command { cmd := &cobra.Command{ Use: "acl", Short: "Manage access-control lists", } cmd.AddCommand(newGitACLListCommand()) cmd.AddCommand(newGitACLUpdateCommand()) cmd.AddCommand(newGitACLDeleteCommand()) return cmd } func newGitACLListCommand() *cobra.Command { run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() var name, owner, instance string if len(args) > 0 { name, owner, instance = parseResourceName(args[0]) } else { var err error name, owner, instance, err = getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } } c := createClientWithInstance("git", cmd, instance) var ( cursor *gitsrht.Cursor user *gitsrht.User username string err error ) if owner != "" { username = strings.TrimLeft(owner, ownerPrefixes) } err = pagerify(func(p pager) error { if username != "" { user, err = gitsrht.AclByUser(c.Client, ctx, username, name, cursor) } else { user, err = gitsrht.AclByRepoName(c.Client, ctx, name, cursor) } if err != nil { return err } else if user == nil { return errors.New("no such user") } else if user.Repository == nil { return fmt.Errorf("no such repository %q", name) } for _, acl := range user.Repository.Acls.Results { printGitACLEntry(p, &acl) } cursor = user.Repository.Acls.Cursor if cursor == nil { return pagerDone } return nil }) if err != nil { log.Fatal(err) } } cmd := &cobra.Command{ Use: "list", Short: "List ACL entries", Args: cobra.MaximumNArgs(1), ValidArgsFunction: cobra.NoFileCompletions, Run: run, } return cmd } func printGitACLEntry(w io.Writer, acl *gitsrht.ACL) { var mode string if acl.Mode != nil { mode = string(*acl.Mode) } created := termfmt.Dim.String(humanize.Time(acl.Created.Time)) fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", termfmt.DarkYellow.Sprintf("#%d", acl.Id), acl.Entity.CanonicalName, mode, created) } func newGitACLUpdateCommand() *cobra.Command { var mode string run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() accessMode, err := gitsrht.ParseAccessMode(mode) if err != nil { log.Fatal(err) } if strings.IndexAny(args[0], ownerPrefixes) != 0 { log.Fatal("user must be in canonical form") } name, owner, instance, err := getGitRepoName(ctx, cmd) if err != nil { log.Fatal(err) } c := createClientWithInstance("git", cmd, instance) id := getRepoID(c, ctx, name, owner) acl, err := gitsrht.UpdateACL(c.Client, ctx, id, accessMode, args[0]) if err != nil { log.Fatal(err) } log.Printf("Updated access rights for %s\n", acl.Entity.CanonicalName) } cmd := &cobra.Command{ Use: "update <user>", Short: "Update/add ACL entries", Args: cobra.ExactArgs(1), ValidArgsFunction: cobra.NoFileCompletions, Run: run, } cmd.Flags().StringVarP(&mode, "mode", "m", "", "access mode") cmd.RegisterFlagCompletionFunc("mode", completeAccessMode) cmd.MarkFlagRequired("mode") return cmd } func newGitACLDeleteCommand() *cobra.Command { run := func(cmd *cobra.Command, args []string) { ctx := cmd.Context() c := createClient("git", cmd) id, err := parseInt32(args[0])