From 4fb16033ee5c5f9db36223430dd66bb5c8672ebe Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Sun, 20 Nov 2022 15:05:53 -0500 Subject: [PATCH 1/2] ensure --repo flag is set This also enables the support of non-github.com hosts. --- cmd/main.go | 30 +---------------- cmd/main_test.go | 2 +- internal/dispatch/ghrepo.go | 46 +++++++++++++++++++++++--- internal/dispatch/ghrepo_test.go | 57 +++++++++++++++++++++++++++----- internal/dispatch/repository.go | 9 ++--- internal/dispatch/root.go | 39 ++++++++++++++++++++++ internal/dispatch/types.go | 3 ++ internal/dispatch/workflow.go | 9 ++--- 8 files changed, 140 insertions(+), 55 deletions(-) create mode 100644 internal/dispatch/root.go diff --git a/cmd/main.go b/cmd/main.go index 3718b47..05468a1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,44 +1,16 @@ package main import ( - "fmt" "os" - "github.com/MakeNowJust/heredoc" - "github.com/cli/go-gh" "github.com/mdb/gh-dispatch/internal/dispatch" - "github.com/spf13/cobra" ) // version's value is passed in at build time. var version string func main() { - rootCmd := &cobra.Command{ - Use: "gh dispatch", - Short: "Send a GitHub dispatch event and watch the resulting GitHub Actions run", - Long: heredoc.Doc(` - Send a workflow_dispatch or repository_dispatch event and watch the resulting - GitHub Actions run. - `), - SilenceUsage: true, - Version: version, - } - - defaultRepo := "" - currentRepo, _ := gh.CurrentRepository() - if currentRepo != nil { - defaultRepo = fmt.Sprintf("%s/%s", currentRepo.Owner(), currentRepo.Name()) - } - - // TODO: how to make this required? - rootCmd.PersistentFlags().StringP("repo", "R", defaultRepo, "The targeted repository's full name (in 'owner/repo' format)") - - repositoryCmd := dispatch.NewCmdRepository() - rootCmd.AddCommand(repositoryCmd) - - workflowCmd := dispatch.NewCmdWorkflow() - rootCmd.AddCommand(workflowCmd) + rootCmd := dispatch.NewCmdRoot(version) if err := rootCmd.Execute(); err != nil { os.Exit(1) diff --git a/cmd/main_test.go b/cmd/main_test.go index cd8ff8a..692119f 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -41,7 +41,7 @@ Available Commands: Flags: -h, --help help for gh - -R, --repo string The targeted repository's full name (in 'owner/repo' format) (default "mdb/gh-dispatch") + -R, --repo string The targeted repository's full name (default "github.com/mdb/gh-dispatch") -v, --version version for gh Use "gh [command] --help" for more information about a command. diff --git a/internal/dispatch/ghrepo.go b/internal/dispatch/ghrepo.go index efd197e..65c20a7 100644 --- a/internal/dispatch/ghrepo.go +++ b/internal/dispatch/ghrepo.go @@ -1,19 +1,59 @@ package dispatch import ( + "errors" "fmt" + "strings" "github.com/cli/go-gh/pkg/auth" + "github.com/spf13/cobra" ) +func getRepoOption(cmd *cobra.Command) (*ghRepo, error) { + r, _ := cmd.Flags().GetString("repo") + if r == "" { + return nil, errors.New("A --repo must be specified in the [HOST/]OWNER/REPO format") + } + + repo, err := newGHRepo(r) + if err != nil { + return nil, err + } + + return repo, nil +} + // ghRepo satisfies the ghrepo interface. // In the context of gh-dispatch, it enables the reuse of // functions packaged in the upstream github.com/cli/cli // codebase for rendering GH Actions run output. // See github.com/cli/cli/v2/internal/ghrepo. type ghRepo struct { - Name string Owner string + Name string + Host string +} + +func newGHRepo(name string) (*ghRepo, error) { + defaultHost, _ := auth.DefaultHost() + nameParts := strings.Split(name, "/") + + switch len(nameParts) { + case 2: + return &ghRepo{ + Owner: nameParts[0], + Name: nameParts[1], + Host: defaultHost, + }, nil + case 3: + return &ghRepo{ + Owner: nameParts[1], + Name: nameParts[2], + Host: nameParts[0], + }, nil + default: + return nil, errors.New("invalid repository name") + } } func (r ghRepo) RepoName() string { @@ -25,9 +65,7 @@ func (r ghRepo) RepoOwner() string { } func (r ghRepo) RepoHost() string { - host, _ := auth.DefaultHost() - - return host + return r.Host } func (r ghRepo) RepoFullName() string { diff --git a/internal/dispatch/ghrepo_test.go b/internal/dispatch/ghrepo_test.go index a5e1a35..be6640e 100644 --- a/internal/dispatch/ghrepo_test.go +++ b/internal/dispatch/ghrepo_test.go @@ -6,14 +6,53 @@ import ( "github.com/stretchr/testify/assert" ) -func TestGHRepo(t *testing.T) { - ghRepo := &ghRepo{ - Name: "REPO", - Owner: "OWNER", - } +func TestNewGHRepo(t *testing.T) { + tests := []struct { + name string + wantName string + wantOwner string + wantHost string + wantFullName string + wantErr bool + errMsg string + }{ + { + name: "foo/bar", + wantOwner: "foo", + wantName: "bar", + wantFullName: "foo/bar", + wantHost: "github.com", + wantErr: false, + }, { + name: "other-github.com/foo/bar", + wantOwner: "foo", + wantName: "bar", + wantFullName: "foo/bar", + wantHost: "other-github.com", + wantErr: false, + }, { + name: "bar", + wantErr: true, + errMsg: "invalid repository name", + }, { + name: "", + wantErr: true, + errMsg: "invalid repository name", + }} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ghr, err := newGHRepo(tt.name) - assert.Equal(t, "OWNER/REPO", ghRepo.RepoFullName()) - assert.Equal(t, "OWNER", ghRepo.RepoOwner()) - assert.Equal(t, "REPO", ghRepo.RepoName()) - assert.Equal(t, "github.com", ghRepo.RepoHost()) + if tt.wantErr { + assert.EqualError(t, err, tt.errMsg) + } else { + assert.NoError(t, err) + assert.Equal(t, tt.wantFullName, ghr.RepoFullName()) + assert.Equal(t, tt.wantOwner, ghr.RepoOwner()) + assert.Equal(t, tt.wantName, ghr.RepoName()) + assert.Equal(t, tt.wantHost, ghr.RepoHost()) + } + }) + } } diff --git a/internal/dispatch/repository.go b/internal/dispatch/repository.go index 67597d9..72470ea 100644 --- a/internal/dispatch/repository.go +++ b/internal/dispatch/repository.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "strings" "github.com/MakeNowJust/heredoc" cliapi "github.com/cli/cli/v2/api" @@ -60,11 +59,9 @@ func NewCmdRepository() *cobra.Command { --workflow Hello `), RunE: func(cmd *cobra.Command, args []string) error { - r, _ := cmd.Flags().GetString("repo") - repoParts := strings.Split(r, "/") - repo := &ghRepo{ - Owner: repoParts[0], - Name: repoParts[1], + repo, err := getRepoOption(cmd) + if err != nil { + return err } b := []byte(repositoryClientPayload) diff --git a/internal/dispatch/root.go b/internal/dispatch/root.go new file mode 100644 index 0000000..6ddaf72 --- /dev/null +++ b/internal/dispatch/root.go @@ -0,0 +1,39 @@ +package dispatch + +import ( + "fmt" + + "github.com/MakeNowJust/heredoc" + "github.com/cli/go-gh" + "github.com/spf13/cobra" +) + +func NewCmdRoot(version string) *cobra.Command { + rootCmd := &cobra.Command{ + Use: "gh dispatch", + Short: "Send a GitHub dispatch event and watch the resulting GitHub Actions run", + Long: heredoc.Doc(` + Send a workflow_dispatch or repository_dispatch event and watch the resulting + GitHub Actions run. + `), + SilenceUsage: true, + Version: version, + } + + defaultRepo := "" + currentRepo, _ := gh.CurrentRepository() + if currentRepo != nil { + defaultRepo = fmt.Sprintf("%s/%s/%s", currentRepo.Host(), currentRepo.Owner(), currentRepo.Name()) + } + + var repo string + rootCmd.PersistentFlags().StringVarP(&repo, "repo", "R", defaultRepo, "The targeted repository's full name") + + repositoryCmd := NewCmdRepository() + rootCmd.AddCommand(repositoryCmd) + + workflowCmd := NewCmdWorkflow() + rootCmd.AddCommand(workflowCmd) + + return rootCmd +} diff --git a/internal/dispatch/types.go b/internal/dispatch/types.go index e37e395..7363e23 100644 --- a/internal/dispatch/types.go +++ b/internal/dispatch/types.go @@ -1,12 +1,15 @@ package dispatch import ( + "errors" "net/http" "github.com/cli/cli/v2/pkg/cmd/run/shared" "github.com/cli/cli/v2/pkg/iostreams" ) +var errUnspecifiedRepo = errors.New("A --repo must be specified in the [HOST/]OWNER/REPO format") + type workflowRun struct { ID int64 `json:"id"` WorkflowID int `json:"workflow_id"` diff --git a/internal/dispatch/workflow.go b/internal/dispatch/workflow.go index b5f542d..54472f7 100644 --- a/internal/dispatch/workflow.go +++ b/internal/dispatch/workflow.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/json" "fmt" - "strings" "github.com/MakeNowJust/heredoc" cliapi "github.com/cli/cli/v2/api" @@ -65,11 +64,9 @@ func NewCmdWorkflow() *cobra.Command { --ref my-feature-branch `), RunE: func(cmd *cobra.Command, args []string) error { - r, _ := cmd.Flags().GetString("repo") - repoParts := strings.Split(r, "/") - repo := &ghRepo{ - Owner: repoParts[0], - Name: repoParts[1], + repo, err := getRepoOption(cmd) + if err != nil { + return err } b := []byte(workflowInputs) From 2c3a6ffad1fd5c08a060dfd57347dba352c7d7b8 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Sun, 20 Nov 2022 15:09:07 -0500 Subject: [PATCH 2/2] patch bump version: 0.1.3 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e3d68fd..3741fc1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ SOURCE=./... GOFMT_FILES?=$$(find . -type f -name '*.go') -VERSION?=0.1.2 +VERSION?=0.1.3 default: build