Skip to content

Commit 322b2ad

Browse files
committed
feat: migrate codeowners to urfave/cli
1 parent 82de268 commit 322b2ad

6 files changed

Lines changed: 187 additions & 253 deletions

File tree

cmd/src/codeowners.go

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,28 @@
11
package main
22

33
import (
4-
"flag"
5-
"fmt"
4+
"errors"
65
"io"
76
"os"
8-
)
97

10-
var codeownersCommands commander
8+
"github.com/sourcegraph/src-cli/internal/clicompat"
9+
"github.com/urfave/cli/v3"
10+
)
1111

12-
func init() {
13-
usage := `'src codeowners' is a tool that manages ingested code ownership data in a Sourcegraph instance.
12+
const codeownersExamples = `'src codeowners' manages ingested code ownership data in a Sourcegraph instance.
1413
1514
Usage:
1615
17-
src codeowners command [command options]
16+
src codeowners [command options]
1817
19-
The commands are:
18+
Examples:
2019
21-
get returns the codeowners file for a repository, if exists
22-
create create a codeowners file
23-
update update a codeowners file
24-
delete delete a codeowners file
25-
26-
Use "src codeowners [command] -h" for more information about a command.
20+
$ src codeowners get -repo='github.com/sourcegraph/sourcegraph'
21+
$ src codeowners create -repo='github.com/sourcegraph/sourcegraph' -f CODEOWNERS
22+
$ src codeowners update -repo='github.com/sourcegraph/sourcegraph' -f CODEOWNERS
23+
$ src codeowners delete -repo='github.com/sourcegraph/sourcegraph'
2724
`
2825

29-
flagSet := flag.NewFlagSet("codeowners", flag.ExitOnError)
30-
handler := func(args []string) error {
31-
codeownersCommands.run(flagSet, "src codeowners", usage, args)
32-
return nil
33-
}
34-
35-
// Register the command.
36-
commands = append(commands, &command{
37-
flagSet: flagSet,
38-
aliases: []string{"codeowner"},
39-
handler: handler,
40-
usageFunc: func() {
41-
fmt.Println(usage)
42-
},
43-
})
44-
}
45-
4626
const codeownersFragment = `
4727
fragment CodeownersFileFields on CodeownersIngestedFile {
4828
contents
@@ -59,9 +39,33 @@ type CodeownersIngestedFile struct {
5939
} `json:"repository"`
6040
}
6141

62-
func readFile(f string) (io.Reader, error) {
42+
var codeownersCommand = clicompat.Wrap(&cli.Command{
43+
Name: "codeowners",
44+
Aliases: []string{"codeowner"},
45+
Usage: "manages ingested code ownership data",
46+
UsageText: "src codeowners [command options]",
47+
Description: codeownersExamples,
48+
HideVersion: true,
49+
Commands: []*cli.Command{
50+
codeownersGetCommand,
51+
codeownersCreateCommand,
52+
codeownersUpdateCommand,
53+
codeownersDeleteCommand,
54+
},
55+
})
56+
57+
func readFile(f string) ([]byte, error) {
6358
if f == "-" {
64-
return os.Stdin, nil
59+
return io.ReadAll(os.Stdin)
60+
}
61+
return os.ReadFile(f)
62+
}
63+
64+
func requiresNotEmpty(errMsg string) func(string) error {
65+
return func(value string) error {
66+
if value == "" {
67+
return errors.New(errMsg)
68+
}
69+
return nil
6570
}
66-
return os.Open(f)
6771
}

cmd/src/codeowners_create.go

Lines changed: 40 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,57 @@ package main
22

33
import (
44
"context"
5-
"flag"
6-
"fmt"
7-
"io"
85
"strings"
96

107
"github.com/sourcegraph/sourcegraph/lib/errors"
118

129
"github.com/sourcegraph/src-cli/internal/api"
10+
"github.com/sourcegraph/src-cli/internal/clicompat"
1311
"github.com/sourcegraph/src-cli/internal/cmderrors"
12+
"github.com/urfave/cli/v3"
1413
)
1514

16-
func init() {
17-
usage := `
18-
Examples:
19-
20-
Create a codeowners file for the repository "github.com/sourcegraph/sourcegraph":
21-
22-
$ src codeowners create -repo='github.com/sourcegraph/sourcegraph' -f CODEOWNERS
15+
const codeownersCreateExamples = `
16+
Create a codeowners file for a repository.
2317
24-
Create a codeowners file for the repository "github.com/sourcegraph/sourcegraph" from stdin:
18+
Examples:
2519
26-
$ src codeowners create -repo='github.com/sourcegraph/sourcegraph' -f -
20+
$ src codeowners create -repo='github.com/sourcegraph/sourcegraph' -f CODEOWNERS
21+
$ src codeowners create -repo='github.com/sourcegraph/sourcegraph' -f -
2722
`
2823

29-
flagSet := flag.NewFlagSet("create", flag.ExitOnError)
30-
usageFunc := func() {
31-
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src codeowners %s':\n", flagSet.Name())
32-
flagSet.PrintDefaults()
33-
fmt.Println(usage)
34-
}
35-
var (
36-
repoFlag = flagSet.String("repo", "", "The repository to attach the data to")
37-
fileFlag = flagSet.String("file", "", "File path to read ownership information from (- for stdin)")
38-
fileShortFlag = flagSet.String("f", "", "File path to read ownership information from (- for stdin). Alias for -file")
39-
40-
apiFlags = api.NewFlags(flagSet)
41-
)
42-
43-
handler := func(args []string) error {
44-
if err := flagSet.Parse(args); err != nil {
45-
return err
46-
}
47-
48-
if *repoFlag == "" {
49-
return errors.New("provide a repo name using -repo")
50-
}
51-
52-
if *fileFlag == "" && *fileShortFlag == "" {
53-
return errors.New("provide a file using -file")
54-
}
55-
if *fileFlag != "" && *fileShortFlag != "" {
56-
return errors.New("have to provide either -file or -f")
57-
}
58-
if *fileShortFlag != "" {
59-
*fileFlag = *fileShortFlag
60-
}
61-
62-
file, err := readFile(*fileFlag)
24+
var codeownersCreateCommand = clicompat.Wrap(&cli.Command{
25+
Name: "create",
26+
Usage: "create a codeowners file",
27+
UsageText: "src codeowners create [options]",
28+
Description: codeownersCreateExamples,
29+
HideVersion: true,
30+
Flags: clicompat.WithAPIFlags(
31+
&cli.StringFlag{
32+
Name: "repo",
33+
Usage: "The repository to attach the data to",
34+
Required: true,
35+
Validator: requiresNotEmpty("provide a repo name using -repo"),
36+
},
37+
&cli.StringFlag{
38+
Name: "file",
39+
Aliases: []string{"f"},
40+
Usage: "File path to read ownership information from (- for stdin)",
41+
TakesFile: true,
42+
Required: true,
43+
Validator: requiresNotEmpty("provide a file using -file"),
44+
},
45+
),
46+
Action: func(ctx context.Context, cmd *cli.Command) error {
47+
repoName := cmd.String("repo")
48+
fileName := cmd.String("file")
49+
50+
content, err := readFile(fileName)
6351
if err != nil {
6452
return err
6553
}
6654

67-
content, err := io.ReadAll(file)
68-
if err != nil {
69-
return err
70-
}
71-
72-
client := cfg.apiClient(apiFlags, flagSet.Output())
55+
client := cfg.apiClient(clicompat.APIFlagsFromCmd(cmd), cmd.Writer)
7356

7457
query := `mutation CreateCodeownersFile(
7558
$repoName: String!,
@@ -89,14 +72,14 @@ Examples:
8972
AddCodeownersFile CodeownersIngestedFile
9073
}
9174
if ok, err := client.NewRequest(query, map[string]any{
92-
"repoName": *repoFlag,
75+
"repoName": repoName,
9376
"content": string(content),
94-
}).Do(context.Background(), &result); err != nil || !ok {
77+
}).Do(ctx, &result); err != nil || !ok {
9578
var gqlErr api.GraphQlErrors
9679
if errors.As(err, &gqlErr) {
9780
for _, e := range gqlErr {
9881
if strings.Contains(e.Error(), "repo not found:") {
99-
return cmderrors.ExitCode(2, errors.Newf("repository %q not found", *repoFlag))
82+
return cmderrors.ExitCode(2, errors.Newf("repository %q not found", repoName))
10083
}
10184
if strings.Contains(e.Error(), "codeowners file has already been ingested for this repository") {
10285
return cmderrors.ExitCode(2, errors.New("codeowners file has already been ingested for this repository"))
@@ -107,12 +90,5 @@ Examples:
10790
}
10891

10992
return nil
110-
}
111-
112-
// Register the command.
113-
codeownersCommands = append(codeownersCommands, &command{
114-
flagSet: flagSet,
115-
handler: handler,
116-
usageFunc: usageFunc,
117-
})
118-
}
93+
},
94+
})

