Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.idea
.DS_Store
.vscode/
.vscode/
coverage-all.out
coverage.out
test-coverage.html
test-results.out
11 changes: 11 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
linters:
enable-all: false
presets:
- bugs
- complexity
- unused
disable-all: false
disable:
- gochecknoinits
- dupl
- gochecknoglobals
83 changes: 76 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,81 @@
help:
@echo "This is a helper makefile for oapi-codegen"
@echo "Targets:"
@echo " generate: regenerate all generated files"
@echo " test: run all tests"
#
# Makefile to build the Blue Secrets Service (Certificate Manager)
#
.PHONY: all lint test
.PHONY: debug-build debug
.PHONY: semver clean deps
.PHONY: int-test

#
# Constants and runtime variables
#
PACKAGE = oapi-codegen
PACKAGE_PATH = gitswarm.f5net.com/indigo/product/controller-thirdparty
FULL_PACKAGE = $(PACKAGE_PATH)/$(PACKAGE)
GO_PKGS = $(shell go list ./... | grep -v test)
GO_PKGS_PATH = $(shell go list -f '{{.Dir}}' ./... | grep -v test)
DOCKER_TAG ?= latest
OUT_DIR ?= build
DEBUG_PACKAGE = $(PACKAGE)-debug


MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
MKFILE_DIR := $(dir $(MKFILE_PATH))
INTEGRATION_DIR = "$(MKFILE_DIR)/test/integration"

TEST_TOOL_NAME = "test_tool.sh"
TEST_TOOL = "$(INTEGRATION_DIR)/$(TEST_TOOL_NAME)"

#
# Targets used for local development
#
all: test lint

export OUT_DIR

clean:
rm -rf ./build_version coverage* test-coverage.html ./deploy test-results.out \
unit_tests.xml full-lint-report.xml $(OUT_DIR)

#
# Generate the template inline files and *.gen.go files
#
generate:
go generate ./pkg/...
go generate ./...
goimports -w ./

#
# Run all tests and aggregate results into single coverage output.
# TODO: want to include -race flag with go test.
#
ifdef VERBOSE
test: generate
@echo "mode: set" > coverage-all.out

@go test -v -timeout 30s -tags unit -coverprofile=coverage.out -race ./... | \
tee -a test-results.out || exit 1 \
tail -n +2 coverage.out >> coverage-all.out || exit 1
@go tool cover -func=coverage-all.out && \
go tool cover -html=coverage-all.out -o test-coverage.html
else
test: generate
@echo "mode: set" > coverage-all.out

@go test -timeout 30s -tags unit -coverprofile=coverage.out -race ./... | \
tee -a test-results.out || exit 1;\
tail -n +2 coverage.out >> coverage-all.out || exit 1
@go tool cover -html=coverage-all.out -o test-coverage.html
endif

#
# Utilities targets
#
# run:
# $(OUT_DIR)/$(PACKAGE)
#
# Lint go code non-critical checks
#
lint:
echo "ignoring lint on this project"

test:
go test -cover ./...
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ write a lot of boilerplate code to perform all the marshalling and unmarshalling
into objects which match the OpenAPI 3.0 definition. The code generator in this
directory does a lot of that for you. You would run it like so:

go get github.com/deepmap/oapi-codegen/cmd/oapi-codegen
go get github.com/weberr13/oapi-codegen/cmd/oapi-codegen
oapi-codegen petstore-expanded.yaml > petstore.gen.go

Let's go through that `petstore.gen.go` file to show you everything which was
Expand Down Expand Up @@ -454,4 +454,4 @@ Go file.
Afterwards you should run `go generate ./...`, and the templates will be updated
accordingly.


>
145 changes: 136 additions & 9 deletions cmd/oapi-codegen/oapi-codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,74 @@ import (
"flag"
"fmt"
"io/ioutil"
"net/url"
"os"
"path/filepath"
"strings"

"github.com/deepmap/oapi-codegen/pkg/codegen"
"github.com/deepmap/oapi-codegen/pkg/util"
"github.com/weberr13/oapi-codegen/pkg/codegen"
"github.com/weberr13/oapi-codegen/pkg/util"
)

func errExit(format string, args ...interface{}) {
_, _ = fmt.Fprintf(os.Stderr, format, args...)
os.Exit(1)
}

func usageErr(format string, args ...interface{}) {
_, _ = fmt.Fprintf(os.Stderr, format, args...)
flag.PrintDefaults()
os.Exit(1)
}

// TODO define a type to allow recording of Type -> Import Path as args
// TODO this is temporary until we sort the config question
type refImports []string

func (ri *refImports) String() string {
return "Reference Import arg"
}

func (ri *refImports) Set(r string) error {
*ri = append(*ri, r)
return nil
}

// TODO define a type to allow recording of package -> Import Path as args
// TODO this is temporary until we sort the config question
type pkgImports []string

func (pi *pkgImports) String() string {
return "Pkg Import arg"
}

func (pi *pkgImports) Set(r string) error {
*pi = append(*pi, r)
return nil
}

