1package main
2
3import (
4 "fmt"
5 "os"
6 "path"
7 "path/filepath"
8 "strings"
9 "time"
10
11 "github.com/pkg/errors"
12 "github.com/spf13/cobra/doc"
13
14 "github.com/MichaelMure/git-bug/bridge"
15 "github.com/MichaelMure/git-bug/commands"
16)
17
18const bridgeExampleFilePath = "commands/bridge_configure_doc.go"
19
20func main() {
21 fmt.Println("Generating documentation ...")
22
23 tasks := map[string]func() error{
24 "BridgeConfig": genBridgeConfig,
25 "ManPage": genManPage,
26 "Markdown": genMarkdown,
27 }
28
29 // Due to concurrency issues in cobra, the following can't be concurrent :(
30
31 // var wg sync.WaitGroup
32 for name, f := range tasks {
33 // wg.Add(1)
34 // go func(name string, f func() error) {
35 // defer wg.Done()
36 err := f()
37 if err != nil {
38 fmt.Printf(" - %s: %v\n", name, err)
39 return
40 }
41 fmt.Printf(" - %s: ok\n", name)
42 // }(name, f)
43 }
44
45 // wg.Wait()
46}
47
48// If a flag is not listed in flagInfos, docs will generate the default values for the flag:
49// flagName = lowercase name
50// defaultVal = $({uppercase name})
51// paramConflicts = none
52var flagInfos = map[string]BridgeFlagInfo{
53 "BaseURL": {
54 flagName: "base-url",
55 defaultVal: "$(BASE_URL)",
56 paramConflicts: []string{},
57 },
58 "CredPrefix": {
59 flagName: "credential",
60 defaultVal: "$(CREDENTIALS)",
61 paramConflicts: []string{
62 "TokenRaw",
63 },
64 },
65 "TokenRaw": {
66 flagName: "token",
67 defaultVal: "$(TOKEN)",
68 paramConflicts: []string{},
69 },
70}
71
72type BridgeFlagInfo struct {
73 flagName string
74 defaultVal string
75 paramConflicts []string
76}
77
78var bridgeUrls = map[string]string{
79 "github": "https://github.com/MichaelMure/git-bug",
80 "gitlab": "https://gitlab.com/gitlab-org/gitlab",
81 "launchpad-preview": "https://bugs.launchpad.net/ubuntu/",
82 // TODO: Insert URL for Jira Project
83}
84
85// genBridgeConfig generates the bridge configuration documentation on go generate
86// Documentation is stored in commands/bridge_configure_doc.go
87func genBridgeConfig() error {
88 var exampleText strings.Builder
89 exampleText.WriteString("`")
90 exampleText.WriteString(`# Interactive example
91[1]: github
92[2]: gitlab
93[3]: jira
94[4]: launchpad-preview
95
96target: 1
97name [default]: default
98
99Detected projects:
100[1]: github.com/a-hilaly/git-bug
101[2]: github.com/MichaelMure/git-bug
102
103[0]: Another project
104
105Select option: 1
106
107[1]: user provided token
108[2]: interactive token creation
109Select option: 1
110
111You can generate a new token by visiting https://github.com/settings/tokens.
112Choose 'Generate new token' and set the necessary access scope for your repository.
113
114The access scope depend on the type of repository.
115Public:
116 - 'public_repo': to be able to read public repositories
117Private:
118 - 'repo' : to be able to read private repositories
119
120Enter token: 87cf5c03b64029f18ea5f9ca5679daa08ccbd700
121Successfully configured bridge: default
122
123`)
124 targets := bridge.Targets()
125 for i, b := range targets {
126 if i != 0 {
127 exampleText.WriteString("\n\n")
128 }
129 exampleText.WriteString("# For ")
130 exampleText.WriteString(strings.Title(b))
131 exampleText.WriteString("\ngit bug bridge configure \\\n")
132
133 exampleText.WriteString(" --target=")
134 exampleText.WriteString(strings.ToLower(b))
135 exampleText.WriteString(" \\\n")
136
137 exampleText.WriteString(" --url=")
138 exampleText.WriteString(bridgeUrls[b])
139 exampleText.WriteString(" \\\n")
140
141 params, err := bridge.ValidParams(b)
142 if err != nil {
143 return errors.Wrap(err, "bridge parameters")
144 }
145
146 for _, param := range params {
147 if param == "URL" || param == "BaseURL" {
148 continue
149 }
150
151 paramString := formatParam(param, params)
152 if paramString == "" {
153 continue
154 }
155
156 exampleText.WriteString(paramString)
157 }
158 }
159 exampleText.WriteString("`")
160
161 _ = os.Remove(bridgeExampleFilePath)
162
163 f, err := os.Create(bridgeExampleFilePath)
164 if err != nil {
165 return err
166 }
167 defer f.Close()
168
169 _, err = f.WriteString(`// Code generated by doc/gen_docs.go; DO NOT EDIT.
170
171package commands
172
173var bridgeConfigureExample =`)
174 if err != nil {
175 return err
176 }
177 _, err = f.WriteString(exampleText.String())
178 if err != nil {
179 return err
180 }
181
182 return nil
183}
184
185// formatParam formats a parameter into a flag example in the command line
186func formatParam(param string, params []string) string {
187 paramString := " --"
188 if flagInfo, ok := flagInfos[param]; ok {
189 if checkParamConflicts(flagInfo.paramConflicts, params) {
190 return ""
191 }
192
193 paramString += flagInfo.flagName + "=" + flagInfo.defaultVal
194 } else {
195 paramString += strings.ToLower(param) + "=$(" + strings.ToUpper(param) + ")"
196 }
197
198 paramString += " \\\n"
199 return paramString
200}
201
202// checkParamConflicts checks the parameter conflicts against the list of present parameters
203// If a conflict is found, it returns true. Otherwise, it returns false
204func checkParamConflicts(paramConflicts []string, params []string) bool {
205 if len(paramConflicts) == 0 {
206 return false
207 }
208
209 for p := range params {
210 for conflict := range paramConflicts {
211 if p == conflict {
212 return true
213 }
214 }
215 }
216 return false
217}
218
219func genManPage() error {
220 cwd, _ := os.Getwd()
221 dir := path.Join(cwd, "doc", "man")
222
223 date := time.Date(2019, 4, 1, 12, 0, 0, 0, time.UTC)
224
225 header := &doc.GenManHeader{
226 Title: "GIT-BUG",
227 Section: "1",
228 Date: &date,
229 Source: "Generated from git-bug's source code",
230 }
231
232 files, err := filepath.Glob(dir + "/*.1")
233 if err != nil {
234 return err
235 }
236 for _, f := range files {
237 if err := os.Remove(f); err != nil {
238 return err
239 }
240 }
241
242 return doc.GenManTree(commands.NewRootCommand(), header, dir)
243}
244
245func genMarkdown() error {
246 cwd, _ := os.Getwd()
247 dir := path.Join(cwd, "doc", "md")
248
249 files, err := filepath.Glob(dir + "/*.md")
250 if err != nil {
251 return err
252 }
253 for _, f := range files {
254 if err := os.Remove(f); err != nil {
255 return err
256 }
257 }
258
259 return doc.GenMarkdownTree(commands.NewRootCommand(), dir)
260}