diff --git a/.gitignore b/.gitignore index e09612418..b75360d04 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ dist testdata/simple*/docs cover.out + # Test binary, build with `go test -c` *.test diff --git a/README.md b/README.md index 4119cea07..356ca3d20 100644 --- a/README.md +++ b/README.md @@ -323,6 +323,20 @@ $ swag init | BasePath | The base path on which the API is served. | // @BasePath /api/v1 | | schemes | The transfer protocol for the operation that separated by spaces. | // @schemes http https | +### Using markdown descriptions +When a short string in your documentation is insufficient, or you need images, code examples and things like that you may want to use markdown descriptions. In order to use markdown descriptions use the following annotations. + + +| annotation | description | example | +|-------------|--------------------------------------------|---------------------------------| +| title | **Required.** The title of the application.| // @title Swagger Example API | +| version | **Required.** Provides the version of the application API.| // @version 1.0 | +| description.markdown | A short description of the application. Parsed from the api.md file. This is an alternative to @description |// @description.markdown No value needed, this parses the description from api.md | +| tag.name | Name of a tag.| // @tag.name This is the name of the tag | +| tag.description.markdown | Description of the tag this is an alternative to tag.description. The description will be read from a file named like tagname.md | // @tag.description.markdown | + + + ## API Operation **Example** diff --git a/cmd/swag/main.go b/cmd/swag/main.go index 61f2ce04c..0d1648bca 100644 --- a/cmd/swag/main.go +++ b/cmd/swag/main.go @@ -10,6 +10,13 @@ import ( "github.com/urfave/cli" ) +const searchDirFlag = "dir" +const generalInfoFlag = "generalInfo" +const propertyStrategyFlag = "propertyStrategy" +const outputFlag = "output" +const parseVendorFlag = "parseVendor" +const markdownFilesDirFlag = "markdownFiles" + func main() { app := cli.NewApp() app.Version = swag.Version @@ -20,11 +27,12 @@ func main() { Aliases: []string{"i"}, Usage: "Create docs.go", Action: func(c *cli.Context) error { - searchDir := c.String("dir") - mainAPIFile := c.String("generalInfo") - strategy := c.String("propertyStrategy") - outputDir := c.String("output") - parseVendor := c.Bool("parseVendor") + searchDir := c.String(searchDirFlag) + mainAPIFile := c.String(generalInfoFlag) + strategy := c.String(propertyStrategyFlag) + outputDir := c.String(outputFlag) + parseVendor := c.Bool(parseVendorFlag) + markdownFilesDir := c.String(markdownFilesDirFlag) switch strategy { case swag.CamelCase, swag.SnakeCase, swag.PascalCase: @@ -38,6 +46,7 @@ func main() { PropNamingStrategy: strategy, OutputDir: outputDir, ParseVendor: parseVendor, + MarkdownFilesDir: markdownFilesDir, }) }, Flags: []cli.Flag{ @@ -65,6 +74,11 @@ func main() { Name: "parseVendor", Usage: "Parse go files in 'vendor' folder, disabled by default", }, + cli.StringFlag{ + Name: "markdownFiles, md", + Value: "", + Usage: "Parse folder containing markdown files to use as description, disabled by default", + }, }, }, } diff --git a/gen/gen.go b/gen/gen.go index c2fc54b1e..cbe95da89 100644 --- a/gen/gen.go +++ b/gen/gen.go @@ -39,6 +39,9 @@ type Config struct { //ParseVendor whether swag should be parse vendor folder ParseVendor bool + + // MarkdownFilesDir used to find markdownfiles, which can be used for tag descriptions + MarkdownFilesDir string } // Build builds swagger json file for gived searchDir and mainAPIFile. Returns json @@ -48,7 +51,7 @@ func (g *Gen) Build(config *Config) error { } log.Println("Generate swagger docs....") - p := swag.New() + p := swag.New(swag.SetMarkdownFileDirectory(config.MarkdownFilesDir)) p.PropNamingStrategy = config.PropNamingStrategy p.ParseVendor = config.ParseVendor @@ -62,7 +65,10 @@ func (g *Gen) Build(config *Config) error { return err } - os.MkdirAll(config.OutputDir, os.ModePerm) + if err := os.MkdirAll(config.OutputDir, os.ModePerm); err != nil { + return err + } + docs, err := os.Create(path.Join(config.OutputDir, "docs.go")) if err != nil { return err @@ -75,7 +81,9 @@ func (g *Gen) Build(config *Config) error { } defer swaggerJSON.Close() - swaggerJSON.Write(b) + if _, err := swaggerJSON.Write(b); err != nil { + return err + } swaggerYAML, err := os.Create(path.Join(config.OutputDir, "swagger.yaml")) if err != nil { @@ -88,7 +96,9 @@ func (g *Gen) Build(config *Config) error { return errors.Wrap(err, "cannot covert json to yaml") } - swaggerYAML.Write(y) + if _, err := swaggerYAML.Write(y); err != nil { + return err + } if err := packageTemplate.Execute(docs, struct { Timestamp time.Time diff --git a/operation_test.go b/operation_test.go index 95d99b6f2..ef4164e92 100644 --- a/operation_test.go +++ b/operation_test.go @@ -87,7 +87,8 @@ func TestParseProduceComment(t *testing.T) { }` comment := `/@Produce json,xml,plain,html,mpfd,x-www-form-urlencoded,json-api,json-stream,octet-stream,png,jpeg,gif,application/health+json` operation := new(Operation) - operation.ParseComment(comment, nil) + err := operation.ParseComment(comment, nil) + assert.NoError(t, err, "ParseComment should not fail") b, _ := json.MarshalIndent(operation, "", " ") assert.JSONEq(t, expected, string(b)) } @@ -202,7 +203,8 @@ func TestParseResponseCommentWithArrayType(t *testing.T) { func TestParseResponseCommentWithBasicType(t *testing.T) { comment := `@Success 200 {string} string "it's ok'"` operation := NewOperation() - operation.ParseComment(comment, nil) + err := operation.ParseComment(comment, nil) + assert.NoError(t, err, "ParseComment should not fail") b, _ := json.MarshalIndent(operation, "", " ") expected := `{ @@ -221,7 +223,9 @@ func TestParseResponseCommentWithBasicType(t *testing.T) { func TestParseEmptyResponseComment(t *testing.T) { comment := `@Success 200 "it's ok"` operation := NewOperation() - operation.ParseComment(comment, nil) + err := operation.ParseComment(comment, nil) + assert.NoError(t, err, "ParseComment should not fail") + b, _ := json.MarshalIndent(operation, "", " ") expected := `{ @@ -237,9 +241,13 @@ func TestParseEmptyResponseComment(t *testing.T) { func TestParseResponseCommentWithHeader(t *testing.T) { comment := `@Success 200 "it's ok"` operation := NewOperation() - operation.ParseComment(comment, nil) + err := operation.ParseComment(comment, nil) + assert.NoError(t, err, "ParseComment should not fail") + comment = `@Header 200 {string} Token "qwerty"` - operation.ParseComment(comment, nil) + err = operation.ParseComment(comment, nil) + assert.NoError(t, err, "ParseComment should not fail") + b, err := json.MarshalIndent(operation, "", " ") assert.NoError(t, err) @@ -262,7 +270,9 @@ func TestParseResponseCommentWithHeader(t *testing.T) { func TestParseEmptyResponseOnlyCode(t *testing.T) { comment := `@Success 200` operation := NewOperation() - operation.ParseComment(comment, nil) + err := operation.ParseComment(comment, nil) + assert.NoError(t, err, "ParseComment should not fail") + b, _ := json.MarshalIndent(operation, "", " ") expected := `{ diff --git a/parser.go b/parser.go index 85887b8d4..18f421d55 100644 --- a/parser.go +++ b/parser.go @@ -5,6 +5,7 @@ import ( "go/ast" goparser "go/parser" "go/token" + "io/ioutil" "net/http" "os" "path" @@ -54,10 +55,13 @@ type Parser struct { // structStack stores full names of the structures that were already parsed or are being parsed now structStack []string + + // markdownFileDir holds the path to the folder, where markdown files are stored + markdownFileDir string } // New creates a new Parser with default properties. -func New() *Parser { +func New(options ...func(*Parser)) *Parser { parser := &Parser{ swagger: &spec.Swagger{ SwaggerProps: spec.SwaggerProps{ @@ -78,16 +82,31 @@ func New() *Parser { CustomPrimitiveTypes: make(map[string]string), registerTypes: make(map[string]*ast.TypeSpec), } + + for _, option := range options { + option(parser) + } + return parser } +// SetMarkdownFileDirectory sets the directory to search for markdownfiles +func SetMarkdownFileDirectory(directoryPath string) func(*Parser) { + return func(p *Parser) { + p.markdownFileDir = directoryPath + } +} + // ParseAPI parses general api info for gived searchDir and mainAPIFile func (parser *Parser) ParseAPI(searchDir string, mainAPIFile string) error { Println("Generate general API Info") if err := parser.getAllGoFileInfo(searchDir); err != nil { return err } - parser.ParseGeneralAPIInfo(path.Join(searchDir, mainAPIFile)) + + if err := parser.ParseGeneralAPIInfo(path.Join(searchDir, mainAPIFile)); err != nil { + return err + } for _, astFile := range parser.files { parser.ParseType(astFile) @@ -143,6 +162,18 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error { } else if multilineBlock { parser.swagger.Info.Description += "\n" + strings.TrimSpace(commentLine[len(attribute):]) } + case "@description.markdown": + filePath, err := getMarkdownFileForTag("api", parser.markdownFileDir) + if err != nil { + return err + } + + commentInfo, err := ioutil.ReadFile(parser.markdownFileDir + "/" + filePath) + if err != nil { + return errors.New("Failed to find matching markdown file for api description: " + "api" + " error: " + err.Error()) + } + + parser.swagger.Info.Description = string(commentInfo) case "@termsofservice": parser.swagger.Info.TermsOfService = strings.TrimSpace(commentLine[len(attribute):]) case "@contact.name": @@ -173,6 +204,20 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error { tag := parser.swagger.Tags[len(parser.swagger.Tags)-1] tag.TagProps.Description = commentInfo replaceLastTag(parser.swagger.Tags, tag) + case "@tag.description.markdown": + tag := parser.swagger.Tags[len(parser.swagger.Tags)-1] + filePath, err := getMarkdownFileForTag(tag.TagProps.Name, parser.markdownFileDir) + if err != nil { + return err + } + + commentInfo, err := ioutil.ReadFile(parser.markdownFileDir + "/" + filePath) + if err != nil { + return errors.New("Failed to find matching markdown file for tag: " + tag.TagProps.Name + " error: " + err.Error()) + } + + tag.TagProps.Description = string(commentInfo) + replaceLastTag(parser.swagger.Tags, tag) case "@tag.docs.url": commentInfo := strings.TrimSpace(commentLine[len(attribute):]) tag := parser.swagger.Tags[len(parser.swagger.Tags)-1] @@ -357,6 +402,30 @@ func (parser *Parser) ParseGeneralAPIInfo(mainAPIFile string) error { return nil } +func getMarkdownFileForTag(tagName string, dirPath string) (string, error) { + filesInfos, err := ioutil.ReadDir(dirPath) + if err != nil { + return "", err + } + + for _, fileInfo := range filesInfos { + if fileInfo.IsDir() { + continue + } + fileName := fileInfo.Name() + + if !strings.Contains(fileName, ".md") { + continue + } + + if strings.Contains(fileName, tagName) { + return fileName, nil + } + } + + return "", errors.New("Unable to find Markdown file in the given directory") +} + func getScopeScheme(scope string) (string, error) { scopeValue := scope[strings.Index(scope, "@scope."):] if scopeValue == "" { @@ -368,13 +437,13 @@ func getScopeScheme(scope string) (string, error) { func isExistsScope(scope string) (bool, error) { s := strings.Fields(scope) for _, v := range s { - if strings.Index(v, "@scope.") != -1 { - if strings.Index(v, ",") != -1 { + if strings.Contains(v, "@scope.") { + if strings.Contains(v, ",") { return false, fmt.Errorf("@scope can't use comma(,) get=" + v) } } } - return strings.Index(scope, "@scope.") != -1, nil + return strings.Contains(scope, "@scope."), nil } // getSchemes parses swagger schemes for given commentLine @@ -899,9 +968,13 @@ func (parser *Parser) parseField(field *ast.Field) (*structField, error) { return nil, err } if len(prop.ArrayType) == 0 { - CheckSchemaType(prop.SchemaType) + if err := CheckSchemaType(prop.SchemaType); err != nil { + return nil, err + } } else { - CheckSchemaType("array") + if err := CheckSchemaType("array"); err != nil { + return nil, err + } } structField := &structField{ name: field.Names[0].Name, @@ -956,8 +1029,12 @@ func (parser *Parser) parseField(field *ast.Field) (*structField, error) { } } - CheckSchemaType(newSchemaType) - CheckSchemaType(newArrayType) + if err := CheckSchemaType(newSchemaType); err != nil { + return nil, err + } + if err := CheckSchemaType(newArrayType); err != nil { + return nil, err + } structField.schemaType = newSchemaType structField.arrayType = newArrayType } diff --git a/parser_test.go b/parser_test.go index e59af253a..562f57c24 100644 --- a/parser_test.go +++ b/parser_test.go @@ -94,7 +94,8 @@ func TestParser_ParseGeneralApiInfo(t *testing.T) { gopath := os.Getenv("GOPATH") assert.NotNil(t, gopath) p := New() - p.ParseGeneralAPIInfo("testdata/main.go") + err := p.ParseGeneralAPIInfo("testdata/main.go") + assert.NoError(t, err) b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) @@ -172,7 +173,8 @@ func TestParser_ParseGeneralApiInfoTemplated(t *testing.T) { gopath := os.Getenv("GOPATH") assert.NotNil(t, gopath) p := New() - p.ParseGeneralAPIInfo("testdata/templated.go") + err := p.ParseGeneralAPIInfo("testdata/templated.go") + assert.NoError(t, err) b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) @@ -197,7 +199,8 @@ func TestParser_ParseGeneralApiInfoWithOpsInSameFile(t *testing.T) { gopath := os.Getenv("GOPATH") assert.NotNil(t, gopath) p := New() - p.ParseGeneralAPIInfo("testdata/single_file_api/main.go") + err := p.ParseGeneralAPIInfo("testdata/single_file_api/main.go") + assert.NoError(t, err) b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) @@ -214,8 +217,9 @@ func TestGetAllGoFileInfo(t *testing.T) { searchDir := "testdata/pet" p := New() - p.getAllGoFileInfo(searchDir) + err := p.getAllGoFileInfo(searchDir) + assert.NoError(t, err) assert.NotEmpty(t, p.files["testdata/pet/main.go"]) assert.NotEmpty(t, p.files["testdata/pet/web/handler.go"]) assert.Equal(t, 2, len(p.files)) @@ -225,7 +229,8 @@ func TestParser_ParseType(t *testing.T) { searchDir := "testdata/simple/" p := New() - p.getAllGoFileInfo(searchDir) + err := p.getAllGoFileInfo(searchDir) + assert.NoError(t, err) for _, file := range p.files { p.ParseType(file) @@ -877,7 +882,9 @@ func TestParseSimpleApi1(t *testing.T) { mainAPIFile := "main.go" p := New() p.PropNamingStrategy = PascalCase - p.ParseAPI(searchDir, mainAPIFile) + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) + b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) } @@ -1365,7 +1372,9 @@ func TestParseSimpleApi_ForSnakecase(t *testing.T) { mainAPIFile := "main.go" p := New() p.PropNamingStrategy = SnakeCase - p.ParseAPI(searchDir, mainAPIFile) + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) + b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) } @@ -1825,7 +1834,9 @@ func TestParseSimpleApi_ForLowerCamelcase(t *testing.T) { searchDir := "testdata/simple3" mainAPIFile := "main.go" p := New() - p.ParseAPI(searchDir, mainAPIFile) + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) + b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) } @@ -1935,7 +1946,8 @@ func TestParseStructComment(t *testing.T) { searchDir := "testdata/struct_comment" mainAPIFile := "main.go" p := New() - p.ParseAPI(searchDir, mainAPIFile) + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) } @@ -1967,8 +1979,8 @@ func TestParsePetApi(t *testing.T) { searchDir := "testdata/pet" mainAPIFile := "main.go" p := New() - p.ParseAPI(searchDir, mainAPIFile) - + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) } @@ -2121,8 +2133,8 @@ func TestParseModelNotUnderRoot(t *testing.T) { searchDir := "testdata/model_not_under_root/cmd" mainAPIFile := "main.go" p := New() - p.ParseAPI(searchDir, mainAPIFile) - + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) } @@ -2191,7 +2203,8 @@ func TestParseModelAsTypeAlias(t *testing.T) { searchDir := "testdata/alias_type" mainAPIFile := "main.go" p := New() - p.ParseAPI(searchDir, mainAPIFile) + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) b, _ := json.MarshalIndent(p.swagger, "", " ") assert.Equal(t, expected, string(b)) @@ -2201,7 +2214,8 @@ func TestParseComposition(t *testing.T) { searchDir := "testdata/composition" mainAPIFile := "main.go" p := New() - p.ParseAPI(searchDir, mainAPIFile) + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) expected, err := ioutil.ReadFile(path.Join(searchDir, "expected.json")) assert.NoError(t, err) @@ -2422,7 +2436,8 @@ func Test3(){ func TestSkip(t *testing.T) { folder1 := "/tmp/vendor" - os.Mkdir(folder1, os.ModePerm) + err := os.Mkdir(folder1, os.ModePerm) + assert.NoError(t, err) f1, _ := os.Stat(folder1) parser := New() @@ -2431,7 +2446,8 @@ func TestSkip(t *testing.T) { assert.NoError(t, os.Remove(folder1)) folder2 := "/tmp/.git" - os.Mkdir(folder2, os.ModePerm) + err = os.Mkdir(folder2, os.ModePerm) + assert.NoError(t, err) f2, _ := os.Stat(folder2) assert.True(t, parser.Skip(folder2, f2) == filepath.SkipDir) @@ -2444,7 +2460,9 @@ func TestSkip(t *testing.T) { func TestSkipMustParseVendor(t *testing.T) { folder1 := "/tmp/vendor" - os.Mkdir(folder1, os.ModePerm) + err := os.Mkdir(folder1, os.ModePerm) + assert.NoError(t, err) + f1, _ := os.Stat(folder1) parser := New() @@ -2454,7 +2472,9 @@ func TestSkipMustParseVendor(t *testing.T) { assert.NoError(t, os.Remove(folder1)) folder2 := "/tmp/.git" - os.Mkdir(folder2, os.ModePerm) + err = os.Mkdir(folder2, os.ModePerm) + assert.NoError(t, err) + f2, _ := os.Stat(folder2) assert.True(t, parser.Skip(folder2, f2) == filepath.SkipDir) @@ -2485,7 +2505,7 @@ func TestSkipMustParseVendor(t *testing.T) { // for i := 0; i < 100; i++ { // p := New() // p.PropNamingStrategy = PascalCase -// p.ParseAPI(searchDir, mainAPIFile) +// err := p.ParseAPI(searchDir, mainAPIFile) // b, _ := json.MarshalIndent(p.swagger, "", " ") // assert.NotEqual(t, "", string(b)) @@ -2502,31 +2522,63 @@ func TestSkipMustParseVendor(t *testing.T) { func TestApiParseTag(t *testing.T) { searchDir := "testdata/tags" mainAPIFile := "main.go" - p := New() + p := New(SetMarkdownFileDirectory(searchDir)) p.PropNamingStrategy = PascalCase - p.ParseAPI(searchDir, mainAPIFile) + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) - if len(p.swagger.Tags) != 2 { - t.Log("Number of tags did not match") - t.Fail() + if len(p.swagger.Tags) != 3 { + t.Error("Number of tags did not match") } dogs := p.swagger.Tags[0] if dogs.TagProps.Name != "dogs" || dogs.TagProps.Description != "Dogs are cool" { - t.Log("Failed to parse dogs name or description") - t.Fail() + t.Error("Failed to parse dogs name or description") } cats := p.swagger.Tags[1] if cats.TagProps.Name != "cats" || cats.TagProps.Description != "Cats are the devil" { - t.Log("Failed to parse cats name or description") - t.Fail() + t.Error("Failed to parse cats name or description") } if cats.TagProps.ExternalDocs.URL != "https://google.de" || cats.TagProps.ExternalDocs.Description != "google is super useful to find out that cats are evil!" { - t.Log("URL: ", cats.TagProps.ExternalDocs.URL) - t.Log("Description: ", cats.TagProps.ExternalDocs.Description) - t.Log("Failed to parse cats external documentation") - t.Fail() + t.Error("URL: ", cats.TagProps.ExternalDocs.URL) + t.Error("Description: ", cats.TagProps.ExternalDocs.Description) + t.Error("Failed to parse cats external documentation") + } +} + +func TestParseTagMarkdownDescription(t *testing.T) { + searchDir := "testdata/tags" + mainAPIFile := "main.go" + p := New(SetMarkdownFileDirectory(searchDir)) + p.PropNamingStrategy = PascalCase + err := p.ParseAPI(searchDir, mainAPIFile) + if err != nil { + t.Error("Failed to parse api description: " + err.Error()) + } + + if len(p.swagger.Tags) != 3 { + t.Error("Number of tags did not match") + } + + apes := p.swagger.Tags[2] + if apes.TagProps.Description == "" { + t.Error("Failed to parse tag description markdown file") + } +} + +func TestParseApiMarkdownDescription(t *testing.T) { + searchDir := "testdata/tags" + mainAPIFile := "main.go" + p := New(SetMarkdownFileDirectory(searchDir)) + p.PropNamingStrategy = PascalCase + err := p.ParseAPI(searchDir, mainAPIFile) + if err != nil { + t.Error("Failed to parse api description: " + err.Error()) + } + + if p.swagger.Info.Description == "" { + t.Error("Failed to parse api description: " + err.Error()) } } diff --git a/property_test.go b/property_test.go index 130ff064c..ec0559038 100644 --- a/property_test.go +++ b/property_test.go @@ -274,22 +274,26 @@ func TestGetPropertyNameInterface(t *testing.T) { func TestParseTag(t *testing.T) { searchDir := "testdata/tags" mainAPIFile := "main.go" - p := New() + p := New(SetMarkdownFileDirectory(searchDir)) p.PropNamingStrategy = PascalCase - p.ParseAPI(searchDir, mainAPIFile) + err := p.ParseAPI(searchDir, mainAPIFile) + assert.NoError(t, err) - if len(p.swagger.Tags) != 2 { + if len(p.swagger.Tags) != 3 { + t.Log(len(p.swagger.Tags)) t.Log("Number of tags did not match") - t.Fail() + t.FailNow() } dogs := p.swagger.Tags[0] if dogs.TagProps.Name != "dogs" || dogs.TagProps.Description != "Dogs are cool" { t.Log("Failed to parse dogs name or description") + t.FailNow() } cats := p.swagger.Tags[1] - if cats.TagProps.Name != "cats" || dogs.TagProps.Description != "Cats are the devil" { + if cats.TagProps.Name != "cats" || cats.TagProps.Description != "Cats are the devil" { t.Log("Failed to parse cats name or description") + t.FailNow() } } diff --git a/testdata/simple2/docs/docs.go b/testdata/simple2/docs/docs.go index da14fd437..d624624ac 100644 --- a/testdata/simple2/docs/docs.go +++ b/testdata/simple2/docs/docs.go @@ -1,6 +1,6 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at -// 2019-03-21 18:50:45.048401 +0900 JST m=+0.038855337 +// 2019-06-12 14:11:08.278195965 +0200 CEST m=+0.065173340 package docs diff --git a/testdata/simple3/docs/docs.go b/testdata/simple3/docs/docs.go index ccb272a97..7e1d0ce52 100644 --- a/testdata/simple3/docs/docs.go +++ b/testdata/simple3/docs/docs.go @@ -1,6 +1,6 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at -// 2019-03-21 18:50:45.056315 +0900 JST m=+0.046769114 +// 2019-06-12 14:11:08.291157752 +0200 CEST m=+0.078135144 package docs diff --git a/testdata/tags/apes.md b/testdata/tags/apes.md new file mode 100644 index 000000000..5e6434d9f --- /dev/null +++ b/testdata/tags/apes.md @@ -0,0 +1,3 @@ +## Apes + +Apes are very cool! \ No newline at end of file diff --git a/testdata/tags/api.md b/testdata/tags/api.md new file mode 100644 index 000000000..94c5bda83 --- /dev/null +++ b/testdata/tags/api.md @@ -0,0 +1,5 @@ +## CoolApi Title + +### Cool API SubTitle + +We love markdown! \ No newline at end of file diff --git a/testdata/tags/main.go b/testdata/tags/main.go index 8b1b7b5d7..381d545f9 100644 --- a/testdata/tags/main.go +++ b/testdata/tags/main.go @@ -1,9 +1,12 @@ package main +// @description.markdown // @tag.name dogs // @tag.description Dogs are cool // @tag.name cats // @tag.description Cats are the devil // @tag.docs.url https://google.de // @tag.docs.description google is super useful to find out that cats are evil! +// @tag.name apes +// @tag.description.markdown func main() {}