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
14 changes: 12 additions & 2 deletions pkg/codegen/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func operationsWithTags(paths *openapi3.Paths, tags map[string]bool, exclude boo
return
}

for _, pathItem := range paths.Map() {
for path, pathItem := range paths.Map() {
ops := pathItem.Operations()
names := make([]string, 0, len(ops))
for name, op := range ops {
Expand All @@ -35,6 +35,11 @@ func operationsWithTags(paths *openapi3.Paths, tags map[string]bool, exclude boo
for _, name := range names {
pathItem.SetOperation(name, nil)
}
// A path whose operations were all filtered out would otherwise be
// left behind as an empty entry in the embedded spec.
if len(names) > 0 && len(pathItem.Operations()) == 0 {
paths.Delete(path)
Comment on lines +40 to +41

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Previously generated types disappear

Deleting the whole path also removes references from its shared parameters. If a filtered-out path has a parameter referencing #/components/schemas/ItemID, that reference previously kept ItemID in the generated Go code. Now pruneUnusedComponents deletes it when nothing else references it, breaking downstream code that uses the exported type. Both filter helpers have this problem.

The repository requires compatibility protection for changes to generated APIs. Preserve the existing type output by default or make this broader change opt-in.

Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/codegen/filter.go
Line: 40-41

Comment:
**Previously generated types disappear**

Deleting the whole path also removes references from its shared parameters. If a filtered-out path has a parameter referencing `#/components/schemas/ItemID`, that reference previously kept `ItemID` in the generated Go code. Now `pruneUnusedComponents` deletes it when nothing else references it, breaking downstream code that uses the exported type. Both filter helpers have this problem.

The repository requires compatibility protection for changes to generated APIs. Preserve the existing type output by default or make this broader change opt-in.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

}
}
}

Expand Down Expand Up @@ -65,7 +70,7 @@ func operationsWithOperationIDs(paths *openapi3.Paths, operationIDs map[string]b
return
}

for _, pathItem := range paths.Map() {
for path, pathItem := range paths.Map() {
ops := pathItem.Operations()
names := make([]string, 0, len(ops))
for name, op := range ops {
Expand All @@ -76,6 +81,11 @@ func operationsWithOperationIDs(paths *openapi3.Paths, operationIDs map[string]b
for _, name := range names {
pathItem.SetOperation(name, nil)
}
// A path whose operations were all filtered out would otherwise be
// left behind as an empty entry in the embedded spec.
if len(names) > 0 && len(pathItem.Operations()) == 0 {
paths.Delete(path)
}
}
}

Expand Down
42 changes: 42 additions & 0 deletions pkg/codegen/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,45 @@ func TestFilterOperationsByOperationID(t *testing.T) {
assert.NotContains(t, code, `"/cat"`)
})
}

func TestFilterRemovesPathsWithNoOperationsLeft(t *testing.T) {
const spec = `
openapi: 3.0.3
info:
title: filter
version: "1"
paths:
/kept:
get:
operationId: getKept
tags: [kept]
responses:
"200":
description: ok
/dropped:
get:
operationId: getDropped
tags: [dropped]
responses:
"200":
description: ok
`
load := func(t *testing.T) *openapi3.T {
t.Helper()
swagger, err := openapi3.NewLoader().LoadFromData([]byte(spec))
assert.NoError(t, err)
return swagger
}

t.Run("by tag", func(t *testing.T) {
swagger := load(t)
filterOperationsByTag(swagger, Configuration{OutputOptions: OutputOptions{IncludeTags: []string{"kept"}}})
assert.Equal(t, []string{"/kept"}, swagger.Paths.Keys())
})

t.Run("by operation id", func(t *testing.T) {
swagger := load(t)
filterOperationsByOperationID(swagger, Configuration{OutputOptions: OutputOptions{ExcludeOperationIDs: []string{"getDropped"}}})
assert.Equal(t, []string{"/kept"}, swagger.Paths.Keys())
Comment on lines +161 to +170

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Path preservation lacks tests

The new test checks only paths with one operation each. Add a path that starts empty and a path with both a kept and a removed operation, then assert that both paths survive under each filter kind. These cases protect the two deletion guards; the current tests would still pass if either guard were removed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: pkg/codegen/filter_test.go
Line: 161-170

Comment:
**Path preservation lacks tests**

The new test checks only paths with one operation each. Add a path that starts empty and a path with both a kept and a removed operation, then assert that both paths survive under each filter kind. These cases protect the two deletion guards; the current tests would still pass if either guard were removed.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

})
}
4 changes: 2 additions & 2 deletions pkg/codegen/prune_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestFilterOnlyCat(t *testing.T) {

assert.NotEmpty(t, swagger.Paths.Value("/cat"), "/cat path should still be in spec")
assert.NotEmpty(t, swagger.Paths.Value("/cat").Get, "GET /cat operation should still be in spec")
assert.Empty(t, swagger.Paths.Value("/dog").Get, "GET /dog should have been removed from spec")
assert.Nil(t, swagger.Paths.Value("/dog"), "/dog path should have been removed from spec")

pruneUnusedComponents(swagger)

Expand Down Expand Up @@ -99,7 +99,7 @@ func TestFilterOnlyDog(t *testing.T) {

assert.NotEmpty(t, swagger.Paths.Value("/dog"))
assert.NotEmpty(t, swagger.Paths.Value("/dog").Get)
assert.Empty(t, swagger.Paths.Value("/cat").Get)
assert.Nil(t, swagger.Paths.Value("/cat"))

pruneUnusedComponents(swagger)

Expand Down
Loading