1package commands
2
3import (
4 "bufio"
5 "fmt"
6 "os"
7 "strconv"
8 "strings"
9 "syscall"
10
11 "github.com/spf13/cobra"
12 "golang.org/x/crypto/ssh/terminal"
13
14 "github.com/MichaelMure/git-bug/bridge"
15 "github.com/MichaelMure/git-bug/bridge/core"
16 "github.com/MichaelMure/git-bug/cache"
17 "github.com/MichaelMure/git-bug/repository"
18 "github.com/MichaelMure/git-bug/util/interrupt"
19)
20
21const (
22 defaultName = "default"
23)
24
25var (
26 bridgeConfigureName string
27 bridgeConfigureTarget string
28 bridgeParams core.BridgeParams
29)
30
31func runBridgeConfigure(cmd *cobra.Command, args []string) error {
32 backend, err := cache.NewRepoCache(repo)
33 if err != nil {
34 return err
35 }
36 defer backend.Close()
37 interrupt.RegisterCleaner(backend.Close)
38
39 termState, err := terminal.GetState(int(syscall.Stdin))
40 if err != nil {
41 return err
42 }
43
44 interrupt.RegisterCleaner(func() error {
45 return terminal.Restore(int(syscall.Stdin), termState)
46 })
47
48 if bridgeConfigureTarget == "" {
49 bridgeConfigureTarget, err = promptTarget()
50 if err != nil {
51 return err
52 }
53 }
54
55 if bridgeConfigureName == "" {
56 bridgeConfigureName, err = promptName(repo)
57 if err != nil {
58 return err
59 }
60 }
61
62 b, err := bridge.NewBridge(backend, bridgeConfigureTarget, bridgeConfigureName)
63 if err != nil {
64 return err
65 }
66
67 err = b.Configure(bridgeParams)
68 if err != nil {
69 return err
70 }
71
72 fmt.Printf("Successfully configured bridge: %s\n", bridgeConfigureName)
73 return nil
74}
75
76func promptTarget() (string, error) {
77 targets := bridge.Targets()
78
79 for {
80 for i, target := range targets {
81 fmt.Printf("[%d]: %s\n", i+1, target)
82 }
83 fmt.Printf("target: ")
84
85 line, err := bufio.NewReader(os.Stdin).ReadString('\n')
86
87 if err != nil {
88 return "", err
89 }
90
91 line = strings.TrimRight(line, "\n")
92
93 index, err := strconv.Atoi(line)
94 if err != nil || index <= 0 || index > len(targets) {
95 fmt.Println("invalid input")
96 continue
97 }
98
99 return targets[index-1], nil
100 }
101}
102
103func promptName(repo repository.RepoCommon) (string, error) {
104 for {
105 fmt.Printf("name [%s]: ", defaultName)
106
107 line, err := bufio.NewReader(os.Stdin).ReadString('\n')
108 if err != nil {
109 return "", err
110 }
111
112 line = strings.TrimRight(line, "\n")
113
114 name := line
115 if name == "" {
116 name = defaultName
117 }
118
119 if !core.BridgeExist(repo, name) {
120 return name, nil
121 }
122
123 fmt.Println("a bridge with the same name already exist")
124 }
125}
126
127var bridgeConfigureCmd = &cobra.Command{
128 Use: "configure",
129 Short: "Configure a new bridge.",
130 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.
131 Repository configuration can be made by passing either the --url flag or the --project and --owner flags. If the three flags are provided git-bug will use --project and --owner flags.
132 Token configuration can be directly passed with the --token flag or in the terminal prompt. If you don't already have one you can use the interactive procedure to generate one.`,
133 Example: `# Interactive example
134[1]: github
135[2]: launchpad-preview
136target: 1
137name [default]: default
138
139Detected projects:
140[1]: github.com/a-hilaly/git-bug
141[2]: github.com/MichaelMure/git-bug
142
143[0]: Another project
144
145Select option: 1
146
147[1]: user provided token
148[2]: interactive token creation
149Select option: 1
150
151You can generate a new token by visiting https://github.com/settings/tokens.
152Choose 'Generate new token' and set the necessary access scope for your repository.
153
154The access scope depend on the type of repository.
155Public:
156 - 'public_repo': to be able to read public repositories
157Private:
158 - 'repo' : to be able to read private repositories
159
160Enter token: 87cf5c03b64029f18ea5f9ca5679daa08ccbd700
161Successfully configured bridge: default
162
163# For GitHub
164git bug bridge configure \
165 --name=default \
166 --target=github \
167 --owner=$(OWNER) \
168 --project=$(PROJECT) \
169 --token=$(TOKEN)
170
171# For Launchpad
172git bug bridge configure \
173 --name=default \
174 --target=launchpad-preview \
175 --url=https://bugs.launchpad.net/ubuntu/
176
177# For Gitlab
178git bug bridge configure \
179 --name=default \
180 --target=github \
181 --url=https://github.com/michaelmure/git-bug \
182 --token=$(TOKEN)`,
183 PreRunE: loadRepo,
184 RunE: runBridgeConfigure,
185}
186
187func init() {
188 bridgeCmd.AddCommand(bridgeConfigureCmd)
189 bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureName, "name", "n", "", "A distinctive name to identify the bridge")
190 bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureTarget, "target", "t", "",
191 fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
192 bridgeConfigureCmd.Flags().StringVarP(&bridgeParams.URL, "url", "u", "", "The URL of the target repository")
193 bridgeConfigureCmd.Flags().StringVarP(&bridgeParams.Owner, "owner", "o", "", "The owner of the target repository")
194 bridgeConfigureCmd.Flags().StringVarP(&bridgeParams.Token, "token", "T", "", "The authentication token for the API")
195 bridgeConfigureCmd.Flags().StringVarP(&bridgeParams.Project, "project", "p", "", "The name of the target repository")
196 bridgeConfigureCmd.Flags().SortFlags = false
197}