bridge_configure.go

  1package commands
  2
  3import (
  4	"bufio"
  5	"fmt"
  6	"os"
  7	"strconv"
  8	"strings"
  9
 10	"github.com/spf13/cobra"
 11
 12	"github.com/MichaelMure/git-bug/bridge"
 13	"github.com/MichaelMure/git-bug/bridge/core"
 14	"github.com/MichaelMure/git-bug/bridge/core/auth"
 15	"github.com/MichaelMure/git-bug/repository"
 16)
 17
 18type bridgeConfigureOptions struct {
 19	name       string
 20	target     string
 21	params     core.BridgeParams
 22	token      string
 23	tokenStdin bool
 24}
 25
 26func newBridgeConfigureCommand() *cobra.Command {
 27	env := newEnv()
 28	options := bridgeConfigureOptions{}
 29
 30	cmd := &cobra.Command{
 31		Use:   "configure",
 32		Short: "Configure a new bridge.",
 33		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.`,
 34		Example:  bridgeConfigureExample,
 35		PreRunE:  loadBackend(env),
 36		PostRunE: closeBackend(env),
 37		RunE: func(cmd *cobra.Command, args []string) error {
 38			return runBridgeConfigure(env, options)
 39		},
 40	}
 41
 42	flags := cmd.Flags()
 43	flags.SortFlags = false
 44
 45	flags.StringVarP(&options.name, "name", "n", "", "A distinctive name to identify the bridge")
 46	flags.StringVarP(&options.target, "target", "t", "",
 47		fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
 48	flags.StringVarP(&options.params.URL, "url", "u", "", "The URL of the remote repository")
 49	flags.StringVarP(&options.params.BaseURL, "base-url", "b", "", "The base URL of your remote issue tracker")
 50	flags.StringVarP(&options.params.Login, "login", "l", "", "The login on your remote issue tracker")
 51	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\")")
 52	flags.StringVar(&options.token, "token", "", "A raw authentication token for the remote issue tracker")
 53	flags.BoolVar(&options.tokenStdin, "token-stdin", false, "Will read the token from stdin and ignore --token")
 54	flags.StringVarP(&options.params.Owner, "owner", "o", "", "The owner of the remote repository")
 55	flags.StringVarP(&options.params.Project, "project", "p", "", "The name of the remote repository")
 56
 57	return cmd
 58}
 59
 60func runBridgeConfigure(env *Env, opts bridgeConfigureOptions) error {
 61	var err error
 62
 63	if (opts.tokenStdin || opts.token != "" || opts.params.CredPrefix != "") &&
 64		(opts.name == "" || opts.target == "") {
 65		return fmt.Errorf("you must provide a bridge name and target to configure a bridge with a credential")
 66	}
 67
 68	// early fail
 69	if opts.params.CredPrefix != "" {
 70		if _, err := auth.LoadWithPrefix(env.repo, opts.params.CredPrefix); err != nil {
 71			return err
 72		}
 73	}
 74
 75	switch {
 76	case opts.tokenStdin:
 77		reader := bufio.NewReader(os.Stdin)
 78		token, err := reader.ReadString('\n')
 79		if err != nil {
 80			return fmt.Errorf("reading from stdin: %v", err)
 81		}
 82		opts.params.TokenRaw = strings.TrimSpace(token)
 83	case opts.token != "":
 84		opts.params.TokenRaw = opts.token
 85	}
 86
 87	if opts.target == "" {
 88		opts.target, err = promptTarget()
 89		if err != nil {
 90			return err
 91		}
 92	}
 93
 94	if opts.name == "" {
 95		opts.name, err = promptName(env.repo)
 96		if err != nil {
 97			return err
 98		}
 99	}
100
101	b, err := bridge.NewBridge(env.backend, opts.target, opts.name)
102	if err != nil {
103		return err
104	}
105
106	err = b.Configure(opts.params)
107	if err != nil {
108		return err
109	}
110
111	env.out.Printf("Successfully configured bridge: %s\n", opts.name)
112	return nil
113}
114
115func promptTarget() (string, error) {
116	// TODO: use the reusable prompt from the input package
117	targets := bridge.Targets()
118
119	for {
120		for i, target := range targets {
121			fmt.Printf("[%d]: %s\n", i+1, target)
122		}
123		fmt.Printf("target: ")
124
125		line, err := bufio.NewReader(os.Stdin).ReadString('\n')
126
127		if err != nil {
128			return "", err
129		}
130
131		line = strings.TrimSpace(line)
132
133		index, err := strconv.Atoi(line)
134		if err != nil || index <= 0 || index > len(targets) {
135			fmt.Println("invalid input")
136			continue
137		}
138
139		return targets[index-1], nil
140	}
141}
142
143func promptName(repo repository.RepoConfig) (string, error) {
144	// TODO: use the reusable prompt from the input package
145	const defaultName = "default"
146
147	defaultExist := core.BridgeExist(repo, defaultName)
148
149	for {
150		if defaultExist {
151			fmt.Printf("name: ")
152		} else {
153			fmt.Printf("name [%s]: ", defaultName)
154		}
155
156		line, err := bufio.NewReader(os.Stdin).ReadString('\n')
157		if err != nil {
158			return "", err
159		}
160
161		line = strings.TrimSpace(line)
162
163		name := line
164		if defaultExist && name == "" {
165			continue
166		}
167
168		if name == "" {
169			name = defaultName
170		}
171
172		if !core.BridgeExist(repo, name) {
173			return name, nil
174		}
175
176		fmt.Println("a bridge with the same name already exist")
177	}
178}