diff --git a/changelog.md b/changelog.md index e5f2e1549c..369a2c0cb6 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,7 @@ - [#4001](https://github.com/ignite/cli/pull/4001) Improve `xgenny` dry run - [#3967](https://github.com/ignite/cli/issues/3967) Add HD wallet parameters `address index` and `account number` to the chain account config - [#4004](https://github.com/ignite/cli/pull/4004) Remove all import placeholders using the `xast` pkg +- [#4077](https://github.com/ignite/cli/pull/4077) Merge the swagger files manually instead use nodetime `swagger-combine` ### Changes diff --git a/go.mod b/go.mod index 73cf9d666c..93a71fb2b9 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,9 @@ require ( github.com/emicklei/proto-contrib v0.15.0 github.com/go-delve/delve v1.21.0 github.com/go-git/go-git/v5 v5.12.0 + github.com/go-openapi/analysis v0.23.0 + github.com/go-openapi/loads v0.22.0 + github.com/go-openapi/spec v0.21.0 github.com/gobuffalo/genny/v2 v2.1.0 github.com/gobuffalo/packd v1.0.2 github.com/gobuffalo/plush/v4 v4.1.19 @@ -131,6 +134,7 @@ require ( github.com/andrew-d/go-termutil v0.0.0-20150726205930-009166a695a2 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/ashanbrown/forbidigo v1.6.0 // indirect github.com/ashanbrown/makezero v1.1.1 // indirect github.com/atotto/clipboard v0.1.2 // indirect @@ -231,6 +235,11 @@ require ( github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/errors v0.22.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect github.com/go-toolsmith/astequal v1.2.0 // indirect @@ -303,6 +312,7 @@ require ( github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect github.com/jjti/go-spancheck v0.5.3 // indirect github.com/jmhodges/levigo v1.0.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/ansi v1.0.3 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/jpillora/requestlog v1.0.0 // indirect @@ -329,6 +339,7 @@ require ( github.com/lufeee/execinquery v1.2.1 // indirect github.com/macabu/inamedparam v0.1.3 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/maratori/testableexamples v1.0.0 // indirect github.com/maratori/testpackage v1.1.1 // indirect github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect @@ -363,6 +374,7 @@ require ( github.com/nunnatsa/ginkgolinter v0.16.2 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect @@ -446,6 +458,7 @@ require ( gitlab.com/bosi/decorder v0.4.1 // indirect go-simpler.org/musttag v0.9.0 // indirect go-simpler.org/sloglint v0.5.0 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect diff --git a/go.sum b/go.sum index 0b26c74595..1f52bdbe78 100644 --- a/go.sum +++ b/go.sum @@ -179,6 +179,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= @@ -557,6 +559,22 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= @@ -928,6 +946,7 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/ansi v1.0.3 h1:nn4Jzti0EmRfDxm7JtEs5LzCbNwd5sv+0aE+LdS9/ZQ= github.com/jpillora/ansi v1.0.3/go.mod h1:D2tT+6uzJvN1nBVQILYWkIdq7zG+b5gcFN5WI/VyjMY= @@ -1025,6 +1044,7 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= @@ -1172,6 +1192,7 @@ github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtb github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= @@ -1542,6 +1563,8 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= diff --git a/ignite/pkg/cosmosgen/generate_openapi.go b/ignite/pkg/cosmosgen/generate_openapi.go index b91eb5c018..ebc029f6c3 100644 --- a/ignite/pkg/cosmosgen/generate_openapi.go +++ b/ignite/pkg/cosmosgen/generate_openapi.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "path/filepath" - "sort" "github.com/iancoleman/strcase" @@ -13,8 +12,7 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/cosmosanalysis/module" "github.com/ignite/cli/v29/ignite/pkg/dirchange" "github.com/ignite/cli/v29/ignite/pkg/errors" - "github.com/ignite/cli/v29/ignite/pkg/nodetime" - swaggercombine "github.com/ignite/cli/v29/ignite/pkg/nodetime/programs/swagger-combine" + swaggercombine "github.com/ignite/cli/v29/ignite/pkg/swagger-combine" "github.com/ignite/cli/v29/ignite/pkg/xos" ) @@ -34,18 +32,8 @@ func (g *generator) openAPITemplateForSTA() string { func (g *generator) generateOpenAPISpec(ctx context.Context) error { var ( specDirs []string - conf = swaggercombine.Config{ - Swagger: "2.0", - Info: swaggercombine.Info{ - Title: "HTTP API Console", - }, - } + conf = swaggercombine.New("HTTP API Console", g.gomodPath) ) - command, cleanup, err := nodetime.Command(nodetime.CommandSwaggerCombine) - if err != nil { - return err - } - defer cleanup() defer func() { for _, dir := range specDirs { os.RemoveAll(dir) @@ -149,100 +137,53 @@ func (g *generator) generateOpenAPISpec(ctx context.Context) error { } } - sort.Slice(conf.APIs, func(a, b int) bool { return conf.APIs[a].ID < conf.APIs[b].ID }) - - // ensure out dir exists. - outDir := filepath.Dir(out) - if err := os.MkdirAll(outDir, 0o766); err != nil { - return err - } - // combine specs into one and save to out. - if err := swaggercombine.Combine(ctx, conf, command, out); err != nil { + if err := conf.Combine(out); err != nil { return err } return dirchange.SaveDirChecksum(specCache, out, g.appPath, out) } +// generateModuleOpenAPISpec generates a spec for a module where it's source code resides at src. +// and adds needed swaggercombine configure for it. func (g *generator) generateModuleOpenAPISpec(ctx context.Context, m module.Module, out string) error { var ( specDirs []string - conf = swaggercombine.Config{ - Swagger: "2.0", - Info: swaggercombine.Info{ - Title: "HTTP API Console " + m.Pkg.Name, - }, - } + title = "HTTP API Console " + m.Pkg.Name + conf = swaggercombine.New(title, g.gomodPath) ) - command, cleanup, err := nodetime.Command(nodetime.CommandSwaggerCombine) - if err != nil { - return err - } - defer cleanup() - defer func() { for _, dir := range specDirs { os.RemoveAll(dir) } }() - // gen generates a spec for a module where it's source code resides at src. - // and adds needed swaggercombine configure for it. - gen := func(m module.Module) (err error) { - dir, err := os.MkdirTemp("", "gen-openapi-module-spec") - if err != nil { - return err - } - - err = g.buf.Generate(ctx, m.Pkg.Path, dir, g.openAPITemplateForSTA(), "module.proto") - if err != nil { - return err - } - - specs, err := xos.FindFiles(dir, xos.JSONFile) - if err != nil { - return err - } - - for _, spec := range specs { - if err != nil { - return err - } - if err := conf.AddSpec(strcase.ToCamel(m.Pkg.Name), spec, false); err != nil { - return err - } - } - specDirs = append(specDirs, dir) - - return nil - } - // generate specs for each module and persist them in the file system // after add their path and config to swaggercombine.Config so we can combine them // into a single spec. - - add := func(modules []module.Module) error { - for _, m := range modules { - if err := gen(m); err != nil { - return err - } - } - return nil + dir, err := os.MkdirTemp("", "gen-openapi-module-spec") + if err != nil { + return err } - // protoc openapi generator acts weird on concurrent run, so do not use goroutines here. - if err := add([]module.Module{m}); err != nil { + err = g.buf.Generate(ctx, m.Pkg.Path, dir, g.openAPITemplateForSTA(), "module.proto") + if err != nil { return err } - sort.Slice(conf.APIs, func(a, b int) bool { return conf.APIs[a].ID < conf.APIs[b].ID }) - - // ensure out dir exists. - outDir := filepath.Dir(out) - if err := os.MkdirAll(outDir, 0o766); err != nil { + specs, err := xos.FindFiles(dir, xos.JSONFile) + if err != nil { return err } + + for _, spec := range specs { + if err := conf.AddSpec(strcase.ToCamel(m.Pkg.Name), spec, false); err != nil { + return err + } + } + specDirs = append(specDirs, dir) + // combine specs into one and save to out. - return swaggercombine.Combine(ctx, conf, command, out) + return conf.Combine(out) } diff --git a/ignite/pkg/nodetime/programs/swagger-combine/swagger-combine.go b/ignite/pkg/nodetime/programs/swagger-combine/swagger-combine.go deleted file mode 100644 index da4a85dc4e..0000000000 --- a/ignite/pkg/nodetime/programs/swagger-combine/swagger-combine.go +++ /dev/null @@ -1,107 +0,0 @@ -package swaggercombine - -import ( - "context" - "encoding/json" - "io" - "os" - "regexp" - - "github.com/ignite/cli/v29/ignite/pkg/cmdrunner/exec" -) - -// Config represent swagger-combine config. -type Config struct { - Swagger string `json:"swagger"` - Info Info `json:"info"` - APIs []API `json:"apis"` -} - -type Info struct { - Title string `json:"title"` - Name string `json:"name"` - Description string `json:"description"` -} - -type API struct { - ID string `json:"-"` - URL string `json:"url"` - OperationIDs OperationIDs `json:"operationIds"` - Dereference struct { - Circular string `json:"circular"` - } `json:"dereference"` -} - -type OperationIDs struct { - Rename map[string]string `json:"rename"` -} - -var opReg = regexp.MustCompile(`(?m)operationId.+?(\w+)`) - -// AddSpec adds a new OpenAPI spec to Config by path in the fs and unique id of spec. -func (c *Config) AddSpec(id, path string, makeUnique bool) error { - // make operationId fields unique. - f, err := os.Open(path) - if err != nil { - return err - } - defer f.Close() - - content, err := io.ReadAll(f) - if err != nil { - return err - } - - ops := opReg.FindAllStringSubmatch(string(content), -1) - rename := make(map[string]string, len(ops)) - - for _, op := range ops { - o := op[1] - if makeUnique { - rename[o] = id + o - } else { - rename[o] = o - } - } - - // add api with replaced operation ids. - c.APIs = append(c.APIs, API{ - ID: id, - URL: path, - OperationIDs: OperationIDs{Rename: rename}, - // Added due to https://github.com/maxdome/swagger-combine/pull/110 after enabling more services to be generated in #835 - Dereference: struct { - Circular string `json:"circular"` - }(struct{ Circular string }{Circular: "ignore"}), - }) - - return nil -} - -// Combine combines openapi specs into one and saves to out path. -// specs is a spec id-fs path pair. -func Combine(ctx context.Context, c Config, command []string, out string) error { - f, err := os.CreateTemp("", "*.json") - if err != nil { - return err - } - defer os.Remove(f.Name()) - - if err := json.NewEncoder(f).Encode(c); err != nil { - return err - } - if err := f.Close(); err != nil { - return err - } - - command = append(command, []string{ - f.Name(), - "-o", out, - "-f", "yaml", - "--continueOnConflictingPaths", "true", - "--includeDefinitions", "true", - }...) - - // execute the command. - return exec.Exec(ctx, command, exec.IncludeStdLogsToError()) -} diff --git a/ignite/pkg/swagger-combine/swagger-combine.go b/ignite/pkg/swagger-combine/swagger-combine.go new file mode 100644 index 0000000000..b44d144e94 --- /dev/null +++ b/ignite/pkg/swagger-combine/swagger-combine.go @@ -0,0 +1,121 @@ +package swaggercombine + +import ( + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/go-openapi/analysis" + "github.com/go-openapi/loads" + "github.com/go-openapi/spec" + + "github.com/ignite/cli/v29/ignite/pkg/errors" +) + +// Config represent swagger-combine config. +type Config struct { + spec *spec.Swagger + specs []*spec.Swagger +} + +// New create a mew swagger combine config. +func New(title, name string) *Config { + return &Config{ + spec: &spec.Swagger{ + SwaggerProps: spec.SwaggerProps{ + ID: name, + Swagger: "2.0", + Info: &spec.Info{ + InfoProps: spec.InfoProps{ + Description: fmt.Sprintf("Chain %s REST API", name), + Title: title, + Contact: &spec.ContactInfo{ContactInfoProps: spec.ContactInfoProps{Name: name}}, + }, + }, + Definitions: make(spec.Definitions), + }, + }, + specs: make([]*spec.Swagger, 0), + } +} + +// AddSpec adds a new OpenAPI spec to Config by path in the fs and unique id of spec. +func (c *Config) AddSpec(id, path string, makeUnique bool) error { + baseDoc, err := loads.Spec(path) + if err != nil { + return errors.Wrapf(err, "failed to load spec from path %s", path) + } + + spec := baseDoc.Spec() + if makeUnique { + for i, specPath := range spec.Paths.Paths { + if specPath.Get != nil { + specPath.Get.ID = id + specPath.Get.ID + } + if specPath.Post != nil { + specPath.Post.ID = id + specPath.Post.ID + } + spec.Paths.Paths[i] = specPath + } + } + + c.specs = append(c.specs, c.mergeTags(c.mergeDefinitions(spec))) + + return nil +} + +// mergeDefinitions merge spec definitions with main spec and erase the spec definition. +func (c *Config) mergeDefinitions(m *spec.Swagger) *spec.Swagger { + for k, v := range m.Definitions { + if _, exists := c.spec.Definitions[k]; exists { + continue + } + c.spec.Definitions[k] = v + } + m.Definitions = nil + return m +} + +// mergeTags merge spec tags with main spec and erase the spec tag. +func (c *Config) mergeTags(m *spec.Swagger) *spec.Swagger { + for _, v := range m.Tags { + found := false + for _, vv := range c.spec.Tags { + if v.Name == vv.Name { + found = true + break + } + } + if found { + continue + } + c.spec.Tags = append(c.spec.Tags, v) + } + m.Tags = nil + return m +} + +// Combine combines openapi specs into one and saves to out path. +func (c *Config) Combine(out string) error { + sort.Slice(c.specs, func(a, b int) bool { return c.specs[a].ID < c.specs[b].ID }) + + errs := analysis.Mixin(c.spec, c.specs...) + if len(errs) > 0 { + return errors.Errorf("invalid mix specs: %s", strings.Join(errs, ", ")) + } + specJSON, err := c.spec.MarshalJSON() + if err != nil { + return err + } + // ensure out dir exists. + outDir := filepath.Dir(out) + if err := os.MkdirAll(outDir, 0o766); err != nil { + return err + } + if err = os.WriteFile(out, specJSON, 0o644); err != nil { + return errors.Wrapf(err, "failed to write combined spec to file %s", out) + } + return nil +}