package commands
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/cache"
"github.com/MichaelMure/git-bug/repository"
"github.com/MichaelMure/git-bug/util/interrupt"
)
const (
defaultName = "default"
)
var (
bridgeConfigureName string
bridgeConfigureTarget string
bridgeConfigureParams core.BridgeParams
bridgeConfigureToken string
bridgeConfigureTokenStdin bool
)
func runBridgeConfigure(cmd *cobra.Command, args []string) error {
backend, err := cache.NewRepoCache(repo)
if err != nil {
return err
}
defer backend.Close()
interrupt.RegisterCleaner(backend.Close)
if (bridgeConfigureTokenStdin || bridgeConfigureToken != "" || bridgeConfigureParams.CredPrefix != "") &&
(bridgeConfigureName == "" || bridgeConfigureTarget == "") {
return fmt.Errorf("you must provide a bridge name and target to configure a bridge with a credential")
}
// early fail
if bridgeConfigureParams.CredPrefix != "" {
if _, err := auth.LoadWithPrefix(repo, bridgeConfigureParams.CredPrefix); err != nil {
return err
}
}
switch {
case bridgeConfigureTokenStdin:
reader := bufio.NewReader(os.Stdin)
token, err := reader.ReadString('\n')
if err != nil {
return fmt.Errorf("reading from stdin: %v", err)
}
bridgeConfigureParams.TokenRaw = strings.TrimSpace(token)
case bridgeConfigureToken != "":
bridgeConfigureParams.TokenRaw = bridgeConfigureToken
}
if bridgeConfigureTarget == "" {
bridgeConfigureTarget, err = promptTarget()
if err != nil {
return err
}
}
if bridgeConfigureName == "" {
bridgeConfigureName, err = promptName(repo)
if err != nil {
return err
}
}
b, err := bridge.NewBridge(backend, bridgeConfigureTarget, bridgeConfigureName)
if err != nil {
return err
}
err = b.Configure(bridgeConfigureParams)
if err != nil {
return err
}
fmt.Printf("Successfully configured bridge: %s\n", bridgeConfigureName)
return nil
}
func promptTarget() (string, error) {
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) {
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")
}
}
var bridgeConfigureCmd = &cobra.Command{
Use: "configure",
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 configure \
--name=default \
--target=github \
--owner=$(OWNER) \
--project=$(PROJECT) \
--token=$(TOKEN)
# For Launchpad
git bug bridge configure \
--name=default \
--target=launchpad-preview \
--url=https://bugs.launchpad.net/ubuntu/
# For Gitlab
git bug bridge configure \
--name=default \
--target=github \
--url=https://github.com/michaelmure/git-bug \
--token=$(TOKEN)`,
PreRunE: loadRepo,
RunE: runBridgeConfigure,
}
func init() {
bridgeCmd.AddCommand(bridgeConfigureCmd)
bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureName, "name", "n", "", "A distinctive name to identify the bridge")
bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureTarget, "target", "t", "",
fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.URL, "url", "u", "", "The URL of the remote repository")
bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.BaseURL, "base-url", "b", "", "The base URL of your remote issue tracker")
bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.Login, "login", "l", "", "The login on your remote issue tracker")
bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.CredPrefix, "credential", "c", "", "The identifier or prefix of an already known credential for your remote issue tracker (see \"git-bug bridge auth\")")
bridgeConfigureCmd.Flags().StringVar(&bridgeConfigureToken, "token", "", "A raw authentication token for the remote issue tracker")
bridgeConfigureCmd.Flags().BoolVar(&bridgeConfigureTokenStdin, "token-stdin", false, "Will read the token from stdin and ignore --token")
bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.Owner, "owner", "o", "", "The owner of the remote repository")
bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.Project, "project", "p", "", "The name of the remote repository")
bridgeConfigureCmd.Flags().SortFlags = false
}