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
37 changes: 21 additions & 16 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,46 @@ jobs:
name: Build Windows
runs-on: windows-latest
steps:
- name: Force git to use LF
# This step is required on Windows to work around issues with go fmt.
# TODO: replace with a checkout option when https://github.com/actions/checkout/issues/226 is implemented
run: |
git config --global core.autocrlf false
git config --global core.eol lf

- name: Checkout code
uses: actions/checkout@v6

- name: Set up Go 1.x
uses: actions/setup-go@v3
uses: actions/setup-go@v6
with:
go-version: 1.23
id: go

- name: Checkout code
uses: actions/checkout@v3

- name: Get dependencies
- name: Format
run: |
go get -v -t -d ./...
go fmt ./...
git diff --exit-code
- name: Test
run: go test ./...
build:
name: Build Linux
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Go 1.x
uses: actions/setup-go@v3
uses: actions/setup-go@v6
with:
go-version: 1.23
id: go

- name: Checkout code
uses: actions/checkout@v3

- name: Get dependencies
- name: Format
run: |
go get -v -t -d ./...
if [ -f Gopkg.toml ]; then
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure
fi
go fmt ./...
git diff --exit-code
- name: Test
run: go test ./...
- name: Coverage
Expand Down
4 changes: 2 additions & 2 deletions bundler/bundler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2319,8 +2319,8 @@ func TestCopySchemaToComponents_NameCollision(t *testing.T) {
func TestCalculateCollisionNameInline_NumericSuffix(t *testing.T) {
// Test: When filename-based name also collides, use numeric suffix
existingNames := map[string]bool{
"Cat": true,
"Cat__external": true, // Filename-based collision also exists
"Cat": true,
"Cat__external": true, // Filename-based collision also exists
"Cat__external__1": true, // First numeric suffix also taken (format: name__basename__N)
}

Expand Down
2 changes: 1 addition & 1 deletion bundler/origin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ func TestCaptureOrigin_FullCoverage(t *testing.T) {
pr := &processRef{
ref: &index.Reference{
FullDefinition: "test.yaml",
Node: &yaml.Node{Line: 5, Column: 2},
Node: &yaml.Node{Line: 5, Column: 2},
},
idx: &index.SpecIndex{},
originalName: "Test",
Expand Down
10 changes: 5 additions & 5 deletions datamodel/high/base/dynamic_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import (
//
// The N value indicates which value is set (0 = A, 1 == B), preventing the need to check both values.
type DynamicValue[A any, B any] struct {
N int // 0 == A, 1 == B
A A
B B
inline bool
renderCtx any // Context for inline rendering (typed as any to avoid import cycles)
N int // 0 == A, 1 == B
A A
B B
inline bool
renderCtx any // Context for inline rendering (typed as any to avoid import cycles)
}

// IsA will return true if the 'A' or left value is set.
Expand Down
10 changes: 5 additions & 5 deletions datamodel/high/overlay/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (
// Action represents a high-level Overlay Action Object.
// https://spec.openapis.org/overlay/v1.1.0#action-object
type Action struct {
Target string `json:"target,omitempty" yaml:"target,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Update *yaml.Node `json:"update,omitempty" yaml:"update,omitempty"`
Remove bool `json:"remove,omitempty" yaml:"remove,omitempty"`
Copy string `json:"copy,omitempty" yaml:"copy,omitempty"`
Target string `json:"target,omitempty" yaml:"target,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Update *yaml.Node `json:"update,omitempty" yaml:"update,omitempty"`
Remove bool `json:"remove,omitempty" yaml:"remove,omitempty"`
Copy string `json:"copy,omitempty" yaml:"copy,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Action
}
Expand Down
6 changes: 3 additions & 3 deletions datamodel/high/overlay/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
// Info represents a high-level Overlay Info Object.
// https://spec.openapis.org/overlay/v1.1.0#info-object
type Info struct {
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Version string `json:"version,omitempty" yaml:"version,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Version string `json:"version,omitempty" yaml:"version,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Info
}
Expand Down
8 changes: 4 additions & 4 deletions datamodel/high/overlay/overlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (
// Overlay represents a high-level OpenAPI Overlay document.
// https://spec.openapis.org/overlay/v1.0.0
type Overlay struct {
Overlay string `json:"overlay,omitempty" yaml:"overlay,omitempty"`
Info *Info `json:"info,omitempty" yaml:"info,omitempty"`
Extends string `json:"extends,omitempty" yaml:"extends,omitempty"`
Actions []*Action `json:"actions,omitempty" yaml:"actions,omitempty"`
Overlay string `json:"overlay,omitempty" yaml:"overlay,omitempty"`
Info *Info `json:"info,omitempty" yaml:"info,omitempty"`
Extends string `json:"extends,omitempty" yaml:"extends,omitempty"`
Actions []*Action `json:"actions,omitempty" yaml:"actions,omitempty"`
Extensions *orderedmap.Map[string, *yaml.Node] `json:"-" yaml:"-"`
low *low.Overlay
}
Expand Down
1 change: 0 additions & 1 deletion datamodel/high/v3/request_body_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,4 +320,3 @@ paths: {}`
assert.NoError(t, err)
assert.NotNil(t, result)
}

1 change: 0 additions & 1 deletion datamodel/high/v3/security_scheme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ func TestSecurityScheme_MarshalYAMLInlineWithContext_Reference(t *testing.T) {
assert.Equal(t, "$ref", yamlNode.Content[0].Value)
}


func TestBuildLowSecurityScheme_Success(t *testing.T) {
yml := `type: apiKey
name: X-API-Key
Expand Down
2 changes: 1 addition & 1 deletion datamodel/high/v3/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// Server represents a high-level OpenAPI 3+ Server object, that is backed by a low level one.
// - https://spec.openapis.org/oas/v3.1.0#server-object
type Server struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"` // OpenAPI 3.2+ name field for documentation
Name string `json:"name,omitempty" yaml:"name,omitempty"` // OpenAPI 3.2+ name field for documentation
URL string `json:"url,omitempty" yaml:"url,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Variables *orderedmap.Map[string, *ServerVariable] `json:"variables,omitempty" yaml:"variables,omitempty"`
Expand Down
28 changes: 14 additions & 14 deletions datamodel/low/v3/security_scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@ import (
// Recommended for most use case is Authorization Code Grant flow with PKCE.
// - https://spec.openapis.org/oas/v3.1.0#security-scheme-object
type SecurityScheme struct {
Type low.NodeReference[string]
Description low.NodeReference[string]
Name low.NodeReference[string]
In low.NodeReference[string]
Scheme low.NodeReference[string]
BearerFormat low.NodeReference[string]
Flows low.NodeReference[*OAuthFlows]
OpenIdConnectUrl low.NodeReference[string]
Type low.NodeReference[string]
Description low.NodeReference[string]
Name low.NodeReference[string]
In low.NodeReference[string]
Scheme low.NodeReference[string]
BearerFormat low.NodeReference[string]
Flows low.NodeReference[*OAuthFlows]
OpenIdConnectUrl low.NodeReference[string]
OAuth2MetadataUrl low.NodeReference[string] // OpenAPI 3.2+ OAuth2 metadata URL
Deprecated low.NodeReference[bool] // OpenAPI 3.2+ deprecated flag
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
KeyNode *yaml.Node
RootNode *yaml.Node
index *index.SpecIndex
context context.Context
Deprecated low.NodeReference[bool] // OpenAPI 3.2+ deprecated flag
Extensions *orderedmap.Map[low.KeyReference[string], low.ValueReference[*yaml.Node]]
KeyNode *yaml.Node
RootNode *yaml.Node
index *index.SpecIndex
context context.Context
*low.Reference
low.NodeMap
}
Expand Down
2 changes: 1 addition & 1 deletion datamodel/spec_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type SpecInfo struct {
APISchema string `json:"-"` // API Schema for supplied spec type (2 or 3)
Generated time.Time `json:"-"`
OriginalIndentation int `json:"-"` // the original whitespace
Self string `json:"-"` // the $self field for OpenAPI 3.2+ documents (base URI)
Self string `json:"-"` // the $self field for OpenAPI 3.2+ documents (base URI)
}

func ExtractSpecInfoWithConfig(spec []byte, config *DocumentConfiguration) (*SpecInfo, error) {
Expand Down
24 changes: 13 additions & 11 deletions datamodel/translate_coverage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ import (
// TestTranslateMapParallel_ContextCancellation specifically targets lines 158-159
// in translate.go which handle context cancellation during job dispatch.
// This test ensures 100% coverage even on single-CPU systems like GitHub runners.
//
//
// The flaky coverage issue occurs because the select statement at lines 156-160:
// select {
// case jobChan <- j:
// case <-ctx.Done():
// return
// }
//
// select {
// case jobChan <- j:
// case <-ctx.Done():
// return
// }
//
// The ctx.Done() branch (lines 158-159) is only hit when the context is cancelled
// while the goroutine is blocked trying to send to jobChan. This is a race condition
// that doesn't always occur, especially on single-CPU systems.
Expand Down Expand Up @@ -57,7 +59,7 @@ func TestTranslateMapParallel_ContextCancellation(t *testing.T) {
time.Sleep(10 * time.Millisecond)
return "", errors.New("trigger cancellation")
}

// Other jobs: count how many get started
jobsBlocked.Add(1)
time.Sleep(100 * time.Millisecond)
Expand All @@ -72,13 +74,13 @@ func TestTranslateMapParallel_ContextCancellation(t *testing.T) {
err := datamodel.TranslateMapParallel[string, int, string](m, translateFunc, resultFunc)
require.Error(t, err)
assert.Contains(t, err.Error(), "trigger cancellation")

// Wait for goroutines to clean up
time.Sleep(20 * time.Millisecond)

// Verify context cancellation prevented all jobs from running
// If lines 158-159 are hit, some jobs will be skipped
assert.Less(t, int(jobsBlocked.Load()), itemCount-1,
assert.Less(t, int(jobsBlocked.Load()), itemCount-1,
"Iteration %d: Context cancellation should prevent some jobs", iteration)
}
}
}
2 changes: 1 addition & 1 deletion index/enhanced_coverage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,4 @@ other: test`,
}
}
})
}
}
26 changes: 13 additions & 13 deletions index/issue361_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,28 +48,28 @@ properties:
// Create a Rolodex and add the standard fs.FS
config := CreateOpenAPIIndexConfig()
rolo := NewRolodex(config)

// Add the fs.FS with a base directory
// The fix ensures that when opening files, relative paths are used
// with the fs.FS interface, not absolute paths
// Use a temporary directory to ensure cross-platform compatibility
tempDir, err := os.MkdirTemp("", "rolodex-test")
require.NoError(t, err, "Should be able to create temp dir")
defer os.RemoveAll(tempDir)

baseDir := filepath.Join(tempDir, "api", "v1")
rolo.AddLocalFS(baseDir, testFS)

// Test 1: Open a file at the root of the FS
f1, err := rolo.Open("openapi.yaml")
require.NoError(t, err, "Should open file using relative path with fs.FS")
assert.Contains(t, f1.GetContent(), "Test API")

// Test 2: Open a nested file
f2, err := rolo.Open("schemas/pet.yaml")
require.NoError(t, err, "Should open nested file using relative path with fs.FS")
assert.Contains(t, f2.GetContent(), "type: object")

// Test 3: Verify absolute paths are converted correctly
// Even if we pass an absolute path matching the base + relative path,
// it should work by converting to relative
Expand All @@ -87,33 +87,33 @@ func TestIssue361_MultipleFileSystems(t *testing.T) {
apiFS := fstest.MapFS{
"api.yaml": {Data: []byte("api content"), ModTime: time.Now()},
}

schemaFS := fstest.MapFS{
"schema.json": {Data: []byte("schema content"), ModTime: time.Now()},
}

// Create Rolodex with multiple file systems
config := CreateOpenAPIIndexConfig()
rolo := NewRolodex(config)

// Use temporary directories for cross-platform compatibility
tempDir, err := os.MkdirTemp("", "rolodex-multi-test")
require.NoError(t, err, "Should be able to create temp dir")
defer os.RemoveAll(tempDir)

rolo.AddLocalFS(filepath.Join(tempDir, "apis"), apiFS)
rolo.AddLocalFS(filepath.Join(tempDir, "schemas"), schemaFS)

// Files should be found in their respective file systems
f1, err := rolo.Open("api.yaml")
require.NoError(t, err, "Should find api.yaml in first FS")
assert.Equal(t, "api content", f1.GetContent())

f2, err := rolo.Open("schema.json")
require.NoError(t, err, "Should find schema.json in second FS")
assert.Equal(t, "schema content", f2.GetContent())

// Non-existent file should return error
_, err = rolo.Open("nonexistent.yaml")
assert.Error(t, err, "Should return error for non-existent file")
}
}
Loading
Loading