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 params, err := bridge.ValidParams(b)
138 if err != nil {
139 return errors.Wrap(err, "bridge parameters")
140 }
141
142 for _, param := range params {
143 if param == "BaseURL" {
144 continue
145 }
146
147 paramString := formatParam(param, params, b)
148 if paramString == "" {
149 continue
150 }
151
152 exampleText.WriteString(paramString)
153 }
154 }
155 exampleText.WriteString("`")
156
157 _ = os.Remove(bridgeExampleFilePath)
158
159 f, err := os.Create(bridgeExampleFilePath)
160 if err != nil {
161 return err
162 }
163 defer f.Close()
164
165 _, err = f.WriteString(`// Code generated by doc/gen_docs.go; DO NOT EDIT.
166
167package commands
168
169var bridgeConfigureExample =`)
170 if err != nil {
171 return err
172 }
173 _, err = f.WriteString(exampleText.String())
174 if err != nil {
175 return err
176 }
177
178 return nil
179}
180
181const paramFormatString = " --%s=%s \\\n"
182
183// formatParam formats a parameter into a flag example in the command line
184func formatParam(param string, params []string, bridge string) string {
185 if flagInfo, ok := flagInfos[param]; ok {
186 if checkParamConflicts(flagInfo.paramConflicts, params) {
187 return ""
188 }
189
190 return fmt.Sprintf(paramFormatString, flagInfo.flagName, flagInfo.defaultVal)
191 } else if param == "URL" {
192 if exampleUrl, ok := bridgeUrls[bridge]; ok {
193 return fmt.Sprintf(paramFormatString, "url", exampleUrl)
194 }
195 }
196
197 return fmt.Sprintf(paramFormatString, strings.ToLower(param), "=$("+strings.ToUpper(param)+")")
198}
199
200// checkParamConflicts checks the parameter conflicts against the list of present parameters
201// If a conflict is found, it returns true. Otherwise, it returns false
202func checkParamConflicts(paramConflicts []string, params []string) bool {
203 if len(paramConflicts) == 0 {
204 return false
205 }
206
207 for p := range params {
208 for conflict := range paramConflicts {
209 if p == conflict {
210 return true
211 }
212 }
213 }
214 return false
215}
216
217func genManPage() error {
218 cwd, _ := os.Getwd()
219 dir := path.Join(cwd, "doc", "man")
220
221 date := time.Date(2019, 4, 1, 12, 0, 0, 0, time.UTC)
222
223 header := &doc.GenManHeader{
224 Title: "GIT-BUG",
225 Section: "1",
226 Date: &date,
227 Source: "Generated from git-bug's source code",
228 }
229
230 files, err := filepath.Glob(dir + "/*.1")
231 if err != nil {
232 return err
233 }
234 for _, f := range files {
235 if err := os.Remove(f); err != nil {
236 return err
237 }
238 }
239
240 return doc.GenManTree(commands.NewRootCommand(), header, dir)
241}
242
243func genMarkdown() error {
244 cwd, _ := os.Getwd()
245 dir := path.Join(cwd, "doc", "md")
246
247 files, err := filepath.Glob(dir + "/*.md")
248 if err != nil {
249 return err
250 }
251 for _, f := range files {
252 if err := os.Remove(f); err != nil {
253 return err
254 }
255 }
256
257 return doc.GenMarkdownTree(commands.NewRootCommand(), dir)
258}