From 46be5508384b4752d15e54ba2258b2f31e52687a Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Wed, 14 Jul 2021 22:23:18 -0300 Subject: [PATCH] refactor: organazing code Signed-off-by: Carlos Alexandro Becker --- cmd/blacklist.go | 19 ++++ main_test.go => cmd/blacklist_test.go | 2 +- cmd/docs.go | 19 ++++ cmd/root.go | 116 +++++++++++++++++++ cmd/version.go | 24 ++++ main.go | 157 +------------------------- 6 files changed, 181 insertions(+), 156 deletions(-) create mode 100644 cmd/blacklist.go rename main_test.go => cmd/blacklist_test.go (96%) create mode 100644 cmd/docs.go create mode 100644 cmd/root.go create mode 100644 cmd/version.go diff --git a/cmd/blacklist.go b/cmd/blacklist.go new file mode 100644 index 0000000..a8eb3fe --- /dev/null +++ b/cmd/blacklist.go @@ -0,0 +1,19 @@ +package cmd + +import "strings" + +func buildBlacklists(blacklist []string) ([]string, []string) { + var userBlacklist []string + var repoBlacklist []string + for _, b := range blacklist { + if strings.HasPrefix(b, "user:") { + userBlacklist = append(userBlacklist, strings.TrimPrefix(b, "user:")) + } else if strings.HasPrefix(b, "repo:") { + repoBlacklist = append(repoBlacklist, strings.TrimPrefix(b, "repo:")) + } else { + userBlacklist = append(userBlacklist, b) + repoBlacklist = append(repoBlacklist, b) + } + } + return userBlacklist, repoBlacklist +} diff --git a/main_test.go b/cmd/blacklist_test.go similarity index 96% rename from main_test.go rename to cmd/blacklist_test.go index 26e84fd..06265f8 100644 --- a/main_test.go +++ b/cmd/blacklist_test.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "testing" diff --git a/cmd/docs.go b/cmd/docs.go new file mode 100644 index 0000000..04912de --- /dev/null +++ b/cmd/docs.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" +) + +var docsCmd = &cobra.Command{ + Use: "docs", + Short: "Generates donuts's command line docs", + SilenceUsage: true, + DisableFlagsInUseLine: true, + Hidden: true, + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + cmd.Root().DisableAutoGenTag = true + return doc.GenMarkdownTree(cmd.Root(), "docs") + }, +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..3ce6b5b --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,116 @@ +package cmd + +import ( + "fmt" + "os" + "path/filepath" + "time" + + "github.com/caarlos0/duration" + "github.com/caarlos0/org-stats/csv" + "github.com/caarlos0/org-stats/highlights" + "github.com/caarlos0/org-stats/orgstats" + "github.com/caarlos0/spin" + "github.com/charmbracelet/lipgloss" + "github.com/spf13/cobra" +) + +var ( + token string + organization string + githubURL string + since string + csvPath string + blacklist []string + top int + includeReviews bool +) + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func init() { + rootCmd.Flags().StringVar(&token, "token", "", "github api token (default $GITHUB_TOKEN)") + rootCmd.MarkFlagRequired(token) + + rootCmd.Flags().StringVarP(&organization, "org", "o", "", "github organization to scan") + rootCmd.MarkFlagRequired("org") + + rootCmd.Flags().StringSliceVarP(&blacklist, "blacklist", "b", []string{}, "blacklist repos and/or users") + rootCmd.Flags().IntVar(&top, "top", 3, "how many users to show") + rootCmd.Flags().StringVar(&githubURL, "github-url", "", "custom github base url (if using github enterprise)") + rootCmd.Flags().StringVar(&since, "since", "0s", "time to look back to gather info (0s means everything)") + rootCmd.Flags().BoolVar(&includeReviews, "include-reviews", false, "include pull request reviews in the stats") + rootCmd.Flags().StringVar(&csvPath, "csv-path", "", "path to write a csv file with all data collected") + + rootCmd.AddCommand(versionCmd, docsCmd) +} + +var rootCmd = &cobra.Command{ + Use: "org-stats", + Short: "Get the contributor stats summary from all repos of any given organization", + Long: `org-stats can be used to get an overall sense of your org's contributors. + +It uses the GitHub API to grab the repositories in the given organization. +Then, iterating one by one, it gets statistics of lines added, removed and number of commits of contributors. +After that, if opted in, it does several searches to get the number of pull requests reviewed by each of the previously find contributors. +Finally, it prints a rank by each category. + + +Important notes: +* The ` + "`" + `--since` + "`" + ` filter does not work "that well" because GitHub summarizes thedata by week, so the data is not as granular as it should be. +* The ` + "`" + `--include-reviews` + "`" + ` only grabs reviews from users that had contributions on the previous step. +* In the ` + "`" + `--blacklist` + "`" + ` option, 'foo' blacklists both the 'foo' user and 'foo' repo, while 'user:foo' blacklists only the user and 'repo:foo' only the repository. +* The ` + "`" + `--since` + "`" + ` option accepts all the regular time.Durations Go accepts, plus a few more: 1y (365d), 1mo (30d), 1w (7d) and 1d (24h).`, + PreRun: func(cmd *cobra.Command, args []string) { + if token == "" { + token = os.Getenv("GITHUB_TOKEN") + } + }, + RunE: func(cmd *cobra.Command, args []string) error { + loadingStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("205")) + spin := spin.New(loadingStyle.Render(" %s Gathering data for '" + organization + "'...")) + spin.Start() + + sinceD, err := duration.Parse(since) + if err != nil { + return fmt.Errorf("invalid --since duration: '%s'", since) + } + + userBlacklist, repoBlacklist := buildBlacklists(blacklist) + + allStats, err := orgstats.Gather( + token, + organization, + userBlacklist, + repoBlacklist, + githubURL, + time.Now().UTC().Add(-1*time.Duration(sinceD)), + includeReviews, + ) + spin.Stop() + if err != nil { + return err + } + + if csvPath != "" { + if err := os.MkdirAll(filepath.Dir(csvPath), 0755); err != nil { + return fmt.Errorf("failed to create csv file: %w", err) + } + f, err := os.OpenFile(csvPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return fmt.Errorf("failed to create csv file: %w", err) + } + if err := csv.Write(f, allStats, includeReviews); err != nil { + return fmt.Errorf("failed to create csv file: %w", err) + } + } + + fmt.Println() + return highlights.Write(os.Stdout, allStats, top, includeReviews) + }, +} diff --git a/cmd/version.go b/cmd/version.go new file mode 100644 index 0000000..dca5e54 --- /dev/null +++ b/cmd/version.go @@ -0,0 +1,24 @@ +package cmd + +import ( + "fmt" + "runtime/debug" + + "github.com/spf13/cobra" +) + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Prints org-stats version", + Run: func(cmd *cobra.Command, args []string) { + if info, ok := debug.ReadBuildInfo(); ok { + sum := info.Main.Sum + if sum == "" { + sum = "none" + } + fmt.Printf("https://%s %s @ %s\n", info.Main.Path, info.Main.Version, sum) + } else { + fmt.Println("unknown") + } + }, +} diff --git a/main.go b/main.go index d46cec5..b48f8b8 100644 --- a/main.go +++ b/main.go @@ -1,162 +1,9 @@ package main import ( - "fmt" - "os" - "path/filepath" - "runtime/debug" - "strings" - "time" - - "github.com/caarlos0/duration" - "github.com/caarlos0/org-stats/csv" - "github.com/caarlos0/org-stats/highlights" - orgstats "github.com/caarlos0/org-stats/orgstats" - "github.com/caarlos0/spin" - "github.com/charmbracelet/lipgloss" - "github.com/spf13/cobra" - "github.com/spf13/cobra/doc" -) - -var ( - token string - organization string - githubURL string - since string - csvPath string - blacklist []string - top int - includeReviews bool + "github.com/caarlos0/org-stats/cmd" ) func main() { - rootCmd := &cobra.Command{ - Use: "org-stats", - Short: "Get the contributor stats summary from all repos of any given organization", - Long: `org-stats can be used to get an overall sense of your org's contributors. - -It uses the GitHub API to grab the repositories in the given organization. -Then, iterating one by one, it gets statistics of lines added, removed and number of commits of contributors. -After that, if opted in, it does several searches to get the number of pull requests reviewed by each of the previously find contributors. -Finally, it prints a rank by each category. - - -Important notes: -* The ` + "`" + `--since` + "`" + ` filter does not work "that well" because GitHub summarizes thedata by week, so the data is not as granular as it should be. -* The ` + "`" + `--include-reviews` + "`" + ` only grabs reviews from users that had contributions on the previous step. -* In the ` + "`" + `--blacklist` + "`" + ` option, 'foo' blacklists both the 'foo' user and 'foo' repo, while 'user:foo' blacklists only the user and 'repo:foo' only the repository. -* The ` + "`" + `--since` + "`" + ` option accepts all the regular time.Durations Go accepts, plus a few more: 1y (365d), 1mo (30d), 1w (7d) and 1d (24h).`, - RunE: func(cmd *cobra.Command, args []string) error { - loadingStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("205")) - spin := spin.New(loadingStyle.Render(" %s Gathering data for '" + organization + "'...")) - spin.Start() - - sinceD, err := duration.Parse(since) - if err != nil { - return fmt.Errorf("invalid --since duration: '%s'", since) - } - - userBlacklist, repoBlacklist := buildBlacklists(blacklist) - - allStats, err := orgstats.Gather( - token, - organization, - userBlacklist, - repoBlacklist, - githubURL, - time.Now().UTC().Add(-1*time.Duration(sinceD)), - includeReviews, - ) - spin.Stop() - if err != nil { - return err - } - - if csvPath != "" { - if err := os.MkdirAll(filepath.Dir(csvPath), 0755); err != nil { - return fmt.Errorf("failed to create csv file: %w", err) - } - f, err := os.OpenFile(csvPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - return fmt.Errorf("failed to create csv file: %w", err) - } - if err := csv.Write(f, allStats, includeReviews); err != nil { - return fmt.Errorf("failed to create csv file: %w", err) - } - } - - fmt.Println() - return highlights.Write(os.Stdout, allStats, top, includeReviews) - }, - PreRun: func(cmd *cobra.Command, args []string) { - if token == "" { - token = os.Getenv("GITHUB_TOKEN") - } - }, - } - - versionCmd := &cobra.Command{ - Use: "version", - Short: "Prints org-stats version", - Run: func(cmd *cobra.Command, args []string) { - if info, ok := debug.ReadBuildInfo(); ok { - sum := info.Main.Sum - if sum == "" { - sum = "none" - } - fmt.Printf("https://%s %s @ %s\n", info.Main.Path, info.Main.Version, sum) - } else { - fmt.Println("unknown") - } - }, - } - - docsCmd := &cobra.Command{ - Use: "docs", - Short: "Generates donuts's command line docs", - SilenceUsage: true, - DisableFlagsInUseLine: true, - Hidden: true, - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - cmd.Root().DisableAutoGenTag = true - return doc.GenMarkdownTree(cmd.Root(), "docs") - }, - } - - rootCmd.Flags().StringVar(&token, "token", "", "github api token (default $GITHUB_TOKEN)") - rootCmd.MarkFlagRequired(token) - - rootCmd.Flags().StringVarP(&organization, "org", "o", "", "github organization to scan") - rootCmd.MarkFlagRequired("org") - - rootCmd.Flags().StringSliceVarP(&blacklist, "blacklist", "b", []string{}, "blacklist repos and/or users") - rootCmd.Flags().IntVar(&top, "top", 3, "how many users to show") - rootCmd.Flags().StringVar(&githubURL, "github-url", "", "custom github base url (if using github enterprise)") - rootCmd.Flags().StringVar(&since, "since", "0s", "time to look back to gather info (0s means everything)") - rootCmd.Flags().BoolVar(&includeReviews, "include-reviews", false, "include pull request reviews in the stats") - rootCmd.Flags().StringVar(&csvPath, "csv-path", "", "path to write a csv file with all data collected") - - rootCmd.AddCommand(versionCmd, docsCmd) - - if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} - -func buildBlacklists(blacklist []string) ([]string, []string) { - var userBlacklist []string - var repoBlacklist []string - for _, b := range blacklist { - if strings.HasPrefix(b, "user:") { - userBlacklist = append(userBlacklist, strings.TrimPrefix(b, "user:")) - } else if strings.HasPrefix(b, "repo:") { - repoBlacklist = append(repoBlacklist, strings.TrimPrefix(b, "repo:")) - } else { - userBlacklist = append(userBlacklist, b) - repoBlacklist = append(repoBlacklist, b) - } - } - return userBlacklist, repoBlacklist + cmd.Execute() }