gen_docs.go

  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}