From 9555f50215524f3fb300a7b83a047b2632431f6a Mon Sep 17 00:00:00 2001 From: Brad Rydzewski Date: Tue, 6 Oct 2015 14:41:55 -0700 Subject: [PATCH] initial commit to add doc generation as part of build --- Makefile | 19 ++-- README.md | 22 +++-- contrib/generate-api-docs.go | 17 ++++ contrib/generate-docs.go | 159 ++++++++++++++++++++++++++++++++++ docs/swagger.yml | 4 +- static/static.go | 3 + static/styles/pages/docs.sass | 11 ++- static/styles_gen/style.css | 8 +- template/amber/docs.amber | 24 +++++ template/amber/swagger.amber | 5 ++ 10 files changed, 248 insertions(+), 24 deletions(-) create mode 100644 contrib/generate-docs.go create mode 100644 template/amber/docs.amber diff --git a/Makefile b/Makefile index 6a28cd38..6042a0fe 100644 --- a/Makefile +++ b/Makefile @@ -7,18 +7,21 @@ all: gen build deps: go get golang.org/x/tools/cmd/cover go get golang.org/x/tools/cmd/vet - go get -u github.com/kr/vexp - go get -u github.com/eknkc/amber/amberc - go get -u github.com/jteeuwen/go-bindata/... - go get -u github.com/elazarl/go-bindata-assetfs/... - go get -u github.com/dchest/jsmin - go get -u github.com/franela/goblin - go get -u github.com/go-swagger/go-swagger + go get github.com/kr/vexp + go get github.com/eknkc/amber/amberc + go get github.com/eknkc/amber + go get github.com/jteeuwen/go-bindata/... + go get github.com/elazarl/go-bindata-assetfs/... + go get github.com/dchest/jsmin + go get github.com/franela/goblin + go get github.com/go-swagger/go-swagger + go get github.com/PuerkitoBio/goquery + go get github.com/russross/blackfriday gen: gen_static gen_template gen_migrations gen_static: - mkdir -p static/docs_gen/api + mkdir -p static/docs_gen/api static/docs_gen/build go generate github.com/drone/drone/static gen_template: diff --git a/README.md b/README.md index 832b24ce..aa7dfb8e 100644 --- a/README.md +++ b/README.md @@ -31,28 +31,26 @@ cd $GOPATH/src/github.com/drone/drone Commands to build from source: ```sh -go run make.go deps # Download required dependencies -go run make.go bindata # Generate required bindata -go run make.go build # Build the binaries -go run make.go image # Build docker images -go run make.go test # Run the test suite -go run make.go clean # Clean up environment +make deps # Download required dependencies +make gen # Generate code +make build # Build the binary ``` Commands for development: ```sh -go run make.go scripts # Concat all javascripts -go run make.go styles # Concat all stylesheets -go run make.go vet # Execute vet command -go run make.go fmt # Execute fmt command +make gen_static # Generate static content +make gen_template # Generate templates from amber files +make gen_migrations # Generate embedded database migrations +make vet # Execute go vet command +make fmt # Execute go fmt command ``` Commands to start drone: ```sh -bin/drone -bin/drone --debug # Debug mode loads static content from filesystem +drone +drone --debug # Debug mode enables more verbose logging ``` If you are seeing slow compile times please install the following: diff --git a/contrib/generate-api-docs.go b/contrib/generate-api-docs.go index c0f16c07..296659f3 100644 --- a/contrib/generate-api-docs.go +++ b/contrib/generate-api-docs.go @@ -12,6 +12,7 @@ import ( "io" "log" "os" + "sort" "github.com/eknkc/amber" "github.com/go-swagger/go-swagger/spec" @@ -179,10 +180,12 @@ func normalize(swag *spec.Swagger) Swagger { } item.Results = append(item.Results, result) } + sort.Sort(ByCode(item.Results)) tag_.Ops = append(tag_.Ops, item) } } + sort.Sort(ByPath(tag_.Ops)) swag_.Tags = append(swag_.Tags, tag_) } @@ -217,3 +220,17 @@ func getMethod(op *spec.Operation, path spec.PathItem) string { } return "" } + +// ByCode helps sort a list of results by status code +type ByCode []Result + +func (a ByCode) Len() int { return len(a) } +func (a ByCode) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ByCode) Less(i, j int) bool { return a[i].Status < a[j].Status } + +// ByPath helps sort a list of endpoints by path +type ByPath []Operation + +func (a ByPath) Len() int { return len(a) } +func (a ByPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ByPath) Less(i, j int) bool { return a[i].Path < a[j].Path } diff --git a/contrib/generate-docs.go b/contrib/generate-docs.go new file mode 100644 index 00000000..fe8b63d8 --- /dev/null +++ b/contrib/generate-docs.go @@ -0,0 +1,159 @@ +// +build ignore + +// This program generates converts our markdown +// documentation to an html website. + +package main + +import ( + "bytes" + "flag" + "html/template" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + + "github.com/PuerkitoBio/goquery" + "github.com/eknkc/amber" + "github.com/russross/blackfriday" +) + +var ( + input = flag.String("input", "docs/README.md", "path to site index") + output = flag.String("output", "_site/", "path to outpute website") + html = flag.String("template", "", "path to documentation template") + name = flag.String("name", "", "name of the site") +) + +func main() { + flag.Parse() + + // read the markdown file into a document element. + document, err := toDocument(*input) + if err != nil { + log.Fatalf("Error opening %s. %s", *input, err) + } + + // we assume this file is the sitemap, so we'll look + // for the first ul element, and assume that contains + // the site hierarchy. + sitemap := document.Find("ul").First() + + site := Site{} + site.Name = *name + site.base = filepath.Dir(*input) + + // for each link in the sitemap we should attempt to + // read the markdown file and add to our list of pages + // to generate. + sitemap.Find("li > a").EachWithBreak(func(i int, s *goquery.Selection) bool { + page, err := toPage(&site, s) + if err != nil { + log.Fatalf("Error following link %s. %s", s.Text(), err) + } + if page != nil { + site.Pages = append(site.Pages, page) + } + return true + }) + site.Nav = &Nav{} + site.Nav.html, err = sitemap.Html() + if err != nil { + log.Fatal(err) + } + + // compiles our template which is in amber/jade format + templ := amber.MustCompileFile(*html, amber.DefaultOptions) + + // for each page in the sitemap we generate a + // corresponding html file using the above template. + for _, page := range site.Pages { + path := filepath.Join(*output, page.Href) + f, err := os.Create(path) + if err != nil { + log.Fatalf("Error creating file %s. %s", path, err) + } + defer f.Close() + + data := map[string]interface{}{ + "Site": site, + "Page": page, + } + err = templ.Execute(f, &data) + if err != nil { + log.Fatalf("Error generating template %s. %s", path, err) + } + } +} + +type Site struct { + Nav *Nav + Pages []*Page + Name string + + base string +} + +type Nav struct { + html string +} + +func (n *Nav) HTML() template.HTML { + return template.HTML(n.html) +} + +type Page struct { + Name string + Href string + html string +} + +func (p *Page) HTML() template.HTML { + return template.HTML(p.html) +} + +// toDocument is a helper function that parses a +// markdown file, converts to html markup, and returns +// a document element. +func toDocument(filename string) (*goquery.Document, error) { + raw, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + raw = blackfriday.MarkdownCommon(raw) + + buf := bytes.NewBuffer(raw) + return goquery.NewDocumentFromReader(buf) +} + +// toPage is a helper function that accepts an anchor +// tag referencing a markdown file, parsing the markdown +// file and returning a page to be included in our docs. +func toPage(site *Site, el *goquery.Selection) (*Page, error) { + + // follow the link to see if this is a page + // that should be added to our documentation. + href, ok := el.Attr("href") + if !ok { + return nil, nil + } + + // read the markdown file, convert to html and + // read into a dom element. + doc, err := toDocument(filepath.Join(site.base, href)) + if err != nil { + return nil, err + } + + // convert the extension from markdown to + // html, in preparation for type conversion. + href = strings.Replace(href, ".md", ".html", -1) + el.SetAttr("href", href) + + page := &Page{} + page.Href = href + page.html, err = doc.Html() + return page, err +} diff --git a/docs/swagger.yml b/docs/swagger.yml index a288c00b..b1c9f0e5 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -200,8 +200,8 @@ paths: description: name of the repository tags: - Repos - summary: Encrypt - description: Creates encrypted environment variable strings. + summary: Encrypt repo secrets + description: Encryptes a Yaml file with secret environment variables for secure public storage. security: - accessToken: [] responses: diff --git a/static/static.go b/static/static.go index 568b08fd..fca849a6 100644 --- a/static/static.go +++ b/static/static.go @@ -7,6 +7,9 @@ import ( ) //go:generate go run ../contrib/generate-js.go -dir scripts/ -o scripts_gen/drone.min.js +//go:generate go run ../contrib/generate-api-docs.go -input ../docs/swagger.yml -template ../template/amber/swagger.amber -output docs_gen/api/index.html +//go:generate go run ../contrib/generate-docs.go -input ../docs/build/README.md -template ../template/amber/docs.amber -output docs_gen/build/ + //go:generate sassc --style compact styles/style.sass styles_gen/style.css //go:generate go-bindata-assetfs -ignore "\\.go" -pkg static -o static_gen.go ./... diff --git a/static/styles/pages/docs.sass b/static/styles/pages/docs.sass index fa780669..cbb0c598 100644 --- a/static/styles/pages/docs.sass +++ b/static/styles/pages/docs.sass @@ -116,7 +116,7 @@ padding-right:40px; pre margin-right: 15px; - font-size: 14px; + font-size: 13px; color: #eff1f5; color: #2b303b; border-radius: 2px; @@ -200,3 +200,12 @@ font-weight:normal; margin-top:5px; + +.operation + aside + background: rgba(239, 241, 245, 0.49) + h4 + color: #2b303b + pre + background: #eff1f5 + color: #2b303b diff --git a/static/styles_gen/style.css b/static/styles_gen/style.css index c8d86560..5de94f23 100644 --- a/static/styles_gen/style.css +++ b/static/styles_gen/style.css @@ -341,7 +341,7 @@ body.login div.alert { position: fixed; top: 0px; left: 0px; right: 0px; line-he .docs { margin-top: 40px; padding: 0px 50px; padding-right: 40px; } -.docs pre { margin-right: 15px; font-size: 14px; color: #eff1f5; color: #2b303b; border-radius: 2px; background: #2b303b; background: #ECF0F1; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; padding: 25px 30px; font-family: "Roboto Mono"; } +.docs pre { margin-right: 15px; font-size: 13px; color: #eff1f5; color: #2b303b; border-radius: 2px; background: #2b303b; background: #ECF0F1; white-space: pre-wrap; word-wrap: break-word; box-sizing: border-box; padding: 25px 30px; font-family: "Roboto Mono"; } .operation { min-height: 100vh; padding: 20px 0px; display: flex; } @@ -369,6 +369,12 @@ body.login div.alert { position: fixed; top: 0px; left: 0px; right: 0px; line-he .operation .params small { display: block; text-transform: uppercase; color: #E67E22; font-size: 11px; font-weight: normal; margin-top: 5px; } +.operation aside { background: rgba(239, 241, 245, 0.49); } + +.operation aside h4 { color: #2b303b; } + +.operation aside pre { background: #eff1f5; color: #2b303b; } + .tt-open { position: absolute; top: 34px; left: 0px; z-index: 100; display: none; background: #FFF; min-width: 100%; border: 1px solid #eee; border-radius: 0px; } .tt-selectable:hover, .tt-cursor { background: #f4f4f4; } diff --git a/template/amber/docs.amber b/template/amber/docs.amber new file mode 100644 index 00000000..09f3485c --- /dev/null +++ b/template/amber/docs.amber @@ -0,0 +1,24 @@ +extends base + +block append head + title #{Site.Name} ยท Drone + +block header + ol + li Documentation + ul.nav.nav-tabs + li.nav-item + a.nav-link[href="#"] Install + li.nav-item + a.nav-link[href="#"] Builds + li.nav-item + a.nav-link[href="#"] Plugins + li.nav-item + a.nav-link[href="#"] API Reference + +block content + div.container-fluid.docs.docs-api + div.row + #{Site.Nav.HTML} + div.row + #{Page.HTML} \ No newline at end of file diff --git a/template/amber/swagger.amber b/template/amber/swagger.amber index 012cadeb..1cd4ff3e 100644 --- a/template/amber/swagger.amber +++ b/template/amber/swagger.amber @@ -56,6 +56,11 @@ block content aside h4 Endpoint pre #{$op.Method} #{$op.Path} + each $param in $op.Params + if $param.Example + h4 Example Request + if $param.IsObject + pre #{$param.Example} each $res in $op.Results if $res.Example h4 Example Response