aboutsummaryrefslogtreecommitdiffstats
path: root/commands/bridge/bridge_new.go
diff options
context:
space:
mode:
Diffstat (limited to 'commands/bridge/bridge_new.go')
-rw-r--r--commands/bridge/bridge_new.go234
1 files changed, 234 insertions, 0 deletions
diff --git a/commands/bridge/bridge_new.go b/commands/bridge/bridge_new.go
new file mode 100644
index 00000000..4cfc903d
--- /dev/null
+++ b/commands/bridge/bridge_new.go
@@ -0,0 +1,234 @@
+package bridgecmd
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/bridge"
+ "github.com/MichaelMure/git-bug/bridge/core"
+ "github.com/MichaelMure/git-bug/bridge/core/auth"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+ "github.com/MichaelMure/git-bug/repository"
+)
+
+type bridgeNewOptions struct {
+ name string
+ target string
+ params core.BridgeParams
+ token string
+ tokenStdin bool
+ nonInteractive bool
+}
+
+func newBridgeNewCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := bridgeNewOptions{}
+
+ cmd := &cobra.Command{
+ Use: "new",
+ Short: "Configure a new bridge",
+ Long: ` Configure a new bridge by passing flags or/and using interactive terminal prompts. You can avoid all the terminal prompts by passing all the necessary flags to configure your bridge.`,
+ Example: `# Interactive example
+[1]: github
+[2]: gitlab
+[3]: jira
+[4]: launchpad-preview
+
+target: 1
+name [default]: default
+
+Detected projects:
+[1]: github.com/a-hilaly/git-bug
+[2]: github.com/MichaelMure/git-bug
+
+[0]: Another project
+
+Select option: 1
+
+[1]: user provided token
+[2]: interactive token creation
+Select option: 1
+
+You can generate a new token by visiting https://github.com/settings/tokens.
+Choose 'Generate new token' and set the necessary access scope for your repository.
+
+The access scope depend on the type of repository.
+Public:
+ - 'public_repo': to be able to read public repositories
+Private:
+ - 'repo' : to be able to read private repositories
+
+Enter token: 87cf5c03b64029f18ea5f9ca5679daa08ccbd700
+Successfully configured bridge: default
+
+# For GitHub
+git bug bridge new \
+ --name=default \
+ --target=github \
+ --owner=$(OWNER) \
+ --project=$(PROJECT) \
+ --token=$(TOKEN)
+
+# For Launchpad
+git bug bridge new \
+ --name=default \
+ --target=launchpad-preview \
+ --url=https://bugs.launchpad.net/ubuntu/
+
+# For Gitlab
+git bug bridge new \
+ --name=default \
+ --target=github \
+ --url=https://github.com/michaelmure/git-bug \
+ --token=$(TOKEN)`,
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBridgeNew(env, options)
+ }),
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.StringVarP(&options.name, "name", "n", "", "A distinctive name to identify the bridge")
+ flags.StringVarP(&options.target, "target", "t", "",
+ fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
+ cmd.RegisterFlagCompletionFunc("target", completion.From(bridge.Targets()))
+ flags.StringVarP(&options.params.URL, "url", "u", "", "The URL of the remote repository")
+ flags.StringVarP(&options.params.BaseURL, "base-url", "b", "", "The base URL of your remote issue tracker")
+ flags.StringVarP(&options.params.Login, "login", "l", "", "The login on your remote issue tracker")
+ flags.StringVarP(&options.params.CredPrefix, "credential", "c", "", "The identifier or prefix of an already known credential for your remote issue tracker (see \"git-bug bridge auth\")")
+ flags.StringVar(&options.token, "token", "", "A raw authentication token for the remote issue tracker")
+ flags.BoolVar(&options.tokenStdin, "token-stdin", false, "Will read the token from stdin and ignore --token")
+ flags.StringVarP(&options.params.Owner, "owner", "o", "", "The owner of the remote repository")
+ flags.StringVarP(&options.params.Project, "project", "p", "", "The name of the remote repository")
+ flags.BoolVar(&options.nonInteractive, "non-interactive", false, "Do not ask for user input")
+
+ return cmd
+}
+
+func runBridgeNew(env *execenv.Env, opts bridgeNewOptions) error {
+ var err error
+
+ if (opts.tokenStdin || opts.token != "" || opts.params.CredPrefix != "") &&
+ (opts.name == "" || opts.target == "") {
+ return fmt.Errorf("you must provide a bridge name and target to configure a bridge with a credential")
+ }
+
+ // early fail
+ if opts.params.CredPrefix != "" {
+ if _, err := auth.LoadWithPrefix(env.Repo, opts.params.CredPrefix); err != nil {
+ return err
+ }
+ }
+
+ switch {
+ case opts.tokenStdin:
+ reader := bufio.NewReader(os.Stdin)
+ token, err := reader.ReadString('\n')
+ if err != nil {
+ return fmt.Errorf("reading from stdin: %v", err)
+ }
+ opts.params.TokenRaw = strings.TrimSpace(token)
+ case opts.token != "":
+ opts.params.TokenRaw = opts.token
+ }
+
+ if !opts.nonInteractive && opts.target == "" {
+ opts.target, err = promptTarget()
+ if err != nil {
+ return err
+ }
+ }
+
+ if !opts.nonInteractive && opts.name == "" {
+ opts.name, err = promptName(env.Repo)
+ if err != nil {
+ return err
+ }
+ }
+
+ b, err := bridge.NewBridge(env.Backend, opts.target, opts.name)
+ if err != nil {
+ return err
+ }
+
+ err = b.Configure(opts.params, !opts.nonInteractive)
+ if err != nil {
+ return err
+ }
+
+ env.Out.Printf("Successfully configured bridge: %s\n", opts.name)
+ return nil
+}
+
+func promptTarget() (string, error) {
+ // TODO: use the reusable prompt from the input package
+ targets := bridge.Targets()
+
+ for {
+ for i, target := range targets {
+ fmt.Printf("[%d]: %s\n", i+1, target)
+ }
+ fmt.Printf("target: ")
+
+ line, err := bufio.NewReader(os.Stdin).ReadString('\n')
+
+ if err != nil {
+ return "", err
+ }
+
+ line = strings.TrimSpace(line)
+
+ index, err := strconv.Atoi(line)
+ if err != nil || index <= 0 || index > len(targets) {
+ fmt.Println("invalid input")
+ continue
+ }
+
+ return targets[index-1], nil
+ }
+}
+
+func promptName(repo repository.RepoConfig) (string, error) {
+ // TODO: use the reusable prompt from the input package
+ const defaultName = "default"
+
+ defaultExist := core.BridgeExist(repo, defaultName)
+
+ for {
+ if defaultExist {
+ fmt.Printf("name: ")
+ } else {
+ fmt.Printf("name [%s]: ", defaultName)
+ }
+
+ line, err := bufio.NewReader(os.Stdin).ReadString('\n')
+ if err != nil {
+ return "", err
+ }
+
+ line = strings.TrimSpace(line)
+
+ name := line
+ if defaultExist && name == "" {
+ continue
+ }
+
+ if name == "" {
+ name = defaultName
+ }
+
+ if !core.BridgeExist(repo, name) {
+ return name, nil
+ }
+
+ fmt.Println("a bridge with the same name already exist")
+ }
+}