diff options
author | Michael Muré <batolettre@gmail.com> | 2019-11-10 18:30:46 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-10 18:30:46 +0100 |
commit | 802b61e254c40042028d5f08bbed0968e78da265 (patch) | |
tree | 1672ea2925533bee62947f6e0a7027b1bff1cb7e | |
parent | 350ab761d7b07df9bd49123130fe9807ea9a3d7e (diff) | |
parent | e0b15ee7644c20533156850e0be5a07597967450 (diff) | |
download | git-bug-802b61e254c40042028d5f08bbed0968e78da265.tar.gz |
Merge pull request #219 from MichaelMure/global-config
Global config, global bridge token
28 files changed, 798 insertions, 24 deletions
diff --git a/bridge/bridges.go b/bridge/bridges.go index dcb35af1..9bbf3941 100644 --- a/bridge/bridges.go +++ b/bridge/bridges.go @@ -3,13 +3,19 @@ package bridge import ( "github.com/MichaelMure/git-bug/bridge/core" - _ "github.com/MichaelMure/git-bug/bridge/github" - _ "github.com/MichaelMure/git-bug/bridge/gitlab" - _ "github.com/MichaelMure/git-bug/bridge/launchpad" + "github.com/MichaelMure/git-bug/bridge/github" + "github.com/MichaelMure/git-bug/bridge/gitlab" + "github.com/MichaelMure/git-bug/bridge/launchpad" "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/repository" ) +func init() { + core.Register(&github.Github{}) + core.Register(&gitlab.Gitlab{}) + core.Register(&launchpad.Launchpad{}) +} + // Targets return all known bridge implementation target func Targets() []string { return core.Targets() diff --git a/bridge/core/bridge.go b/bridge/core/bridge.go index ddf041f1..e419ed77 100644 --- a/bridge/core/bridge.go +++ b/bridge/core/bridge.go @@ -71,6 +71,12 @@ func Targets() []string { return result } +// TargetExist return true if the given target has a bridge implementation +func TargetExist(target string) bool { + _, ok := bridgeImpl[target] + return ok +} + // Instantiate a new Bridge for a repo, from the given target and name func NewBridge(repo *cache.RepoCache, target string, name string) (*Bridge, error) { implType, ok := bridgeImpl[target] diff --git a/bridge/core/token.go b/bridge/core/token.go new file mode 100644 index 00000000..2ceabca2 --- /dev/null +++ b/bridge/core/token.go @@ -0,0 +1,182 @@ +package core + +import ( + "crypto/sha256" + "errors" + "fmt" + "regexp" + "sort" + "strings" + "time" + + "github.com/MichaelMure/git-bug/entity" + "github.com/MichaelMure/git-bug/repository" +) + +const ( + tokenConfigKeyPrefix = "git-bug.token" + tokenValueKey = "value" + tokenTargetKey = "target" + tokenCreateTimeKey = "createtime" +) + +var ErrTokenNotExist = errors.New("token doesn't exist") + +func NewErrMultipleMatchToken(matching []entity.Id) *entity.ErrMultipleMatch { + return entity.NewErrMultipleMatch("token", matching) +} + +// Token holds an API access token data +type Token struct { + Value string + Target string + CreateTime time.Time +} + +// NewToken instantiate a new token +func NewToken(value, target string) *Token { + return &Token{ + Value: value, + Target: target, + CreateTime: time.Now(), + } +} + +func (t *Token) ID() entity.Id { + sum := sha256.Sum256([]byte(t.Value)) + return entity.Id(fmt.Sprintf("%x", sum)) +} + +// Validate ensure token important fields are valid +func (t *Token) Validate() error { + if t.Value == "" { + return fmt.Errorf("missing value") + } + if t.Target == "" { + return fmt.Errorf("missing target") + } + if t.CreateTime.IsZero() || t.CreateTime.Equal(time.Time{}) { + return fmt.Errorf("missing creation time") + } + if !TargetExist(t.Target) { + return fmt.Errorf("unknown target") + } + return nil +} + +// LoadToken loads a token from the repo config +func LoadToken(repo repository.RepoCommon, id entity.Id) (*Token, error) { + keyPrefix := fmt.Sprintf("git-bug.token.%s.", id) + + // read token config pairs + rawconfigs, err := repo.GlobalConfig().ReadAll(keyPrefix) + if err != nil { + // Not exactly right due to the limitation of ReadAll() + return nil, ErrTokenNotExist + } + + // trim key prefix + configs := make(map[string]string) + for key, value := range rawconfigs { + newKey := strings.TrimPrefix(key, keyPrefix) + configs[newKey] = value + } + + token := &Token{} + + token.Value = configs[tokenValueKey] + token.Target = configs[tokenTargetKey] + if createTime, ok := configs[tokenCreateTimeKey]; ok { + if t, err := repository.ParseTimestamp(createTime); err == nil { + token.CreateTime = t + } + } + + return token, nil +} + +// LoadTokenPrefix load a token from the repo config with a prefix +func LoadTokenPrefix(repo repository.RepoCommon, prefix string) (*Token, error) { + tokens, err := ListTokens(repo) + if err != nil { + return nil, err + } + + // preallocate but empty + matching := make([]entity.Id, 0, 5) + + for _, id := range tokens { + if id.HasPrefix(prefix) { + matching = append(matching, id) + } + } + + if len(matching) > 1 { + return nil, NewErrMultipleMatchToken(matching) + } + + if len(matching) == 0 { + return nil, ErrTokenNotExist + } + + return LoadToken(repo, matching[0]) +} + +// ListTokens return a map representing the stored tokens in the repo config and global config +// along with their type (global: true, local:false) +func ListTokens(repo repository.RepoCommon) ([]entity.Id, error) { + configs, err := repo.GlobalConfig().ReadAll(tokenConfigKeyPrefix + ".") + if err != nil { + return nil, err + } + + re, err := regexp.Compile(tokenConfigKeyPrefix + `.([^.]+)`) + if err != nil { + panic(err) + } + + set := make(map[string]interface{}) + + for key := range configs { + res := re.FindStringSubmatch(key) + + if res == nil { + continue + } + + set[res[1]] = nil + } + + result := make([]entity.Id, 0, len(set)) + for key := range set { + result = append(result, entity.Id(key)) + } + + sort.Sort(entity.Alphabetical(result)) + + return result, nil +} + +// StoreToken stores a token in the repo config +func StoreToken(repo repository.RepoCommon, token *Token) error { + storeValueKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID().String(), tokenValueKey) + err := repo.GlobalConfig().StoreString(storeValueKey, token.Value) + if err != nil { + return err + } + + storeTargetKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID().String(), tokenTargetKey) + err = repo.GlobalConfig().StoreString(storeTargetKey, token.Target) + if err != nil { + return err + } + + createTimeKey := fmt.Sprintf("git-bug.token.%s.%s", token.ID().String(), tokenCreateTimeKey) + return repo.GlobalConfig().StoreTimestamp(createTimeKey, token.CreateTime) +} + +// RemoveToken removes a token from the repo config +func RemoveToken(repo repository.RepoCommon, id entity.Id) error { + keyPrefix := fmt.Sprintf("git-bug.token.%s", id) + return repo.GlobalConfig().RemoveAll(keyPrefix) +} diff --git a/bridge/github/github.go b/bridge/github/github.go index 176bdd84..e4fb03dd 100644 --- a/bridge/github/github.go +++ b/bridge/github/github.go @@ -10,10 +10,6 @@ import ( "github.com/MichaelMure/git-bug/bridge/core" ) -func init() { - core.Register(&Github{}) -} - type Github struct{} func (*Github) Target() string { diff --git a/bridge/gitlab/gitlab.go b/bridge/gitlab/gitlab.go index f4b980ac..05721bfe 100644 --- a/bridge/gitlab/gitlab.go +++ b/bridge/gitlab/gitlab.go @@ -23,10 +23,6 @@ const ( defaultTimeout = 60 * time.Second ) -func init() { - core.Register(&Gitlab{}) -} - type Gitlab struct{} func (*Gitlab) Target() string { diff --git a/bridge/launchpad/launchpad.go b/bridge/launchpad/launchpad.go index 1fd9edc2..030d9169 100644 --- a/bridge/launchpad/launchpad.go +++ b/bridge/launchpad/launchpad.go @@ -5,10 +5,6 @@ import ( "github.com/MichaelMure/git-bug/bridge/core" ) -func init() { - core.Register(&Launchpad{}) -} - type Launchpad struct{} func (*Launchpad) Target() string { diff --git a/commands/bridge_auth.go b/commands/bridge_auth.go new file mode 100644 index 00000000..e7fce1bd --- /dev/null +++ b/commands/bridge_auth.go @@ -0,0 +1,53 @@ +package commands + +import ( + "fmt" + + "github.com/spf13/cobra" + + text "github.com/MichaelMure/go-term-text" + + "github.com/MichaelMure/git-bug/bridge/core" + "github.com/MichaelMure/git-bug/util/colors" +) + +func runBridgeAuth(cmd *cobra.Command, args []string) error { + tokens, err := core.ListTokens(repo) + if err != nil { + return err + } + + for _, token := range tokens { + token, err := core.LoadToken(repo, token) + if err != nil { + return err + } + printToken(token) + } + + return nil +} + +func printToken(token *core.Token) { + targetFmt := text.LeftPadMaxLine(token.Target, 10, 0) + + fmt.Printf("%s %s %s %s\n", + colors.Cyan(token.ID().Human()), + colors.Yellow(targetFmt), + colors.Magenta("token"), + token.Value, + ) +} + +var bridgeAuthCmd = &cobra.Command{ + Use: "auth", + Short: "List all known bridge authentication credentials.", + PreRunE: loadRepo, + RunE: runBridgeAuth, + Args: cobra.NoArgs, +} + +func init() { + bridgeCmd.AddCommand(bridgeAuthCmd) + bridgeAuthCmd.Flags().SortFlags = false +} diff --git a/commands/bridge_auth_add.go b/commands/bridge_auth_add.go new file mode 100644 index 00000000..ae2c4dbc --- /dev/null +++ b/commands/bridge_auth_add.go @@ -0,0 +1,74 @@ +package commands + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/mattn/go-isatty" + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "github.com/MichaelMure/git-bug/bridge" + "github.com/MichaelMure/git-bug/bridge/core" +) + +var ( + bridgeAuthAddTokenTarget string +) + +func runBridgeTokenAdd(cmd *cobra.Command, args []string) error { + var value string + + if bridgeAuthAddTokenTarget == "" { + return fmt.Errorf("auth target is required") + } + + if !core.TargetExist(bridgeAuthAddTokenTarget) { + return fmt.Errorf("unknown target") + } + + if len(args) == 1 { + value = args[0] + } else { + // Read from Stdin + if isatty.IsTerminal(os.Stdin.Fd()) { + fmt.Println("Enter the token:") + } + reader := bufio.NewReader(os.Stdin) + raw, err := reader.ReadString('\n') + if err != nil { + return fmt.Errorf("reading from stdin: %v", err) + } + value = strings.TrimSuffix(raw, "\n") + } + + token := core.NewToken(value, bridgeAuthAddTokenTarget) + if err := token.Validate(); err != nil { + return errors.Wrap(err, "invalid token") + } + + err := core.StoreToken(repo, token) + if err != nil { + return err + } + + fmt.Printf("token %s added\n", token.ID()) + return nil +} + +var bridgeAuthAddTokenCmd = &cobra.Command{ + Use: "add-token [<token>]", + Short: "Store a new token", + PreRunE: loadRepo, + RunE: runBridgeTokenAdd, + Args: cobra.MaximumNArgs(1), +} + +func init() { + bridgeAuthCmd.AddCommand(bridgeAuthAddTokenCmd) + bridgeAuthAddTokenCmd.Flags().StringVarP(&bridgeAuthAddTokenTarget, "target", "t", "", + fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ","))) + bridgeAuthAddTokenCmd.Flags().SortFlags = false +} diff --git a/commands/bridge_auth_rm.go b/commands/bridge_auth_rm.go new file mode 100644 index 00000000..b0b4d437 --- /dev/null +++ b/commands/bridge_auth_rm.go @@ -0,0 +1,36 @@ +package commands + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/MichaelMure/git-bug/bridge/core" +) + +func runBridgeAuthRm(cmd *cobra.Command, args []string) error { + token, err := core.LoadTokenPrefix(repo, args[0]) + if err != nil { + return err + } + + err = core.RemoveToken(repo, token.ID()) + if err != nil { + return err + } + + fmt.Printf("token %s removed\n", token.ID()) + return nil +} + +var bridgeAuthRmCmd = &cobra.Command{ + Use: "rm <id>", + Short: "Remove a credential.", + PreRunE: loadRepo, + RunE: runBridgeAuthRm, + Args: cobra.ExactArgs(1), +} + +func init() { + bridgeAuthCmd.AddCommand(bridgeAuthRmCmd) +} diff --git a/commands/bridge_auth_show.go b/commands/bridge_auth_show.go new file mode 100644 index 00000000..94141b93 --- /dev/null +++ b/commands/bridge_auth_show.go @@ -0,0 +1,37 @@ +package commands + +import ( + "fmt" + "time" + + "github.com/spf13/cobra" + + "github.com/MichaelMure/git-bug/bridge/core" +) + +func runBridgeAuthShow(cmd *cobra.Command, args []string) error { + token, err := core.LoadTokenPrefix(repo, args[0]) + if err != nil { + return err + } + + fmt.Printf("Id: %s\n", token.ID()) + fmt.Printf("Target: %s\n", token.Target) + fmt.Printf("Type: token\n") + fmt.Printf("Value: %s\n", token.Value) + fmt.Printf("Creation: %s\n", token.CreateTime.Format(time.RFC822)) + + return nil +} + +var bridgeAuthShowCmd = &cobra.Command{ + Use: "show", + Short: "Display an authentication credential.", + PreRunE: loadRepo, + RunE: runBridgeAuthShow, + Args: cobra.ExactArgs(1), +} + +func init() { + bridgeAuthCmd.AddCommand(bridgeAuthShowCmd) +} diff --git a/doc/man/git-bug-bridge-auth-add-token.1 b/doc/man/git-bug-bridge-auth-add-token.1 new file mode 100644 index 00000000..a76ed793 --- /dev/null +++ b/doc/man/git-bug-bridge-auth-add-token.1 @@ -0,0 +1,33 @@ +.TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" "" +.nh +.ad l + + +.SH NAME +.PP +git\-bug\-bridge\-auth\-add\-token \- Store a new token + + +.SH SYNOPSIS +.PP +\fBgit\-bug bridge auth add\-token [<token>] [flags]\fP + + +.SH DESCRIPTION +.PP +Store a new token + + +.SH OPTIONS +.PP +\fB\-t\fP, \fB\-\-target\fP="" + The target of the bridge. Valid values are [github,gitlab,launchpad\-preview] + +.PP +\fB\-h\fP, \fB\-\-help\fP[=false] + help for add\-token + + +.SH SEE ALSO +.PP +\fBgit\-bug\-bridge\-auth(1)\fP diff --git a/doc/man/git-bug-bridge-auth-rm.1 b/doc/man/git-bug-bridge-auth-rm.1 new file mode 100644 index 00000000..b0222b72 --- /dev/null +++ b/doc/man/git-bug-bridge-auth-rm.1 @@ -0,0 +1,29 @@ +.TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" "" +.nh +.ad l + + +.SH NAME +.PP +git\-bug\-bridge\-auth\-rm \- Remove a credential. + + +.SH SYNOPSIS +.PP +\fBgit\-bug bridge auth rm <id> [flags]\fP + + +.SH DESCRIPTION +.PP +Remove a credential. + + +.SH OPTIONS +.PP +\fB\-h\fP, \fB\-\-help\fP[=false] + help for rm + + +.SH SEE ALSO +.PP +\fBgit\-bug\-bridge\-auth(1)\fP diff --git a/doc/man/git-bug-bridge-auth-show.1 b/doc/man/git-bug-bridge-auth-show.1 new file mode 100644 index 00000000..6e0d345c --- /dev/null +++ b/doc/man/git-bug-bridge-auth-show.1 @@ -0,0 +1,29 @@ +.TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" "" +.nh +.ad l + + +.SH NAME +.PP +git\-bug\-bridge\-auth\-show \- Display an authentication credential. + + +.SH SYNOPSIS +.PP +\fBgit\-bug bridge auth show [flags]\fP + + +.SH DESCRIPTION +.PP +Display an authentication credential. + + +.SH OPTIONS +.PP +\fB\-h\fP, \fB\-\-help\fP[=false] + help for show + + +.SH SEE ALSO +.PP +\fBgit\-bug\-bridge\-auth(1)\fP diff --git a/doc/man/git-bug-bridge-auth.1 b/doc/man/git-bug-bridge-auth.1 new file mode 100644 index 00000000..0e400c41 --- /dev/null +++ b/doc/man/git-bug-bridge-auth.1 @@ -0,0 +1,29 @@ +.TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" "" +.nh +.ad l + + +.SH NAME +.PP +git\-bug\-bridge\-auth \- List all known bridge authentication credentials. + + +.SH SYNOPSIS +.PP +\fBgit\-bug bridge auth [flags]\fP + + +.SH DESCRIPTION +.PP +List all known bridge authentication credentials. + + +.SH OPTIONS +.PP +\fB\-h\fP, \fB\-\-help\fP[=false] + help for auth + + +.SH SEE ALSO +.PP +\fBgit\-bug\-bridge(1)\fP, \fBgit\-bug\-bridge\-auth\-add\-token(1)\fP, \fBgit\-bug\-bridge\-auth\-rm(1)\fP, \fBgit\-bug\-bridge\-auth\-show(1)\fP diff --git a/doc/man/git-bug-bridge.1 b/doc/man/git-bug-bridge.1 index dfede4e0..8e885f10 100644 --- a/doc/man/git-bug-bridge.1 +++ b/doc/man/git-bug-bridge.1 @@ -26,4 +26,4 @@ Configure and use bridges to other bug trackers. .SH SEE ALSO .PP -\fBgit\-bug(1)\fP, \fBgit\-bug\-bridge\-configure(1)\fP, \fBgit\-bug\-bridge\-pull(1)\fP, \fBgit\-bug\-bridge\-push(1)\fP, \fBgit\-bug\-bridge\-rm(1)\fP +\fBgit\-bug(1)\fP, \fBgit\-bug\-bridge\-auth(1)\fP, \fBgit\-bug\-bridge\-configure(1)\fP, \fBgit\-bug\-bridge\-pull(1)\fP, \fBgit\-bug\-bridge\-push(1)\fP, \fBgit\-bug\-bridge\-rm(1)\fP diff --git a/doc/md/git-bug_bridge.md b/doc/md/git-bug_bridge.md index dfd61e29..3ddb9892 100644 --- a/doc/md/git-bug_bridge.md +++ b/doc/md/git-bug_bridge.md @@ -19,6 +19,7 @@ git-bug bridge [flags] ### SEE ALSO * [git-bug](git-bug.md) - A bug tracker embedded in Git. +* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials. * [git-bug bridge configure](git-bug_bridge_configure.md) - Configure a new bridge. * [git-bug bridge pull](git-bug_bridge_pull.md) - Pull updates. * [git-bug bridge push](git-bug_bridge_push.md) - Push updates. diff --git a/doc/md/git-bug_bridge_auth.md b/doc/md/git-bug_bridge_auth.md new file mode 100644 index 00000000..e953f0ec --- /dev/null +++ b/doc/md/git-bug_bridge_auth.md @@ -0,0 +1,25 @@ +## git-bug bridge auth + +List all known bridge authentication credentials. + +### Synopsis + +List all known bridge authentication credentials. + +``` +git-bug bridge auth [flags] +``` + +### Options + +``` + -h, --help help for auth +``` + +### SEE ALSO + +* [git-bug bridge](git-bug_bridge.md) - Configure and use bridges to other bug trackers. +* [git-bug bridge auth add-token](git-bug_bridge_auth_add-token.md) - Store a new token +* [git-bug bridge auth rm](git-bug_bridge_auth_rm.md) - Remove a credential. +* [git-bug bridge auth show](git-bug_bridge_auth_show.md) - Display an authentication credential. + diff --git a/doc/md/git-bug_bridge_auth_add-token.md b/doc/md/git-bug_bridge_auth_add-token.md new file mode 100644 index 00000000..7067c3ca --- /dev/null +++ b/doc/md/git-bug_bridge_auth_add-token.md @@ -0,0 +1,23 @@ +## git-bug bridge auth add-token + +Store a new token + +### Synopsis + +Store a new token + +``` +git-bug bridge auth add-token [<token>] [flags] +``` + +### Options + +``` + -t, --target string The target of the bridge. Valid values are [github,gitlab,launchpad-preview] + -h, --help help for add-token +``` + +### SEE ALSO + +* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials. + diff --git a/doc/md/git-bug_bridge_auth_rm.md b/doc/md/git-bug_bridge_auth_rm.md new file mode 100644 index 00000000..059aa43d --- /dev/null +++ b/doc/md/git-bug_bridge_auth_rm.md @@ -0,0 +1,22 @@ +## git-bug bridge auth rm + +Remove a credential. + +### Synopsis + +Remove a credential. + +``` +git-bug bridge auth rm <id> [flags] +``` + +### Options + +``` + -h, --help help for rm +``` + +### SEE ALSO + +* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials. + diff --git a/doc/md/git-bug_bridge_auth_show.md b/doc/md/git-bug_bridge_auth_show.md new file mode 100644 index 00000000..5da3820f --- /dev/null +++ b/doc/md/git-bug_bridge_auth_show.md @@ -0,0 +1,22 @@ +## git-bug bridge auth show + +Display an authentication credential. + +### Synopsis + +Display an authentication credential. + +``` +git-bug bridge auth show [flags] +``` + +### Options + +``` + -h, --help help for show +``` + +### SEE ALSO + +* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials. + diff --git a/entity/id.go b/entity/id.go index 7ff6b223..1b78aacd 100644 --- a/entity/id.go +++ b/entity/id.go @@ -65,3 +65,21 @@ func (i Id) Validate() error { } return nil } + +/* + * Sorting + */ + +type Alphabetical []Id + +func (a Alphabetical) Len() int { + return len(a) +} + +func (a Alphabetical) Less(i, j int) bool { + return a[i] < a[j] +} + +func (a Alphabetical) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} diff --git a/misc/bash_completion/git-bug b/misc/bash_completion/git-bug index 2088fd4d..9dc3ac87 100644 --- a/misc/bash_completion/git-bug +++ b/misc/bash_completion/git-bug @@ -287,6 +287,93 @@ _git-bug_add() noun_aliases=() } +_git-bug_bridge_auth_add-token() +{ + last_command="git-bug_bridge_auth_add-token" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + flags+=("--target=") + two_word_flags+=("--target") + two_word_flags+=("-t") + local_nonpersistent_flags+=("--target=") + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_git-bug_bridge_auth_rm() +{ + last_command="git-bug_bridge_auth_rm" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_git-bug_bridge_auth_show() +{ + last_command="git-bug_bridge_auth_show" + + command_aliases=() + + commands=() + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + +_git-bug_bridge_auth() +{ + last_command="git-bug_bridge_auth" + + command_aliases=() + + commands=() + commands+=("add-token") + commands+=("rm") + commands+=("show") + + flags=() + two_word_flags=() + local_nonpersistent_flags=() + flags_with_completion=() + flags_completion=() + + + must_have_one_flag=() + must_have_one_noun=() + noun_aliases=() +} + _git-bug_bridge_configure() { last_command="git-bug_bridge_configure" @@ -407,6 +494,7 @@ _git-bug_bridge() command_aliases=() commands=() + commands+=("auth") commands+=("configure") commands+=("pull") commands+=("push") diff --git a/misc/powershell_completion/git-bug b/misc/powershell_completion/git-bug index 34037531..5f043932 100644 --- a/misc/powershell_completion/git-bug +++ b/misc/powershell_completion/git-bug @@ -48,12 +48,30 @@ Register-ArgumentCompleter -Native -CommandName 'git-bug' -ScriptBlock { break } 'git-bug;bridge' { + [CompletionResult]::new('auth', 'auth', [CompletionResultType]::ParameterValue, 'List all known bridge authentication credentials.') [CompletionResult]::new('configure', 'configure', [CompletionResultType]::ParameterValue, 'Configure a new bridge.') [CompletionResult]::new('pull', 'pull', [CompletionResultType]::ParameterValue, 'Pull updates.') [CompletionResult]::new('push', 'push', [CompletionResultType]::ParameterValue, 'Push updates.') [CompletionResult]::new('rm', 'rm', [CompletionResultType]::ParameterValue, 'Delete a configured bridge.') break } + 'git-bug;bridge;auth' { + [CompletionResult]::new('add-token', 'add-token', [CompletionResultType]::ParameterValue, 'Store a new token') + [CompletionResult]::new('rm', 'rm', [CompletionResultType]::ParameterValue, 'Remove a credential.') + [CompletionResult]::new('show', 'show', [CompletionResultType]::ParameterValue, 'Display an authentication credential.') + break + } + 'git-bug;bridge;auth;add-token' { + [CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'The target of the bridge. Valid values are [github,gitlab,launchpad-preview]') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'The target of the bridge. Valid values are [github,gitlab,launchpad-preview]') + break + } + 'git-bug;bridge;auth;rm' { + break + } + 'git-bug;bridge;auth;show' { + break + } 'git-bug;bridge;configure' { [CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'A distinctive name to identify the bridge') [CompletionResult]::new('--name', 'name', [CompletionResultType]::ParameterName, 'A distinctive name to identify the bridge') diff --git a/misc/zsh_completion/git-bug b/misc/zsh_completion/git-bug index 9951bab9..230061dd 100644 --- a/misc/zsh_completion/git-bug +++ b/misc/zsh_completion/git-bug @@ -114,6 +114,7 @@ function _git-bug_bridge { case $state in cmnds) commands=( + "auth:List all known bridge authentication credentials." "configure:Configure a new bridge." "pull:Pull updates." "push:Push updates." @@ -124,6 +125,9 @@ function _git-bug_bridge { esac case "$words[1]" in + auth) + _git-bug_bridge_auth + ;; configure) _git-bug_bridge_configure ;; @@ -139,6 +143,51 @@ function _git-bug_bridge { esac } + +function _git-bug_bridge_auth { + local -a commands + + _arguments -C \ + "1: :->cmnds" \ + "*::arg:->args" + + case $state in + cmnds) + commands=( + "add-token:Store a new token" + "rm:Remove a credential." + "show:Display an authentication credential." + ) + _describe "command" commands + ;; + esac + + case "$words[1]" in + add-token) + _git-bug_bridge_auth_add-token + ;; + rm) + _git-bug_bridge_auth_rm + ;; + show) + _git-bug_bridge_auth_show + ;; + esac +} + +function _git-bug_bridge_auth_add-token { + _arguments \ + '(-t --target)'{-t,--target}'[The target of the bridge. Valid values are [github,gitlab,launchpad-preview]]:' +} + +function _git-bug_bridge_auth_rm { + _arguments +} + +function _git-bug_bridge_auth_show { + _arguments +} + function _git-bug_bridge_configure { _arguments \ '(-n --name)'{-n,--name}'[A distinctive name to identify the bridge]:' \ diff --git a/repository/config.go b/repository/config.go index d72e7b4e..4fa5c69b 100644 --- a/repository/config.go +++ b/repository/config.go @@ -38,7 +38,7 @@ type Config interface { RemoveAll(keyPrefix string) error } -func parseTimestamp(s string) (time.Time, error) { +func ParseTimestamp(s string) (time.Time, error) { timestamp, err := strconv.Atoi(s) if err != nil { return time.Time{}, err diff --git a/repository/config_git.go b/repository/config_git.go index 63ca2457..cff82afb 100644 --- a/repository/config_git.go +++ b/repository/config_git.go @@ -116,7 +116,7 @@ func (gc *gitConfig) ReadTimestamp(key string) (time.Time, error) { if err != nil { return time.Time{}, err } - return parseTimestamp(value) + return ParseTimestamp(value) } func (gc *gitConfig) rmSection(keyPrefix string) error { diff --git a/repository/git.go b/repository/git.go index 2b00d1f2..2c72fccd 100644 --- a/repository/git.go +++ b/repository/git.go @@ -15,11 +15,15 @@ import ( "github.com/MichaelMure/git-bug/util/lamport" ) -const createClockFile = "/git-bug/create-clock" -const editClockFile = "/git-bug/edit-clock" +const ( + createClockFile = "/git-bug/create-clock" + editClockFile = "/git-bug/edit-clock" +) -// ErrNotARepo is the error returned when the git repo root wan't be found -var ErrNotARepo = errors.New("not a git repository") +var ( + // ErrNotARepo is the error returned when the git repo root wan't be found + ErrNotARepo = errors.New("not a git repository") +) var _ ClockedRepo = &GitRepo{} diff --git a/repository/repo.go b/repository/repo.go index 7d655bde..e8c67a5e 100644 --- a/repository/repo.go +++ b/repository/repo.go @@ -10,8 +10,10 @@ import ( "github.com/MichaelMure/git-bug/util/lamport" ) -var ErrNoConfigEntry = errors.New("no config entry for the given key") -var ErrMultipleConfigEntry = errors.New("multiple config entry for the given key") +var ( + ErrNoConfigEntry = errors.New("no config entry for the given key") + ErrMultipleConfigEntry = errors.New("multiple config entry for the given key") +) // RepoCommon represent the common function the we want all the repo to implement type RepoCommon interface { |