aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bridge/bridges.go12
-rw-r--r--bridge/core/bridge.go6
-rw-r--r--bridge/core/token.go182
-rw-r--r--bridge/github/github.go4
-rw-r--r--bridge/gitlab/gitlab.go4
-rw-r--r--bridge/launchpad/launchpad.go4
-rw-r--r--commands/bridge_auth.go53
-rw-r--r--commands/bridge_auth_add.go74
-rw-r--r--commands/bridge_auth_rm.go36
-rw-r--r--commands/bridge_auth_show.go37
-rw-r--r--doc/man/git-bug-bridge-auth-add-token.133
-rw-r--r--doc/man/git-bug-bridge-auth-rm.129
-rw-r--r--doc/man/git-bug-bridge-auth-show.129
-rw-r--r--doc/man/git-bug-bridge-auth.129
-rw-r--r--doc/man/git-bug-bridge.12
-rw-r--r--doc/md/git-bug_bridge.md1
-rw-r--r--doc/md/git-bug_bridge_auth.md25
-rw-r--r--doc/md/git-bug_bridge_auth_add-token.md23
-rw-r--r--doc/md/git-bug_bridge_auth_rm.md22
-rw-r--r--doc/md/git-bug_bridge_auth_show.md22
-rw-r--r--entity/id.go18
-rw-r--r--misc/bash_completion/git-bug88
-rw-r--r--misc/powershell_completion/git-bug18
-rw-r--r--misc/zsh_completion/git-bug49
-rw-r--r--repository/config.go2
-rw-r--r--repository/config_git.go2
-rw-r--r--repository/git.go12
-rw-r--r--repository/repo.go6
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 {