diff --git a/bridge/bridges.go b/bridge/bridges.go index bfd51cb4187a9573aaa91027a66d707b56db6b8d..2fcb13d326e7e9f750d5fdd972a9e95c5d320759 100644 --- a/bridge/bridges.go +++ b/bridge/bridges.go @@ -3,6 +3,7 @@ package bridge import ( "github.com/MichaelMure/git-bug/bridge/core" _ "github.com/MichaelMure/git-bug/bridge/github" + "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/repository" ) @@ -11,6 +12,14 @@ func Targets() []string { return core.Targets() } +func NewBridge(repo *cache.RepoCache, target string, name string) (*core.Bridge, error) { + return core.NewBridge(repo, target, name) +} + func ConfiguredBridges(repo repository.RepoCommon) ([]string, error) { return core.ConfiguredBridges(repo) } + +func RemoveBridges(repo repository.RepoCommon, fullName string) error { + return core.RemoveBridge(repo, fullName) +} diff --git a/bridge/core/bridge.go b/bridge/core/bridge.go index 0c83e03e7bd019bc9b023564d9eee2924f71cff6..0eb24c6d9f3aec7d645953aaa98f035ab054ad76 100644 --- a/bridge/core/bridge.go +++ b/bridge/core/bridge.go @@ -62,14 +62,14 @@ func NewBridge(repo *cache.RepoCache, target string, name string) (*Bridge, erro } func ConfiguredBridges(repo repository.RepoCommon) ([]string, error) { - configs, err := repo.ReadConfigs("git-bug.") + configs, err := repo.ReadConfigs("git-bug.bridge.") if err != nil { return nil, errors.Wrap(err, "can't read configured bridges") } - re, err := regexp.Compile(`git-bug.([^\.]+\.[^\.]+)`) + re, err := regexp.Compile(`git-bug.bridge.([^\.]+\.[^\.]+)`) if err != nil { - return nil, err + panic(err) } set := make(map[string]interface{}) @@ -95,19 +95,18 @@ func ConfiguredBridges(repo repository.RepoCommon) ([]string, error) { return result, nil } -func (b *Bridge) String() string { - var _type string - if b.impl.Importer() != nil && b.impl.Exporter() != nil { - _type = "import/export" - } else if b.impl.Importer() != nil { - _type = "import" - } else if b.impl.Exporter() != nil { - _type = "export" - } else { - panic("bad bridge impl, neither import nor export") +func RemoveBridge(repo repository.RepoCommon, fullName string) error { + re, err := regexp.Compile(`^[^\.]+\.[^\.]+$`) + if err != nil { + panic(err) + } + + if !re.MatchString(fullName) { + return fmt.Errorf("bad bridge fullname: %s", fullName) } - return fmt.Sprintf("%s.%s: %s", b.impl.Target(), b.Name, _type) + keyPrefix := fmt.Sprintf("git-bug.bridge.%s", fullName) + return repo.RmConfigs(keyPrefix) } func (b *Bridge) Configure() error { @@ -123,7 +122,7 @@ func (b *Bridge) Configure() error { func (b *Bridge) storeConfig(conf Configuration) error { for key, val := range conf { - storeKey := fmt.Sprintf("git-bug.%s.%s.%s", b.impl.Target(), b.Name, key) + storeKey := fmt.Sprintf("git-bug.bridge.%s.%s.%s", b.impl.Target(), b.Name, key) err := b.repo.StoreConfig(storeKey, val) if err != nil { @@ -147,7 +146,7 @@ func (b Bridge) getConfig() (Configuration, error) { } func (b Bridge) loadConfig() (Configuration, error) { - keyPrefix := fmt.Sprintf("git-bug.%s.%s.", b.impl.Target(), b.Name) + keyPrefix := fmt.Sprintf("git-bug.bridge.%s.%s.", b.impl.Target(), b.Name) pairs, err := b.repo.ReadConfigs(keyPrefix) if err != nil { diff --git a/bridge/github/config.go b/bridge/github/config.go index 385630a76f2d8a5f2de8f43f1a4521a886f96d38..b8531dfe61fe3290fdb9a28e5a2274233a91870d 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -214,7 +214,7 @@ func promptURL() (string, string, error) { func splitURL(url string) (string, string, error) { re, err := regexp.Compile(`github\.com\/([^\/]*)\/([^\/]*)`) if err != nil { - return "", "", err + panic(err) } res := re.FindStringSubmatch(url) diff --git a/cache/repo_cache.go b/cache/repo_cache.go index 0f27090931f3751eb985edaf1388a483ae70afb3..4ca191502105887fff80f527900c9edd749cd0f0 100644 --- a/cache/repo_cache.go +++ b/cache/repo_cache.go @@ -75,14 +75,21 @@ func (c *RepoCache) GetUserEmail() (string, error) { return c.repo.GetUserEmail() } +// StoreConfig store a single key/value pair in the config of the repo func (c *RepoCache) StoreConfig(key string, value string) error { return c.repo.StoreConfig(key, value) } +// ReadConfigs read all key/value pair matching the key prefix func (c *RepoCache) ReadConfigs(keyPrefix string) (map[string]string, error) { return c.repo.ReadConfigs(keyPrefix) } +// RmConfigs remove all key/value pair matching the key prefix +func (c *RepoCache) RmConfigs(keyPrefix string) error { + return c.repo.RmConfigs(keyPrefix) +} + func (c *RepoCache) lock() error { lockPath := repoLockFilePath(c.repo) diff --git a/commands/bridge_configure.go b/commands/bridge_configure.go index 564affccc0d930181789b7c4c952ff14ebb7193d..f6aa6bfdc90b19554a96992c4c9602c769f13def 100644 --- a/commands/bridge_configure.go +++ b/commands/bridge_configure.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/MichaelMure/git-bug/bridge" - "github.com/MichaelMure/git-bug/bridge/core" "github.com/MichaelMure/git-bug/cache" "github.com/spf13/cobra" ) @@ -29,7 +28,7 @@ func runBridgeConfigure(cmd *cobra.Command, args []string) error { return err } - b, err := core.NewBridge(backend, target, name) + b, err := bridge.NewBridge(backend, target, name) if err != nil { return err } diff --git a/commands/bridge_rm.go b/commands/bridge_rm.go new file mode 100644 index 0000000000000000000000000000000000000000..acde9da54339ff7cf8a8d97100e889e60f921db8 --- /dev/null +++ b/commands/bridge_rm.go @@ -0,0 +1,33 @@ +package commands + +import ( + "github.com/MichaelMure/git-bug/bridge" + "github.com/MichaelMure/git-bug/cache" + "github.com/spf13/cobra" +) + +func runBridgeRm(cmd *cobra.Command, args []string) error { + backend, err := cache.NewRepoCache(repo) + if err != nil { + return err + } + defer backend.Close() + + err = bridge.RemoveBridges(backend, args[0]) + if err != nil { + return err + } + + return nil +} + +var bridgeRmCmd = &cobra.Command{ + Use: "rm name ", + Short: "Delete a configured bridge", + RunE: runBridgeRm, + Args: cobra.ExactArgs(1), +} + +func init() { + bridgeCmd.AddCommand(bridgeRmCmd) +} diff --git a/doc/man/git-bug-bridge-rm.1 b/doc/man/git-bug-bridge-rm.1 new file mode 100644 index 0000000000000000000000000000000000000000..f32e8d40a789255f8185e1c2559ca70ebc5aeea3 --- /dev/null +++ b/doc/man/git-bug-bridge-rm.1 @@ -0,0 +1,29 @@ +.TH "GIT-BUG" "1" "Sep 2018" "Generated from git-bug's source code" "" +.nh +.ad l + + +.SH NAME +.PP +git\-bug\-bridge\-rm \- Delete a configured bridge + + +.SH SYNOPSIS +.PP +\fBgit\-bug bridge rm name [flags]\fP + + +.SH DESCRIPTION +.PP +Delete a configured bridge + + +.SH OPTIONS +.PP +\fB\-h\fP, \fB\-\-help\fP[=false] + help for rm + + +.SH SEE ALSO +.PP +\fBgit\-bug\-bridge(1)\fP diff --git a/doc/man/git-bug-bridge.1 b/doc/man/git-bug-bridge.1 index c5720413a83c7230d8a1520eaf65c27b8a536291..3e7b39fd583bee74d87ebf1c3eae82ae4ebdf6ac 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(1)\fP, \fBgit\-bug\-bridge\-configure(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 ce4f6d6d564fdba921915c49a2022d1690a77c17..7dd6c73d949a76becab1c890dd886422e4dbbe48 100644 --- a/doc/md/git-bug_bridge.md +++ b/doc/md/git-bug_bridge.md @@ -20,4 +20,5 @@ git-bug bridge [flags] * [git-bug](git-bug.md) - A bug tracker embedded in Git * [git-bug bridge configure](git-bug_bridge_configure.md) - Configure a new bridge +* [git-bug bridge rm](git-bug_bridge_rm.md) - Delete a configured bridge diff --git a/doc/md/git-bug_bridge_rm.md b/doc/md/git-bug_bridge_rm.md new file mode 100644 index 0000000000000000000000000000000000000000..15b20749134f129e4f7f821713d378a0dcea507a --- /dev/null +++ b/doc/md/git-bug_bridge_rm.md @@ -0,0 +1,22 @@ +## git-bug bridge rm + +Delete a configured bridge + +### Synopsis + +Delete a configured bridge + +``` +git-bug bridge rm name [flags] +``` + +### Options + +``` + -h, --help help for rm +``` + +### SEE ALSO + +* [git-bug bridge](git-bug_bridge.md) - Configure and use bridges to other bug trackers + diff --git a/misc/bash_completion/git-bug b/misc/bash_completion/git-bug index 88f2e8711c6df40ddd139378bf2f65da4d5e7022..0f9d3f01cdb1e472ca01e9b0f0ff354ec75fb74e 100644 --- a/misc/bash_completion/git-bug +++ b/misc/bash_completion/git-bug @@ -297,6 +297,26 @@ _git-bug_bridge_configure() noun_aliases=() } +_git-bug_bridge_rm() +{ + last_command="git-bug_bridge_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() { last_command="git-bug_bridge" @@ -305,6 +325,7 @@ _git-bug_bridge() commands=() commands+=("configure") + commands+=("rm") flags=() two_word_flags=() diff --git a/misc/zsh_completion/git-bug b/misc/zsh_completion/git-bug index 78f835cee8b256c1b33c8758aa6761dce7bbe869..15b572be3be8fad586b1daa0c607338ac3b4b05b 100644 --- a/misc/zsh_completion/git-bug +++ b/misc/zsh_completion/git-bug @@ -17,8 +17,11 @@ case $state in ;; level2) case $words[2] in + title) + _arguments '2: :(edit)' + ;; bridge) - _arguments '2: :(configure)' + _arguments '2: :(configure rm)' ;; comment) _arguments '2: :(add)' @@ -29,9 +32,6 @@ case $state in status) _arguments '2: :(close open)' ;; - title) - _arguments '2: :(edit)' - ;; *) _arguments '*: :_files' ;; diff --git a/repository/git.go b/repository/git.go index 51c4f46bdfcbc821b28db26f4ddb3c912a2bbe3b..af251aa26b7031ca94c9edbb8cafcedab7481f1d 100644 --- a/repository/git.go +++ b/repository/git.go @@ -170,8 +170,14 @@ func (repo *GitRepo) StoreConfig(key string, value string) error { func (repo *GitRepo) ReadConfigs(keyPrefix string) (map[string]string, error) { stdout, err := repo.runGitCommand("config", "--get-regexp", keyPrefix) + // / \ + // / ! \ + // ------- + // + // There can be a legitimate error here, but I see no portable way to + // distinguish them from the git error that say "no matching value exist" if err != nil { - return nil, err + return nil, nil } lines := strings.Split(stdout, "\n") @@ -194,6 +200,13 @@ func (repo *GitRepo) ReadConfigs(keyPrefix string) (map[string]string, error) { return result, nil } +// RmConfigs remove all key/value pair matching the key prefix +func (repo *GitRepo) RmConfigs(keyPrefix string) error { + _, err := repo.runGitCommand("config", "--remove-section", keyPrefix) + + return err +} + // FetchRefs fetch git refs from a remote func (repo *GitRepo) FetchRefs(remote, refSpec string) (string, error) { stdout, err := repo.runGitCommand("fetch", remote, refSpec) diff --git a/repository/mock_repo.go b/repository/mock_repo.go index 2389a8e0014feae171115740dba9d894dcb1311c..74de8f573923c2ea5edd82f5309d5f89d3303cff 100644 --- a/repository/mock_repo.go +++ b/repository/mock_repo.go @@ -73,6 +73,15 @@ func (r *mockRepoForTest) ReadConfigs(keyPrefix string) (map[string]string, erro return result, nil } +func (r *mockRepoForTest) RmConfigs(keyPrefix string) error { + for key := range r.config { + if strings.HasPrefix(key, keyPrefix) { + delete(r.config, key) + } + } + return nil +} + // PushRefs push git refs to a remote func (r *mockRepoForTest) PushRefs(remote string, refSpec string) (string, error) { return "", nil diff --git a/repository/repo.go b/repository/repo.go index c029a145af52694ca8faf83da1d702c68b55be47..d0004c8bbf3efa5dfe99af532e4f0a871f7054cf 100644 --- a/repository/repo.go +++ b/repository/repo.go @@ -28,6 +28,9 @@ type RepoCommon interface { // ReadConfigs read all key/value pair matching the key prefix ReadConfigs(keyPrefix string) (map[string]string, error) + + // RmConfigs remove all key/value pair matching the key prefix + RmConfigs(keyPrefix string) error } // Repo represents a source code repository.