code to generate API documentation
This commit is contained in:
parent
25d6a8c4bc
commit
2b00d12bb6
7 changed files with 579 additions and 501 deletions
14
Makefile
14
Makefile
|
@ -13,9 +13,19 @@ deps:
|
|||
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
|
||||
|
||||
gen:
|
||||
go generate $(PACKAGES)
|
||||
gen: gen_static gen_template gen_migrations
|
||||
|
||||
gen_static:
|
||||
mkdir -p static/docs_gen/api
|
||||
go generate github.com/drone/drone/static
|
||||
|
||||
gen_template:
|
||||
go generate github.com/drone/drone/template
|
||||
|
||||
gen_migrations:
|
||||
go generate github.com/drone/drone/shared/database
|
||||
|
||||
build:
|
||||
go build
|
||||
|
|
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 ""
|
||||
}
|
499
docs/api.raml
499
docs/api.raml
|
@ -1,499 +0,0 @@
|
|||
#%RAML 0.8
|
||||
|
||||
title: Drone API
|
||||
baseUri: http://localhost:8080/api
|
||||
traits:
|
||||
- authenticate:
|
||||
description: Some requests require authentication.
|
||||
queryParameters:
|
||||
access_token:
|
||||
description: Access Token
|
||||
type: string
|
||||
example: ACCESS_TOKEN
|
||||
- authorize:
|
||||
responses:
|
||||
401:
|
||||
description: |
|
||||
Access Denied. User must be authenticated.
|
||||
403:
|
||||
description: |
|
||||
Access Forbidden. User must be a system administrator.
|
||||
|
||||
/repos/{owner}/{name}:
|
||||
is: [ authorize, authenticate ]
|
||||
uriParameters:
|
||||
owner:
|
||||
displayName: Owner
|
||||
description: Owner of the repository
|
||||
type: string
|
||||
required: true
|
||||
name:
|
||||
displayName: Name
|
||||
description: Name of the repository
|
||||
type: string
|
||||
required: true
|
||||
|
||||
get:
|
||||
displayName: Find Repository
|
||||
description: |
|
||||
Retrieve a Repository by Name
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/repo.json
|
||||
404:
|
||||
description: |
|
||||
Unable to find the Repository in the database
|
||||
|
||||
patch:
|
||||
displayName: Update Repository
|
||||
description: |
|
||||
Update a Repository
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/repo.json
|
||||
400:
|
||||
description: |
|
||||
Unable to update the Repository record in the database
|
||||
404:
|
||||
description: |
|
||||
Unable to find the Repository in the database
|
||||
|
||||
post:
|
||||
displayName: Activate Repository
|
||||
description: |
|
||||
Activate a Repository
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/repo.json
|
||||
400:
|
||||
description: |
|
||||
Unable to update the Repository record in the database
|
||||
403:
|
||||
description: |
|
||||
Unable to activate the Repository due to insufficient privileges
|
||||
404:
|
||||
description: |
|
||||
Unable to retrieve the Repository from the remote system (ie GitHub)
|
||||
409:
|
||||
description: |
|
||||
Unable to activate the Repository because it is already activate
|
||||
500:
|
||||
description: |
|
||||
Unable to activate the Repository due to an internal server error.
|
||||
This may indicate a problem adding hooks to the remote system (ie Github),
|
||||
generating SSH deployment keys, or persisting to the database.
|
||||
|
||||
delete:
|
||||
displayName: Delete Repository
|
||||
description: |
|
||||
Deletes a Repository
|
||||
responses:
|
||||
200:
|
||||
description: |
|
||||
Successfully deleted the Repository
|
||||
400:
|
||||
description: |
|
||||
Unable to remove post-commit hooks from the remote system (ie GitHub)
|
||||
404:
|
||||
description: |
|
||||
Unable to find the Repository in the database
|
||||
500:
|
||||
description: |
|
||||
Unable to update the Repository record in the database
|
||||
|
||||
/watch:
|
||||
is: [ authorize, authenticate ]
|
||||
description: |
|
||||
Watch the Repository
|
||||
post:
|
||||
responses:
|
||||
200:
|
||||
description: |
|
||||
Successfully Watching this Repository
|
||||
400:
|
||||
description: |
|
||||
Unable to insert the Starred record in the database
|
||||
404:
|
||||
description: |
|
||||
Unable to find the Repository in the database
|
||||
|
||||
/unwatch:
|
||||
is: [ authorize, authenticate ]
|
||||
description: |
|
||||
Unwatch the Repository
|
||||
delete:
|
||||
responses:
|
||||
200:
|
||||
description: |
|
||||
Successfully Unwatched this Repository
|
||||
400:
|
||||
description: |
|
||||
Unable to delete the Starred record in the database
|
||||
404:
|
||||
description: |
|
||||
Unable to find the Repository in the database
|
||||
|
||||
|
||||
#
|
||||
# Builds
|
||||
#
|
||||
|
||||
/repos/{owner}/{name}/builds:
|
||||
displayName: Builds
|
||||
is: [ authorize, authenticate ]
|
||||
uriParameters:
|
||||
owner:
|
||||
displayName: Owner
|
||||
description: Owner of the repository
|
||||
type: string
|
||||
required: true
|
||||
name:
|
||||
displayName: Name
|
||||
description: Name of the repository
|
||||
type: string
|
||||
required: true
|
||||
|
||||
get:
|
||||
displayName: List Builds
|
||||
description: |
|
||||
Retrieve the list of recent Builds for the Repository
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/builds.json
|
||||
404:
|
||||
description: |
|
||||
Unable to find the Repository in the database
|
||||
|
||||
/{number}:
|
||||
is: [ authorize, authenticate ]
|
||||
uriParameters:
|
||||
number:
|
||||
displayName: Number
|
||||
type: integer
|
||||
|
||||
get:
|
||||
displayName: Find Build
|
||||
description: |
|
||||
Retrieve a specific Build by Number
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/build.json
|
||||
404:
|
||||
description: |
|
||||
Unable to find the Build in the database
|
||||
|
||||
delete:
|
||||
displayName: Cancel Build
|
||||
description: |
|
||||
Cancel an running Build by Number
|
||||
responses:
|
||||
200:
|
||||
description: |
|
||||
Successfully cancelled the Build
|
||||
404:
|
||||
description: |
|
||||
Cannot find Build by Number
|
||||
409:
|
||||
description: |
|
||||
Cannot cancel a Build that is already stopped
|
||||
|
||||
post:
|
||||
displayName: Restart Build
|
||||
description: |
|
||||
Restart a completed Build
|
||||
responses:
|
||||
202:
|
||||
description: |
|
||||
Successfully restarted the Build
|
||||
404:
|
||||
description: |
|
||||
Cannot find Build by Number
|
||||
409:
|
||||
description: |
|
||||
Cannot re-start a Build that is running
|
||||
|
||||
#
|
||||
# Build Logs
|
||||
#
|
||||
|
||||
|
||||
/repos/{owner}/{name}/logs/{number}/{job}:
|
||||
displayName: Builds
|
||||
is: [ authorize, authenticate ]
|
||||
uriParameters:
|
||||
owner:
|
||||
displayName: Owner
|
||||
description: Owner of the repository
|
||||
type: string
|
||||
required: true
|
||||
name:
|
||||
displayName: Name
|
||||
description: Name of the repository
|
||||
type: string
|
||||
required: true
|
||||
number:
|
||||
displayName: Build Number
|
||||
description: Incremental Build Number
|
||||
type: integer
|
||||
required: true
|
||||
job:
|
||||
displayName: Job Number
|
||||
description: Sequential Job Number
|
||||
type: integer
|
||||
required: true
|
||||
|
||||
get:
|
||||
displayName: Find Build Logs
|
||||
description: |
|
||||
Retrieve the Logs for a specific Build Job
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
text/plain:
|
||||
404:
|
||||
description: |
|
||||
Cannot find Build Logs
|
||||
|
||||
|
||||
#
|
||||
# User Endpoint
|
||||
#
|
||||
|
||||
/user:
|
||||
is: [ authorize, authenticate ]
|
||||
displayName: User
|
||||
|
||||
get:
|
||||
description: |
|
||||
Retrieve the currently authenticated User
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/user.json
|
||||
|
||||
patch:
|
||||
description: |
|
||||
Update the currently authenticated User
|
||||
responses:
|
||||
200:
|
||||
description: |
|
||||
Updated User
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/user.json
|
||||
400:
|
||||
description: |
|
||||
Bad Request. Error updating User
|
||||
|
||||
|
||||
|
||||
#
|
||||
# User Repos
|
||||
#
|
||||
|
||||
/user/repos:
|
||||
is: [ authorize, authenticate ]
|
||||
displayName: User Repos
|
||||
|
||||
get:
|
||||
description: |
|
||||
Retrieve the currently authenticated User's Repository list
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/repos.json
|
||||
400:
|
||||
description: |
|
||||
Bad Request. Error retrieving Repository list
|
||||
|
||||
|
||||
#
|
||||
# User Tokens
|
||||
#
|
||||
|
||||
/user/tokens:
|
||||
is: [ authorize, authenticate ]
|
||||
displayName: User Tokens
|
||||
|
||||
get:
|
||||
description: |
|
||||
Retrieve the currently authenticated User's active Token list
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/tokens.json
|
||||
400:
|
||||
description: |
|
||||
Error retrieving the Token list
|
||||
|
||||
post:
|
||||
description: |
|
||||
Generate a new User Token
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/token.json
|
||||
400:
|
||||
description: |
|
||||
Error when attempting to generate the JWT token
|
||||
500:
|
||||
description: |
|
||||
Error when attempting to save the Token
|
||||
|
||||
/{label}:
|
||||
is: [ authorize, authenticate ]
|
||||
delete:
|
||||
description: |
|
||||
Delete a specific User Token by Label
|
||||
responses:
|
||||
200:
|
||||
description: |
|
||||
Successfully deleted the Token
|
||||
400:
|
||||
description: |
|
||||
Error attempting to delete Token from database
|
||||
404:
|
||||
description: |
|
||||
Unable to find Token in database
|
||||
|
||||
#
|
||||
# Users Endpoint
|
||||
#
|
||||
|
||||
/users:
|
||||
is: [ authorize, authenticate ]
|
||||
displayName: Users
|
||||
|
||||
get:
|
||||
description: Retrieve a list of all registered Users.
|
||||
displayName: List Users
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
example: !include samples/users.json
|
||||
|
||||
/{login}:
|
||||
is: [ authorize, authenticate ]
|
||||
uriParameters:
|
||||
login:
|
||||
displayName: Login
|
||||
description: Username in remote system
|
||||
example: Octocat
|
||||
type: string
|
||||
required: true
|
||||
|
||||
get:
|
||||
displayName: Find User
|
||||
description: |
|
||||
Retrieve a specific User by Login name
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
schema: !include schemas/user.json
|
||||
404:
|
||||
description: |
|
||||
Cannot find the User
|
||||
|
||||
post:
|
||||
displayName: Enable User
|
||||
description: |
|
||||
Enable a new User by Login name
|
||||
responses:
|
||||
201:
|
||||
body:
|
||||
application/json:
|
||||
schema: !include schemas/user.json
|
||||
400:
|
||||
description: |
|
||||
Error inserting User into the database
|
||||
|
||||
patch:
|
||||
displayName: Update User
|
||||
description: |
|
||||
Update a specific User
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/json:
|
||||
schema: !include schemas/user.json
|
||||
400:
|
||||
description: |
|
||||
Error updating User record in the database
|
||||
|
||||
delete:
|
||||
displayName: Delete User
|
||||
description: |
|
||||
Delete a specific User
|
||||
responses:
|
||||
204:
|
||||
description: |
|
||||
Successfully deleted the User
|
||||
400:
|
||||
description: |
|
||||
Error deleting the User from the database
|
||||
403:
|
||||
description: |
|
||||
Cannot delete your own User account
|
||||
404:
|
||||
description: |
|
||||
Cannot find the User
|
||||
|
||||
|
||||
#
|
||||
# Badge Endpoint
|
||||
#
|
||||
|
||||
/badges/{owner}/{name}:
|
||||
displayName: Badges
|
||||
uriParameters:
|
||||
owner:
|
||||
displayName: Owner
|
||||
description: Owner of the repository
|
||||
type: string
|
||||
required: true
|
||||
name:
|
||||
displayName: Name
|
||||
description: Name of the repository
|
||||
type: string
|
||||
required: true
|
||||
|
||||
/status.svg:
|
||||
description: Returns an SVG status badge for the latest Build
|
||||
displayName: Status Badge
|
||||
get:
|
||||
queryParameters:
|
||||
branch:
|
||||
default: master
|
||||
required: false
|
||||
type: string
|
||||
example: master
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
image/svg+xml:
|
||||
|
||||
/cc.xml:
|
||||
description: Returns a CCMenu feed for the Repository
|
||||
displayName: CCMenu
|
||||
get:
|
||||
responses:
|
||||
200:
|
||||
body:
|
||||
application/xml:
|
||||
example: !include samples/ccmenu.xml
|
202
static/styles/pages/docs.sass
Normal file
202
static/styles/pages/docs.sass
Normal file
|
@ -0,0 +1,202 @@
|
|||
|
||||
.toc
|
||||
list-style-type: none;
|
||||
padding:0px;
|
||||
margin:0px;
|
||||
padding-bottom:40px;
|
||||
|
||||
h2
|
||||
font-size:21px;
|
||||
font-weight:normal;
|
||||
margin-bottom:20px;
|
||||
color:#2b303b;
|
||||
|
||||
ul
|
||||
list-style-type: none;
|
||||
padding:0px;
|
||||
margin:0px;
|
||||
margin-bottom:40px;
|
||||
border-bottom: 1px solid #EEE;
|
||||
padding-bottom:40px;
|
||||
li
|
||||
line-height:25px;
|
||||
a
|
||||
color: #2b303b;
|
||||
text-decoration:none;
|
||||
a:hover
|
||||
text-decoration:underline;
|
||||
|
||||
[data-method]:before
|
||||
content: attr(data-method);
|
||||
padding:0px 10px;
|
||||
line-height:18px;
|
||||
min-width:70px;
|
||||
font-size:11px;
|
||||
text-transform:uppercase;
|
||||
display: inline-block;
|
||||
text-align:center;
|
||||
color:#FFF;
|
||||
border-radius:2px;
|
||||
margin-right:20px;
|
||||
|
||||
[data-method="GET"]:before
|
||||
background-color:#1ABC9C;
|
||||
[data-method="PUT"]:before
|
||||
background-color:#9B59B6;
|
||||
[data-method="POST"]:before
|
||||
background-color:#3498DB;
|
||||
[data-method="PATCH"]:before
|
||||
background-color:#E67E22;
|
||||
[data-method="DELETE"]:before
|
||||
background-color:#E74C3C;
|
||||
|
||||
|
||||
|
||||
[data-method]:before
|
||||
background:#FFF;
|
||||
border:1px solid #FFF;
|
||||
[data-method="GET"]:before
|
||||
color:#1ABC9C;
|
||||
border-color:#1ABC9C;
|
||||
[data-method="PUT"]:before
|
||||
color:#9B59B6;
|
||||
border-color:#9B59B6;
|
||||
[data-method="POST"]:before
|
||||
color:#3498DB;
|
||||
border-color:#3498DB;
|
||||
[data-method="PATCH"]:before
|
||||
color:#E67E22;
|
||||
border-color:#E67E22;
|
||||
[data-method="DELETE"]:before
|
||||
color:#E74C3C;
|
||||
border-color:#E74C3C;
|
||||
|
||||
.operation
|
||||
|
||||
[data-method]:before
|
||||
content: attr(data-method);
|
||||
padding:0px 10px;
|
||||
line-height:18px;
|
||||
min-width:70px;
|
||||
font-size:11px;
|
||||
text-transform:uppercase;
|
||||
display: inline-block;
|
||||
text-align:center;
|
||||
color:#FFF;
|
||||
border-radius:2px;
|
||||
margin-right:20px;
|
||||
background:#FFF;
|
||||
border:1px solid #FFF;
|
||||
line-height: 20px;
|
||||
vertical-align: top;
|
||||
|
||||
|
||||
[data-method]:before
|
||||
background:#FFF;
|
||||
border:1px solid #FFF;
|
||||
[data-method="GET"]:before
|
||||
color:#1ABC9C;
|
||||
border-color:#1ABC9C;
|
||||
[data-method="PUT"]:before
|
||||
color:#9B59B6;
|
||||
border-color:#9B59B6;
|
||||
[data-method="POST"]:before
|
||||
color:#3498DB;
|
||||
border-color:#3498DB;
|
||||
[data-method="PATCH"]:before
|
||||
color:#E67E22;
|
||||
border-color:#E67E22;
|
||||
[data-method="DELETE"]:before
|
||||
color:#E74C3C;
|
||||
border-color:#E74C3C;
|
||||
|
||||
.docs
|
||||
margin-top:40px;
|
||||
padding: 0px 50px;
|
||||
padding-right:40px;
|
||||
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";
|
||||
|
||||
|
||||
.operation
|
||||
min-height:100vh;
|
||||
padding:20px 0px;
|
||||
display: flex
|
||||
&> aside,
|
||||
&> div
|
||||
min-width:50%;
|
||||
max-width:50%;
|
||||
width:50%;
|
||||
padding-right:40px;
|
||||
h2
|
||||
color:#2b303b;
|
||||
font-size:21px;
|
||||
h3
|
||||
font-size:16px;
|
||||
margin-bottom:20px;
|
||||
margin-top:40px;
|
||||
aside
|
||||
background: rgba(43, 48, 59, 0.95);
|
||||
box-sizing: border-box;
|
||||
padding: 20px 0px 10px 0px;
|
||||
border-radius:2px;
|
||||
h4
|
||||
color: #d0d4d7;
|
||||
font-size:15px;
|
||||
padding:20px;
|
||||
padding-left:40px;
|
||||
pre
|
||||
background: #2b303b;
|
||||
color: #d0d4d7;
|
||||
margin-right:0px;
|
||||
padding-left:40px;
|
||||
|
||||
.params
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
list-style-type: none;
|
||||
border-top: 1px solid #f0f4f7
|
||||
li
|
||||
padding:15px 10px;
|
||||
border-bottom:1px solid #f0f4f7;
|
||||
font-size:15px
|
||||
p
|
||||
line-height:20px;
|
||||
margin: 0 0 0 170px;
|
||||
|
||||
li:after
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
font-size: 0;
|
||||
content: " ";
|
||||
clear: both;
|
||||
height: 0;
|
||||
|
||||
h4
|
||||
float:left;
|
||||
line-height:20px;
|
||||
text-align:right;
|
||||
padding-right:20px;
|
||||
width:150px;
|
||||
font-weight:bold;
|
||||
font-size:15px;
|
||||
|
||||
small
|
||||
display:block;
|
||||
text-transform: uppercase;
|
||||
color:#E67E22;
|
||||
font-size:11px;
|
||||
font-weight:normal;
|
||||
margin-top:5px;
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
@import pages/repo.sass
|
||||
@import pages/login.sass
|
||||
@import pages/feed.sass
|
||||
@import pages/docs.sass
|
||||
|
||||
@import header
|
||||
@import search
|
||||
|
|
|
@ -289,6 +289,86 @@ body.login div.alert { position: fixed; top: 0px; left: 0px; right: 0px; line-he
|
|||
|
||||
.repo-row .card-header { background: #FFF; border-bottom: none; padding-right: 0px; padding-left: 0px; width: 45px; }
|
||||
|
||||
.toc { list-style-type: none; padding: 0px; margin: 0px; padding-bottom: 40px; }
|
||||
|
||||
.toc h2 { font-size: 21px; font-weight: normal; margin-bottom: 20px; color: #2b303b; }
|
||||
|
||||
.toc ul { list-style-type: none; padding: 0px; margin: 0px; margin-bottom: 40px; border-bottom: 1px solid #EEE; padding-bottom: 40px; }
|
||||
|
||||
.toc ul li { line-height: 25px; }
|
||||
|
||||
.toc ul li a { color: #2b303b; text-decoration: none; }
|
||||
|
||||
.toc ul li a:hover { text-decoration: underline; }
|
||||
|
||||
.toc [data-method]:before { content: attr(data-method); padding: 0px 10px; line-height: 18px; min-width: 70px; font-size: 11px; text-transform: uppercase; display: inline-block; text-align: center; color: #FFF; border-radius: 2px; margin-right: 20px; }
|
||||
|
||||
.toc [data-method="GET"]:before { background-color: #1ABC9C; }
|
||||
|
||||
.toc [data-method="PUT"]:before { background-color: #9B59B6; }
|
||||
|
||||
.toc [data-method="POST"]:before { background-color: #3498DB; }
|
||||
|
||||
.toc [data-method="PATCH"]:before { background-color: #E67E22; }
|
||||
|
||||
.toc [data-method="DELETE"]:before { background-color: #E74C3C; }
|
||||
|
||||
.toc [data-method]:before { background: #FFF; border: 1px solid #FFF; }
|
||||
|
||||
.toc [data-method="GET"]:before { color: #1ABC9C; border-color: #1ABC9C; }
|
||||
|
||||
.toc [data-method="PUT"]:before { color: #9B59B6; border-color: #9B59B6; }
|
||||
|
||||
.toc [data-method="POST"]:before { color: #3498DB; border-color: #3498DB; }
|
||||
|
||||
.toc [data-method="PATCH"]:before { color: #E67E22; border-color: #E67E22; }
|
||||
|
||||
.toc [data-method="DELETE"]:before { color: #E74C3C; border-color: #E74C3C; }
|
||||
|
||||
.operation [data-method]:before { content: attr(data-method); padding: 0px 10px; line-height: 18px; min-width: 70px; font-size: 11px; text-transform: uppercase; display: inline-block; text-align: center; color: #FFF; border-radius: 2px; margin-right: 20px; background: #FFF; border: 1px solid #FFF; line-height: 20px; vertical-align: top; }
|
||||
|
||||
.operation [data-method]:before { background: #FFF; border: 1px solid #FFF; }
|
||||
|
||||
.operation [data-method="GET"]:before { color: #1ABC9C; border-color: #1ABC9C; }
|
||||
|
||||
.operation [data-method="PUT"]:before { color: #9B59B6; border-color: #9B59B6; }
|
||||
|
||||
.operation [data-method="POST"]:before { color: #3498DB; border-color: #3498DB; }
|
||||
|
||||
.operation [data-method="PATCH"]:before { color: #E67E22; border-color: #E67E22; }
|
||||
|
||||
.operation [data-method="DELETE"]:before { color: #E74C3C; border-color: #E74C3C; }
|
||||
|
||||
.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"; }
|
||||
|
||||
.operation { min-height: 100vh; padding: 20px 0px; display: flex; }
|
||||
|
||||
.operation > aside, .operation > div { min-width: 50%; max-width: 50%; width: 50%; padding-right: 40px; }
|
||||
|
||||
.operation h2 { color: #2b303b; font-size: 21px; }
|
||||
|
||||
.operation h3 { font-size: 16px; margin-bottom: 20px; margin-top: 40px; }
|
||||
|
||||
.operation aside { background: rgba(43, 48, 59, 0.95); box-sizing: border-box; padding: 20px 0px 10px 0px; border-radius: 2px; }
|
||||
|
||||
.operation aside h4 { color: #d0d4d7; font-size: 15px; padding: 20px; padding-left: 40px; }
|
||||
|
||||
.operation aside pre { background: #2b303b; color: #d0d4d7; margin-right: 0px; padding-left: 40px; }
|
||||
|
||||
.operation .params { padding: 0px; margin: 0px; list-style-type: none; border-top: 1px solid #f0f4f7; }
|
||||
|
||||
.operation .params li { padding: 15px 10px; border-bottom: 1px solid #f0f4f7; font-size: 15px; }
|
||||
|
||||
.operation .params li p { line-height: 20px; margin: 0 0 0 170px; }
|
||||
|
||||
.operation .params li:after { visibility: hidden; display: block; font-size: 0; content: " "; clear: both; height: 0; }
|
||||
|
||||
.operation .params h4 { float: left; line-height: 20px; text-align: right; padding-right: 20px; width: 150px; font-weight: bold; font-size: 15px; }
|
||||
|
||||
.operation .params small { display: block; text-transform: uppercase; color: #E67E22; font-size: 11px; font-weight: normal; margin-top: 5px; }
|
||||
|
||||
.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; }
|
||||
|
|
65
template/amber/swagger.amber
Normal file
65
template/amber/swagger.amber
Normal file
|
@ -0,0 +1,65 @@
|
|||
extends base
|
||||
|
||||
block append head
|
||||
title API · 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.active[href="#"] API Reference
|
||||
|
||||
block content
|
||||
div.container-fluid.docs.docs-api
|
||||
a[name="top"]
|
||||
div.row
|
||||
ul.toc
|
||||
each $tag in Swagger.Tags
|
||||
li
|
||||
h2 #{$tag.Name}
|
||||
ul
|
||||
each $op in $tag.Ops
|
||||
li
|
||||
a[href="#"+$op.ID][data-method=$op.Method] #{$op.Path}
|
||||
div.row
|
||||
each $tag in Swagger.Tags
|
||||
each $op in $tag.Ops
|
||||
a[name=$op.ID]
|
||||
div.operation
|
||||
div
|
||||
h2[data-method=$op.Method] #{$op.Summary}
|
||||
p #{$op.Desc}
|
||||
|
||||
h3 Request Parameters
|
||||
ul.params
|
||||
each $param in $op.Params
|
||||
li
|
||||
h4
|
||||
| #{$param.Name}
|
||||
small Required
|
||||
p #{$param.Desc}
|
||||
|
||||
h3 Response Messages
|
||||
ul.params
|
||||
each $result in $op.Results
|
||||
li
|
||||
h4
|
||||
| #{$result.Status}
|
||||
p #{$result.Desc}
|
||||
aside
|
||||
h4 Endpoint
|
||||
pre #{$op.Method} #{$op.Path}
|
||||
each $res in $op.Results
|
||||
if $res.Example
|
||||
h4 Example Response
|
||||
if $res.IsArray
|
||||
pre [#{$res.Example}]
|
||||
else if $res.IsObject
|
||||
pre #{$res.Example}
|
Loading…
Reference in a new issue