func main() {
var (
packageName string
generate string
outputFile string
includeTags string
excludeTags string
refImports refImports
pkgImports pkgImports
allowRefs bool
insecure bool
)

flag.StringVar(&packageName, "package", "", "The package name for generated code")
flag.StringVar(&generate, "generate", "types,client,server,spec",
`Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "skip-fmt", "spec"`)
flag.StringVar(&outputFile, "o", "", "Where to output generated code, stdout is default")
flag.StringVar(&includeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.")
flag.StringVar(&excludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.")
flag.Var(&refImports, "ri", "Repeated reference import statements of the form Type=<[package:]import path>")
flag.Var(&pkgImports, "pi", "Repeated package import statements of the form <package>=<[package:]import path>")
flag.BoolVar(&allowRefs, "extrefs", false, "Allow resolving external references")
flag.BoolVar(&insecure, "insecure", false, "Allow resolving remote URL's that have bad SSL/TLS")
flag.Parse()

if flag.NArg() < 1 {
Expand Down Expand Up @@ -76,10 +117,12 @@ func main() {
opts.EmbedSpec = true
case "skip-fmt":
opts.SkipFmt = true
case "resolved-spec":
opts.ClearRefsSpec = true
opts.EmbedSpec = true
default:
fmt.Printf("unknown generate option %s\n", g)
flag.PrintDefaults()
os.Exit(1)
// never returns
usageErr("unknown generate option %s\n", g)
}
}

Expand All @@ -90,9 +133,21 @@ func main() {
errExit("can not specify both server and chi-server targets simultaneously")
}

swagger, err := util.LoadSwagger(flag.Arg(0))
if opts.ClearRefsSpec && (opts.GenerateClient || opts.GenerateServer || opts.GenerateTypes) {
// never returns
usageErr("resolved-spec option is only valid when specified on its own")
}

// Add user defined type -> import mapping
opts.ImportedTypes = importPackages(pkgImports, allowRefs, insecure)
// override with specific imports if so indicated
for k, v := range importTypes(refImports) {
opts.ImportedTypes[k] = v
}

swagger, err := util.LoadSwagger(flag.Arg(0), allowRefs, insecure, opts.ClearRefsSpec)
if err != nil {
errExit("error loading swagger spec\n: %s", err)
errExit("error loading swagger spec:\n%s\n", err)
}

code, err := codegen.Generate(swagger, packageName, opts)
Expand All @@ -103,7 +158,7 @@ func main() {
if outputFile != "" {
err = ioutil.WriteFile(outputFile, []byte(code), 0644)
if err != nil {
errExit("error writing generated code to file: %s", err)
errExit("error writing generated code to file: %s\n", err)
}
} else {
fmt.Println(code)
Expand All @@ -125,3 +180,75 @@ func splitCSVArg(input string) []string {
}
return args
}

func mapArgSlice(as []string, an string) map[string]string {
m := map[string]string{}
for _, ri := range as {
parts := strings.Split(ri, "=")
if len(parts) != 2 {
fmt.Printf("invalid %s arg. %s\n", an, ri)
flag.PrintDefaults()
os.Exit(1)
}
m[parts[0]] = parts[1]
}
return m
}

func importPackages(imports pkgImports, allowRefs, insecure bool) map[string]codegen.TypeImportSpec {
importedTypes := map[string]codegen.TypeImportSpec{}
pi := mapArgSlice(imports, "package import")

for sr, p := range pi {
var u *url.URL
var err error

if u, err = url.Parse(sr); err != nil {
errExit("package import: specified schema ref is not a URL:\n%s\n", err)
}
swagger, err := util.LoadSwaggerFromURL(u, allowRefs, insecure)
if err != nil {
errExit("package import: error loading swagger spec:\n%s\n", err)
}

// iterate over model to find schema names - extract only top level names
for n := range swagger.Components.Schemas {
if _, ok := importedTypes[n]; !ok {
importedTypes[n] = getImportedType(n, p)
}
}
}
return importedTypes
}

func importTypes(typeImports refImports) map[string]codegen.TypeImportSpec {
importedTypes := map[string]codegen.TypeImportSpec{}
pi := mapArgSlice(typeImports, "type imports")

for t, p := range pi {
importedTypes[t] = getImportedType(t, p)
}
return importedTypes
}

func getImportedType(typeName, pkgImport string) codegen.TypeImportSpec {
var pkgName string
var impPath string

// if a package name was specified in the form pkg:<import path>, use that, otherwise use last part of import path
parts := strings.Split(pkgImport, ":")
if len(parts) > 2 {
errExit("Parsing type import: too many fragments. At most one ':' expected (type:%s, import:%s)", typeName, pkgImport)
}

if len(parts) == 2 {
pkgName = parts[0]
impPath = parts[1]
} else {
parts = strings.Split(pkgImport, "/")
pkgName = parts[len(parts)-1]
impPath = pkgImport
}

return codegen.NewTypeImportSpec(typeName, pkgName, impPath)
}
18 changes: 4 additions & 14 deletions examples/petstore-expanded/chi/api/petstore.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 4 additions & 8 deletions examples/petstore-expanded/echo/api/petstore-server.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading