Skip to content
Merged
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
28 changes: 28 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: "2"

linters:
default: standard
enable:
- godoclint
disable:
- errcheck
settings:
godoclint:
default-rule-set: basic
rules:
- max-len
options:
max-len:
length: 100

formatters:
enable:
- gofmt
- golines
settings:
golines:
max-len: 100
shorten-comments: true

run:
timeout: 5m
12 changes: 5 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ $(NAME): $(wildcard *.go) $(wildcard */*.go)
all: generate test fmt lint staticcheck vet ## Runs a fmt, lint, test, staticcheck, and vet.

.PHONY: fmt
fmt: ## Verifies all files have been `gofmt`ed.
@ echo "+ Verifying all files have been gofmt-ed..."
@if [[ ! -z "$(shell gofmt -s -d . | grep -v -e internal/generate/test_generated -e internal/generate/test_utils | tee /dev/stderr)" ]]; then \
exit 1; \
fi
fmt: tools ## Formats Go code including long line wrapping.
@ echo "+ Formatting Go code..."
@ $(GOBIN)/golangci-lint fmt
Comment on lines +38 to +40
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely not for this pull request but I've been giving a bit of thought to how we use tools in our Go projects. Go 1.24 introduced support for tool dependencies where we can run tools using go tool that are versioned in go.mod separately from our normal dependencies. I'd love for us to switch to something like that rather than maintaining some VERSION_* env vars.


.PHONY: fmt-md
fmt-md: ## Formats markdown files with prettier.
Expand All @@ -49,7 +47,7 @@ fmt-md: ## Formats markdown files with prettier.
.PHONY: lint
lint: tools ## Verifies `golangci-lint` passes.
@ echo "+ Running Go linters..."
@ $(GOBIN)/golangci-lint run -E gofmt
@ $(GOBIN)/golangci-lint run

.PHONY: test
test: ## Runs the go tests.
Expand Down Expand Up @@ -90,7 +88,7 @@ help:
# want to run the linters or generate the SDK.
VERSION_DIR:=$(GOBIN)/versions
VERSION_GOIMPORTS:=v0.33.0
VERSION_GOLANGCILINT:=v1.64.8
VERSION_GOLANGCILINT:=v2.8.0
VERSION_STATICCHECK:=2025.1.1
VERSION_WHATSIT:=053446d

Expand Down
5 changes: 4 additions & 1 deletion internal/generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ func loadAPIFromFile(file string) (*openapi3.T, error) {
// symbolic link target to get the versioned filename, then construct the URL
// to the actual versioned specification.
func getOpenAPISpecURL(omicronVersion string) (*url.URL, error) {
rawURL := fmt.Sprintf("https://raw.githubusercontent.com/oxidecomputer/omicron/%s", omicronVersion)
rawURL := fmt.Sprintf(
"https://raw.githubusercontent.com/oxidecomputer/omicron/%s",
omicronVersion,
)
baseURL, err := url.Parse(rawURL)
if err != nil {
return nil, fmt.Errorf("error parsing base url %q: %w", rawURL, err)
Expand Down
80 changes: 64 additions & 16 deletions internal/generate/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,14 @@ func buildPath(f *os.File, spec *openapi3.T, path string, p *openapi3.PathItem)
return nil
}

func buildMethod(f *os.File, spec *openapi3.T, method string, path string, o *openapi3.Operation, isGetAllPages bool) error {
func buildMethod(
f *os.File,
spec *openapi3.T,
method string,
path string,
o *openapi3.Operation,
isGetAllPages bool,
) error {
respType, pagedRespType, err := getSuccessResponseType(o, isGetAllPages)
if err != nil {
return err
Expand All @@ -141,7 +148,10 @@ func buildMethod(f *os.File, spec *openapi3.T, method string, path string, o *op
}

if o.Tags[0] == "console-auth" {
fmt.Printf("[WARN] TODO: skipping operation %q, since it is for console authentication\n", o.OperationID)
fmt.Printf(
"[WARN] TODO: skipping operation %q, since it is for console authentication\n",
o.OperationID,
)
return nil
}

Expand Down Expand Up @@ -247,7 +257,11 @@ func getSuccessResponseType(o *openapi3.Operation, isGetAllPages bool) (string,
}

if response.Ref != "" {
fmt.Printf("[WARN] TODO: skipping response for %q, since it is a reference: %q\n", name, response.Ref)
fmt.Printf(
"[WARN] TODO: skipping response for %q, since it is a reference: %q\n",
name,
response.Ref,
)
continue
}

Expand All @@ -258,7 +272,11 @@ func getSuccessResponseType(o *openapi3.Operation, isGetAllPages bool) (string,
if items, ok := content.Schema.Value.Properties["items"]; ok {
getAllPagesType = convertToValidGoType("", "", items)
} else {
fmt.Printf("[WARN] TODO: skipping response for %q, since it is a get all pages response and has no `items` property:\n%#v\n", o.OperationID, content.Schema.Value.Properties)
fmt.Printf(
"[WARN] TODO: skipping response for %q, since it is a get all pages response and has no `items` property:\n%#v\n",
o.OperationID,
content.Schema.Value.Properties,
)
return "", "", nil
}
}
Expand All @@ -267,7 +285,10 @@ func getSuccessResponseType(o *openapi3.Operation, isGetAllPages bool) (string,
}

if content.Schema.Value.Type.Is("array") {
return fmt.Sprintf("[]%s", getReferenceSchema(content.Schema.Value.Items)), getAllPagesType, nil
return fmt.Sprintf(
"[]%s",
getReferenceSchema(content.Schema.Value.Items),
), getAllPagesType, nil
}

return fmt.Sprintf("%sResponse", strcase.ToCamel(o.OperationID)), getAllPagesType, nil
Expand All @@ -279,8 +300,8 @@ func getSuccessResponseType(o *openapi3.Operation, isGetAllPages bool) (string,

// cleanPath returns the path as a function we can use for a go template.
func cleanPath(path string) string {
path = strings.Replace(path, "{", "{{.", -1)
return strings.Replace(path, "}", "}}", -1)
path = strings.ReplaceAll(path, "{", "{{.")
return strings.ReplaceAll(path, "}", "}}")
}

// splitDocString inserts newlines into doc comments at approximately 100 character intervals.
Expand Down Expand Up @@ -315,27 +336,42 @@ func writeTpl(f *os.File, config methodTemplate) error {
var err error

if config.IsListAll {
t, err = template.ParseFiles("./templates/listall_method.go.tpl", "./templates/description.go.tpl")
t, err = template.ParseFiles(
"./templates/listall_method.go.tpl",
"./templates/description.go.tpl",
)
if err != nil {
return err
}
} else if config.ResponseType == "" && config.HasBody {
t, err = template.ParseFiles("./templates/no_resptype_body_method.go.tpl", "./templates/description.go.tpl")
t, err = template.ParseFiles(
"./templates/no_resptype_body_method.go.tpl",
"./templates/description.go.tpl",
)
if err != nil {
return err
}
} else if config.ResponseType == "" {
t, err = template.ParseFiles("./templates/no_resptype_method.go.tpl", "./templates/description.go.tpl")
t, err = template.ParseFiles(
"./templates/no_resptype_method.go.tpl",
"./templates/description.go.tpl",
)
if err != nil {
return err
}
} else if config.HasBody {
t, err = template.ParseFiles("./templates/resptype_body_method.go.tpl", "./templates/description.go.tpl")
t, err = template.ParseFiles(
"./templates/resptype_body_method.go.tpl",
"./templates/description.go.tpl",
)
if err != nil {
return err
}
} else {
t, err = template.ParseFiles("./templates/resptype_method.go.tpl", "./templates/description.go.tpl")
t, err = template.ParseFiles(
"./templates/resptype_method.go.tpl",
"./templates/description.go.tpl",
)
if err != nil {
return err
}
Expand All @@ -349,7 +385,10 @@ func writeTpl(f *os.File, config methodTemplate) error {
return nil
}

func buildPathOrQueryParams(paramType string, params map[string]*openapi3.Parameter) ([]string, error) {
func buildPathOrQueryParams(
paramType string,
params map[string]*openapi3.Parameter,
) ([]string, error) {
pathParams := make([]string, 0)
if paramType != "query" && paramType != "path" {
return nil, errors.New("paramType must be one of 'query' or 'path'")
Expand All @@ -376,11 +415,17 @@ func buildPathOrQueryParams(paramType string, params map[string]*openapi3.Parame
case "bool":
pathParams = append(pathParams, fmt.Sprintf("%q: strconv.FormatBool(%s),", name, n))
case "*bool":
pathParams = append(pathParams, fmt.Sprintf("%q: strconv.FormatBool(*%s),", name, n))
pathParams = append(
pathParams,
fmt.Sprintf("%q: strconv.FormatBool(*%s),", name, n),
)
case "*int":
pathParams = append(pathParams, fmt.Sprintf("%q: PointerIntToStr(%s),", name, n))
case "*time.Time":
pathParams = append(pathParams, fmt.Sprintf("%q: %s.Format(time.RFC3339),", name, n))
pathParams = append(
pathParams,
fmt.Sprintf("%q: %s.Format(time.RFC3339),", name, n),
)
default:
pathParams = append(pathParams, fmt.Sprintf("%q: string(%s),", name, n))
}
Expand All @@ -399,7 +444,10 @@ func buildParams(operation *openapi3.Operation, opID string) paramsInfo {

for _, p := range operation.Parameters {
if p.Ref != "" {
fmt.Printf("[WARN] TODO: skipping parameter for %q, since it is a reference\n", p.Value.Name)
fmt.Printf(
"[WARN] TODO: skipping parameter for %q, since it is a reference\n",
p.Value.Name,
)
continue
}

Expand Down
5 changes: 4 additions & 1 deletion internal/generate/responses_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ func Test_generateResponses(t *testing.T) {
return
}

if err := compareFiles("test_utils/responses_output_expected", tt.args.file); err != nil {
if err := compareFiles(
"test_utils/responses_output_expected",
tt.args.file,
); err != nil {
t.Error(err)
}
})
Expand Down
Loading