cmd/src/codeowners_delete.go

Lines changed: 29 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,41 @@ package main
22

33
import (
44
"context"
5-
"flag"
6-
"fmt"
75
"strings"
86

97
"github.com/sourcegraph/sourcegraph/lib/errors"
108

119
"github.com/sourcegraph/src-cli/internal/api"
10+
"github.com/sourcegraph/src-cli/internal/clicompat"
1211
"github.com/sourcegraph/src-cli/internal/cmderrors"
12+
"github.com/urfave/cli/v3"
1313
)
1414

15-
func init() {
16-
usage := `
17-
Examples:
15+
const codeownersDeleteExamples = `
16+
Delete a codeowners file for a repository.
1817
19-
Delete a codeowners file for the repository "github.com/sourcegraph/sourcegraph":
18+
Examples:
2019
21-
$ src codeowners delete -repo='github.com/sourcegraph/sourcegraph'
20+
$ src codeowners delete -repo='github.com/sourcegraph/sourcegraph'
2221
`
2322

24-
flagSet := flag.NewFlagSet("delete", flag.ExitOnError)
25-
usageFunc := func() {
26-
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src codeowners %s':\n", flagSet.Name())
27-
flagSet.PrintDefaults()
28-
fmt.Println(usage)
29-
}
30-
var (
31-
repoFlag = flagSet.String("repo", "", "The repository to delete the data for")
32-
apiFlags = api.NewFlags(flagSet)
33-
)
34-
35-
handler := func(args []string) error {
36-
if err := flagSet.Parse(args); err != nil {
37-
return err
38-
}
39-
40-
if *repoFlag == "" {
41-
return errors.New("provide a repo name using -repo")
42-
}
43-
44-
client := cfg.apiClient(apiFlags, flagSet.Output())
23+
var codeownersDeleteCommand = clicompat.Wrap(&cli.Command{
24+
Name: "delete",
25+
Usage: "delete a codeowners file",
26+
UsageText: "src codeowners delete [options]",
27+
Description: codeownersDeleteExamples,
28+
HideVersion: true,
29+
Flags: clicompat.WithAPIFlags(
30+
&cli.StringFlag{
31+
Name: "repo",
32+
Usage: "The repository to delete the data for",
33+
Required: true,
34+
Validator: requiresNotEmpty("provide a repo name using -repo"),
35+
},
36+
),
37+
Action: func(ctx context.Context, cmd *cli.Command) error {
38+
repoName := cmd.String("repo")
39+
client := cfg.apiClient(clicompat.APIFlagsFromCmd(cmd), cmd.Writer)
4540

4641
query := `mutation DeleteCodeownersFile(
4742
$repoName: String!,
@@ -58,29 +53,22 @@ Examples:
5853
DeleteCodeownersFile CodeownersIngestedFile
5954
}
6055
if ok, err := client.NewRequest(query, map[string]any{
61-
"repoName": *repoFlag,
62-
}).Do(context.Background(), &result); err != nil || !ok {
56+
"repoName": repoName,
57+
}).Do(ctx, &result); err != nil || !ok {
6358
var gqlErr api.GraphQlErrors
6459
if errors.As(err, &gqlErr) {
6560
for _, e := range gqlErr {
6661
if strings.Contains(e.Error(), "repo not found:") {
67-
return cmderrors.ExitCode(2, errors.Newf("repository %q not found", *repoFlag))
62+
return cmderrors.ExitCode(2, errors.Newf("repository %q not found", repoName))
6863
}
6964
if strings.Contains(e.Error(), "codeowners file not found:") {
70-
return cmderrors.ExitCode(2, errors.Newf("no data found for repository %q", *repoFlag))
65+
return cmderrors.ExitCode(2, errors.Newf("no data found for repository %q", repoName))
7166
}
7267
}
7368
}
7469
return err
7570
}
7671

7772
return nil
78-
}
79-
80-
// Register the command.
81-
codeownersCommands = append(codeownersCommands, &command{
82-
flagSet: flagSet,
83-
handler: handler,
84-
usageFunc: usageFunc,
85-
})
86-
}
73+
},
74+
})

0 commit comments

Comments
 (0)