forked from swaggo/swag
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: remove gomonkey dependency from formatter (swaggo#1192)
- Loading branch information
Atte Kojo
authored and
jixiufeng
committed
May 17, 2022
1 parent
fa3b9d8
commit c8cbd5a
Showing
7 changed files
with
470 additions
and
739 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,118 @@ | ||
package format | ||
|
||
import ( | ||
"log" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/swaggo/swag" | ||
) | ||
|
||
type Fmt struct { | ||
// Format implements `fmt` command for formatting swag comments in Go source | ||
// files. | ||
type Format struct { | ||
formatter *swag.Formatter | ||
|
||
// exclude exclude dirs and files in SearchDir | ||
exclude map[string]bool | ||
} | ||
|
||
func New() *Fmt { | ||
return &Fmt{} | ||
// New creates a new Format instance | ||
func New() *Format { | ||
return &Format{ | ||
exclude: map[string]bool{}, | ||
formatter: swag.NewFormatter(), | ||
} | ||
} | ||
|
||
// Config specifies configuration for a format run | ||
type Config struct { | ||
// SearchDir the swag would be parse | ||
SearchDir string | ||
|
||
// excludes dirs and files in SearchDir,comma separated | ||
Excludes string | ||
|
||
// MainFile (DEPRECATED) | ||
MainFile string | ||
} | ||
|
||
func (f *Fmt) Build(config *Config) error { | ||
log.Println("Formating code.... ") | ||
var defaultExcludes = []string{"docs", "vendor"} | ||
|
||
// Build runs formatter according to configuration in config | ||
func (f *Format) Build(config *Config) error { | ||
searchDirs := strings.Split(config.SearchDir, ",") | ||
for _, searchDir := range searchDirs { | ||
if _, err := os.Stat(searchDir); os.IsNotExist(err) { | ||
return fmt.Errorf("fmt: %w", err) | ||
} | ||
for _, d := range defaultExcludes { | ||
f.exclude[filepath.Join(searchDir, d)] = true | ||
} | ||
} | ||
for _, fi := range strings.Split(config.Excludes, ",") { | ||
if fi = strings.TrimSpace(fi); fi != "" { | ||
f.exclude[filepath.Clean(fi)] = true | ||
} | ||
} | ||
for _, searchDir := range searchDirs { | ||
err := filepath.Walk(searchDir, f.visit) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (f *Format) visit(path string, fileInfo os.FileInfo, err error) error { | ||
if fileInfo.IsDir() && f.excludeDir(path) { | ||
return filepath.SkipDir | ||
} | ||
if f.excludeFile(path) { | ||
return nil | ||
} | ||
if err := f.format(path); err != nil { | ||
return fmt.Errorf("fmt: %w", err) | ||
} | ||
return nil | ||
} | ||
|
||
func (f *Format) excludeDir(path string) bool { | ||
return f.exclude[path] || | ||
filepath.Base(path)[0] == '.' && len(filepath.Base(path)) > 1 // exclude hidden folders | ||
} | ||
|
||
func (f *Format) excludeFile(path string) bool { | ||
return f.exclude[path] || | ||
strings.HasSuffix(strings.ToLower(path), "_test.go") || | ||
filepath.Ext(path) != ".go" | ||
} | ||
|
||
func (f *Format) format(path string) error { | ||
contents, err := ioutil.ReadFile(path) | ||
if err != nil { | ||
return err | ||
} | ||
formatted, err := f.formatter.Format(path, contents) | ||
if err != nil { | ||
return err | ||
} | ||
return write(path, formatted) | ||
} | ||
|
||
return swag.NewFormatter().FormatAPI(config.SearchDir, config.Excludes, config.MainFile) | ||
func write(path string, contents []byte) error { | ||
f, err := ioutil.TempFile(filepath.Split(path)) | ||
if err != nil { | ||
return err | ||
} | ||
defer os.Remove(f.Name()) | ||
if _, err := f.Write(contents); err != nil { | ||
return err | ||
} | ||
if err := f.Close(); err != nil { | ||
return err | ||
} | ||
return os.Rename(f.Name(), path) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package format | ||
|
||
import ( | ||
"bytes" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestFormat_Format(t *testing.T) { | ||
fx := setup(t) | ||
assert.NoError(t, New().Build(&Config{SearchDir: fx.basedir})) | ||
assert.True(t, fx.isFormatted("main.go")) | ||
assert.True(t, fx.isFormatted("api/api.go")) | ||
} | ||
|
||
func TestFormat_ExcludeDir(t *testing.T) { | ||
fx := setup(t) | ||
assert.NoError(t, New().Build(&Config{ | ||
SearchDir: fx.basedir, | ||
Excludes: filepath.Join(fx.basedir, "api"), | ||
})) | ||
assert.False(t, fx.isFormatted("api/api.go")) | ||
} | ||
|
||
func TestFormat_ExcludeFile(t *testing.T) { | ||
fx := setup(t) | ||
assert.NoError(t, New().Build(&Config{ | ||
SearchDir: fx.basedir, | ||
Excludes: filepath.Join(fx.basedir, "main.go"), | ||
})) | ||
assert.False(t, fx.isFormatted("main.go")) | ||
} | ||
|
||
func TestFormat_DefaultExcludes(t *testing.T) { | ||
fx := setup(t) | ||
assert.NoError(t, New().Build(&Config{SearchDir: fx.basedir})) | ||
assert.False(t, fx.isFormatted("api/api_test.go")) | ||
assert.False(t, fx.isFormatted("docs/docs.go")) | ||
} | ||
|
||
func TestFormat_ParseError(t *testing.T) { | ||
fx := setup(t) | ||
ioutil.WriteFile(filepath.Join(fx.basedir, "parse_error.go"), []byte(`package main | ||
func invalid() {`), 0644) | ||
assert.Error(t, New().Build(&Config{SearchDir: fx.basedir})) | ||
} | ||
|
||
func TestFormat_ReadError(t *testing.T) { | ||
fx := setup(t) | ||
os.Chmod(filepath.Join(fx.basedir, "main.go"), 0) | ||
assert.Error(t, New().Build(&Config{SearchDir: fx.basedir})) | ||
} | ||
|
||
func TestFormat_WriteError(t *testing.T) { | ||
fx := setup(t) | ||
os.Chmod(fx.basedir, 0555) | ||
assert.Error(t, New().Build(&Config{SearchDir: fx.basedir})) | ||
os.Chmod(fx.basedir, 0755) | ||
} | ||
|
||
func TestFormat_InvalidSearchDir(t *testing.T) { | ||
formatter := New() | ||
assert.Error(t, formatter.Build(&Config{SearchDir: "no_such_dir"})) | ||
} | ||
|
||
type fixture struct { | ||
t *testing.T | ||
basedir string | ||
} | ||
|
||
func setup(t *testing.T) *fixture { | ||
fx := &fixture{ | ||
t: t, | ||
basedir: t.TempDir(), | ||
} | ||
for filename, contents := range testFiles { | ||
fullpath := filepath.Join(fx.basedir, filepath.Clean(filename)) | ||
if err := os.MkdirAll(filepath.Dir(fullpath), 0755); err != nil { | ||
t.Fatal(err) | ||
} | ||
if err := ioutil.WriteFile(fullpath, contents, 0644); err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
return fx | ||
} | ||
|
||
func (fx *fixture) isFormatted(file string) bool { | ||
contents, err := ioutil.ReadFile(filepath.Join(fx.basedir, filepath.Clean(file))) | ||
if err != nil { | ||
fx.t.Fatal(err) | ||
} | ||
return !bytes.Equal(testFiles[file], contents) | ||
} | ||
|
||
var testFiles = map[string][]byte{ | ||
"api/api.go": []byte(`package api | ||
import "net/http" | ||
// @Summary Add a new pet to the store | ||
// @Description get string by ID | ||
func GetStringByInt(w http.ResponseWriter, r *http.Request) { | ||
//write your code | ||
}`), | ||
"api/api_test.go": []byte(`package api | ||
// @Summary API Test | ||
// @Description Should not be formatted | ||
func TestApi(t *testing.T) {}`), | ||
"docs/docs.go": []byte(`package docs | ||
// @Summary Documentation package | ||
// @Description Should not be formatted`), | ||
"main.go": []byte(`package main | ||
import ( | ||
"net/http" | ||
"github.com/swaggo/swag/format/testdata/api" | ||
) | ||
// @title Swagger Example API | ||
// @version 1.0 | ||
func main() { | ||
http.HandleFunc("/testapi/get-string-by-int/", api.GetStringByInt) | ||
}`), | ||
"README.md": []byte(`# Format test`), | ||
} |
Oops, something went wrong.