mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-11-02 06:42:47 +00:00
code to generate API documentation
This commit is contained in:
219
contrib/generate-api-docs.go
Normal file
219
contrib/generate-api-docs.go
Normal file
@@ -0,0 +1,219 @@
|
||||
// +build ignore
|
||||
|
||||
// This program generates api documentation from a
|
||||
// swaggerfile using an amber template.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/eknkc/amber"
|
||||
"github.com/go-swagger/go-swagger/spec"
|
||||
)
|
||||
|
||||
var (
|
||||
templ = flag.String("template", "index.amber", "")
|
||||
input = flag.String("input", "swagger.json", "")
|
||||
output = flag.String("output", "", "")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
// parses the swagger spec file
|
||||
spec, err := spec.YAMLSpec(*input)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
swag := spec.Spec()
|
||||
|
||||
// create output source for file. defaults to
|
||||
// stdout but may be file.
|
||||
var w io.WriteCloser = os.Stdout
|
||||
if *output != "" {
|
||||
w, err = os.Create(*output)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
return
|
||||
}
|
||||
defer w.Close()
|
||||
}
|
||||
|
||||
// we wrap the swagger file in a map, otherwise it
|
||||
// won't work with our existing templates, which expect
|
||||
// a map as the root parameter.
|
||||
var data = map[string]interface{}{
|
||||
"Swagger": normalize(swag),
|
||||
}
|
||||
|
||||
t := amber.MustCompileFile(*templ, amber.DefaultOptions)
|
||||
err = t.Execute(w, data)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Swagger is a simplified representation of the swagger
|
||||
// document with a subset of the fields used to generate
|
||||
// our API documentation.
|
||||
type Swagger struct {
|
||||
Tags []Tag
|
||||
}
|
||||
|
||||
type Tag struct {
|
||||
Name string
|
||||
Ops []Operation
|
||||
}
|
||||
|
||||
type Operation struct {
|
||||
ID string
|
||||
Method string
|
||||
Path string
|
||||
Desc string
|
||||
Summary string
|
||||
|
||||
Params []Param
|
||||
Results []Result
|
||||
}
|
||||
|
||||
type Param struct {
|
||||
Name string
|
||||
Desc string
|
||||
Type string
|
||||
Example interface{}
|
||||
InputTo string
|
||||
IsObject bool
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Status int
|
||||
Desc string
|
||||
Example interface{}
|
||||
IsObject bool
|
||||
IsArray bool
|
||||
}
|
||||
|
||||
// normalize is a helper function that normalizes the swagger
|
||||
// file to a simpler format that makes it easier to work with
|
||||
// inside the template.
|
||||
func normalize(swag *spec.Swagger) Swagger {
|
||||
swag_ := Swagger{}
|
||||
|
||||
for _, tag := range swag.Tags {
|
||||
tag_ := Tag{Name: tag.Name}
|
||||
|
||||
// group the paths based on their tag value.
|
||||
for route, path := range swag.Paths.Paths {
|
||||
|
||||
var ops = []*spec.Operation{
|
||||
path.Get,
|
||||
path.Put,
|
||||
path.Post,
|
||||
path.Patch,
|
||||
path.Delete,
|
||||
}
|
||||
|
||||
// flatten the operations into an array and convert
|
||||
// the underlying data so that it is a bit easier to
|
||||
// work with.
|
||||
for _, op := range ops {
|
||||
|
||||
// the operation must have a tag to
|
||||
// be rendered in our custom template.
|
||||
if op == nil || !hasTag(tag.Name, op.Tags) {
|
||||
continue
|
||||
}
|
||||
|
||||
item := Operation{}
|
||||
item.Path = route
|
||||
item.Method = getMethod(op, path)
|
||||
item.Desc = op.Description
|
||||
item.Summary = op.Summary
|
||||
item.ID = fmt.Sprintf("%x", md5.Sum([]byte(item.Path+item.Method)))
|
||||
|
||||
// convert the operation input parameters into
|
||||
// our internal format so that it is easier to
|
||||
// work with in the template.
|
||||
for _, param := range op.Parameters {
|
||||
param_ := Param{}
|
||||
param_.Name = param.Name
|
||||
param_.Desc = param.Description
|
||||
param_.Type = param.Type
|
||||
param_.IsObject = param.Schema != nil
|
||||
param_.InputTo = param.In
|
||||
|
||||
if param_.IsObject {
|
||||
param_.Type = param.Schema.Ref.GetPointer().String()[13:]
|
||||
param_.Example = param.Schema.Example
|
||||
}
|
||||
item.Params = append(item.Params, param_)
|
||||
}
|
||||
|
||||
// convert the operation response types into
|
||||
// our internal format so that it is easier to
|
||||
// work with in the template.
|
||||
for code, resp := range op.Responses.StatusCodeResponses {
|
||||
result := Result{}
|
||||
result.Desc = resp.Description
|
||||
result.Status = code
|
||||
result.IsObject = resp.Schema != nil
|
||||
if result.IsObject {
|
||||
result.IsArray = resp.Schema.Items != nil
|
||||
|
||||
name := resp.Schema.Ref.GetPointer().String()
|
||||
if len(name) != 0 {
|
||||
def, _ := swag.Definitions[name[13:]]
|
||||
result.Example = def.Example
|
||||
}
|
||||
}
|
||||
if result.IsArray {
|
||||
name := resp.Schema.Items.Schema.Ref.GetPointer().String()
|
||||
def, _ := swag.Definitions[name[13:]]
|
||||
result.Example = def.Example
|
||||
}
|
||||
item.Results = append(item.Results, result)
|
||||
}
|
||||
tag_.Ops = append(tag_.Ops, item)
|
||||
}
|
||||
}
|
||||
|
||||
swag_.Tags = append(swag_.Tags, tag_)
|
||||
}
|
||||
|
||||
return swag_
|
||||
}
|
||||
|
||||
// hasTag is a helper function that returns true if
|
||||
// an operation has the specified tag label.
|
||||
func hasTag(want string, in []string) bool {
|
||||
for _, got := range in {
|
||||
if got == want {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getMethod is a helper function that returns the http
|
||||
// method for the specified operation in a path.
|
||||
func getMethod(op *spec.Operation, path spec.PathItem) string {
|
||||
switch {
|
||||
case op == path.Get:
|
||||
return "GET"
|
||||
case op == path.Put:
|
||||
return "PUT"
|
||||
case op == path.Patch:
|
||||
return "PATCH"
|
||||
case op == path.Post:
|
||||
return "POST"
|
||||
case op == path.Delete:
|
||||
return "DELETE"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user