diff --git a/cmd/auth/auth.go b/cmd/auth/auth.go index 3c921bd..1f296bd 100644 --- a/cmd/auth/auth.go +++ b/cmd/auth/auth.go @@ -16,6 +16,7 @@ import ( "os" "os/signal" "path" + "path/filepath" "time" "github.com/cli/browser" @@ -79,7 +80,7 @@ func run() (string, error) { return "", fmt.Errorf("PKCE error: %v", err.Error()) } - supabaseAuthURL := fmt.Sprintf("https://%s.supabase.co/auth/v1/authorize", supabaseID) + supabaseAuthURL := fmt.Sprintf("https://%s.supabase.co/auth/v1/authorize", supabaseBetaID) queryParams := url.Values{ "provider": {"github"}, "code_challenge": {codeChallenge}, @@ -172,8 +173,8 @@ func run() (string, error) { return username, nil } -func getSession(authCode, codeVerifier string) (*accessTokenResponse, error) { - url := fmt.Sprintf("https://%s.supabase.co/auth/v1/token?grant_type=pkce", supabaseID) +func getSession(authCode, codeVerifier string) (*AccessTokenResponse, error) { + url := fmt.Sprintf("https://%s.supabase.co/auth/v1/token?grant_type=pkce", supabaseBetaID) payload := map[string]string{ "auth_code": authCode, @@ -196,7 +197,7 @@ func getSession(authCode, codeVerifier string) (*accessTokenResponse, error) { return nil, fmt.Errorf("unexpected status: %s", res.Status) } - var responseData accessTokenResponse + var responseData AccessTokenResponse if err := json.NewDecoder(res.Body).Decode(&responseData); err != nil { return nil, fmt.Errorf("could not decode JSON response: %s", err.Error()) } @@ -223,3 +224,29 @@ func shutdown(server *http.Server) { } }() } + +func GetUserSession() (AccessTokenResponse, error) { + var accessToken AccessTokenResponse + homeDir, err := os.UserHomeDir() + if err != nil { + return accessToken, err + } + sessionFilePath := filepath.Join(homeDir, ".pizza", "session.json") + + _, err = os.Stat(sessionFilePath) + if err != nil { + return accessToken, fmt.Errorf("Authentication is needed to perform this command. Authenticate using 'pizza login'") + } + + bytes, err := os.ReadFile(sessionFilePath) + if err != nil { + return accessToken, fmt.Errorf("could not read session file") + } + + err = json.Unmarshal(bytes, &accessToken) + if err != nil { + return accessToken, fmt.Errorf("could not unmarshal the token") + } + + return accessToken, nil +} diff --git a/cmd/auth/constants.go b/cmd/auth/constants.go index cb355b8..627a52d 100644 --- a/cmd/auth/constants.go +++ b/cmd/auth/constants.go @@ -2,7 +2,8 @@ package auth const ( codeChallengeLength = 87 - supabaseID = "ibcwmlhcimymasokhgvn" - supabasePublicKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYyOTkzMDc3OCwiZXhwIjoxOTQ1NTA2Nzc4fQ.zcdbd7kDhk7iNSMo8SjsTaXi0wlLNNQcSZkzZ84NUDg" + supabaseBetaID = "fcqqkxwlntnrtjfbcioz" + supabaseProdID = "ibcwmlhcimymasokhgvn" + supabasePublicKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImZjcXFreHdsbnRucnRqZmJjaW96Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTg0MTkyNzQsImV4cCI6MjAxMzk5NTI3NH0.ymWWYdnJC2gsnrJx4lZX2cfSOp-1xVuWFGt1Wr6zwtg" authCallbackAddr = "localhost:3000" ) diff --git a/cmd/auth/schema.go b/cmd/auth/schema.go index 67af08f..4651fb0 100644 --- a/cmd/auth/schema.go +++ b/cmd/auth/schema.go @@ -1,15 +1,15 @@ package auth -type accessTokenResponse struct { +type AccessTokenResponse struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` TokenType string `json:"token_type"` ExpiresIn int `json:"expires_in"` ExpiresAt int `json:"expires_at"` - User userSchema `json:"user"` + User UserSchema `json:"user"` } -type userSchema struct { +type UserSchema struct { ID string `json:"id"` Aud string `json:"aud,omitempty"` Role string `json:"role"` @@ -28,7 +28,7 @@ type userSchema struct { LastSignInAt string `json:"last_sign_in_at"` AppMetadata map[string]interface{} `json:"app_metadata"` UserMetadata map[string]interface{} `json:"user_metadata"` - Factors []mfaFactorSchema `json:"factors"` + Factors []MfaFactorSchema `json:"factors"` Identities []interface{} `json:"identities"` BannedUntil string `json:"banned_until"` CreatedAt string `json:"created_at"` @@ -36,7 +36,7 @@ type userSchema struct { DeletedAt string `json:"deleted_at"` } -type mfaFactorSchema struct { +type MfaFactorSchema struct { ID string `json:"id"` Status string `json:"status"` FriendlyName string `json:"friendly_name"` diff --git a/cmd/bake/bake.go b/cmd/bake/bake.go index 0cd7d99..7dca583 100644 --- a/cmd/bake/bake.go +++ b/cmd/bake/bake.go @@ -76,7 +76,7 @@ func NewBakeCommand() *cobra.Command { } func run(opts *Options) error { - repositories, err := utils.HandleRepositoryValues(opts.Repos, opts.FilePath) + repositories, err := utils.HandleUniqueValues(opts.Repos, opts.FilePath) if err != nil { return err } diff --git a/cmd/insights/contributors.go b/cmd/insights/contributors.go index 28c76a6..8241fd9 100644 --- a/cmd/insights/contributors.go +++ b/cmd/insights/contributors.go @@ -68,7 +68,7 @@ func (opts *contributorsOptions) run(ctx context.Context) error { return fmt.Errorf("invalid period: %d, accepts (7,30,90)", opts.Period) } - repositories, err := utils.HandleRepositoryValues(opts.Repos, opts.FilePath) + repositories, err := utils.HandleUniqueValues(opts.Repos, opts.FilePath) if err != nil { return err } diff --git a/cmd/insights/repositories.go b/cmd/insights/repositories.go index 1b7987b..f64a7a5 100644 --- a/cmd/insights/repositories.go +++ b/cmd/insights/repositories.go @@ -65,7 +65,7 @@ func NewRepositoriesCommand() *cobra.Command { } func (opts *repositoriesOptions) run(ctx context.Context) error { - repositories, err := utils.HandleRepositoryValues(opts.Repos, opts.FilePath) + repositories, err := utils.HandleUniqueValues(opts.Repos, opts.FilePath) if err != nil { return err } diff --git a/cmd/insights/user-contributions.go b/cmd/insights/user-contributions.go index 4f6e312..5941f7f 100644 --- a/cmd/insights/user-contributions.go +++ b/cmd/insights/user-contributions.go @@ -78,7 +78,7 @@ func NewUserContributionsCommand() *cobra.Command { } func (opts *userContributionsOptions) run(ctx context.Context) error { - repositories, err := utils.HandleRepositoryValues(opts.Repos, opts.FilePath) + repositories, err := utils.HandleUniqueValues(opts.Repos, opts.FilePath) if err != nil { return err } diff --git a/cmd/root/root.go b/cmd/root/root.go index faf1ba5..294aee0 100644 --- a/cmd/root/root.go +++ b/cmd/root/root.go @@ -10,6 +10,7 @@ import ( repoquery "github.com/open-sauced/pizza-cli/cmd/repo-query" "github.com/open-sauced/pizza-cli/cmd/show" "github.com/open-sauced/pizza-cli/cmd/version" + "github.com/open-sauced/pizza-cli/cmd/workspaces" "github.com/open-sauced/pizza-cli/pkg/constants" "github.com/spf13/cobra" ) @@ -44,6 +45,7 @@ func NewRootCommand() (*cobra.Command, error) { cmd.AddCommand(insights.NewInsightsCommand()) cmd.AddCommand(version.NewVersionCommand()) cmd.AddCommand(show.NewShowCommand()) + cmd.AddCommand(workspaces.NewWorkspacesCommand()) return cmd, nil } diff --git a/cmd/workspaces/add.go b/cmd/workspaces/add.go new file mode 100644 index 0000000..5f643af --- /dev/null +++ b/cmd/workspaces/add.go @@ -0,0 +1,96 @@ +package workspaces + +import ( + "context" + "fmt" + "net/http" + + client "github.com/open-sauced/go-api/client" + "github.com/open-sauced/pizza-cli/cmd/auth" + "github.com/open-sauced/pizza-cli/pkg/constants" + "github.com/open-sauced/pizza-cli/pkg/utils" + "github.com/spf13/cobra" +) + +type AddCommand struct { + *workspacesOptions + // Repos is the array of git repository urls + Repos []string + // FilePath: the path to the yaml file + FilePath string + // TUI: terminal interface mode + TUI bool +} + +func NewAddWorkSpaceCommand(workspaceOpts *workspacesOptions) *cobra.Command { + addCmd := &AddCommand{FilePath: "", workspacesOptions: workspaceOpts} + cmd := &cobra.Command{ + Use: "add url... [flags]", + Short: "add repositories and contributors to a workspace", + Long: "add repositories and contributors to a workspace", + PreRunE: func(_ *cobra.Command, args []string) error { + if addCmd.Session.AccessToken == "" { + session, err := auth.GetUserSession() + if err != nil { + return err + } + addCmd.Session = session + } + return nil + }, + Args: func(cmd *cobra.Command, args []string) error { + fileFlag := cmd.Flags().Lookup(constants.FlagNameFile) + if !fileFlag.Changed && len(args) == 0 && !addCmd.TUI { + return fmt.Errorf("must specify git repository url argument(s) or provide %s flag", fileFlag.Name) + + } + addCmd.Repos = append(addCmd.Repos, args...) + return nil + }, + + RunE: func(cmd *cobra.Command, args []string) error { + return addCmd.run() + }, + TraverseChildren: true, + } + + cmd.Flags().StringVarP(&addCmd.FilePath, constants.FlagNameFile, "f", "", "Path to yaml file containing an array of git repository urls") + cmd.Flags().StringVarP(&addCmd.WorkspaceName, "name", "n", addCmd.WorkspaceName, "name of the workspace to be created") + cmd.Flags().BoolVar(&addCmd.TUI, "tui", addCmd.TUI, "use terminal user interface") + return cmd +} + +func (a *AddCommand) run() error { + var workspaceData client.CreateWorkspaceDto + var err error + if a.TUI { + workspaceData, err = a.createView() + if err != nil { + return err + } + } else { + repos, err := utils.HandleUniqueValues(a.Repos, a.FilePath) + if err != nil { + return err + } + parsedRepos := make([]interface{}, len(repos)) + i := 0 + for repo := range repos { + parsedRepos[i] = repo + i++ + } + workspaceData = *client.NewCreateWorkspaceDto(a.WorkspaceName, "my workspace", []interface{}{a.Session.User.UserMetadata["user_name"]}, parsedRepos) + } + + authCtx := context.WithValue(context.Background(), client.ContextAccessToken, a.Session.AccessToken) + _, r, err := a.APIClient.WorkspacesServiceAPI.CreateWorkspaceForUser(authCtx).CreateWorkspaceDto(workspaceData).Execute() + if err != nil { + return err + } + if r.StatusCode != http.StatusCreated { + return fmt.Errorf("HTTP status: %d", r.StatusCode) + } + + fmt.Printf("Workspace %s, has been created!", workspaceData.Name) + return nil +} diff --git a/cmd/workspaces/list.go b/cmd/workspaces/list.go new file mode 100644 index 0000000..67dbb3c --- /dev/null +++ b/cmd/workspaces/list.go @@ -0,0 +1,51 @@ +package workspaces + +import ( + "context" + "fmt" + "net/http" + + sw "github.com/open-sauced/go-api/client" + "github.com/open-sauced/pizza-cli/cmd/auth" + "github.com/spf13/cobra" +) + +type ListCommandOpts struct { + *workspacesOptions +} + +func NewListWorkSpaceCommand(workspaceOpts *workspacesOptions) *cobra.Command { + opts := &ListCommandOpts{workspaceOpts} + cmd := &cobra.Command{ + Use: "list", + Short: "list all workspaces", + Long: "retrieve all the workspaces", + PreRunE: func(_ *cobra.Command, args []string) error { + if opts.Session.AccessToken == "" { + session, err := auth.GetUserSession() + if err != nil { + return err + } + opts.Session = session + } + return nil + }, + RunE: func(_ *cobra.Command, args []string) error { + return opts.run() + }, + } + return cmd +} + +func (opts *ListCommandOpts) run() error { + authCtx := context.WithValue(context.Background(), sw.ContextAccessToken, opts.Session.AccessToken) + // here should return an array of DbWorkspace + _, r, err := opts.APIClient.WorkspacesServiceAPI.GetWorkspaceForUser(authCtx).Execute() + if err != nil { + return err + } + if r.StatusCode != http.StatusOK { + return fmt.Errorf("HTTP status: %d", r.StatusCode) + } + return nil +} diff --git a/cmd/workspaces/views.go b/cmd/workspaces/views.go new file mode 100644 index 0000000..ee9cb20 --- /dev/null +++ b/cmd/workspaces/views.go @@ -0,0 +1,53 @@ +package workspaces + +import ( + "fmt" + + "github.com/charmbracelet/huh" + client "github.com/open-sauced/go-api/client" + "github.com/open-sauced/pizza-cli/pkg/utils" +) + +func (a *AddCommand) createView() (client.CreateWorkspaceDto, error) { + formValues := client.CreateWorkspaceDto{} + var reposInput, membersInput string + form := huh.NewForm( + huh.NewGroup( + huh.NewInput().Title("Workspace Name").Value(&formValues.Name).Validate(func(s string) error { + if s == "" { + return fmt.Errorf("workspace name required") + } + return nil + }), + huh.NewText().Title("Description").Value(&formValues.Description).Lines(2), + huh.NewText().Title("Repositories"). + Description("repositories to add to the workspace (yaml file, or comma separated values)").Lines(2). + Validate(func(input string) error { + if _, err := utils.ParseFileAndCSV(input); err != nil { + return err + } + + return nil + }).Value(&reposInput), + huh.NewText().Title("Members").Description("members to add to the workspace (yaml file, or comma separated values)").Lines(2). + Validate(func(input string) error { + if _, err := utils.ParseFileAndCSV(input); err != nil { + return err + } + return nil + }).Value(&membersInput), + ), + ) + + if err := form.Run(); err != nil { + return formValues, err + } + + // errors are checked in form + repos, _ := utils.ParseFileAndCSV(reposInput) + members, _ := utils.ParseFileAndCSV(membersInput) + formValues.Repos = repos + formValues.Members = members + + return formValues, nil +} diff --git a/cmd/workspaces/workspaces.go b/cmd/workspaces/workspaces.go new file mode 100644 index 0000000..c6c267b --- /dev/null +++ b/cmd/workspaces/workspaces.go @@ -0,0 +1,52 @@ +package workspaces + +import ( + "context" + "fmt" + + "github.com/google/uuid" + "github.com/open-sauced/go-api/client" + "github.com/open-sauced/pizza-cli/cmd/auth" + "github.com/open-sauced/pizza-cli/pkg/api" + "github.com/open-sauced/pizza-cli/pkg/constants" + "github.com/spf13/cobra" +) + +// workspacesOptions are the options for the pizza workspaces command including user +// defined configurations +type workspacesOptions struct { + // WorkspaceName: name of the workspaces to be created + WorkspaceName string + // APIClient: api client to interface with open sauced api + APIClient *client.APIClient + // Session: the user session + Session auth.AccessTokenResponse + + ServerContext context.Context +} + +func newDefaultWorkspacesOptions() *workspacesOptions { + return &workspacesOptions{ + WorkspaceName: fmt.Sprintf("workspace-%s", uuid.NewString()), + APIClient: api.NewGoClient(constants.EndpointBeta), + Session: auth.AccessTokenResponse{}, + ServerContext: context.TODO(), + } +} + +// NewWorkspacesCommand returns a new cobra command for 'pizza workspaces' +func NewWorkspacesCommand() *cobra.Command { + opts := newDefaultWorkspacesOptions() + cmd := &cobra.Command{ + Use: "workspaces [flags] [flags]", + Short: "Manage, share, and track open source projects", + Long: "Centralized hub for managing, sharing, and tracking open source projects", + RunE: func(cmd *cobra.Command, _ []string) error { + return cmd.Help() + }, + } + cmd.Flags().StringVarP(&opts.WorkspaceName, "name", "n", opts.WorkspaceName, "name of the workspace to be created") + cmd.AddCommand(NewListWorkSpaceCommand(opts)) + cmd.AddCommand(NewAddWorkSpaceCommand(opts)) + return cmd +} diff --git a/go.mod b/go.mod index 0445ee7..8390d93 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,12 @@ module github.com/open-sauced/pizza-cli go 1.21 require ( - github.com/charmbracelet/bubbles v0.16.1 - github.com/charmbracelet/bubbletea v0.24.2 + github.com/charmbracelet/bubbles v0.17.2-0.20240108170749-ec883029c8e6 + github.com/charmbracelet/bubbletea v0.25.0 + github.com/charmbracelet/huh v0.3.0 github.com/charmbracelet/lipgloss v0.9.1 github.com/cli/browser v1.3.0 + github.com/google/uuid v1.3.1 github.com/open-sauced/go-api/client v0.0.0-20240205155059-a3159bc0517e github.com/posthog/posthog-go v0.0.0-20230801140217-d607812dee69 github.com/spf13/cobra v1.7.0 @@ -18,8 +20,8 @@ require ( require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/catppuccin/go v0.2.0 // indirect github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 // indirect - github.com/google/uuid v1.3.1 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -30,7 +32,7 @@ require ( github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/sahilm/fuzzy v0.1.0 // indirect + github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect golang.org/x/sync v0.4.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect diff --git a/go.sum b/go.sum index 628dc94..6b8afd4 100644 --- a/go.sum +++ b/go.sum @@ -3,16 +3,18 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY= -github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc= -github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY= -github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg= +github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA= +github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc= +github.com/charmbracelet/bubbles v0.17.2-0.20240108170749-ec883029c8e6 h1:6nVCV8pqGaeyxetur3gpX3AAaiyKgzjIoCPV3NXKZBE= +github.com/charmbracelet/bubbles v0.17.2-0.20240108170749-ec883029c8e6/go.mod h1:9HxZWlkCqz2PRwsCbYl7a3KXvGzFaDHpYbSYMJ+nE3o= +github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= +github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= +github.com/charmbracelet/huh v0.3.0 h1:CxPplWkgW2yUTDDG0Z4S5HH8SJOosWHd4LxCvi0XsKE= +github.com/charmbracelet/huh v0.3.0/go.mod h1:fujUdKX8tC45CCSaRQdw789O6uaCRwx8l2NDyKfC4jA= github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo= github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk= -github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= -github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5 h1:Ig+OPkE3XQrrl+SKsOqAjlkrBN/zrr+Qpw7rCuDjRCE= github.com/containerd/console v1.0.4-0.20230706203907-8f6c4e4faef5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -41,14 +43,6 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= -github.com/open-sauced/go-api/client v0.0.0-20231023202852-271ed316d5fd h1:xWarN75bBSNVdXJ9DkTRwWnmDG/uAooasLp1IOakIPI= -github.com/open-sauced/go-api/client v0.0.0-20231023202852-271ed316d5fd/go.mod h1:W/TRuLUqYpMvkmElDUQvQ07xlxhK8TOfpwRh8SCAuNA= -github.com/open-sauced/go-api/client v0.0.0-20231024233005-61e58f577005 h1:qrsKqDy8Duw/MNPoaAyD3R/kZScSYosWKBI5jIR6Iwk= -github.com/open-sauced/go-api/client v0.0.0-20231024233005-61e58f577005/go.mod h1:W/TRuLUqYpMvkmElDUQvQ07xlxhK8TOfpwRh8SCAuNA= -github.com/open-sauced/go-api/client v0.0.0-20231025234817-a8f01f3b26d8 h1:qzSaxN4BdovOr2DjXcYJz4LH7RSXEdhw98zAdnJVqJU= -github.com/open-sauced/go-api/client v0.0.0-20231025234817-a8f01f3b26d8/go.mod h1:W/TRuLUqYpMvkmElDUQvQ07xlxhK8TOfpwRh8SCAuNA= -github.com/open-sauced/go-api/client v0.0.0-20240202223515-f3f8157b083d h1:e9c07oVveXyHHhcu85hKHicl2K+ruAcAXX5BUd4StO8= -github.com/open-sauced/go-api/client v0.0.0-20240202223515-f3f8157b083d/go.mod h1:W/TRuLUqYpMvkmElDUQvQ07xlxhK8TOfpwRh8SCAuNA= github.com/open-sauced/go-api/client v0.0.0-20240205155059-a3159bc0517e h1:3j5r7ArokAO+u8vhgQPklp5qnGxA+MkXluRYt2qTnik= github.com/open-sauced/go-api/client v0.0.0-20240205155059-a3159bc0517e/go.mod h1:W/TRuLUqYpMvkmElDUQvQ07xlxhK8TOfpwRh8SCAuNA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -60,8 +54,8 @@ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= -github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= +github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wrYjDSCcZ78NoftLQyHBSLW/Cx79Y= +github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= diff --git a/pkg/utils/arguments.go b/pkg/utils/arguments.go index bcef797..0191f60 100644 --- a/pkg/utils/arguments.go +++ b/pkg/utils/arguments.go @@ -1,29 +1,72 @@ package utils import ( + "fmt" "os" + "strings" "gopkg.in/yaml.v3" ) -func HandleRepositoryValues(repos []string, filePath string) (map[string]struct{}, error) { - uniqueRepoURLs := make(map[string]struct{}) - for _, repo := range repos { - uniqueRepoURLs[repo] = struct{}{} +// HandleUniqueValues: returns unique values +func HandleUniqueValues(args []string, filePath string) (map[string]struct{}, error) { + uniqueValues := make(map[string]struct{}) + for _, arg := range args { + uniqueValues[arg] = struct{}{} } if filePath != "" { file, err := os.ReadFile(filePath) if err != nil { return nil, err } - var reposFromYaml []string - err = yaml.Unmarshal(file, &reposFromYaml) + var valuesFromYaml []string + err = yaml.Unmarshal(file, &valuesFromYaml) if err != nil { return nil, err } - for _, repo := range reposFromYaml { - uniqueRepoURLs[repo] = struct{}{} + for _, arg := range valuesFromYaml { + uniqueValues[arg] = struct{}{} } } - return uniqueRepoURLs, nil + return uniqueValues, nil +} + +// IsYAMLFile: returns true if the file given is a yaml file +func IsYAMLFile(input string) bool { + contents := strings.Split(input, ".") + if len(contents) != 2 { + return false + } + return contents[1] == "yml" || contents[1] == "yaml" +} + +// ParseFileAndCSV: parses arguments in csv form or a yaml filepath, and returns the values as a string slice +func ParseFileAndCSV(input string) ([]interface{}, error) { + var parsedValues []interface{} + if input == "" { + return parsedValues, fmt.Errorf("field was not provided") + } + + var values map[string]struct{} + var err error + if IsYAMLFile(input) { + values, err = HandleUniqueValues([]string{}, input) + if err != nil { + return parsedValues, err + } + } else { + csv := strings.Split(input, ",") + values, err = HandleUniqueValues(csv, "") + if err != nil { + return parsedValues, err + } + } + + parsedValues = make([]interface{}, len(values)) + i := 0 + for val := range values { + parsedValues[i] = val + i++ + } + return parsedValues, nil }