From ec8d38a048fde54d61eae3f750d53085fd42273e Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Wed, 4 Sep 2024 14:28:06 -0700 Subject: [PATCH 01/36] init command --- cmd/generate/config/config.go | 51 +++++++++++++++++++++++++++++++++++ cmd/generate/generate.go | 3 +++ 2 files changed, 54 insertions(+) create mode 100644 cmd/generate/config/config.go diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go new file mode 100644 index 0000000..cd70f54 --- /dev/null +++ b/cmd/generate/config/config.go @@ -0,0 +1,51 @@ +package config + +import ( + "errors" + "github.com/spf13/cobra" + + "github.com/open-sauced/pizza-cli/pkg/config" +) + +// Options for the codeowners generation command +type Options struct { + // the path to the git repository on disk to generate a codeowners file for + path string + + tty bool + loglevel int + + config *config.Spec +} + +const codeownersLongDesc string = `WARNING: Proof of concept feature. + +Generates a ~/.sauced.yaml configuration file. The attribution of emails to given entities +is based on the repository this command is ran in.` + +func NewConfigCommand() *cobra.Command { + opts := &Options{} + print(opts.path); + + cmd := &cobra.Command{ + Use: "config path/to/repo [flags]", + Short: "Generates a \"~/.sauced.yaml\" config based on the current repository", + Long: codeownersLongDesc, + Args: func(_ *cobra.Command, args []string) error { + if len(args) != 1 { + return errors.New("you must provide exactly one argument: the path to the repository") + } + + path := args[0] + print(path) + + return nil + }, + + RunE: func(cmd *cobra.Command, _ []string) error { + return nil + }, + } + + return cmd +} diff --git a/cmd/generate/generate.go b/cmd/generate/generate.go index b3ff321..6d1a29f 100644 --- a/cmd/generate/generate.go +++ b/cmd/generate/generate.go @@ -6,6 +6,8 @@ import ( "github.com/spf13/cobra" "github.com/open-sauced/pizza-cli/cmd/generate/codeowners" + + "github.com/open-sauced/pizza-cli/cmd/generate/config" ) const generateLongDesc string = `WARNING: Proof of concept feature. @@ -28,6 +30,7 @@ func NewGenerateCommand() *cobra.Command { } cmd.AddCommand(codeowners.NewCodeownersCommand()) + cmd.AddCommand(config.NewConfigCommand()) return cmd } From 104bf47830a7374e7d672c750bbd05ceafcbdcd0 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Wed, 4 Sep 2024 16:45:19 -0700 Subject: [PATCH 02/36] print every commit and its author email and name --- cmd/generate/config/config.go | 50 ++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index cd70f54..a74f0c9 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -2,6 +2,12 @@ package config import ( "errors" + "fmt" + "os" + "path/filepath" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/object" "github.com/spf13/cobra" "github.com/open-sauced/pizza-cli/pkg/config" @@ -12,8 +18,9 @@ type Options struct { // the path to the git repository on disk to generate a codeowners file for path string - tty bool - loglevel int + previousDays int + tty bool + loglevel int config *config.Spec } @@ -25,7 +32,6 @@ is based on the repository this command is ran in.` func NewConfigCommand() *cobra.Command { opts := &Options{} - print(opts.path); cmd := &cobra.Command{ Use: "config path/to/repo [flags]", @@ -37,15 +43,47 @@ func NewConfigCommand() *cobra.Command { } path := args[0] - print(path) - return nil + // Validate that the path is a real path on disk and accessible by the user + absPath, err := filepath.Abs(path) + if err != nil { + return err + } + + if _, err := os.Stat(absPath); os.IsNotExist(err) { + return fmt.Errorf("the provided path does not exist: %w", err) + } + + opts.path = absPath + return nil }, RunE: func(cmd *cobra.Command, _ []string) error { - return nil + // TODO: error checking based on given command + + return run(opts, cmd) }, } return cmd } + +func run(opts *Options, cmd *cobra.Command) error { + configuration := &config.Spec{} + fmt.Println("CONFIG", configuration) + + // Open repo + repo, err := git.PlainOpen(opts.path) + if err != nil { + return fmt.Errorf("error opening repo: %w", err) + } + + commitIter, err := repo.CommitObjects() + + commitIter.ForEach(func(c *object.Commit) error { + fmt.Println("COMMIT", c.Author.Email, c.Author.Name) + return nil + }) + + return nil +} From 1d5fdebd98d98bed3c6e71bbb4e747a68477e2c6 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Wed, 4 Sep 2024 17:06:48 -0700 Subject: [PATCH 03/36] remove passed cmd to run, create attributionMap based on commits --- cmd/generate/config/config.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index a74f0c9..fd71278 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -1,10 +1,12 @@ package config import ( + "encoding/json" "errors" "fmt" "os" "path/filepath" + "slices" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" @@ -61,16 +63,16 @@ func NewConfigCommand() *cobra.Command { RunE: func(cmd *cobra.Command, _ []string) error { // TODO: error checking based on given command - return run(opts, cmd) + return run(opts) }, } return cmd } -func run(opts *Options, cmd *cobra.Command) error { - configuration := &config.Spec{} - fmt.Println("CONFIG", configuration) +func run(opts *Options) error { + attributionMap := make(map[string][]string) + fmt.Println("CONFIG", attributionMap) // Open repo repo, err := git.PlainOpen(opts.path) @@ -81,9 +83,20 @@ func run(opts *Options, cmd *cobra.Command) error { commitIter, err := repo.CommitObjects() commitIter.ForEach(func(c *object.Commit) error { - fmt.Println("COMMIT", c.Author.Email, c.Author.Name) + name := c.Author.Name + email := c.Author.Email + + doesEmailExist := slices.Contains(attributionMap[name], email) + if !doesEmailExist { + attributionMap[name] = append(attributionMap[name], email) + } + return nil }) + // for pretty print test + test, err := json.MarshalIndent(attributionMap, "", " ") + fmt.Println(string(test)) + return nil } From 62c2793a284696538f584acec451ec83eed1bd3d Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Thu, 5 Sep 2024 10:51:44 -0700 Subject: [PATCH 04/36] remove ununsed Options props, create .sauced.yaml file --- cmd/generate/config/config.go | 21 ++++++++++----------- cmd/generate/config/output.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 cmd/generate/config/output.go diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index fd71278..56b6d5e 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -1,7 +1,6 @@ package config import ( - "encoding/json" "errors" "fmt" "os" @@ -18,12 +17,7 @@ import ( // Options for the codeowners generation command type Options struct { // the path to the git repository on disk to generate a codeowners file for - path string - - previousDays int - tty bool - loglevel int - + path string config *config.Spec } @@ -72,7 +66,6 @@ func NewConfigCommand() *cobra.Command { func run(opts *Options) error { attributionMap := make(map[string][]string) - fmt.Println("CONFIG", attributionMap) // Open repo repo, err := git.PlainOpen(opts.path) @@ -86,17 +79,23 @@ func run(opts *Options) error { name := c.Author.Name email := c.Author.Email + // TODO: edge case- same email multiple names + // eg: 'coding@zeu.dev' = 'zeudev' & 'Zeu Capua' + + // AUTOMATIC: set every name and associated emails doesEmailExist := slices.Contains(attributionMap[name], email) if !doesEmailExist { attributionMap[name] = append(attributionMap[name], email) } + // TODO: INTERACTIVE: per unique email, set a name (existing or new) + return nil }) - // for pretty print test - test, err := json.MarshalIndent(attributionMap, "", " ") - fmt.Println(string(test)) + // generate an output file + // default: `~/.sauced.yaml` + generateOutputFile(".sauced.yaml", attributionMap) return nil } diff --git a/cmd/generate/config/output.go b/cmd/generate/config/output.go new file mode 100644 index 0000000..77e2ca5 --- /dev/null +++ b/cmd/generate/config/output.go @@ -0,0 +1,34 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/open-sauced/pizza-cli/pkg/config" + "github.com/open-sauced/pizza-cli/pkg/utils" +) + +func generateOutputFile(outputPath string, attributionMap map[string][]string) error { + // Open the file for writing + homeDir, err := os.UserHomeDir() + file, err := os.Create(filepath.Join(homeDir, outputPath)) + if err != nil { + return fmt.Errorf("error creating %s file: %w", outputPath, err) + } + defer file.Close() + + var config config.Spec + config.Attributions = attributionMap + + // for pretty print test + yaml, err := utils.OutputYAML(config) + + if err != nil { + return fmt.Errorf("Failed to turn into YAML") + } + + file.WriteString(yaml) + + return nil +} From 06e9bf1398ddc940dc16349b89f7492ba9b69c38 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Thu, 5 Sep 2024 11:15:38 -0700 Subject: [PATCH 05/36] implement --output-path flag --- cmd/generate/config/config.go | 25 +++++++++++++++++-------- cmd/generate/config/output.go | 5 +---- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 56b6d5e..dd549ca 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -10,18 +10,18 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" "github.com/spf13/cobra" - - "github.com/open-sauced/pizza-cli/pkg/config" ) -// Options for the codeowners generation command +// Options for the config generation command type Options struct { // the path to the git repository on disk to generate a codeowners file for path string - config *config.Spec + + // where the '.sauced.yaml' file will go + outputPath string } -const codeownersLongDesc string = `WARNING: Proof of concept feature. +const configLongDesc string = `WARNING: Proof of concept feature. Generates a ~/.sauced.yaml configuration file. The attribution of emails to given entities is based on the repository this command is ran in.` @@ -32,7 +32,7 @@ func NewConfigCommand() *cobra.Command { cmd := &cobra.Command{ Use: "config path/to/repo [flags]", Short: "Generates a \"~/.sauced.yaml\" config based on the current repository", - Long: codeownersLongDesc, + Long: configLongDesc, Args: func(_ *cobra.Command, args []string) error { if len(args) != 1 { return errors.New("you must provide exactly one argument: the path to the repository") @@ -57,10 +57,13 @@ func NewConfigCommand() *cobra.Command { RunE: func(cmd *cobra.Command, _ []string) error { // TODO: error checking based on given command + opts.outputPath, _ = cmd.Flags().GetString("output-path"); + return run(opts) }, } + cmd.PersistentFlags().StringP("output-path", "o", "~/", "Directory to create the `.sauced.yaml` file.") return cmd } @@ -94,8 +97,14 @@ func run(opts *Options) error { }) // generate an output file - // default: `~/.sauced.yaml` - generateOutputFile(".sauced.yaml", attributionMap) + // default: `~/.sauced.yaml` + if opts.outputPath == "~/" { + homeDir, _ := os.UserHomeDir() + generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + } else { + generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + } + return nil } diff --git a/cmd/generate/config/output.go b/cmd/generate/config/output.go index 77e2ca5..8cc4723 100644 --- a/cmd/generate/config/output.go +++ b/cmd/generate/config/output.go @@ -3,16 +3,13 @@ package config import ( "fmt" "os" - "path/filepath" "github.com/open-sauced/pizza-cli/pkg/config" "github.com/open-sauced/pizza-cli/pkg/utils" ) func generateOutputFile(outputPath string, attributionMap map[string][]string) error { - // Open the file for writing - homeDir, err := os.UserHomeDir() - file, err := os.Create(filepath.Join(homeDir, outputPath)) + file, err := os.Create(outputPath) if err != nil { return fmt.Errorf("error creating %s file: %w", outputPath, err) } From 702ccefbbcc933bca9cca9ffd0e77faf3089cfa6 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Fri, 6 Sep 2024 13:28:56 -0700 Subject: [PATCH 06/36] wip interactive mode --- cmd/generate/config/config.go | 132 ++++++++++++++++++++++++++++++---- go.mod | 5 +- go.sum | 2 + 3 files changed, 126 insertions(+), 13 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index dd549ca..6bc9eb6 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -9,16 +9,26 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" + "github.com/jpmcb/gopherlogs" + "github.com/open-sauced/pizza-cli/pkg/logging" "github.com/spf13/cobra" + + "github.com/charmbracelet/bubbles/help" + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" ) // Options for the config generation command type Options struct { // the path to the git repository on disk to generate a codeowners file for - path string + path string // where the '.sauced.yaml' file will go outputPath string + + // whether to use interactive mode + isInteractive bool } const configLongDesc string = `WARNING: Proof of concept feature. @@ -57,17 +67,21 @@ func NewConfigCommand() *cobra.Command { RunE: func(cmd *cobra.Command, _ []string) error { // TODO: error checking based on given command - opts.outputPath, _ = cmd.Flags().GetString("output-path"); + opts.outputPath, _ = cmd.Flags().GetString("output-path") + opts.isInteractive, _ = cmd.Flags().GetBool("interactive") return run(opts) }, } cmd.PersistentFlags().StringP("output-path", "o", "~/", "Directory to create the `.sauced.yaml` file.") + cmd.PersistentFlags().BoolP("interactive", "i", true, "Whether to be interactive") return cmd } func run(opts *Options) error { + logger, err := gopherlogs.NewLogger() + attributionMap := make(map[string][]string) // Open repo @@ -84,20 +98,30 @@ func run(opts *Options) error { // TODO: edge case- same email multiple names // eg: 'coding@zeu.dev' = 'zeudev' & 'Zeu Capua' - - // AUTOMATIC: set every name and associated emails - doesEmailExist := slices.Contains(attributionMap[name], email) - if !doesEmailExist { - attributionMap[name] = append(attributionMap[name], email) + + if !opts.isInteractive { + doesEmailExist := slices.Contains(attributionMap[name], email) + if !doesEmailExist { + // AUTOMATIC: set every name and associated emails + attributionMap[name] = append(attributionMap[name], email) + } + } else { + // TODO: INTERACTIVE: per unique email, set a name (existing or new or ignore) + var uniqueEmails []string + if slices.Contains(uniqueEmails, email) { + uniqueEmails = append(uniqueEmails, email) + } + program := tea.NewProgram(initialModel(uniqueEmails)) + if _, err := program.Run(); err != nil { + logger.V(logging.LogError).Info(err.Error()) + } } - - // TODO: INTERACTIVE: per unique email, set a name (existing or new) - return nil }) + // generate an output file - // default: `~/.sauced.yaml` + // default: `~/.sauced.yaml` if opts.outputPath == "~/" { homeDir, _ := os.UserHomeDir() generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) @@ -105,6 +129,90 @@ func run(opts *Options) error { generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) } - return nil } + +// Bubbletea for Interactive Mode + +type model struct { + textInput textinput.Model + help help.Model + keymap keymap + + attributionMap map[string][]string + uniqueEmails []string + currentIndex int +} + +type keymap struct{} + +func (k keymap) ShortHelp() []key.Binding { + return []key.Binding{ + key.NewBinding(key.WithKeys("tab"), key.WithHelp("tab", "complete")), + key.NewBinding(key.WithKeys("ctrl+n"), key.WithHelp("ctrl+n", "next")), + key.NewBinding(key.WithKeys("ctrl+p"), key.WithHelp("ctrl+p", "prev")), + key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "quit")), + } +} + +func (k keymap) FullHelp() [][]key.Binding { + return [][]key.Binding{k.ShortHelp()} +} + +func initialModel(uniqueEmails []string) model { + ti := textinput.New() + ti.Placeholder = "name" + ti.Focus() + ti.ShowSuggestions = true + + return model{ + textInput: ti, + help: help.New(), + keymap: keymap{}, + + attributionMap: make(map[string][]string), + uniqueEmails: uniqueEmails, + currentIndex: 0, + } +} + +func (m model) Init() tea.Cmd { + return textinput.Blink +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var cmd tea.Cmd + currentEmail := m.uniqueEmails[m.currentIndex] + + + existingUsers := make([]string, len(m.attributionMap)) + for k := range m.attributionMap { + existingUsers = append(existingUsers, k) + } + + m.textInput.SetSuggestions(existingUsers) + + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.Type { + case tea.KeyCtrlC, tea.KeyEsc: + return m, tea.Quit + + case tea.KeyEnter: + m.attributionMap[currentEmail] = append(m.attributionMap[currentEmail], m.textInput.Value()) + } + } + + m.textInput, cmd = m.textInput.Update(msg) + + return m, cmd +} + +func (m model) View() string { + return fmt.Sprintf( + "Found email %s - who to attribute to?: %s\n\n%s\n", + m.uniqueEmails[m.currentIndex], + m.textInput.View(), + m.help.View(m.keymap), + ) +} diff --git a/go.mod b/go.mod index a28aa98..dd05559 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,10 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) -require github.com/charmbracelet/bubbletea v0.27.1 // indirect +require ( + github.com/atotto/clipboard v0.1.4 // indirect + github.com/charmbracelet/bubbletea v0.27.1 // indirect +) require ( dario.cat/mergo v1.0.0 // indirect diff --git a/go.sum b/go.sum index 3adc853..51da393 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +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/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= From 852cd6196abdf3503028b0f3fb69177f7e272fa1 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Fri, 6 Sep 2024 14:23:40 -0700 Subject: [PATCH 07/36] go through each email with autocomplete --- cmd/generate/config/config.go | 68 +++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 6bc9eb6..fc9f713 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -9,8 +9,6 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" - "github.com/jpmcb/gopherlogs" - "github.com/open-sauced/pizza-cli/pkg/logging" "github.com/spf13/cobra" "github.com/charmbracelet/bubbles/help" @@ -80,8 +78,6 @@ func NewConfigCommand() *cobra.Command { } func run(opts *Options) error { - logger, err := gopherlogs.NewLogger() - attributionMap := make(map[string][]string) // Open repo @@ -92,13 +88,14 @@ func run(opts *Options) error { commitIter, err := repo.CommitObjects() + var uniqueEmails []string commitIter.ForEach(func(c *object.Commit) error { name := c.Author.Name email := c.Author.Email // TODO: edge case- same email multiple names // eg: 'coding@zeu.dev' = 'zeudev' & 'Zeu Capua' - + if !opts.isInteractive { doesEmailExist := slices.Contains(attributionMap[name], email) if !doesEmailExist { @@ -106,19 +103,18 @@ func run(opts *Options) error { attributionMap[name] = append(attributionMap[name], email) } } else { - // TODO: INTERACTIVE: per unique email, set a name (existing or new or ignore) - var uniqueEmails []string - if slices.Contains(uniqueEmails, email) { + if !slices.Contains(uniqueEmails, email) { uniqueEmails = append(uniqueEmails, email) } - program := tea.NewProgram(initialModel(uniqueEmails)) - if _, err := program.Run(); err != nil { - logger.V(logging.LogError).Info(err.Error()) - } } return nil }) + // TODO: INTERACTIVE: per unique email, set a name (existing or new or ignore) + program := tea.NewProgram(initialModel(uniqueEmails)) + if _, err := program.Run(); err != nil { + return fmt.Errorf(err.Error()) + } // generate an output file // default: `~/.sauced.yaml` @@ -136,12 +132,12 @@ func run(opts *Options) error { type model struct { textInput textinput.Model - help help.Model - keymap keymap + help help.Model + keymap keymap attributionMap map[string][]string - uniqueEmails []string - currentIndex int + uniqueEmails []string + currentIndex int } type keymap struct{} @@ -151,7 +147,9 @@ func (k keymap) ShortHelp() []key.Binding { key.NewBinding(key.WithKeys("tab"), key.WithHelp("tab", "complete")), key.NewBinding(key.WithKeys("ctrl+n"), key.WithHelp("ctrl+n", "next")), key.NewBinding(key.WithKeys("ctrl+p"), key.WithHelp("ctrl+p", "prev")), + key.NewBinding(key.WithKeys("ctrl+i"), key.WithHelp("ctrl+i", "ignore email")), key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "quit")), + key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "submit")), } } @@ -167,12 +165,12 @@ func initialModel(uniqueEmails []string) model { return model{ textInput: ti, - help: help.New(), - keymap: keymap{}, + help: help.New(), + keymap: keymap{}, attributionMap: make(map[string][]string), - uniqueEmails: uniqueEmails, - currentIndex: 0, + uniqueEmails: uniqueEmails, + currentIndex: 0, } } @@ -184,23 +182,31 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd currentEmail := m.uniqueEmails[m.currentIndex] - - existingUsers := make([]string, len(m.attributionMap)) + existingUsers := make([]string, 0, len(m.attributionMap)) for k := range m.attributionMap { - existingUsers = append(existingUsers, k) + existingUsers = append(existingUsers, k) } m.textInput.SetSuggestions(existingUsers) switch msg := msg.(type) { - case tea.KeyMsg: - switch msg.Type { - case tea.KeyCtrlC, tea.KeyEsc: - return m, tea.Quit - - case tea.KeyEnter: - m.attributionMap[currentEmail] = append(m.attributionMap[currentEmail], m.textInput.Value()) + case tea.KeyMsg: + switch msg.Type { + case tea.KeyCtrlC, tea.KeyEsc: + return m, tea.Quit + + case tea.KeyCtrlI: + m.currentIndex++ + return m, nil + + case tea.KeyEnter: + m.attributionMap[m.textInput.Value()] = append(m.attributionMap[currentEmail], currentEmail) + m.currentIndex++ + if m.currentIndex > len(m.attributionMap) { + return m, tea.Quit } + return m, nil + } } m.textInput, cmd = m.textInput.Update(msg) @@ -212,7 +218,7 @@ func (m model) View() string { return fmt.Sprintf( "Found email %s - who to attribute to?: %s\n\n%s\n", m.uniqueEmails[m.currentIndex], - m.textInput.View(), + m.textInput.View(), m.help.View(m.keymap), ) } From 49f1fd3fc4df24b95724feb1918dc80276cd017e Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Fri, 6 Sep 2024 18:11:44 -0400 Subject: [PATCH 08/36] fix: skip interactive steps in generate codeowners with --tty-disable flag (#159) --- cmd/generate/codeowners/codeowners.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/generate/codeowners/codeowners.go b/cmd/generate/codeowners/codeowners.go index 4741a67..76e9050 100644 --- a/cmd/generate/codeowners/codeowners.go +++ b/cmd/generate/codeowners/codeowners.go @@ -171,6 +171,11 @@ func run(opts *Options, cmd *cobra.Command) error { opts.logger.V(logging.LogInfo).Style(0, colors.FgGreen).Infof("Finished generating file: %s\n", outputPath) opts.telemetry.CaptureCodeownersGenerate() + // ignore the interactive prompts for CI/CD environments + if opts.tty { + return nil + } + // 1. Ask if they want to add users to a list var input string fmt.Print("Do you want to add these codeowners to an OpenSauced Contributor Insight? (y/n): ") From 19b17116a1e79706563718da56a53bf494f83181 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Fri, 6 Sep 2024 22:12:23 +0000 Subject: [PATCH 09/36] chore(patch): release 1.3.1-beta.1 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.3.1-beta.1](https://github.com/open-sauced/pizza-cli/compare/v1.3.0...v1.3.1-beta.1) (2024-09-06) ### 🐛 Bug Fixes * skip interactive steps in generate codeowners with --tty-disable flag ([#159](https://github.com/open-sauced/pizza-cli/issues/159)) ([49f1fd3](https://github.com/open-sauced/pizza-cli/commit/49f1fd3fc4df24b95724feb1918dc80276cd017e)) --- CHANGELOG.md | 7 +++++++ npm/package-lock.json | 4 ++-- npm/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bfa1fc..31dd581 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.3.1-beta.1](https://github.com/open-sauced/pizza-cli/compare/v1.3.0...v1.3.1-beta.1) (2024-09-06) + + +### 🐛 Bug Fixes + +* skip interactive steps in generate codeowners with --tty-disable flag ([#159](https://github.com/open-sauced/pizza-cli/issues/159)) ([49f1fd3](https://github.com/open-sauced/pizza-cli/commit/49f1fd3fc4df24b95724feb1918dc80276cd017e)) + ## [1.3.0](https://github.com/open-sauced/pizza-cli/compare/v1.2.1...v1.3.0) (2024-09-06) diff --git a/npm/package-lock.json b/npm/package-lock.json index 4d6af96..b04c894 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,12 +1,12 @@ { "name": "pizza", - "version": "1.3.0", + "version": "1.3.1-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pizza", - "version": "1.3.0", + "version": "1.3.1-beta.1", "hasInstallScript": true, "license": "MIT", "bin": { diff --git a/npm/package.json b/npm/package.json index 8a0d82d..baeea76 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "pizza", - "version": "1.3.0", + "version": "1.3.1-beta.1", "description": "A command line utility for insights, metrics, and all things OpenSauced", "repository": "https://github.com/open-sauced/pizza-cli", "license": "MIT", From af2f3612e26634455602d1840714c5bf15e1e40a Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Fri, 6 Sep 2024 18:39:56 -0500 Subject: [PATCH 10/36] fix: use the local directory and home directory as fallback for .sauced.yaml (#158) --- cmd/generate/codeowners/codeowners.go | 6 ++-- cmd/root/root.go | 2 +- pkg/config/config.go | 40 +++++++++++++-------------- pkg/config/config_test.go | 10 +++---- 4 files changed, 28 insertions(+), 30 deletions(-) diff --git a/cmd/generate/codeowners/codeowners.go b/cmd/generate/codeowners/codeowners.go index 76e9050..3e092e8 100644 --- a/cmd/generate/codeowners/codeowners.go +++ b/cmd/generate/codeowners/codeowners.go @@ -48,7 +48,7 @@ type Options struct { const codeownersLongDesc string = `WARNING: Proof of concept feature. -Generates a CODEOWNERS file for a given git repository. This uses a ~/.sauced.yaml +Generates a CODEOWNERS file for a given git repository. This uses a .sauced.yaml configuration to attribute emails with given entities. The generated file specifies up to 3 owners for EVERY file in the git tree based on the @@ -59,7 +59,7 @@ func NewCodeownersCommand() *cobra.Command { cmd := &cobra.Command{ Use: "codeowners path/to/repo [flags]", - Short: "Generates a CODEOWNERS file for a given repository using a \"~/.sauced.yaml\" config", + Short: "Generates a CODEOWNERS file for a given repository using a \".sauced.yaml\" config", Long: codeownersLongDesc, Args: func(_ *cobra.Command, args []string) error { if len(args) != 1 { @@ -90,7 +90,7 @@ func NewCodeownersCommand() *cobra.Command { defer opts.telemetry.Done() configPath, _ := cmd.Flags().GetString("config") - opts.config, err = config.LoadConfig(configPath, filepath.Join(opts.path, ".sauced.yaml")) + opts.config, err = config.LoadConfig(configPath) if err != nil { return err } diff --git a/cmd/root/root.go b/cmd/root/root.go index 379baaa..9dbbc45 100644 --- a/cmd/root/root.go +++ b/cmd/root/root.go @@ -36,7 +36,7 @@ func NewRootCommand() (*cobra.Command, error) { cmd.PersistentFlags().StringP(constants.FlagNameEndpoint, "e", constants.EndpointProd, "The API endpoint to send requests to") cmd.PersistentFlags().Bool(constants.FlagNameBeta, false, fmt.Sprintf("Shorthand for using the beta OpenSauced API endpoint (\"%s\"). Supersedes the '--%s' flag", constants.EndpointBeta, constants.FlagNameEndpoint)) cmd.PersistentFlags().Bool(constants.FlagNameTelemetry, false, "Disable sending telemetry data to OpenSauced") - cmd.PersistentFlags().StringP("config", "c", "~/.sauced.yaml", "The saucectl config") + cmd.PersistentFlags().StringP("config", "c", ".sauced.yaml", "The saucectl config") cmd.PersistentFlags().StringP("log-level", "l", "info", "The logging level. Options: error, warn, info, debug") cmd.PersistentFlags().Bool("tty-disable", false, "Disable log stylization. Suitable for CI/CD and automation") diff --git a/pkg/config/config.go b/pkg/config/config.go index 1bc53ba..ed722c5 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -9,27 +9,15 @@ import ( "gopkg.in/yaml.v3" ) -const DefaultConfigPath = "~/.sauced.yaml" - // LoadConfig loads a configuration file at a given path. It attempts to load -// the default location of a ".sauced.yaml" in the user's home directory if an -// empty path is provided. If none is found in the user's home directory, it tries to load -// ".sauced.yaml" from the fallback path, which is the root path of a repository. -func LoadConfig(path string, repoRootPathConfig string) (*Spec, error) { +// the default location of a ".sauced.yaml" in the current working directory if an +// empty path is provided. If none is found, it tries to load +// "~/.sauced.yaml" from the fallback path, which is the user's home directory. +func LoadConfig(path string) (*Spec, error) { println("Config path loading from -c flag", path) config := &Spec{} - if path == DefaultConfigPath || path == "" { - // load the default file path under the user's home dir - usr, err := user.Current() - if err != nil { - return nil, fmt.Errorf("could not get user home directory: %w", err) - } - - path = filepath.Join(usr.HomeDir, ".sauced.yaml") - } - absPath, err := filepath.Abs(path) if err != nil { return nil, fmt.Errorf("error resolving absolute path: %w", err) @@ -39,15 +27,27 @@ func LoadConfig(path string, repoRootPathConfig string) (*Spec, error) { if err != nil { // If the file does not exist, check if the fallback path exists if os.IsNotExist(err) { - _, err = os.Stat(repoRootPathConfig) + // load the default file path under the user's home dir + usr, err := user.Current() + if err != nil { - return nil, fmt.Errorf("error reading config file from %s or %s", absPath, repoRootPathConfig) + return nil, fmt.Errorf("could not get user home directory: %w", err) } - data, err = os.ReadFile(repoRootPathConfig) + homeDirPathConfig, err := filepath.Abs(filepath.Join(usr.HomeDir, ".sauced.yaml")) + + if err != nil { + return nil, fmt.Errorf("error home directory absolute path: %w", err) + } + + _, err = os.Stat(homeDirPathConfig) + if err != nil { + return nil, fmt.Errorf("error reading config file from %s", homeDirPathConfig) + } + data, err = os.ReadFile(homeDirPathConfig) if err != nil { - return nil, fmt.Errorf("error reading config file from %s", repoRootPathConfig) + return nil, fmt.Errorf("error reading config file from %s or %s", absPath, homeDirPathConfig) } } else { return nil, fmt.Errorf("error reading config file: %w", err) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index bec5564..c0da2e6 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -30,7 +30,7 @@ attribution: require.NoError(t, os.WriteFile(configFilePath, []byte(fileContents), 0600)) - config, err := LoadConfig(configFilePath, "") + config, err := LoadConfig(configFilePath) require.NoError(t, err) assert.NotNil(t, config) @@ -47,12 +47,12 @@ attribution: tmpDir := t.TempDir() nonExistentPath := filepath.Join(tmpDir, ".sauced.yaml") - config, err := LoadConfig(nonExistentPath, "") + config, err := LoadConfig(nonExistentPath) require.Error(t, err) assert.Nil(t, config) }) - t.Run("Non-existent file with fallback", func(t *testing.T) { + t.Run("Providing a custom .sauced.yaml location", func(t *testing.T) { t.Parallel() fileContents := `# Configuration for attributing commits with emails to GitHub user profiles # Used during codeowners generation. @@ -78,9 +78,7 @@ attribution: _, err := os.ReadFile(fallbackPath) require.NoError(t, err) - nonExistentPath := filepath.Join(tmpDir, "non-existent.yaml") - - config, err := LoadConfig(nonExistentPath, fallbackPath) + config, err := LoadConfig(fallbackPath) require.NoError(t, err) assert.NotNil(t, config) From 7f051829e629e958b3dcafa7b6ebbd2dbf6aaee8 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Fri, 6 Sep 2024 23:40:26 +0000 Subject: [PATCH 11/36] chore(patch): release 1.3.1-beta.2 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.3.1-beta.2](https://github.com/open-sauced/pizza-cli/compare/v1.3.1-beta.1...v1.3.1-beta.2) (2024-09-06) ### 🐛 Bug Fixes * use the local directory and home directory as fallback for .sauced.yaml ([#158](https://github.com/open-sauced/pizza-cli/issues/158)) ([af2f361](https://github.com/open-sauced/pizza-cli/commit/af2f3612e26634455602d1840714c5bf15e1e40a)) --- CHANGELOG.md | 7 +++++++ npm/package-lock.json | 4 ++-- npm/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31dd581..82b63eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.3.1-beta.2](https://github.com/open-sauced/pizza-cli/compare/v1.3.1-beta.1...v1.3.1-beta.2) (2024-09-06) + + +### 🐛 Bug Fixes + +* use the local directory and home directory as fallback for .sauced.yaml ([#158](https://github.com/open-sauced/pizza-cli/issues/158)) ([af2f361](https://github.com/open-sauced/pizza-cli/commit/af2f3612e26634455602d1840714c5bf15e1e40a)) + ## [1.3.1-beta.1](https://github.com/open-sauced/pizza-cli/compare/v1.3.0...v1.3.1-beta.1) (2024-09-06) diff --git a/npm/package-lock.json b/npm/package-lock.json index b04c894..8cd7f72 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,12 +1,12 @@ { "name": "pizza", - "version": "1.3.1-beta.1", + "version": "1.3.1-beta.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pizza", - "version": "1.3.1-beta.1", + "version": "1.3.1-beta.2", "hasInstallScript": true, "license": "MIT", "bin": { diff --git a/npm/package.json b/npm/package.json index baeea76..d59677c 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "pizza", - "version": "1.3.1-beta.1", + "version": "1.3.1-beta.2", "description": "A command line utility for insights, metrics, and all things OpenSauced", "repository": "https://github.com/open-sauced/pizza-cli", "license": "MIT", From 6908e1626ab7adac8102ce4483f8f4f6d1a5511c Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 03:07:29 -0700 Subject: [PATCH 12/36] tidy go.mod --- go.mod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 603715d..757f5ea 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.22 require ( github.com/charmbracelet/bubbles v0.19.0 + github.com/charmbracelet/bubbletea v0.27.1 github.com/charmbracelet/lipgloss v0.13.0 github.com/cli/browser v1.3.0 github.com/go-git/go-git/v5 v5.12.0 @@ -17,8 +18,7 @@ require ( ) require ( - github.com/charmbracelet/bubbletea v0.27.1 // indirect - github.com/charmbracelet/bubbletea v0.27.1 // indirect + github.com/atotto/clipboard v0.1.4 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect From 545974ee2e4fbc8b9c2c3effdf3299d940c6ea2e Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 03:48:49 -0700 Subject: [PATCH 13/36] make interactive mode non default, working interactive mode --- cmd/generate/config/config.go | 71 ++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 21 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index fc9f713..5b8b5e5 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" "slices" + "strings" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" @@ -72,8 +73,8 @@ func NewConfigCommand() *cobra.Command { }, } - cmd.PersistentFlags().StringP("output-path", "o", "~/", "Directory to create the `.sauced.yaml` file.") - cmd.PersistentFlags().BoolP("interactive", "i", true, "Whether to be interactive") + cmd.PersistentFlags().StringP("output-path", "o", "./", "Directory to create the `.sauced.yaml` file.") + cmd.PersistentFlags().BoolP("interactive", "i", false, "Whether to be interactive") return cmd } @@ -111,18 +112,18 @@ func run(opts *Options) error { }) // TODO: INTERACTIVE: per unique email, set a name (existing or new or ignore) - program := tea.NewProgram(initialModel(uniqueEmails)) - if _, err := program.Run(); err != nil { - return fmt.Errorf(err.Error()) - } - - // generate an output file - // default: `~/.sauced.yaml` - if opts.outputPath == "~/" { - homeDir, _ := os.UserHomeDir() - generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + if opts.isInteractive { + program := tea.NewProgram(initialModel(opts, uniqueEmails)) + if _, err := program.Run(); err != nil { + return fmt.Errorf(err.Error()) + } } else { - generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + if opts.outputPath == "~/" { + homeDir, _ := os.UserHomeDir() + generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + } else { + generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + } } return nil @@ -135,6 +136,7 @@ type model struct { help help.Model keymap keymap + opts *Options attributionMap map[string][]string uniqueEmails []string currentIndex int @@ -144,7 +146,6 @@ type keymap struct{} func (k keymap) ShortHelp() []key.Binding { return []key.Binding{ - key.NewBinding(key.WithKeys("tab"), key.WithHelp("tab", "complete")), key.NewBinding(key.WithKeys("ctrl+n"), key.WithHelp("ctrl+n", "next")), key.NewBinding(key.WithKeys("ctrl+p"), key.WithHelp("ctrl+p", "prev")), key.NewBinding(key.WithKeys("ctrl+i"), key.WithHelp("ctrl+i", "ignore email")), @@ -157,7 +158,7 @@ func (k keymap) FullHelp() [][]key.Binding { return [][]key.Binding{k.ShortHelp()} } -func initialModel(uniqueEmails []string) model { +func initialModel(opts *Options, uniqueEmails []string) model { ti := textinput.New() ti.Placeholder = "name" ti.Focus() @@ -168,6 +169,7 @@ func initialModel(uniqueEmails []string) model { help: help.New(), keymap: keymap{}, + opts: opts, attributionMap: make(map[string][]string), uniqueEmails: uniqueEmails, currentIndex: 0, @@ -200,11 +202,16 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil case tea.KeyEnter: - m.attributionMap[m.textInput.Value()] = append(m.attributionMap[currentEmail], currentEmail) - m.currentIndex++ - if m.currentIndex > len(m.attributionMap) { - return m, tea.Quit + if len(strings.Trim(m.textInput.Value(), " ")) == 0 { + return m, nil + } + m.attributionMap[m.textInput.Value()] = append(m.attributionMap[m.textInput.Value()], currentEmail) + m.textInput.Reset() + if m.currentIndex+1 >= len(m.uniqueEmails) { + return m, runOutputGeneration(m.opts, m.attributionMap) } + + m.currentIndex++ return m, nil } } @@ -215,10 +222,32 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } func (m model) View() string { + currentEmail := "" + if m.currentIndex < len(m.uniqueEmails) { + currentEmail = m.uniqueEmails[m.currentIndex] + } + return fmt.Sprintf( - "Found email %s - who to attribute to?: %s\n\n%s\n", - m.uniqueEmails[m.currentIndex], + "Found email %s - who to attribute to?: \n%s\n\n%s\n", + currentEmail, m.textInput.View(), m.help.View(m.keymap), ) } + +func runOutputGeneration(opts *Options, attributionMap map[string][]string) tea.Cmd { + // generate an output file + // default: `./.sauced.yaml` + // fallback for home directories + return func() tea.Msg { + if opts.outputPath == "~/" { + homeDir, _ := os.UserHomeDir() + generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + } else { + generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + } + + return tea.Quit() + } + +} From f960daa3cfd76501067172a6ccfaeda84022f5d5 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 9 Sep 2024 10:10:11 -0400 Subject: [PATCH 14/36] chore: now docs are autogenerated as part of the release process (#157) * chore: now docs are autogenerated as part of the release process * Revert "chore: now docs are autogenerated as part of the release process" This reverts commit d770873e18a75d38f9a753531ac5a10ac8810a26. * chore: now docs are autogenerated as part of the release process --- .github/workflows/release.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index aa3e092..68c1232 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -85,6 +85,15 @@ jobs: - name: "🤲 Setup Just" uses: extractions/setup-just@v2 + - name: "📗 Generate Documentation" + run: | + just gen-docs + git config user.name 'open-sauced[bot]' + git config user.email '63161813+open-sauced[bot]@users.noreply.github.com' + git add docs/ + git commit -m "chore: automated docs generation for release" || echo "No changes to commit" + git push origin HEAD:${{ github.ref }} + - name: "🔧 Build all and upload artifacts to release" env: GH_TOKEN: ${{ github.token }} From 847426bcb202e8846287461fb0e3735d04f4c82e Mon Sep 17 00:00:00 2001 From: John McBride Date: Mon, 9 Sep 2024 08:20:50 -0600 Subject: [PATCH 15/36] feat: Posthog events bootstrapping (#160) * feat: Posthog events bootstrapping Signed-off-by: John McBride * Update pkg/utils/posthog.go inline comment Co-authored-by: Nick Taylor --------- Signed-off-by: John McBride Co-authored-by: Nick Taylor --- cmd/auth/auth.go | 7 +- cmd/generate/codeowners/codeowners.go | 27 ++--- cmd/insights/contributors.go | 7 +- cmd/insights/repositories.go | 7 +- go.mod | 3 +- go.sum | 4 + justfile | 16 +++ pkg/utils/posthog.go | 142 ++++++++++++++++---------- pkg/utils/telemetry.go | 66 ++++++++++++ telemetry.go | 75 ++++++++++++++ 10 files changed, 276 insertions(+), 78 deletions(-) create mode 100644 pkg/utils/telemetry.go create mode 100644 telemetry.go diff --git a/cmd/auth/auth.go b/cmd/auth/auth.go index 802410f..86835dd 100644 --- a/cmd/auth/auth.go +++ b/cmd/auth/auth.go @@ -35,16 +35,17 @@ func NewLoginCommand() *cobra.Command { disableTelem, _ := cmd.Flags().GetBool(constants.FlagNameTelemetry) opts.telemetry = utils.NewPosthogCliClient(!disableTelem) - defer opts.telemetry.Done() username, err := run() if err != nil { - opts.telemetry.CaptureFailedLogin() + _ = opts.telemetry.CaptureFailedLogin() } else { - opts.telemetry.CaptureLogin(username) + _ = opts.telemetry.CaptureLogin(username) } + _ = opts.telemetry.Done() + return err }, } diff --git a/cmd/generate/codeowners/codeowners.go b/cmd/generate/codeowners/codeowners.go index 3e092e8..8f174dd 100644 --- a/cmd/generate/codeowners/codeowners.go +++ b/cmd/generate/codeowners/codeowners.go @@ -87,7 +87,6 @@ func NewCodeownersCommand() *cobra.Command { disableTelem, _ := cmd.Flags().GetBool(constants.FlagNameTelemetry) opts.telemetry = utils.NewPosthogCliClient(!disableTelem) - defer opts.telemetry.Done() configPath, _ := cmd.Flags().GetString("config") opts.config, err = config.LoadConfig(configPath) @@ -112,7 +111,11 @@ func NewCodeownersCommand() *cobra.Command { opts.loglevel = logging.LogDebug } - return run(opts, cmd) + err = run(opts, cmd) + + _ = opts.telemetry.Done() + + return err }, } @@ -135,7 +138,7 @@ func run(opts *Options, cmd *cobra.Command) error { repo, err := git.PlainOpen(opts.path) if err != nil { - opts.telemetry.CaptureFailedCodeownersGenerate() + _ = opts.telemetry.CaptureFailedCodeownersGenerate() return fmt.Errorf("error opening repo: %w", err) } opts.logger.V(logging.LogDebug).Style(0, colors.FgBlue).Infof("Opened repo at: %s\n", opts.path) @@ -150,7 +153,7 @@ func run(opts *Options, cmd *cobra.Command) error { codeowners, err := processOptions.process() if err != nil { - opts.telemetry.CaptureFailedCodeownersGenerate() + _ = opts.telemetry.CaptureFailedCodeownersGenerate() return fmt.Errorf("error traversing git log: %w", err) } @@ -165,11 +168,11 @@ func run(opts *Options, cmd *cobra.Command) error { opts.logger.V(logging.LogDebug).Style(0, colors.FgBlue).Infof("Processing codeowners file at: %s\n", outputPath) err = generateOutputFile(codeowners, outputPath, opts, cmd) if err != nil { - opts.telemetry.CaptureFailedCodeownersGenerate() + _ = opts.telemetry.CaptureFailedCodeownersGenerate() return fmt.Errorf("error generating github style codeowners file: %w", err) } opts.logger.V(logging.LogInfo).Style(0, colors.FgGreen).Infof("Finished generating file: %s\n", outputPath) - opts.telemetry.CaptureCodeownersGenerate() + _ = opts.telemetry.CaptureCodeownersGenerate() // ignore the interactive prompts for CI/CD environments if opts.tty { @@ -209,11 +212,11 @@ func run(opts *Options, cmd *cobra.Command) error { case "y", "Y", "yes": user, err := authenticator.Login() if err != nil { - opts.telemetry.CaptureFailedCodeownersGenerateAuth() + _ = opts.telemetry.CaptureFailedCodeownersGenerateAuth() opts.logger.V(logging.LogInfo).Style(0, colors.FgRed).Infof("Error logging in\n") return fmt.Errorf("could not log in: %w", err) } - opts.telemetry.CaptureCodeownersGenerateAuth(user) + _ = opts.telemetry.CaptureCodeownersGenerateAuth(user) opts.logger.V(logging.LogInfo).Style(0, colors.FgGreen).Infof("Logged in as: %s\n", user) case "n", "N", "no": @@ -226,7 +229,7 @@ func run(opts *Options, cmd *cobra.Command) error { opts.token, err = authenticator.GetSessionToken() if err != nil { - opts.telemetry.CaptureFailedCodeownersGenerateContributorInsight() + _ = opts.telemetry.CaptureFailedCodeownersGenerateContributorInsight() opts.logger.V(logging.LogInfo).Style(0, colors.FgRed).Infof("Error getting session token\n") return fmt.Errorf("could not get session token: %w", err) } @@ -236,7 +239,7 @@ func run(opts *Options, cmd *cobra.Command) error { opts.logger.V(logging.LogDebug).Style(0, colors.FgBlue).Infof("Looking up OpenSauced workspace: Pizza CLI\n") workspace, err := findCreatePizzaCliWorkspace(opts) if err != nil { - opts.telemetry.CaptureFailedCodeownersGenerateContributorInsight() + _ = opts.telemetry.CaptureFailedCodeownersGenerateContributorInsight() opts.logger.V(logging.LogInfo).Style(0, colors.FgRed).Infof("Error finding Workspace: Pizza CLI\n") return fmt.Errorf("could not find Pizza CLI workspace: %w", err) } @@ -245,13 +248,13 @@ func run(opts *Options, cmd *cobra.Command) error { opts.logger.V(logging.LogDebug).Style(0, colors.FgBlue).Infof("Looking up Contributor Insight for local repository: %s\n", listName) userList, err := updateCreateLocalWorkspaceUserList(opts, listName, workspace, codeowners) if err != nil { - opts.telemetry.CaptureFailedCodeownersGenerateContributorInsight() + _ = opts.telemetry.CaptureFailedCodeownersGenerateContributorInsight() opts.logger.V(logging.LogInfo).Style(0, colors.FgRed).Infof("Error finding Workspace Contributor Insight: %s\n", listName) return fmt.Errorf("could not find Workspace Contributor Insight: %s - %w", listName, err) } opts.logger.V(logging.LogDebug).Style(0, colors.FgGreen).Infof("Updated Contributor Insight for local repository: %s\n", listName) opts.logger.V(logging.LogInfo).Style(0, colors.FgCyan).Infof("Access list on OpenSauced:\n%s\n", fmt.Sprintf("https://app.opensauced.pizza/workspaces/%s/contributor-insights/%s", workspace.ID, userList.ID)) - opts.telemetry.CaptureCodeownersGenerateContributorInsight() + _ = opts.telemetry.CaptureCodeownersGenerateContributorInsight() return nil } diff --git a/cmd/insights/contributors.go b/cmd/insights/contributors.go index b1103e4..031d033 100644 --- a/cmd/insights/contributors.go +++ b/cmd/insights/contributors.go @@ -57,7 +57,6 @@ func NewContributorsCommand() *cobra.Command { disableTelem, _ := cmd.Flags().GetBool(constants.FlagNameTelemetry) opts.telemetry = utils.NewPosthogCliClient(!disableTelem) - defer opts.telemetry.Done() endpointURL, _ := cmd.Flags().GetString(constants.FlagNameEndpoint) opts.APIClient = api.NewClient(endpointURL) @@ -67,11 +66,13 @@ func NewContributorsCommand() *cobra.Command { err := opts.run() if err != nil { - opts.telemetry.CaptureInsights() + _ = opts.telemetry.CaptureInsights() } else { - opts.telemetry.CaptureFailedInsights() + _ = opts.telemetry.CaptureFailedInsights() } + _ = opts.telemetry.Done() + return err }, } diff --git a/cmd/insights/repositories.go b/cmd/insights/repositories.go index a86a380..ca4a1fe 100644 --- a/cmd/insights/repositories.go +++ b/cmd/insights/repositories.go @@ -57,7 +57,6 @@ func NewRepositoriesCommand() *cobra.Command { disableTelem, _ := cmd.Flags().GetBool(constants.FlagNameTelemetry) opts.telemetry = utils.NewPosthogCliClient(!disableTelem) - defer opts.telemetry.Done() endpointURL, _ := cmd.Flags().GetString(constants.FlagNameEndpoint) opts.APIClient = api.NewClient(endpointURL) @@ -67,11 +66,13 @@ func NewRepositoriesCommand() *cobra.Command { err := opts.run() if err != nil { - opts.telemetry.CaptureInsights() + _ = opts.telemetry.CaptureInsights() } else { - opts.telemetry.CaptureFailedInsights() + _ = opts.telemetry.CaptureFailedInsights() } + _ = opts.telemetry.Done() + return err }, } diff --git a/go.mod b/go.mod index bc698f7..78f7d42 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/cli/browser v1.3.0 github.com/go-git/go-git/v5 v5.12.0 github.com/jpmcb/gopherlogs v0.2.0 - github.com/posthog/posthog-go v1.2.19 + github.com/posthog/posthog-go v1.2.21 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 @@ -40,6 +40,7 @@ require ( github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/uuid v1.6.0 github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect diff --git a/go.sum b/go.sum index e0f49bc..ed84a48 100644 --- a/go.sum +++ b/go.sum @@ -64,6 +64,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= @@ -103,6 +105,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posthog/posthog-go v1.2.19 h1:0udGG2do4LjOzE0D/ik7S3uM2wwFKwzSqswBfdcQ1y4= github.com/posthog/posthog-go v1.2.19/go.mod h1:uYC2l1Yktc8E+9FAHJ9QZG4vQf/NHJPD800Hsm7DzoM= +github.com/posthog/posthog-go v1.2.21 h1:p2ea0l+Qwtk+VC2LCAI87Dz36vwj9i+QHw5s6CpRikA= +github.com/posthog/posthog-go v1.2.21/go.mod h1:uYC2l1Yktc8E+9FAHJ9QZG4vQf/NHJPD800Hsm7DzoM= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= diff --git a/justfile b/justfile index 79f06de..a5b8a10 100644 --- a/justfile +++ b/justfile @@ -203,3 +203,19 @@ gen-docs: # Runs all the dev tasks (like formatting, linting, building, etc.) dev: format lint test build-all + +# Calls the various Posthog capture events to add the Insights to the database +bootstrap-telemetry: + #!/usr/bin/env sh + echo "Building telemetry-oneshot" + + go build \ + -tags telemetry \ + -ldflags="-s -w" \ + -ldflags="-X 'github.com/open-sauced/pizza-cli/pkg/utils.writeOnlyPublicPosthogKey=${POSTHOG_PUBLIC_API_KEY}'" \ + -o build/telemetry-oneshot \ + telemetry.go + + ./build/telemetry-oneshot + + rm ./build/telemetry-oneshot diff --git a/pkg/utils/posthog.go b/pkg/utils/posthog.go index ac66728..6383c10 100644 --- a/pkg/utils/posthog.go +++ b/pkg/utils/posthog.go @@ -1,19 +1,27 @@ package utils import ( + "fmt" + "github.com/posthog/posthog-go" ) var ( writeOnlyPublicPosthogKey = "dev" - posthogEndpoint = "https://app.posthog.com" + posthogEndpoint = "https://us.i.posthog.com" ) // PosthogCliClient is a wrapper around the posthog-go client and is used as a // API entrypoint for sending OpenSauced telemetry data for CLI commands type PosthogCliClient struct { - client posthog.Client + // client is the Posthog Go client + client posthog.Client + + // activated denotes if the user has enabled or disabled telemetry activated bool + + // uniqueID is the user's unique, anonymous identifier + uniqueID string } // NewPosthogCliClient returns a PosthogCliClient which can be used to capture @@ -32,120 +40,142 @@ func NewPosthogCliClient(activated bool) *PosthogCliClient { panic(err) } + uniqueID, err := getOrCreateUniqueID() + if err != nil { + fmt.Printf("could not build anonymous telemetry client: %s\n", err) + } + return &PosthogCliClient{ client: client, activated: activated, + uniqueID: uniqueID, } } // Done should always be called in order to flush the Posthog buffers before // the CLI exits to ensure all events are accurately captured. -// -//nolint:errcheck -func (p *PosthogCliClient) Done() { - p.client.Close() +func (p *PosthogCliClient) Done() error { + return p.client.Close() } // CaptureLogin gathers telemetry on users who log into OpenSauced via the CLI -// -//nolint:errcheck -func (p *PosthogCliClient) CaptureLogin(username string) { +func (p *PosthogCliClient) CaptureLogin(username string) error { if p.activated { - p.client.Enqueue(posthog.Capture{ + return p.client.Enqueue(posthog.Capture{ DistinctId: username, - Event: "cli_user logged in", + Event: "pizza_cli_user_logged_in", }) } + + return nil } // CaptureFailedLogin gathers telemetry on failed logins via the CLI -// -//nolint:errcheck -func (p *PosthogCliClient) CaptureFailedLogin() { +func (p *PosthogCliClient) CaptureFailedLogin() error { if p.activated { - p.client.Enqueue(posthog.Capture{ - DistinctId: "login-failures", - Event: "cli_user failed log in", + return p.client.Enqueue(posthog.Capture{ + DistinctId: p.uniqueID, + Event: "pizza_cli_user_failed_log_in", }) } + + return nil } -//nolint:errcheck -func (p *PosthogCliClient) CaptureCodeownersGenerate() { +// CaptureCodeownersGenerate gathers telemetry on successful codeowners generation +func (p *PosthogCliClient) CaptureCodeownersGenerate() error { if p.activated { - p.client.Enqueue(posthog.Capture{ - DistinctId: "codeowners-generated", - Event: "cli generated codeowners", + return p.client.Enqueue(posthog.Capture{ + DistinctId: p.uniqueID, + Event: "pizza_cli_generated_codeowners", }) } + + return nil } -//nolint:errcheck -func (p *PosthogCliClient) CaptureFailedCodeownersGenerate() { +// CaptureFailedCodeownersGenerate gathers telemetry on failed codeowners generation +func (p *PosthogCliClient) CaptureFailedCodeownersGenerate() error { if p.activated { - p.client.Enqueue(posthog.Capture{ - DistinctId: "failed-codeowners-generated", - Event: "cli failed to generate codeowners", + return p.client.Enqueue(posthog.Capture{ + DistinctId: p.uniqueID, + Event: "pizza_cli_failed_to_generate_codeowners", }) } + + return nil } -//nolint:errcheck -func (p *PosthogCliClient) CaptureCodeownersGenerateAuth(username string) { +// CaptureCodeownersGenerateAuth gathers telemetry on successful auth flows during codeowners generation +func (p *PosthogCliClient) CaptureCodeownersGenerateAuth(username string) error { if p.activated { - p.client.Enqueue(posthog.Capture{ + return p.client.Enqueue(posthog.Capture{ DistinctId: username, - Event: "user authenticated during generate codeowners flow", + Event: "pizza_cli_user_authenticated_during_generate_codeowners_flow", }) } + + return nil } -//nolint:errcheck -func (p *PosthogCliClient) CaptureFailedCodeownersGenerateAuth() { +// CaptureFailedCodeownersGenerateAuth gathers telemetry on failed auth flows during codeowners generations +func (p *PosthogCliClient) CaptureFailedCodeownersGenerateAuth() error { if p.activated { - p.client.Enqueue(posthog.Capture{ - DistinctId: "codeowners-generate-auth-failed", - Event: "user failed to authenticate during generate codeowners flow", + return p.client.Enqueue(posthog.Capture{ + DistinctId: p.uniqueID, + Event: "pizza_cli_user_failed_to_authenticate_during_generate_codeowners_flow", }) } + + return nil } -//nolint:errcheck -func (p *PosthogCliClient) CaptureCodeownersGenerateContributorInsight() { +// CaptureCodeownersGenerateContributorInsight gathers telemetry on successful +// Contributor Insights creation/update during codeowners generation +func (p *PosthogCliClient) CaptureCodeownersGenerateContributorInsight() error { if p.activated { - p.client.Enqueue(posthog.Capture{ - DistinctId: "codeowners-generate-contributor-insight", - Event: "cli created/updated contributor list for user", + return p.client.Enqueue(posthog.Capture{ + DistinctId: p.uniqueID, + Event: "pizza_cli_created_updated_contributor_list", }) } + + return nil } -//nolint:errcheck -func (p *PosthogCliClient) CaptureFailedCodeownersGenerateContributorInsight() { +// CaptureFailedCodeownersGenerateContributorInsight gathers telemetry on failed +// Contributor Insights during codeowners generation +func (p *PosthogCliClient) CaptureFailedCodeownersGenerateContributorInsight() error { if p.activated { - p.client.Enqueue(posthog.Capture{ - DistinctId: "failed-codeowners-generation-contributor-insight", - Event: "cli failed to create/update contributor insight for user", + return p.client.Enqueue(posthog.Capture{ + DistinctId: p.uniqueID, + Event: "pizza_cli_failed_to_create_update_contributor_insight_for_user", }) } + + return nil } -//nolint:errcheck -func (p *PosthogCliClient) CaptureInsights() { +// CaptureInsights gathers telemetry on successful Insights command runs +func (p *PosthogCliClient) CaptureInsights() error { if p.activated { - p.client.Enqueue(posthog.Capture{ - DistinctId: "insights", - Event: "cli called insights command", + return p.client.Enqueue(posthog.Capture{ + DistinctId: p.uniqueID, + Event: "pizza_cli_called_insights_command", }) } + + return nil } -//nolint:errcheck -func (p *PosthogCliClient) CaptureFailedInsights() { +// CaptureFailedInsights gathers telemetry on failed Insights command runs +func (p *PosthogCliClient) CaptureFailedInsights() error { if p.activated { - p.client.Enqueue(posthog.Capture{ - DistinctId: "failed-insight", - Event: "cli failed to call insights command", + return p.client.Enqueue(posthog.Capture{ + DistinctId: p.uniqueID, + Event: "pizza_cli_failed_to_call_insights_command", }) } + + return nil } diff --git a/pkg/utils/telemetry.go b/pkg/utils/telemetry.go new file mode 100644 index 0000000..ca0d82b --- /dev/null +++ b/pkg/utils/telemetry.go @@ -0,0 +1,66 @@ +package utils + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + + "github.com/google/uuid" +) + +var telemetryFilePath = filepath.Join(os.Getenv("HOME"), ".pizza-cli", "telemetry.json") + +// userTelemetryConfig is the config for the user's anonymous telemetry data +type userTelemetryConfig struct { + ID string `json:"id"` +} + +// getOrCreateUniqueID reads the telemetry.json file to fetch the user's anonymous, unique ID. +// In case of error (i.e., if the file doesn't exist or is invalid) it generates +// a new UUID and stores it in the telemetry.json file +func getOrCreateUniqueID() (string, error) { + if _, err := os.Stat(telemetryFilePath); os.IsNotExist(err) { + return createTelemetryUUID() + } + + data, err := os.ReadFile(telemetryFilePath) + if err != nil { + return createTelemetryUUID() + } + + // Try parsing the telemetry file + var teleData userTelemetryConfig + err = json.Unmarshal(data, &teleData) + if err != nil || teleData.ID == "" { + return createTelemetryUUID() + } + + return teleData.ID, nil +} + +// createTelemetryUUID generates a new UUID and writes it to the user's telemetry.json file +func createTelemetryUUID() (string, error) { + newUUID := uuid.New().String() + + teleData := userTelemetryConfig{ + ID: newUUID, + } + + data, err := json.Marshal(teleData) + if err != nil { + return "", fmt.Errorf("error creating telemetry data: %w", err) + } + + err = os.MkdirAll(filepath.Dir(telemetryFilePath), 0755) + if err != nil { + return "", fmt.Errorf("error creating directory for telemetry file: %w", err) + } + + err = os.WriteFile(telemetryFilePath, data, 0600) + if err != nil { + return "", fmt.Errorf("error writing telemetry file: %w", err) + } + + return newUUID, nil +} diff --git a/telemetry.go b/telemetry.go new file mode 100644 index 0000000..71d910a --- /dev/null +++ b/telemetry.go @@ -0,0 +1,75 @@ +//go:build telemetry +// +build telemetry + +package main + +import "github.com/open-sauced/pizza-cli/pkg/utils" + +// This alternate main is used as a one-shot for bootstrapping Posthog events: +// the various events called herein do not exist in Posthog's datalake until the +// event has landed. +// +// Therefore, this is useful for when there are new events for Posthog that need +// a dashboard bootstrapped for them. + +func main() { + println("Started bootstrapping Posthog events") + client := utils.NewPosthogCliClient(true) + + err := client.CaptureLogin("test-user") + if err != nil { + panic(err) + } + + err = client.CaptureFailedLogin() + if err != nil { + panic(err) + } + + err = client.CaptureCodeownersGenerate() + if err != nil { + panic(err) + } + + err = client.CaptureFailedCodeownersGenerate() + if err != nil { + panic(err) + } + + err = client.CaptureCodeownersGenerateAuth("test-user") + if err != nil { + panic(err) + } + + err = client.CaptureFailedCodeownersGenerateAuth() + if err != nil { + panic(err) + } + + err = client.CaptureCodeownersGenerateContributorInsight() + if err != nil { + panic(err) + } + + err = client.CaptureFailedCodeownersGenerateContributorInsight() + if err != nil { + panic(err) + } + + err = client.CaptureInsights() + if err != nil { + panic(err) + } + + err = client.CaptureFailedInsights() + if err != nil { + panic(err) + } + + err = client.Done() + if err != nil { + panic(err) + } + + println("Done bootstrapping Posthog events") +} From 54cf017ce3f0c2a876af33b4ed1ab623a87de51a Mon Sep 17 00:00:00 2001 From: John McBride Date: Mon, 9 Sep 2024 14:21:32 +0000 Subject: [PATCH 16/36] chore(minor): release 1.4.0-beta.1 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.4.0-beta.1](https://github.com/open-sauced/pizza-cli/compare/v1.3.1-beta.2...v1.4.0-beta.1) (2024-09-09) ### 🍕 Features * Posthog events bootstrapping ([#160](https://github.com/open-sauced/pizza-cli/issues/160)) ([847426b](https://github.com/open-sauced/pizza-cli/commit/847426bcb202e8846287461fb0e3735d04f4c82e)) --- CHANGELOG.md | 7 +++++++ npm/package-lock.json | 4 ++-- npm/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 82b63eb..ed0caaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.4.0-beta.1](https://github.com/open-sauced/pizza-cli/compare/v1.3.1-beta.2...v1.4.0-beta.1) (2024-09-09) + + +### 🍕 Features + +* Posthog events bootstrapping ([#160](https://github.com/open-sauced/pizza-cli/issues/160)) ([847426b](https://github.com/open-sauced/pizza-cli/commit/847426bcb202e8846287461fb0e3735d04f4c82e)) + ## [1.3.1-beta.2](https://github.com/open-sauced/pizza-cli/compare/v1.3.1-beta.1...v1.3.1-beta.2) (2024-09-06) diff --git a/npm/package-lock.json b/npm/package-lock.json index 8cd7f72..1377570 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,12 +1,12 @@ { "name": "pizza", - "version": "1.3.1-beta.2", + "version": "1.4.0-beta.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pizza", - "version": "1.3.1-beta.2", + "version": "1.4.0-beta.1", "hasInstallScript": true, "license": "MIT", "bin": { diff --git a/npm/package.json b/npm/package.json index d59677c..b4dc2c9 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "pizza", - "version": "1.3.1-beta.2", + "version": "1.4.0-beta.1", "description": "A command line utility for insights, metrics, and all things OpenSauced", "repository": "https://github.com/open-sauced/pizza-cli", "license": "MIT", From 5341e16daaeeecdc664895d165246a82623accbe Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 9 Sep 2024 12:11:40 -0400 Subject: [PATCH 17/36] fix: fixed docs generation in release workflow (#162) --- .github/workflows/release.yaml | 10 +++------- scripts/generate-docs.sh | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 7 deletions(-) create mode 100755 scripts/generate-docs.sh diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 68c1232..0e47cb0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -86,13 +86,9 @@ jobs: uses: extractions/setup-just@v2 - name: "📗 Generate Documentation" - run: | - just gen-docs - git config user.name 'open-sauced[bot]' - git config user.email '63161813+open-sauced[bot]@users.noreply.github.com' - git add docs/ - git commit -m "chore: automated docs generation for release" || echo "No changes to commit" - git push origin HEAD:${{ github.ref }} + run: ./scripts/generate-docs.sh + env: + GITHUB_REF: ${{ github.ref }} - name: "🔧 Build all and upload artifacts to release" env: diff --git a/scripts/generate-docs.sh b/scripts/generate-docs.sh new file mode 100755 index 0000000..8b73d27 --- /dev/null +++ b/scripts/generate-docs.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status. +set -e + +# Configure git to use the OpenSauced bot account +git config user.name 'open-sauced[bot]' +git config user.email '63161813+open-sauced[bot]@users.noreply.github.com' + +# Semantic release made changes, so pull the latest changes from the current branch +git pull origin "$GITHUB_REF" + +# Generate documentation +just gen-docs + +# Get the author of the last non-merge commit +LAST_COMMIT_AUTHOR=$(git log -1 --no-merges --pretty=format:'%an <%ae>') + +# Commit with co-authorship and push changes +git add docs/ +git commit -m "chore: automated docs generation for release + +Co-authored-by: $LAST_COMMIT_AUTHOR" || echo "No changes to commit" +git push origin HEAD:"$GITHUB_REF" From 7f802a0b44bcb227aa1d67d09ad35ff56566c2be Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 9 Sep 2024 16:13:07 +0000 Subject: [PATCH 18/36] chore(patch): release 1.4.0-beta.2 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.4.0-beta.2](https://github.com/open-sauced/pizza-cli/compare/v1.4.0-beta.1...v1.4.0-beta.2) (2024-09-09) ### 🐛 Bug Fixes * fixed docs generation in release workflow ([#162](https://github.com/open-sauced/pizza-cli/issues/162)) ([5341e16](https://github.com/open-sauced/pizza-cli/commit/5341e16daaeeecdc664895d165246a82623accbe)) --- CHANGELOG.md | 7 +++++++ npm/package-lock.json | 4 ++-- npm/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed0caaf..372149c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.4.0-beta.2](https://github.com/open-sauced/pizza-cli/compare/v1.4.0-beta.1...v1.4.0-beta.2) (2024-09-09) + + +### 🐛 Bug Fixes + +* fixed docs generation in release workflow ([#162](https://github.com/open-sauced/pizza-cli/issues/162)) ([5341e16](https://github.com/open-sauced/pizza-cli/commit/5341e16daaeeecdc664895d165246a82623accbe)) + ## [1.4.0-beta.1](https://github.com/open-sauced/pizza-cli/compare/v1.3.1-beta.2...v1.4.0-beta.1) (2024-09-09) diff --git a/npm/package-lock.json b/npm/package-lock.json index 1377570..806c8e8 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,12 +1,12 @@ { "name": "pizza", - "version": "1.4.0-beta.1", + "version": "1.4.0-beta.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pizza", - "version": "1.4.0-beta.1", + "version": "1.4.0-beta.2", "hasInstallScript": true, "license": "MIT", "bin": { diff --git a/npm/package.json b/npm/package.json index b4dc2c9..acf5a34 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "pizza", - "version": "1.4.0-beta.1", + "version": "1.4.0-beta.2", "description": "A command line utility for insights, metrics, and all things OpenSauced", "repository": "https://github.com/open-sauced/pizza-cli", "license": "MIT", From 583c49a1d2db5ca1c2631d9648280be7b64de455 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 10:31:17 -0700 Subject: [PATCH 19/36] add more error handling --- cmd/generate/config/config.go | 42 ++++++++++++++++++++++++++--------- cmd/generate/config/output.go | 10 ++++++--- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 5b8b5e5..8fbab34 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -84,19 +84,20 @@ func run(opts *Options) error { // Open repo repo, err := git.PlainOpen(opts.path) if err != nil { - return fmt.Errorf("error opening repo: %w", err) + return fmt.Errorf("Error opening repo: %w", err) } commitIter, err := repo.CommitObjects() + if err != nil { + return fmt.Errorf("Error opening repo commits: %w", err) + } + var uniqueEmails []string - commitIter.ForEach(func(c *object.Commit) error { + err = commitIter.ForEach(func(c *object.Commit) error { name := c.Author.Name email := c.Author.Email - // TODO: edge case- same email multiple names - // eg: 'coding@zeu.dev' = 'zeudev' & 'Zeu Capua' - if !opts.isInteractive { doesEmailExist := slices.Contains(attributionMap[name], email) if !doesEmailExist { @@ -111,18 +112,31 @@ func run(opts *Options) error { return nil }) - // TODO: INTERACTIVE: per unique email, set a name (existing or new or ignore) + if err != nil { + return fmt.Errorf("Error iterating over repo commits: %w", err) + } + + // INTERACTIVE: per unique email, set a name (existing or new or ignore) if opts.isInteractive { program := tea.NewProgram(initialModel(opts, uniqueEmails)) if _, err := program.Run(); err != nil { - return fmt.Errorf(err.Error()) + return fmt.Errorf("Error running interactive mode: %w", err) } } else { + // generate an output file + // default: `./.sauced.yaml` + // fallback for home directories if opts.outputPath == "~/" { homeDir, _ := os.UserHomeDir() - generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + err := generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + if err != nil { + return fmt.Errorf("Error generating output file: %w", err) + } } else { - generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + err := generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + if err != nil { + return fmt.Errorf("Error generating output file: %w", err) + } } } @@ -242,9 +256,15 @@ func runOutputGeneration(opts *Options, attributionMap map[string][]string) tea. return func() tea.Msg { if opts.outputPath == "~/" { homeDir, _ := os.UserHomeDir() - generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + err := generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + if err != nil { + return fmt.Errorf("Error generating output file: %w", err) + } } else { - generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + err := generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + if err != nil { + return fmt.Errorf("Error generating output file: %w", err) + } } return tea.Quit() diff --git a/cmd/generate/config/output.go b/cmd/generate/config/output.go index 8cc4723..f5a06aa 100644 --- a/cmd/generate/config/output.go +++ b/cmd/generate/config/output.go @@ -11,7 +11,7 @@ import ( func generateOutputFile(outputPath string, attributionMap map[string][]string) error { file, err := os.Create(outputPath) if err != nil { - return fmt.Errorf("error creating %s file: %w", outputPath, err) + return fmt.Errorf("Error creating %s file: %w", outputPath, err) } defer file.Close() @@ -22,10 +22,14 @@ func generateOutputFile(outputPath string, attributionMap map[string][]string) e yaml, err := utils.OutputYAML(config) if err != nil { - return fmt.Errorf("Failed to turn into YAML") + return fmt.Errorf("Failed to turn into YAML: %w", err) } - file.WriteString(yaml) + _, err = file.WriteString(yaml) + + if err != nil { + return fmt.Errorf("Failed to turn into YAML: %w", err) + } return nil } From 613ced5710d145b91dae6bc7b2496cc6d2248aea Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 11:10:38 -0700 Subject: [PATCH 20/36] change else to else if, replace one case switch to if statement --- cmd/generate/config/config.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 8fbab34..17d2431 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -104,10 +104,8 @@ func run(opts *Options) error { // AUTOMATIC: set every name and associated emails attributionMap[name] = append(attributionMap[name], email) } - } else { - if !slices.Contains(uniqueEmails, email) { - uniqueEmails = append(uniqueEmails, email) - } + } else if !slices.Contains(uniqueEmails, email) { + uniqueEmails = append(uniqueEmails, email) } return nil }) @@ -205,9 +203,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.textInput.SetSuggestions(existingUsers) - switch msg := msg.(type) { - case tea.KeyMsg: - switch msg.Type { + keyMsg, ok := msg.(tea.KeyMsg) + + if ok { + switch keyMsg.Type { case tea.KeyCtrlC, tea.KeyEsc: return m, tea.Quit From a970a73f494f34464a4c8b6ba993d38ecb4e2ec4 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 9 Sep 2024 14:25:51 -0400 Subject: [PATCH 21/36] fix: now --tty-disable is set so the action can complete instead of hanging (#164) --- .github/workflows/pizza.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pizza.yml b/.github/workflows/pizza.yml index d4661f2..aa0b863 100644 --- a/.github/workflows/pizza.yml +++ b/.github/workflows/pizza.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Pizza Action - uses: open-sauced/pizza-action@v2.0.0 + uses: open-sauced/pizza-action@v2.1.0 with: commit-and-pr: "true" From 452e14592e8922ee7e1c586a364743c6182aa8b7 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 9 Sep 2024 18:26:33 +0000 Subject: [PATCH 22/36] chore(patch): release 1.4.0-beta.3 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.4.0-beta.3](https://github.com/open-sauced/pizza-cli/compare/v1.4.0-beta.2...v1.4.0-beta.3) (2024-09-09) ### 🐛 Bug Fixes * now --tty-disable is set so the action can complete instead of hanging ([#164](https://github.com/open-sauced/pizza-cli/issues/164)) ([a970a73](https://github.com/open-sauced/pizza-cli/commit/a970a73f494f34464a4c8b6ba993d38ecb4e2ec4)) --- CHANGELOG.md | 7 +++++++ npm/package-lock.json | 4 ++-- npm/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 372149c..8855254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.4.0-beta.3](https://github.com/open-sauced/pizza-cli/compare/v1.4.0-beta.2...v1.4.0-beta.3) (2024-09-09) + + +### 🐛 Bug Fixes + +* now --tty-disable is set so the action can complete instead of hanging ([#164](https://github.com/open-sauced/pizza-cli/issues/164)) ([a970a73](https://github.com/open-sauced/pizza-cli/commit/a970a73f494f34464a4c8b6ba993d38ecb4e2ec4)) + ## [1.4.0-beta.2](https://github.com/open-sauced/pizza-cli/compare/v1.4.0-beta.1...v1.4.0-beta.2) (2024-09-09) diff --git a/npm/package-lock.json b/npm/package-lock.json index 806c8e8..9c9dd1b 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,12 +1,12 @@ { "name": "pizza", - "version": "1.4.0-beta.2", + "version": "1.4.0-beta.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pizza", - "version": "1.4.0-beta.2", + "version": "1.4.0-beta.3", "hasInstallScript": true, "license": "MIT", "bin": { diff --git a/npm/package.json b/npm/package.json index acf5a34..ba1aa99 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "pizza", - "version": "1.4.0-beta.2", + "version": "1.4.0-beta.3", "description": "A command line utility for insights, metrics, and all things OpenSauced", "repository": "https://github.com/open-sauced/pizza-cli", "license": "MIT", From 33c205787394de76db7992345b66194040e72057 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 11:41:34 -0700 Subject: [PATCH 23/36] lint via golangci-liint --fix --- cmd/generate/config/config.go | 7 +++---- cmd/generate/generate.go | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 17d2431..4742544 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -8,14 +8,13 @@ import ( "slices" "strings" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/spf13/cobra" - "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/key" "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/spf13/cobra" ) // Options for the config generation command diff --git a/cmd/generate/generate.go b/cmd/generate/generate.go index 6d1a29f..fee0146 100644 --- a/cmd/generate/generate.go +++ b/cmd/generate/generate.go @@ -6,7 +6,6 @@ import ( "github.com/spf13/cobra" "github.com/open-sauced/pizza-cli/cmd/generate/codeowners" - "github.com/open-sauced/pizza-cli/cmd/generate/config" ) From f924b09188ae69a9e0336abff7f484271022512f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:03:56 -0400 Subject: [PATCH 24/36] chore (automated): OpenSauced updates (#166) Co-authored-by: open-sauced[bot] <63161813+open-sauced[bot]@users.noreply.github.com> --- CODEOWNERS | 89 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 13 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index a782015..ab3a50d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,40 +1,103 @@ # This file is generated automatically by OpenSauced pizza-cli. DO NOT EDIT. Stay saucy! +# +# Generated with command: +# $ pizza generate codeowners pizza-cli/ --tty-disable true +.env @jpmcb .github/ISSUE_TEMPLATE/bug_report.yaml @jpmcb .github/ISSUE_TEMPLATE/config.yaml @jpmcb .github/ISSUE_TEMPLATE/feature_request.yaml @jpmcb .github/workflows/auto-add-to-project.yml @jpmcb -.github/workflows/release.yaml @jpmcb +.github/workflows/pizza.yml @nickytonline @jpmcb +.github/workflows/release.yaml @jpmcb @nickytonline .github/workflows/test.yaml @jpmcb .golangci.yaml @jpmcb -CHANGELOG.md @jpmcb @brandonroberts @nickytonline +.sauced.yaml @nickytonline @jpmcb +CHANGELOG.md @jpmcb @nickytonline @brandonroberts +CODEOWNERS @nickytonline @jpmcb Dockerfile @jpmcb @nickytonline Makefile @jpmcb README.md @jpmcb +api/auth/auth.go @jpmcb +api/auth/success.html @nickytonline @jpmcb +api/client.go @jpmcb +api/mock/mock.go @jpmcb +api/services/contributors/contributors.go @jpmcb +api/services/contributors/contributors_test.go @jpmcb +api/services/contributors/spec.go @jpmcb +api/services/histogram/histogram.go @jpmcb +api/services/histogram/histogram_test.go @jpmcb +api/services/histogram/spec.go @jpmcb +api/services/repository/repository.go @jpmcb +api/services/repository/repository_test.go @jpmcb +api/services/repository/spec.go @jpmcb +api/services/spec.go @jpmcb +api/services/workspaces/spec.go @jpmcb +api/services/workspaces/userlists/spec.go @jpmcb +api/services/workspaces/userlists/userlists.go @jpmcb +api/services/workspaces/userlists/userlists_test.go @jpmcb +api/services/workspaces/workspaces.go @jpmcb +api/services/workspaces/workspaces_test.go @jpmcb +api/utils/validators.go @jpmcb cmd/auth/auth.go @jpmcb +cmd/auth/constants.go @jpmcb +cmd/auth/schema.go @jpmcb +cmd/auth/success.html @jpmcb +cmd/auth/success.html @jpmcb cmd/bake/bake.go @jpmcb cmd/bake/bake_test.go @jpmcb -cmd/generate/codeowners/codeowners.go @jpmcb -cmd/generate/codeowners/output.go @jpmcb @brandonroberts -cmd/generate/codeowners/output_test.go @brandonroberts +cmd/docs/docs.go @nickytonline @jpmcb +cmd/docs/docs_test.go @nickytonline @jpmcb +cmd/generate/codeowners/codeowners.go @jpmcb @nickytonline @zeucapua +cmd/generate/codeowners/output.go @jpmcb @zeucapua @brandonroberts +cmd/generate/codeowners/output_test.go @jpmcb @brandonroberts cmd/generate/codeowners/spec.go @jpmcb cmd/generate/codeowners/traversal.go @jpmcb cmd/generate/generate.go @jpmcb cmd/insights/contributors.go @jpmcb -cmd/insights/insights.go @jpmcb +cmd/insights/insights.go @jpmcb @brandonroberts cmd/insights/repositories.go @jpmcb cmd/insights/user-contributions.go @jpmcb cmd/insights/utils.go @jpmcb cmd/repo-query/repo-query.go @jpmcb -cmd/root/root.go @jpmcb +cmd/root/root.go @jpmcb @brandonroberts @nickytonline +cmd/show/constants.go @jpmcb +cmd/show/contributors.go @jpmcb +cmd/show/dashboard.go @jpmcb cmd/show/show.go @jpmcb +cmd/show/tui.go @jpmcb cmd/version/version.go @jpmcb @nickytonline -go.mod @jpmcb -go.sum @jpmcb +docs/pizza.md @nickytonline @jpmcb +docs/pizza_completion.md @nickytonline @jpmcb +docs/pizza_completion_bash.md @nickytonline @jpmcb +docs/pizza_completion_fish.md @nickytonline @jpmcb +docs/pizza_completion_powershell.md @nickytonline @jpmcb +docs/pizza_completion_zsh.md @nickytonline @jpmcb +docs/pizza_generate.md @nickytonline @jpmcb +docs/pizza_generate_codeowners.md @nickytonline @jpmcb +docs/pizza_insights.md @nickytonline @jpmcb +docs/pizza_insights_contributors.md @nickytonline @jpmcb +docs/pizza_insights_repositories.md @nickytonline @jpmcb +docs/pizza_insights_user-contributions.md @nickytonline @jpmcb +docs/pizza_login.md @nickytonline @jpmcb +docs/pizza_version.md @nickytonline @jpmcb +go.mod @jpmcb @nickytonline +go.sum @jpmcb @nickytonline justfile @jpmcb @nickytonline -npm/package.json @jpmcb @brandonroberts @nickytonline -pkg/config/config.go @jpmcb -pkg/config/spec.go @jpmcb +npm/.gitignore @jpmcb +npm/package-lock.json @jpmcb @nickytonline @brandonroberts +npm/package.json @jpmcb @nickytonline @brandonroberts +pkg/api/client.go @jpmcb +pkg/api/validation.go @jpmcb +pkg/config/config.go @jpmcb @nickytonline @brandonroberts +pkg/config/config_test.go @nickytonline @jpmcb @brandonroberts +pkg/config/file.go @jpmcb +pkg/config/spec.go @jpmcb @brandonroberts +pkg/constants/flags.go @jpmcb pkg/logging/constants.go @jpmcb +pkg/utils/posthog.go @jpmcb pkg/utils/root.go @jpmcb -pkg/utils/version.go @nickytonline +pkg/utils/telemetry.go @jpmcb +pkg/utils/version.go @nickytonline @jpmcb +scripts/generate-docs.sh @nickytonline +telemetry.go @jpmcb From 1e42988c06fcab6694d4fca9670c59796352e7a5 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 9 Sep 2024 18:28:16 -0400 Subject: [PATCH 25/36] fix: docs generation runs outside of build matrix now (#165) * fix: docs generation runs outside of build matrix now * chore: update GH_TOKEN Co-authored-by: Brandon Roberts * keeping the name fields uniform by using double quotes --------- Co-authored-by: Brandon Roberts --- .github/workflows/release.yaml | 41 +++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0e47cb0..a49980c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -59,10 +59,46 @@ jobs: NPM_PACKAGE_ROOT: "npm" SKIP_DOCKER_PUBLISH: true + docs: + name: Update documentation + needs: + - release + + runs-on: ubuntu-latest + + steps: + - name: "Generate token" + id: generate_token + uses: tibdex/github-app-token@v2 + with: + app_id: ${{ secrets.OS_GITHUB_APP_ID }} + private_key: ${{ secrets.OS_GITHUB_APP_PRIVATE_KEY }} + + - name: "☁️ checkout repository" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ steps.generate_token.outputs.token }} + + - name: "🐹 Setup Go" + uses: actions/setup-go@v5 + with: + go-version: 1.22.x + + - name: "🤲 Setup Just" + uses: extractions/setup-just@v2 + + - name: "📗 Generate Documentation" + run: ./scripts/generate-docs.sh + env: + GITHUB_REF: ${{ github.ref }} + GH_TOKEN: ${{ steps.generate_token.outputs.token }} + build: name: Build and publish artifacts needs: - release + - docs if: needs.release.outputs.release-tag != '' runs-on: ubuntu-latest permissions: @@ -85,11 +121,6 @@ jobs: - name: "🤲 Setup Just" uses: extractions/setup-just@v2 - - name: "📗 Generate Documentation" - run: ./scripts/generate-docs.sh - env: - GITHUB_REF: ${{ github.ref }} - - name: "🔧 Build all and upload artifacts to release" env: GH_TOKEN: ${{ github.token }} From c8f2d1ff79cf9f2ef41cd5bb55773bef21e57202 Mon Sep 17 00:00:00 2001 From: Nick Taylor Date: Mon, 9 Sep 2024 22:28:56 +0000 Subject: [PATCH 26/36] chore(patch): release 1.4.0-beta.4 on beta channel [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [1.4.0-beta.4](https://github.com/open-sauced/pizza-cli/compare/v1.4.0-beta.3...v1.4.0-beta.4) (2024-09-09) ### 🐛 Bug Fixes * docs generation runs outside of build matrix now ([#165](https://github.com/open-sauced/pizza-cli/issues/165)) ([1e42988](https://github.com/open-sauced/pizza-cli/commit/1e42988c06fcab6694d4fca9670c59796352e7a5)) --- CHANGELOG.md | 7 +++++++ npm/package-lock.json | 4 ++-- npm/package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8855254..08f8fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ > All notable changes to this project will be documented in this file +## [1.4.0-beta.4](https://github.com/open-sauced/pizza-cli/compare/v1.4.0-beta.3...v1.4.0-beta.4) (2024-09-09) + + +### 🐛 Bug Fixes + +* docs generation runs outside of build matrix now ([#165](https://github.com/open-sauced/pizza-cli/issues/165)) ([1e42988](https://github.com/open-sauced/pizza-cli/commit/1e42988c06fcab6694d4fca9670c59796352e7a5)) + ## [1.4.0-beta.3](https://github.com/open-sauced/pizza-cli/compare/v1.4.0-beta.2...v1.4.0-beta.3) (2024-09-09) diff --git a/npm/package-lock.json b/npm/package-lock.json index 9c9dd1b..310be49 100644 --- a/npm/package-lock.json +++ b/npm/package-lock.json @@ -1,12 +1,12 @@ { "name": "pizza", - "version": "1.4.0-beta.3", + "version": "1.4.0-beta.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pizza", - "version": "1.4.0-beta.3", + "version": "1.4.0-beta.4", "hasInstallScript": true, "license": "MIT", "bin": { diff --git a/npm/package.json b/npm/package.json index ba1aa99..bbda5d2 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,6 +1,6 @@ { "name": "pizza", - "version": "1.4.0-beta.3", + "version": "1.4.0-beta.4", "description": "A command line utility for insights, metrics, and all things OpenSauced", "repository": "https://github.com/open-sauced/pizza-cli", "license": "MIT", From 9c9db9a188793d363e192d281714a164011d1920 Mon Sep 17 00:00:00 2001 From: "open-sauced[bot]" <63161813+open-sauced[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 22:29:32 +0000 Subject: [PATCH 27/36] chore: automated docs generation for release Co-authored-by: Nick Taylor --- docs/pizza.md | 2 +- docs/pizza_completion.md | 2 +- docs/pizza_completion_bash.md | 2 +- docs/pizza_completion_fish.md | 2 +- docs/pizza_completion_powershell.md | 2 +- docs/pizza_completion_zsh.md | 2 +- docs/pizza_generate.md | 4 ++-- docs/pizza_generate_codeowners.md | 6 +++--- docs/pizza_insights.md | 2 +- docs/pizza_insights_contributors.md | 2 +- docs/pizza_insights_repositories.md | 2 +- docs/pizza_insights_user-contributions.md | 2 +- docs/pizza_login.md | 2 +- docs/pizza_version.md | 2 +- 14 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/pizza.md b/docs/pizza.md index 49abe05..d265d6f 100644 --- a/docs/pizza.md +++ b/docs/pizza.md @@ -13,7 +13,7 @@ pizza [flags] ### Options ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -h, --help help for pizza -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") diff --git a/docs/pizza_completion.md b/docs/pizza_completion.md index 65a7507..eb0665e 100644 --- a/docs/pizza_completion.md +++ b/docs/pizza_completion.md @@ -17,7 +17,7 @@ See each sub-command's help for details on how to use the generated script. ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_bash.md b/docs/pizza_completion_bash.md index 5beed9d..6870d8c 100644 --- a/docs/pizza_completion_bash.md +++ b/docs/pizza_completion_bash.md @@ -40,7 +40,7 @@ pizza completion bash ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_fish.md b/docs/pizza_completion_fish.md index 93bb9de..5aa9ed9 100644 --- a/docs/pizza_completion_fish.md +++ b/docs/pizza_completion_fish.md @@ -31,7 +31,7 @@ pizza completion fish [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_powershell.md b/docs/pizza_completion_powershell.md index bec9a87..4514dd6 100644 --- a/docs/pizza_completion_powershell.md +++ b/docs/pizza_completion_powershell.md @@ -28,7 +28,7 @@ pizza completion powershell [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_zsh.md b/docs/pizza_completion_zsh.md index 22b1734..5910a5b 100644 --- a/docs/pizza_completion_zsh.md +++ b/docs/pizza_completion_zsh.md @@ -42,7 +42,7 @@ pizza completion zsh [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_generate.md b/docs/pizza_generate.md index edd658d..86eb183 100644 --- a/docs/pizza_generate.md +++ b/docs/pizza_generate.md @@ -21,7 +21,7 @@ pizza generate [subcommand] [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation @@ -30,5 +30,5 @@ pizza generate [subcommand] [flags] ### SEE ALSO * [pizza](pizza.md) - OpenSauced CLI -* [pizza generate codeowners](pizza_generate_codeowners.md) - Generates a CODEOWNERS file for a given repository using a "~/.sauced.yaml" config +* [pizza generate codeowners](pizza_generate_codeowners.md) - Generates a CODEOWNERS file for a given repository using a ".sauced.yaml" config diff --git a/docs/pizza_generate_codeowners.md b/docs/pizza_generate_codeowners.md index 0cb8357..3752264 100644 --- a/docs/pizza_generate_codeowners.md +++ b/docs/pizza_generate_codeowners.md @@ -1,12 +1,12 @@ ## pizza generate codeowners -Generates a CODEOWNERS file for a given repository using a "~/.sauced.yaml" config +Generates a CODEOWNERS file for a given repository using a ".sauced.yaml" config ### Synopsis WARNING: Proof of concept feature. -Generates a CODEOWNERS file for a given git repository. This uses a ~/.sauced.yaml +Generates a CODEOWNERS file for a given git repository. This uses a .sauced.yaml configuration to attribute emails with given entities. The generated file specifies up to 3 owners for EVERY file in the git tree based on the @@ -27,7 +27,7 @@ pizza generate codeowners path/to/repo [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_insights.md b/docs/pizza_insights.md index c7be12d..f841a91 100644 --- a/docs/pizza_insights.md +++ b/docs/pizza_insights.md @@ -20,7 +20,7 @@ pizza insights [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_insights_contributors.md b/docs/pizza_insights_contributors.md index ce13c4e..0e12b79 100644 --- a/docs/pizza_insights_contributors.md +++ b/docs/pizza_insights_contributors.md @@ -21,7 +21,7 @@ pizza insights contributors url... [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_insights_repositories.md b/docs/pizza_insights_repositories.md index 64070d4..dd297b5 100644 --- a/docs/pizza_insights_repositories.md +++ b/docs/pizza_insights_repositories.md @@ -21,7 +21,7 @@ pizza insights repositories url... [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_insights_user-contributions.md b/docs/pizza_insights_user-contributions.md index 5ec8b0b..26fd69d 100644 --- a/docs/pizza_insights_user-contributions.md +++ b/docs/pizza_insights_user-contributions.md @@ -23,7 +23,7 @@ pizza insights user-contributions url... [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_login.md b/docs/pizza_login.md index 7ca5124..a3d9a2e 100644 --- a/docs/pizza_login.md +++ b/docs/pizza_login.md @@ -22,7 +22,7 @@ pizza login [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_version.md b/docs/pizza_version.md index 5848855..db9900e 100644 --- a/docs/pizza_version.md +++ b/docs/pizza_version.md @@ -15,7 +15,7 @@ pizza version [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The saucectl config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation From 5e7e4bcba1f1c933556240035df91f213944e3b4 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 17:31:09 -0700 Subject: [PATCH 28/36] lowercase error messages --- cmd/generate/config/config.go | 16 ++++++++-------- cmd/generate/config/output.go | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 4742544..c543b2a 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -83,13 +83,13 @@ func run(opts *Options) error { // Open repo repo, err := git.PlainOpen(opts.path) if err != nil { - return fmt.Errorf("Error opening repo: %w", err) + return fmt.Errorf("error opening repo: %w", err) } commitIter, err := repo.CommitObjects() if err != nil { - return fmt.Errorf("Error opening repo commits: %w", err) + return fmt.Errorf("error opening repo commits: %w", err) } var uniqueEmails []string @@ -110,14 +110,14 @@ func run(opts *Options) error { }) if err != nil { - return fmt.Errorf("Error iterating over repo commits: %w", err) + return fmt.Errorf("error iterating over repo commits: %w", err) } // INTERACTIVE: per unique email, set a name (existing or new or ignore) if opts.isInteractive { program := tea.NewProgram(initialModel(opts, uniqueEmails)) if _, err := program.Run(); err != nil { - return fmt.Errorf("Error running interactive mode: %w", err) + return fmt.Errorf("error running interactive mode: %w", err) } } else { // generate an output file @@ -127,12 +127,12 @@ func run(opts *Options) error { homeDir, _ := os.UserHomeDir() err := generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) if err != nil { - return fmt.Errorf("Error generating output file: %w", err) + return fmt.Errorf("error generating output file: %w", err) } } else { err := generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) if err != nil { - return fmt.Errorf("Error generating output file: %w", err) + return fmt.Errorf("error generating output file: %w", err) } } } @@ -256,12 +256,12 @@ func runOutputGeneration(opts *Options, attributionMap map[string][]string) tea. homeDir, _ := os.UserHomeDir() err := generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) if err != nil { - return fmt.Errorf("Error generating output file: %w", err) + return fmt.Errorf("error generating output file: %w", err) } } else { err := generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) if err != nil { - return fmt.Errorf("Error generating output file: %w", err) + return fmt.Errorf("error generating output file: %w", err) } } diff --git a/cmd/generate/config/output.go b/cmd/generate/config/output.go index f5a06aa..f8db065 100644 --- a/cmd/generate/config/output.go +++ b/cmd/generate/config/output.go @@ -11,7 +11,7 @@ import ( func generateOutputFile(outputPath string, attributionMap map[string][]string) error { file, err := os.Create(outputPath) if err != nil { - return fmt.Errorf("Error creating %s file: %w", outputPath, err) + return fmt.Errorf("error creating %s file: %w", outputPath, err) } defer file.Close() @@ -22,13 +22,13 @@ func generateOutputFile(outputPath string, attributionMap map[string][]string) e yaml, err := utils.OutputYAML(config) if err != nil { - return fmt.Errorf("Failed to turn into YAML: %w", err) + return fmt.Errorf("failed to turn into YAML: %w", err) } _, err = file.WriteString(yaml) if err != nil { - return fmt.Errorf("Failed to turn into YAML: %w", err) + return fmt.Errorf("failed to turn into YAML: %w", err) } return nil From 38dda02d412ad9114985c416fdff08cd78390863 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 17:35:46 -0700 Subject: [PATCH 29/36] remove todo and empty lines --- cmd/generate/config/config.go | 3 --- go.mod | 1 - 2 files changed, 4 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index c543b2a..22d0156 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -63,8 +63,6 @@ func NewConfigCommand() *cobra.Command { }, RunE: func(cmd *cobra.Command, _ []string) error { - // TODO: error checking based on given command - opts.outputPath, _ = cmd.Flags().GetString("output-path") opts.isInteractive, _ = cmd.Flags().GetBool("interactive") @@ -267,5 +265,4 @@ func runOutputGeneration(opts *Options, attributionMap map[string][]string) tea. return tea.Quit() } - } diff --git a/go.mod b/go.mod index 757f5ea..cbf822d 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,6 @@ require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - ) require ( From 75eccb8d10e28d155bd2b2fd4f6e3f807eaa2a57 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 17:46:21 -0700 Subject: [PATCH 30/36] move bubbletea program to spec.go --- cmd/generate/config/config.go | 140 +-------------------------------- cmd/generate/config/spec.go | 142 ++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 136 deletions(-) create mode 100644 cmd/generate/config/spec.go diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 22d0156..5c571a4 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -6,11 +6,7 @@ import ( "os" "path/filepath" "slices" - "strings" - "github.com/charmbracelet/bubbles/help" - "github.com/charmbracelet/bubbles/key" - "github.com/charmbracelet/bubbles/textinput" tea "github.com/charmbracelet/bubbletea" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" @@ -27,11 +23,11 @@ type Options struct { // whether to use interactive mode isInteractive bool -} -const configLongDesc string = `WARNING: Proof of concept feature. + ttyDisabled bool +} -Generates a ~/.sauced.yaml configuration file. The attribution of emails to given entities +const configLongDesc string = `Generates a ~/.sauced.yaml configuration file. The attribution of emails to given entities is based on the repository this command is ran in.` func NewConfigCommand() *cobra.Command { @@ -65,6 +61,7 @@ func NewConfigCommand() *cobra.Command { RunE: func(cmd *cobra.Command, _ []string) error { opts.outputPath, _ = cmd.Flags().GetString("output-path") opts.isInteractive, _ = cmd.Flags().GetBool("interactive") + opts.ttyDisabled, _ = cmd.Flags().GetBool("tty-disable") return run(opts) }, @@ -137,132 +134,3 @@ func run(opts *Options) error { return nil } - -// Bubbletea for Interactive Mode - -type model struct { - textInput textinput.Model - help help.Model - keymap keymap - - opts *Options - attributionMap map[string][]string - uniqueEmails []string - currentIndex int -} - -type keymap struct{} - -func (k keymap) ShortHelp() []key.Binding { - return []key.Binding{ - key.NewBinding(key.WithKeys("ctrl+n"), key.WithHelp("ctrl+n", "next")), - key.NewBinding(key.WithKeys("ctrl+p"), key.WithHelp("ctrl+p", "prev")), - key.NewBinding(key.WithKeys("ctrl+i"), key.WithHelp("ctrl+i", "ignore email")), - key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "quit")), - key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "submit")), - } -} - -func (k keymap) FullHelp() [][]key.Binding { - return [][]key.Binding{k.ShortHelp()} -} - -func initialModel(opts *Options, uniqueEmails []string) model { - ti := textinput.New() - ti.Placeholder = "name" - ti.Focus() - ti.ShowSuggestions = true - - return model{ - textInput: ti, - help: help.New(), - keymap: keymap{}, - - opts: opts, - attributionMap: make(map[string][]string), - uniqueEmails: uniqueEmails, - currentIndex: 0, - } -} - -func (m model) Init() tea.Cmd { - return textinput.Blink -} - -func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { - var cmd tea.Cmd - currentEmail := m.uniqueEmails[m.currentIndex] - - existingUsers := make([]string, 0, len(m.attributionMap)) - for k := range m.attributionMap { - existingUsers = append(existingUsers, k) - } - - m.textInput.SetSuggestions(existingUsers) - - keyMsg, ok := msg.(tea.KeyMsg) - - if ok { - switch keyMsg.Type { - case tea.KeyCtrlC, tea.KeyEsc: - return m, tea.Quit - - case tea.KeyCtrlI: - m.currentIndex++ - return m, nil - - case tea.KeyEnter: - if len(strings.Trim(m.textInput.Value(), " ")) == 0 { - return m, nil - } - m.attributionMap[m.textInput.Value()] = append(m.attributionMap[m.textInput.Value()], currentEmail) - m.textInput.Reset() - if m.currentIndex+1 >= len(m.uniqueEmails) { - return m, runOutputGeneration(m.opts, m.attributionMap) - } - - m.currentIndex++ - return m, nil - } - } - - m.textInput, cmd = m.textInput.Update(msg) - - return m, cmd -} - -func (m model) View() string { - currentEmail := "" - if m.currentIndex < len(m.uniqueEmails) { - currentEmail = m.uniqueEmails[m.currentIndex] - } - - return fmt.Sprintf( - "Found email %s - who to attribute to?: \n%s\n\n%s\n", - currentEmail, - m.textInput.View(), - m.help.View(m.keymap), - ) -} - -func runOutputGeneration(opts *Options, attributionMap map[string][]string) tea.Cmd { - // generate an output file - // default: `./.sauced.yaml` - // fallback for home directories - return func() tea.Msg { - if opts.outputPath == "~/" { - homeDir, _ := os.UserHomeDir() - err := generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) - if err != nil { - return fmt.Errorf("error generating output file: %w", err) - } - } else { - err := generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) - if err != nil { - return fmt.Errorf("error generating output file: %w", err) - } - } - - return tea.Quit() - } -} diff --git a/cmd/generate/config/spec.go b/cmd/generate/config/spec.go new file mode 100644 index 0000000..b8732ba --- /dev/null +++ b/cmd/generate/config/spec.go @@ -0,0 +1,142 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/charmbracelet/bubbles/help" + "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" +) + +// Bubbletea for Interactive Mode + +type model struct { + textInput textinput.Model + help help.Model + keymap keymap + + opts *Options + attributionMap map[string][]string + uniqueEmails []string + currentIndex int +} + +type keymap struct{} + +func (k keymap) ShortHelp() []key.Binding { + return []key.Binding{ + key.NewBinding(key.WithKeys("ctrl+n"), key.WithHelp("ctrl+n", "next")), + key.NewBinding(key.WithKeys("ctrl+p"), key.WithHelp("ctrl+p", "prev")), + key.NewBinding(key.WithKeys("ctrl+i"), key.WithHelp("ctrl+i", "ignore email")), + key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "quit")), + key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "submit")), + } +} + +func (k keymap) FullHelp() [][]key.Binding { + return [][]key.Binding{k.ShortHelp()} +} + +func initialModel(opts *Options, uniqueEmails []string) model { + ti := textinput.New() + ti.Placeholder = "name" + ti.Focus() + ti.ShowSuggestions = true + + return model{ + textInput: ti, + help: help.New(), + keymap: keymap{}, + + opts: opts, + attributionMap: make(map[string][]string), + uniqueEmails: uniqueEmails, + currentIndex: 0, + } +} + +func (m model) Init() tea.Cmd { + return textinput.Blink +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + var cmd tea.Cmd + currentEmail := m.uniqueEmails[m.currentIndex] + + existingUsers := make([]string, 0, len(m.attributionMap)) + for k := range m.attributionMap { + existingUsers = append(existingUsers, k) + } + + m.textInput.SetSuggestions(existingUsers) + + keyMsg, ok := msg.(tea.KeyMsg) + + if ok { + switch keyMsg.Type { + case tea.KeyCtrlC, tea.KeyEsc: + return m, tea.Quit + + case tea.KeyCtrlI: + m.currentIndex++ + return m, nil + + case tea.KeyEnter: + if len(strings.Trim(m.textInput.Value(), " ")) == 0 { + return m, nil + } + m.attributionMap[m.textInput.Value()] = append(m.attributionMap[m.textInput.Value()], currentEmail) + m.textInput.Reset() + if m.currentIndex+1 >= len(m.uniqueEmails) { + return m, runOutputGeneration(m.opts, m.attributionMap) + } + + m.currentIndex++ + return m, nil + } + } + + m.textInput, cmd = m.textInput.Update(msg) + + return m, cmd +} + +func (m model) View() string { + currentEmail := "" + if m.currentIndex < len(m.uniqueEmails) { + currentEmail = m.uniqueEmails[m.currentIndex] + } + + return fmt.Sprintf( + "Found email %s - who to attribute to?: \n%s\n\n%s\n", + currentEmail, + m.textInput.View(), + m.help.View(m.keymap), + ) +} + +func runOutputGeneration(opts *Options, attributionMap map[string][]string) tea.Cmd { + // generate an output file + // default: `./.sauced.yaml` + // fallback for home directories + return func() tea.Msg { + if opts.outputPath == "~/" { + homeDir, _ := os.UserHomeDir() + err := generateOutputFile(filepath.Join(homeDir, ".sauced.yaml"), attributionMap) + if err != nil { + return fmt.Errorf("error generating output file: %w", err) + } + } else { + err := generateOutputFile(filepath.Join(opts.outputPath, ".sauced.yaml"), attributionMap) + if err != nil { + return fmt.Errorf("error generating output file: %w", err) + } + } + + return tea.Quit() + } +} From be30445a9546f9884fbce635358260876336fa69 Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Mon, 9 Sep 2024 17:49:11 -0700 Subject: [PATCH 31/36] check for tty-disable flag --- cmd/generate/config/config.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 5c571a4..99e9825 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -24,6 +24,7 @@ type Options struct { // whether to use interactive mode isInteractive bool + // from global config ttyDisabled bool } @@ -92,7 +93,7 @@ func run(opts *Options) error { name := c.Author.Name email := c.Author.Email - if !opts.isInteractive { + if opts.ttyDisabled || !opts.isInteractive { doesEmailExist := slices.Contains(attributionMap[name], email) if !doesEmailExist { // AUTOMATIC: set every name and associated emails @@ -109,7 +110,7 @@ func run(opts *Options) error { } // INTERACTIVE: per unique email, set a name (existing or new or ignore) - if opts.isInteractive { + if opts.isInteractive && !opts.ttyDisabled { program := tea.NewProgram(initialModel(opts, uniqueEmails)) if _, err := program.Run(); err != nil { return fmt.Errorf("error running interactive mode: %w", err) From fcf9e9f38f828d8935d55f1a3fdd41afeb6be042 Mon Sep 17 00:00:00 2001 From: BekahHW <34313413+BekahHW@users.noreply.github.com> Date: Tue, 10 Sep 2024 14:57:46 -0400 Subject: [PATCH 32/36] chore: update docs for generate and codeowners (#163) * Clarify short description * Create more informative flag descriptions * Add Example section * Fix linebreaks * Add long description to generate * Revise short description for generate * Add generating codeowners to long description * Add generate docs * Change saucedctl to codeowners * Change all saucectl to codeowners to reflect changes * Remove POC message and extra indents * Remove duplicated line * Remove command repetition * Add back tick back in * Adds configuration documentation to explain the sauced.yaml file * Remove indentation from examples * Use correct path for default --- README.md | 2 +- cmd/generate/codeowners/codeowners.go | 36 ++++++++++++++++----- cmd/generate/generate.go | 6 ++-- cmd/root/root.go | 4 +-- docs/pizza.md | 6 ++-- docs/pizza_completion.md | 2 +- docs/pizza_completion_bash.md | 2 +- docs/pizza_completion_fish.md | 2 +- docs/pizza_completion_powershell.md | 2 +- docs/pizza_completion_zsh.md | 2 +- docs/pizza_generate.md | 13 +++++--- docs/pizza_generate_codeowners.md | 39 ++++++++++++++++------- docs/pizza_insights.md | 2 +- docs/pizza_insights_contributors.md | 2 +- docs/pizza_insights_repositories.md | 2 +- docs/pizza_insights_user-contributions.md | 2 +- docs/pizza_login.md | 2 +- docs/pizza_version.md | 2 +- 18 files changed, 83 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 27f4d3e..9f4b80c 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ Flags: Global Flags: --beta Shorthand for using the beta OpenSauced API endpoint ("https://beta.api.opensauced.pizza"). Supersedes the '--endpoint' flag - -c, --config string The saucectl config (default "~/.sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -e, --endpoint string The API endpoint to send requests to (default "https://api.opensauced.pizza") -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") diff --git a/cmd/generate/codeowners/codeowners.go b/cmd/generate/codeowners/codeowners.go index 8f174dd..20491dd 100644 --- a/cmd/generate/codeowners/codeowners.go +++ b/cmd/generate/codeowners/codeowners.go @@ -46,21 +46,41 @@ type Options struct { config *config.Spec } -const codeownersLongDesc string = `WARNING: Proof of concept feature. +const codeownersLongDesc string = `Generates a CODEOWNERS file for a given git repository. The generated file specifies up to 3 owners for EVERY file in the git tree based on the number of lines touched in that specific file over the specified range of time. -Generates a CODEOWNERS file for a given git repository. This uses a .sauced.yaml -configuration to attribute emails with given entities. +Configuration: +The command requires a .sauced.yaml file for accurate attribution. This file maps +commit email addresses to GitHub usernames. The command looks for this file in two locations: -The generated file specifies up to 3 owners for EVERY file in the git tree based on the -number of lines touched in that specific file over the specified range of time.` +1. In the root of the specified repository path +2. In the user's home directory (~/.sauced.yaml) if not found in the repository + +If you run the command on a specific path, it will first look for .sauced.yaml in that +path. If not found, it will fall back to ~/.sauced.yaml.` func NewCodeownersCommand() *cobra.Command { opts := &Options{} cmd := &cobra.Command{ Use: "codeowners path/to/repo [flags]", - Short: "Generates a CODEOWNERS file for a given repository using a \".sauced.yaml\" config", + Short: "Generate a CODEOWNERS file for a GitHub repository using a \"~/.sauced.yaml\" config", Long: codeownersLongDesc, + Example: ` +# Generate CODEOWNERS file for the current directory +pizza generate codeowners . + +# Generate CODEOWNERS file for a specific repository +pizza generate codeowners /path/to/your/repo + +# Generate CODEOWNERS file analyzing the last 180 days +pizza generate codeowners . --range 180 + +# Generate an OWNERS style file instead of CODEOWNERS +pizza generate codeowners . --owners-style-file + +# Specify a custom location for the .sauced.yaml file +pizza generate codeowners . --config /path/to/.sauced.yaml + `, Args: func(_ *cobra.Command, args []string) error { if len(args) != 1 { return errors.New("you must provide exactly one argument: the path to the repository") @@ -119,8 +139,8 @@ func NewCodeownersCommand() *cobra.Command { }, } - cmd.PersistentFlags().IntP("range", "r", 90, "The number of days to lookback") - cmd.PersistentFlags().Bool("owners-style-file", false, "Whether to generate an agnostic OWNERS style file.") + cmd.PersistentFlags().IntP("range", "r", 90, "The number of days to analyze commit history (default 90)") + cmd.PersistentFlags().Bool("owners-style-file", false, "Generate an agnostic OWNERS style file instead of CODEOWNERS.") return cmd } diff --git a/cmd/generate/generate.go b/cmd/generate/generate.go index b3ff321..aa2c800 100644 --- a/cmd/generate/generate.go +++ b/cmd/generate/generate.go @@ -8,14 +8,12 @@ import ( "github.com/open-sauced/pizza-cli/cmd/generate/codeowners" ) -const generateLongDesc string = `WARNING: Proof of concept feature. - -XXX` +const generateLongDesc string = `The 'generate' command provides tools to automate the creation of important project documentation and derive insights from your codebase.` func NewGenerateCommand() *cobra.Command { cmd := &cobra.Command{ Use: "generate [subcommand] [flags]", - Short: "Generates something", + Short: "Generates documentation and insights from your codebase", Long: generateLongDesc, Args: func(_ *cobra.Command, args []string) error { if len(args) != 1 { diff --git a/cmd/root/root.go b/cmd/root/root.go index 9dbbc45..7b35e4a 100644 --- a/cmd/root/root.go +++ b/cmd/root/root.go @@ -19,7 +19,7 @@ func NewRootCommand() (*cobra.Command, error) { cmd := &cobra.Command{ Use: "pizza [flags]", Short: "OpenSauced CLI", - Long: "A command line utility for insights, metrics, and all things OpenSauced", + Long: "A command line utility for insights, metrics, and generating CODEOWNERS documentation for your open source projects", RunE: run, Args: func(cmd *cobra.Command, _ []string) error { betaFlag := cmd.Flags().Lookup(constants.FlagNameBeta) @@ -36,7 +36,7 @@ func NewRootCommand() (*cobra.Command, error) { cmd.PersistentFlags().StringP(constants.FlagNameEndpoint, "e", constants.EndpointProd, "The API endpoint to send requests to") cmd.PersistentFlags().Bool(constants.FlagNameBeta, false, fmt.Sprintf("Shorthand for using the beta OpenSauced API endpoint (\"%s\"). Supersedes the '--%s' flag", constants.EndpointBeta, constants.FlagNameEndpoint)) cmd.PersistentFlags().Bool(constants.FlagNameTelemetry, false, "Disable sending telemetry data to OpenSauced") - cmd.PersistentFlags().StringP("config", "c", ".sauced.yaml", "The saucectl config") + cmd.PersistentFlags().StringP("config", "c", "~/.sauced.yaml", "The codeowners config") cmd.PersistentFlags().StringP("log-level", "l", "info", "The logging level. Options: error, warn, info, debug") cmd.PersistentFlags().Bool("tty-disable", false, "Disable log stylization. Suitable for CI/CD and automation") diff --git a/docs/pizza.md b/docs/pizza.md index d265d6f..16f72ba 100644 --- a/docs/pizza.md +++ b/docs/pizza.md @@ -4,7 +4,7 @@ OpenSauced CLI ### Synopsis -A command line utility for insights, metrics, and all things OpenSauced +A command line utility for insights, metrics, and generating CODEOWNERS documentation for your open source projects ``` pizza [flags] @@ -13,7 +13,7 @@ pizza [flags] ### Options ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -h, --help help for pizza -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") @@ -23,7 +23,7 @@ pizza [flags] ### SEE ALSO * [pizza completion](pizza_completion.md) - Generate the autocompletion script for the specified shell -* [pizza generate](pizza_generate.md) - Generates something +* [pizza generate](pizza_generate.md) - Generates documentation and insights from your codebase * [pizza insights](pizza_insights.md) - Gather insights about git contributors, repositories, users and pull requests * [pizza login](pizza_login.md) - Log into the CLI via GitHub * [pizza version](pizza_version.md) - Displays the build version of the CLI diff --git a/docs/pizza_completion.md b/docs/pizza_completion.md index eb0665e..242f5e5 100644 --- a/docs/pizza_completion.md +++ b/docs/pizza_completion.md @@ -17,7 +17,7 @@ See each sub-command's help for details on how to use the generated script. ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_bash.md b/docs/pizza_completion_bash.md index 6870d8c..cabb559 100644 --- a/docs/pizza_completion_bash.md +++ b/docs/pizza_completion_bash.md @@ -40,7 +40,7 @@ pizza completion bash ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_fish.md b/docs/pizza_completion_fish.md index 5aa9ed9..d58cc2b 100644 --- a/docs/pizza_completion_fish.md +++ b/docs/pizza_completion_fish.md @@ -31,7 +31,7 @@ pizza completion fish [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_powershell.md b/docs/pizza_completion_powershell.md index 4514dd6..2256317 100644 --- a/docs/pizza_completion_powershell.md +++ b/docs/pizza_completion_powershell.md @@ -28,7 +28,7 @@ pizza completion powershell [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_zsh.md b/docs/pizza_completion_zsh.md index 5910a5b..0b8d87e 100644 --- a/docs/pizza_completion_zsh.md +++ b/docs/pizza_completion_zsh.md @@ -42,7 +42,7 @@ pizza completion zsh [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_generate.md b/docs/pizza_generate.md index 86eb183..74f6ae5 100644 --- a/docs/pizza_generate.md +++ b/docs/pizza_generate.md @@ -1,12 +1,15 @@ ## pizza generate -Generates something +Generates documentation and insights from your codebase ### Synopsis -WARNING: Proof of concept feature. +The 'generate' command provides tools to automate the creation of important project documentation and derive insights from your codebase. -XXX +Currently, it supports generating CODEOWNERS files. + +Available subcommands: + - codeowners: Generate a more granular GitHub-style CODEOWNERS file based on git history. ``` pizza generate [subcommand] [flags] @@ -21,7 +24,7 @@ pizza generate [subcommand] [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation @@ -30,5 +33,5 @@ pizza generate [subcommand] [flags] ### SEE ALSO * [pizza](pizza.md) - OpenSauced CLI -* [pizza generate codeowners](pizza_generate_codeowners.md) - Generates a CODEOWNERS file for a given repository using a ".sauced.yaml" config +* [pizza generate codeowners](pizza_generate_codeowners.md) - Generate a CODEOWNERS file for a GitHub repository using a "~/.sauced.yaml" config diff --git a/docs/pizza_generate_codeowners.md b/docs/pizza_generate_codeowners.md index 3752264..8b476dc 100644 --- a/docs/pizza_generate_codeowners.md +++ b/docs/pizza_generate_codeowners.md @@ -1,33 +1,50 @@ ## pizza generate codeowners -Generates a CODEOWNERS file for a given repository using a ".sauced.yaml" config +Generate a CODEOWNERS file for a GitHub repository using a "~/.sauced.yaml" config ### Synopsis -WARNING: Proof of concept feature. +Generates a CODEOWNERS file for a given git repository. This uses a ~/.sauced.yaml configuration to attribute emails with given entities. -Generates a CODEOWNERS file for a given git repository. This uses a .sauced.yaml -configuration to attribute emails with given entities. - -The generated file specifies up to 3 owners for EVERY file in the git tree based on the -number of lines touched in that specific file over the specified range of time. +The generated file specifies up to 3 owners for EVERY file in the git tree based on the number of lines touched in that specific file over the specified range of time. ``` pizza generate codeowners path/to/repo [flags] ``` +### Examples + +``` + + # Generate CODEOWNERS file for the current directory + pizza generate codeowners . + + # Generate CODEOWNERS file for a specific repository + pizza generate codeowners /path/to/your/repo + + # Generate CODEOWNERS file analyzing the last 180 days + pizza generate codeowners . --range 180 + + # Generate an OWNERS style file instead of CODEOWNERS + pizza generate codeowners . --owners-style-file + + # Specify a custom location for the .sauced.yaml file + pizza generate codeowners . --config /path/to/.sauced.yaml + +``` + ### Options ``` -h, --help help for codeowners - --owners-style-file Whether to generate an agnostic OWNERS style file. - -r, --range int The number of days to lookback (default 90) + --owners-style-file Generate an agnostic OWNERS style file instead of CODEOWNERS. + -r, --range int The number of days to analyze commit history (default 90) (default 90) ``` ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation @@ -35,5 +52,5 @@ pizza generate codeowners path/to/repo [flags] ### SEE ALSO -* [pizza generate](pizza_generate.md) - Generates something +* [pizza generate](pizza_generate.md) - Generates documentation and insights from your codebase diff --git a/docs/pizza_insights.md b/docs/pizza_insights.md index f841a91..b71a3a7 100644 --- a/docs/pizza_insights.md +++ b/docs/pizza_insights.md @@ -20,7 +20,7 @@ pizza insights [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_insights_contributors.md b/docs/pizza_insights_contributors.md index 0e12b79..499ed2e 100644 --- a/docs/pizza_insights_contributors.md +++ b/docs/pizza_insights_contributors.md @@ -21,7 +21,7 @@ pizza insights contributors url... [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_insights_repositories.md b/docs/pizza_insights_repositories.md index dd297b5..b46c2a1 100644 --- a/docs/pizza_insights_repositories.md +++ b/docs/pizza_insights_repositories.md @@ -21,7 +21,7 @@ pizza insights repositories url... [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_insights_user-contributions.md b/docs/pizza_insights_user-contributions.md index 26fd69d..d59b71e 100644 --- a/docs/pizza_insights_user-contributions.md +++ b/docs/pizza_insights_user-contributions.md @@ -23,7 +23,7 @@ pizza insights user-contributions url... [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_login.md b/docs/pizza_login.md index a3d9a2e..8859efd 100644 --- a/docs/pizza_login.md +++ b/docs/pizza_login.md @@ -22,7 +22,7 @@ pizza login [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_version.md b/docs/pizza_version.md index db9900e..a19188b 100644 --- a/docs/pizza_version.md +++ b/docs/pizza_version.md @@ -15,7 +15,7 @@ pizza version [flags] ### Options inherited from parent commands ``` - -c, --config string The saucectl config (default ".sauced.yaml") + -c, --config string The codeowners config (default ".sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation From 07bac4b0c05d719a36ad7763e1179e4e0c1ee095 Mon Sep 17 00:00:00 2001 From: "open-sauced[bot]" <63161813+open-sauced[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 18:58:40 +0000 Subject: [PATCH 33/36] chore: automated docs generation for release Co-authored-by: BekahHW <34313413+BekahHW@users.noreply.github.com> --- docs/pizza.md | 2 +- docs/pizza_completion.md | 2 +- docs/pizza_completion_bash.md | 2 +- docs/pizza_completion_fish.md | 2 +- docs/pizza_completion_powershell.md | 2 +- docs/pizza_completion_zsh.md | 2 +- docs/pizza_generate.md | 7 +---- docs/pizza_generate_codeowners.md | 34 ++++++++++++++--------- docs/pizza_insights.md | 2 +- docs/pizza_insights_contributors.md | 2 +- docs/pizza_insights_repositories.md | 2 +- docs/pizza_insights_user-contributions.md | 2 +- docs/pizza_login.md | 2 +- docs/pizza_version.md | 2 +- 14 files changed, 34 insertions(+), 31 deletions(-) diff --git a/docs/pizza.md b/docs/pizza.md index 16f72ba..58ea659 100644 --- a/docs/pizza.md +++ b/docs/pizza.md @@ -13,7 +13,7 @@ pizza [flags] ### Options ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -h, --help help for pizza -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") diff --git a/docs/pizza_completion.md b/docs/pizza_completion.md index 242f5e5..1506e1b 100644 --- a/docs/pizza_completion.md +++ b/docs/pizza_completion.md @@ -17,7 +17,7 @@ See each sub-command's help for details on how to use the generated script. ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_bash.md b/docs/pizza_completion_bash.md index cabb559..3a32c97 100644 --- a/docs/pizza_completion_bash.md +++ b/docs/pizza_completion_bash.md @@ -40,7 +40,7 @@ pizza completion bash ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_fish.md b/docs/pizza_completion_fish.md index d58cc2b..734d1e0 100644 --- a/docs/pizza_completion_fish.md +++ b/docs/pizza_completion_fish.md @@ -31,7 +31,7 @@ pizza completion fish [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_powershell.md b/docs/pizza_completion_powershell.md index 2256317..06b2036 100644 --- a/docs/pizza_completion_powershell.md +++ b/docs/pizza_completion_powershell.md @@ -28,7 +28,7 @@ pizza completion powershell [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_completion_zsh.md b/docs/pizza_completion_zsh.md index 0b8d87e..5e45162 100644 --- a/docs/pizza_completion_zsh.md +++ b/docs/pizza_completion_zsh.md @@ -42,7 +42,7 @@ pizza completion zsh [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_generate.md b/docs/pizza_generate.md index 74f6ae5..5cb89e4 100644 --- a/docs/pizza_generate.md +++ b/docs/pizza_generate.md @@ -6,11 +6,6 @@ Generates documentation and insights from your codebase The 'generate' command provides tools to automate the creation of important project documentation and derive insights from your codebase. -Currently, it supports generating CODEOWNERS files. - -Available subcommands: - - codeowners: Generate a more granular GitHub-style CODEOWNERS file based on git history. - ``` pizza generate [subcommand] [flags] ``` @@ -24,7 +19,7 @@ pizza generate [subcommand] [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_generate_codeowners.md b/docs/pizza_generate_codeowners.md index 8b476dc..dcbbfd0 100644 --- a/docs/pizza_generate_codeowners.md +++ b/docs/pizza_generate_codeowners.md @@ -4,9 +4,17 @@ Generate a CODEOWNERS file for a GitHub repository using a "~/.sauced.yaml" conf ### Synopsis -Generates a CODEOWNERS file for a given git repository. This uses a ~/.sauced.yaml configuration to attribute emails with given entities. +Generates a CODEOWNERS file for a given git repository. The generated file specifies up to 3 owners for EVERY file in the git tree based on the number of lines touched in that specific file over the specified range of time. -The generated file specifies up to 3 owners for EVERY file in the git tree based on the number of lines touched in that specific file over the specified range of time. +Configuration: +The command requires a .sauced.yaml file for accurate attribution. This file maps +commit email addresses to GitHub usernames. The command looks for this file in two locations: + +1. In the root of the specified repository path +2. In the user's home directory (~/.sauced.yaml) if not found in the repository + +If you run the command on a specific path, it will first look for .sauced.yaml in that +path. If not found, it will fall back to ~/.sauced.yaml. ``` pizza generate codeowners path/to/repo [flags] @@ -16,20 +24,20 @@ pizza generate codeowners path/to/repo [flags] ``` - # Generate CODEOWNERS file for the current directory - pizza generate codeowners . +# Generate CODEOWNERS file for the current directory +pizza generate codeowners . - # Generate CODEOWNERS file for a specific repository - pizza generate codeowners /path/to/your/repo +# Generate CODEOWNERS file for a specific repository +pizza generate codeowners /path/to/your/repo - # Generate CODEOWNERS file analyzing the last 180 days - pizza generate codeowners . --range 180 +# Generate CODEOWNERS file analyzing the last 180 days +pizza generate codeowners . --range 180 - # Generate an OWNERS style file instead of CODEOWNERS - pizza generate codeowners . --owners-style-file +# Generate an OWNERS style file instead of CODEOWNERS +pizza generate codeowners . --owners-style-file - # Specify a custom location for the .sauced.yaml file - pizza generate codeowners . --config /path/to/.sauced.yaml +# Specify a custom location for the .sauced.yaml file +pizza generate codeowners . --config /path/to/.sauced.yaml ``` @@ -44,7 +52,7 @@ pizza generate codeowners path/to/repo [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_insights.md b/docs/pizza_insights.md index b71a3a7..7933480 100644 --- a/docs/pizza_insights.md +++ b/docs/pizza_insights.md @@ -20,7 +20,7 @@ pizza insights [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_insights_contributors.md b/docs/pizza_insights_contributors.md index 499ed2e..6c9d868 100644 --- a/docs/pizza_insights_contributors.md +++ b/docs/pizza_insights_contributors.md @@ -21,7 +21,7 @@ pizza insights contributors url... [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_insights_repositories.md b/docs/pizza_insights_repositories.md index b46c2a1..9754648 100644 --- a/docs/pizza_insights_repositories.md +++ b/docs/pizza_insights_repositories.md @@ -21,7 +21,7 @@ pizza insights repositories url... [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_insights_user-contributions.md b/docs/pizza_insights_user-contributions.md index d59b71e..8f07c9d 100644 --- a/docs/pizza_insights_user-contributions.md +++ b/docs/pizza_insights_user-contributions.md @@ -23,7 +23,7 @@ pizza insights user-contributions url... [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") -o, --output string The formatting for command output. One of: (table, yaml, csv, json) (default "table") diff --git a/docs/pizza_login.md b/docs/pizza_login.md index 8859efd..54ead8f 100644 --- a/docs/pizza_login.md +++ b/docs/pizza_login.md @@ -22,7 +22,7 @@ pizza login [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation diff --git a/docs/pizza_version.md b/docs/pizza_version.md index a19188b..ce6c725 100644 --- a/docs/pizza_version.md +++ b/docs/pizza_version.md @@ -15,7 +15,7 @@ pizza version [flags] ### Options inherited from parent commands ``` - -c, --config string The codeowners config (default ".sauced.yaml") + -c, --config string The codeowners config (default "~/.sauced.yaml") --disable-telemetry Disable sending telemetry data to OpenSauced -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") --tty-disable Disable log stylization. Suitable for CI/CD and automation From bfdd66918c433934b629de1582624d97665d013e Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Tue, 10 Sep 2024 13:07:30 -0700 Subject: [PATCH 34/36] change placeholder/help copy --- cmd/generate/config/config.go | 4 ++-- cmd/generate/config/spec.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/generate/config/config.go b/cmd/generate/config/config.go index 99e9825..e5e3e19 100644 --- a/cmd/generate/config/config.go +++ b/cmd/generate/config/config.go @@ -28,7 +28,7 @@ type Options struct { ttyDisabled bool } -const configLongDesc string = `Generates a ~/.sauced.yaml configuration file. The attribution of emails to given entities +const configLongDesc string = `Generates a ".sauced.yaml" configuration file. The attribution of emails to given entities is based on the repository this command is ran in.` func NewConfigCommand() *cobra.Command { @@ -36,7 +36,7 @@ func NewConfigCommand() *cobra.Command { cmd := &cobra.Command{ Use: "config path/to/repo [flags]", - Short: "Generates a \"~/.sauced.yaml\" config based on the current repository", + Short: "Generates a \".sauced.yaml\" config based on the current repository", Long: configLongDesc, Args: func(_ *cobra.Command, args []string) error { if len(args) != 1 { diff --git a/cmd/generate/config/spec.go b/cmd/generate/config/spec.go index b8732ba..4b24c8d 100644 --- a/cmd/generate/config/spec.go +++ b/cmd/generate/config/spec.go @@ -29,8 +29,8 @@ type keymap struct{} func (k keymap) ShortHelp() []key.Binding { return []key.Binding{ - key.NewBinding(key.WithKeys("ctrl+n"), key.WithHelp("ctrl+n", "next")), - key.NewBinding(key.WithKeys("ctrl+p"), key.WithHelp("ctrl+p", "prev")), + key.NewBinding(key.WithKeys("ctrl+n"), key.WithHelp("ctrl+n", "next suggestion")), + key.NewBinding(key.WithKeys("ctrl+p"), key.WithHelp("ctrl+p", "prev suggestion")), key.NewBinding(key.WithKeys("ctrl+i"), key.WithHelp("ctrl+i", "ignore email")), key.NewBinding(key.WithKeys("esc"), key.WithHelp("esc", "quit")), key.NewBinding(key.WithKeys("enter"), key.WithHelp("enter", "submit")), @@ -43,7 +43,7 @@ func (k keymap) FullHelp() [][]key.Binding { func initialModel(opts *Options, uniqueEmails []string) model { ti := textinput.New() - ti.Placeholder = "name" + ti.Placeholder = "username" ti.Focus() ti.ShowSuggestions = true From 315a97b9c4cdfbda43c6a1b24fe5b23aa46ca51a Mon Sep 17 00:00:00 2001 From: Zeu Capua Date: Tue, 10 Sep 2024 13:42:09 -0700 Subject: [PATCH 35/36] check if last attribution is ignored --- cmd/generate/config/spec.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/generate/config/spec.go b/cmd/generate/config/spec.go index 4b24c8d..5284cc9 100644 --- a/cmd/generate/config/spec.go +++ b/cmd/generate/config/spec.go @@ -83,6 +83,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case tea.KeyCtrlI: m.currentIndex++ + if m.currentIndex+1 >= len(m.uniqueEmails) { + return m, runOutputGeneration(m.opts, m.attributionMap) + } return m, nil case tea.KeyEnter: From 9f6a92c9a57f7343a7ad251198b74c17e7d44851 Mon Sep 17 00:00:00 2001 From: "open-sauced[bot]" <63161813+open-sauced[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:46:36 +0000 Subject: [PATCH 36/36] chore: automated docs generation for release Co-authored-by: Zeu Capua --- docs/pizza_generate.md | 1 + docs/pizza_generate_config.md | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 docs/pizza_generate_config.md diff --git a/docs/pizza_generate.md b/docs/pizza_generate.md index 5cb89e4..61b0e8e 100644 --- a/docs/pizza_generate.md +++ b/docs/pizza_generate.md @@ -29,4 +29,5 @@ pizza generate [subcommand] [flags] * [pizza](pizza.md) - OpenSauced CLI * [pizza generate codeowners](pizza_generate_codeowners.md) - Generate a CODEOWNERS file for a GitHub repository using a "~/.sauced.yaml" config +* [pizza generate config](pizza_generate_config.md) - Generates a ".sauced.yaml" config based on the current repository diff --git a/docs/pizza_generate_config.md b/docs/pizza_generate_config.md new file mode 100644 index 0000000..0366cad --- /dev/null +++ b/docs/pizza_generate_config.md @@ -0,0 +1,34 @@ +## pizza generate config + +Generates a ".sauced.yaml" config based on the current repository + +### Synopsis + +Generates a ".sauced.yaml" configuration file. The attribution of emails to given entities +is based on the repository this command is ran in. + +``` +pizza generate config path/to/repo [flags] +``` + +### Options + +``` + -h, --help help for config + -i, --interactive Whether to be interactive + -o, --output-path .sauced.yaml Directory to create the .sauced.yaml file. (default "./") +``` + +### Options inherited from parent commands + +``` + -c, --config string The codeowners config (default "~/.sauced.yaml") + --disable-telemetry Disable sending telemetry data to OpenSauced + -l, --log-level string The logging level. Options: error, warn, info, debug (default "info") + --tty-disable Disable log stylization. Suitable for CI/CD and automation +``` + +### SEE ALSO + +* [pizza generate](pizza_generate.md) - Generates documentation and insights from your codebase +