Bug fixes, config generator
This commit is contained in:
parent
5d2ca40d04
commit
cdf92c8a54
10
README.md
10
README.md
@ -3,6 +3,16 @@
|
||||
## TODO
|
||||
|
||||
- Fix NPE when cache is reset or project for whatever reason leaves an orphaned alias
|
||||
- Add config setters and getters
|
||||
- Add TTL check to cache load, and add -f / --force flag to re-build regardless
|
||||
- For each project loaded, check if it is the same, and do nothing
|
||||
- prevents clobbering cache on a partial update
|
||||
- track loaded projects in []*Project to diff after load
|
||||
- should prune missing after the load is complete
|
||||
- Add open command
|
||||
- config should exist for editor (vim, code, etc..)
|
||||
- Update README for shell completion, aliases, usage
|
||||
- Make a Makefile
|
||||
|
||||
## Purpose
|
||||
|
||||
|
@ -17,3 +17,9 @@ var aliasCmd = &cobra.Command{
|
||||
func init() {
|
||||
rootCmd.AddCommand(aliasCmd)
|
||||
}
|
||||
|
||||
func mustHaveAliases(cmd *cobra.Command, args []string) {
|
||||
if len(cache.Aliases) == 0 {
|
||||
plog.Fatal("No aliases set, nothing to " + cmd.Name())
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ var aliasDeleteCmd = &cobra.Command{
|
||||
Aliases: []string{"rm", "del", "d"},
|
||||
Short: "Delete a project alias",
|
||||
Long: aliasDeleteCmdLong,
|
||||
PreRun: mustHaveAliases,
|
||||
Run: runDeleteAliasCmd,
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ var aliasListCmd = &cobra.Command{
|
||||
Use: "list",
|
||||
Aliases: []string{"dump", "show", "ls", "ll", "l"},
|
||||
Short: "List Aliases",
|
||||
PreRun: mustHaveAliases,
|
||||
Long: aliasListCmdLong,
|
||||
Run: runListAliasCmd,
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ var cache *projects.Cache
|
||||
|
||||
var cacheCmd = &cobra.Command{
|
||||
Use: "cache",
|
||||
Aliases: []string{"a", "ln"},
|
||||
Short: "Manage GitLab project cache",
|
||||
Long: cacheCmdLong,
|
||||
PersistentPreRun: runCacheCmd,
|
||||
|
16
cmd/config.go
Normal file
16
cmd/config.go
Normal file
@ -0,0 +1,16 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var configCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "GitLab Project Manager Configuration",
|
||||
Aliases: []string{"conf"},
|
||||
Long: configCmdLong,
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(configCmd)
|
||||
}
|
27
cmd/config_generate.go
Normal file
27
cmd/config_generate.go
Normal file
@ -0,0 +1,27 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"gitlab.sweetwater.com/it/devops/tools/gitlab-project-manager/internal/config"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var configGenerateCmd = &cobra.Command{
|
||||
Use: "generate",
|
||||
Short: "Generate a default configuration",
|
||||
Aliases: []string{"gen", "new", "default"},
|
||||
Long: configGenCmdLong,
|
||||
Run: runConfigGenerateCmd,
|
||||
}
|
||||
|
||||
func runConfigGenerateCmd(cmd *cobra.Command, args []string) {
|
||||
plog.Info("Suggest running with > " + defConfigPath)
|
||||
c, _ := yaml.Marshal(config.DefaultConfig)
|
||||
fmt.Print(string(c))
|
||||
}
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configGenerateCmd)
|
||||
}
|
@ -46,6 +46,7 @@ func getProject(args []string) *gitlab.Project {
|
||||
|
||||
func initProjectCmd(cmd *cobra.Command, args []string) {
|
||||
initProjectCache(cmd, args)
|
||||
mustHaveProjects(cmd, args)
|
||||
}
|
||||
|
||||
func postProjectCmd(cmd *cobra.Command, args []string) {
|
||||
@ -55,3 +56,9 @@ func postProjectCmd(cmd *cobra.Command, args []string) {
|
||||
func init() {
|
||||
rootCmd.AddCommand(projectCmd)
|
||||
}
|
||||
|
||||
func mustHaveProjects(cmd *cobra.Command, args []string) {
|
||||
if len(cache.Aliases) == 0 {
|
||||
plog.Fatal("No projects to " + cmd.Name() + ", try running cache load")
|
||||
}
|
||||
}
|
||||
|
24
cmd/root.go
24
cmd/root.go
@ -38,7 +38,7 @@ func Execute() {
|
||||
err := rootCmd.ExecuteContext(ctx)
|
||||
|
||||
if err != nil {
|
||||
plog.Error("Failed to execute command", plog.Args("err", err))
|
||||
pterm.Error.Printfln(pterm.LightYellow("Command failed, " + err.Error()))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@ -48,12 +48,12 @@ func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
|
||||
rootCmd.PersistentFlags().String("config", "",
|
||||
"config file (default is $HOME/.gitlab-project-manager.yaml)")
|
||||
"config file (default is "+defConfigPath+")")
|
||||
rootCmd.PersistentFlags().String("gitlabHost", defGitlabHost,
|
||||
"GitLab Hostname (e.g. gitlab.com)")
|
||||
rootCmd.PersistentFlags().String("gitlabToken", "",
|
||||
"GitLab Tokenname (e.g. gitlab.com)")
|
||||
rootCmd.PersistentFlags().String("projectPath", defProjectsPath,
|
||||
rootCmd.PersistentFlags().String("projectPath", "",
|
||||
"Sets a path for local clones of projects")
|
||||
rootCmd.PersistentFlags().String("logLevel", defLogLevel,
|
||||
"Default log level -- info, warn, error, debug")
|
||||
@ -73,16 +73,14 @@ func initConfig() {
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".gitlab-project-manager" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
viper.AddConfigPath(home + "/.config")
|
||||
viper.SetConfigType("yaml")
|
||||
viper.SetConfigName(".gitlab-project-manager")
|
||||
viper.SetConfigName("gitlab-project-manager")
|
||||
}
|
||||
|
||||
viper.AutomaticEnv()
|
||||
viper.ReadInConfig()
|
||||
|
||||
checkConfigPerms(viper.ConfigFileUsed()) // Abort on world-readable config
|
||||
|
||||
// Configure pretty logger
|
||||
plog = pterm.DefaultLogger.
|
||||
WithLevel(getPtermLogLevel(viper.GetString("logLevel"))).
|
||||
@ -97,6 +95,18 @@ func initConfig() {
|
||||
plog.Error("Failed loading config", plog.Args("err", err))
|
||||
}
|
||||
|
||||
if len(os.Args) > 0 && strings.HasPrefix(os.Args[1], "conf") {
|
||||
plog.Debug("Permitting missing config for config sub-command")
|
||||
return
|
||||
} else if conf.ProjectPath == "" {
|
||||
plog.Fatal("Minimal configuration missing, must have projectPath", plog.Args(
|
||||
"do",
|
||||
"Try running `gitlab-project-manager config default > "+defConfigPath,
|
||||
))
|
||||
}
|
||||
|
||||
checkConfigPerms(viper.ConfigFileUsed()) // Abort on world-readable config
|
||||
|
||||
plog.Debug("Configuration loaded", plog.Args("conf", conf))
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,8 @@ package cmd
|
||||
|
||||
const (
|
||||
defGitlabHost = "gitlab.sweetwater.com"
|
||||
defProjectsPath = "~/work/projects"
|
||||
defLogLevel = "info"
|
||||
defConfigPath = "~/.config/gitlab-project-manager.yaml"
|
||||
)
|
||||
|
||||
const aliasCmdLong = `Manages project aliases, with options for
|
||||
@ -43,3 +43,9 @@ uses fuzzy find to locate the project`
|
||||
|
||||
const projShowCmdLong = `Shows detail for a particular project
|
||||
Will always fuzzy find`
|
||||
|
||||
const configCmdLong = `Commands for managing configuration, particulary
|
||||
useful for seeding a new config file`
|
||||
|
||||
const configGenCmdLong = `Produces yaml to stdout that can be used
|
||||
to seed the configuration file`
|
||||
|
@ -13,13 +13,28 @@ type Config struct {
|
||||
}
|
||||
}
|
||||
|
||||
type cacheConfig struct {
|
||||
Ttl time.Duration `yaml:"ttl" json:"ttl"`
|
||||
File string `yaml:"file" json:"file"`
|
||||
Load struct {
|
||||
type loadConfig struct {
|
||||
OwnerOnly bool `yaml:"ownerOnly" json:"ownerOnly"`
|
||||
} `yaml:"load" json:"load"`
|
||||
Clear struct {
|
||||
ClearAliases bool `yaml:"clearAliases" json:"clearAliases"`
|
||||
} `yaml:"clear" json:"clear"`
|
||||
}
|
||||
|
||||
type cacheConfig struct {
|
||||
Ttl time.Duration `yaml:"ttl,omitempty" json:"ttl,omitempty"`
|
||||
File string `yaml:"file,omitempty" json:"file,omitempty"`
|
||||
Load loadConfig `yaml:"load" json:"load"`
|
||||
Clear struct {
|
||||
ClearAliases bool `yaml:"clearAliases,omitempty" json:"clearAliases,omitempty"`
|
||||
} `yaml:"clear,omitempty" json:"clear,omitempty"`
|
||||
}
|
||||
|
||||
var DefaultConfig = Config{
|
||||
GitlabHost: "https://gitlab.com",
|
||||
GitlabToken: "yourtokenhere",
|
||||
LogLevel: "warn",
|
||||
ProjectPath: "~/work/projects",
|
||||
Cache: cacheConfig{
|
||||
Ttl: 168 * time.Hour,
|
||||
Load: loadConfig{
|
||||
OwnerOnly: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -129,16 +129,17 @@ func (c *Client) streamProjects(pi *ProgressInfo, ownerOnly bool) {
|
||||
for {
|
||||
projects, resp, err := c.ListProjects(listOpts)
|
||||
|
||||
if err != nil {
|
||||
pi.ErrorChan <- err
|
||||
break
|
||||
}
|
||||
|
||||
// We're done when we have it all or our context is done
|
||||
if c.Ctx.Err() != nil || resp.NextPage == 0 {
|
||||
pi.DoneChan <- nil
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
pi.ErrorChan <- err
|
||||
}
|
||||
|
||||
numProjects += len(projects)
|
||||
pi.ProjectsChan <- projects
|
||||
pi.ProgressChan <- Progress{
|
||||
|
Loading…
Reference in New Issue
Block a user