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
62 changes: 62 additions & 0 deletions lint/app_yaml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package lint

import (
"os"
"path/filepath"
"strings"

"gopkg.in/yaml.v3"
)

type appYamlFileEntry struct {
Path string `yaml:"path"`
OriginalPath string `yaml:"originalPath"`
}

type appYamlStructure struct {
Files []appYamlFileEntry `yaml:"files"`
}

// loadOriginalPathMap reads modelsource/app.yaml and returns disk path → original path.
// Missing or unreadable app.yaml yields an empty map (callers fall back to identity).
func loadOriginalPathMap(modelSourcePath string) map[string]string {
appYamlPath := filepath.Join(modelSourcePath, "app.yaml")
data, err := os.ReadFile(appYamlPath)
if err != nil {
return map[string]string{}
}

var structure appYamlStructure
if err := yaml.Unmarshal(data, &structure); err != nil {
log.Debugf("Could not parse %s for originalPath mapping: %v", appYamlPath, err)
return map[string]string{}
}

pathMap := make(map[string]string, len(structure.Files))
for _, entry := range structure.Files {
path := filepath.ToSlash(strings.TrimSpace(entry.Path))
if path == "" {
continue
}
original := filepath.ToSlash(strings.TrimSpace(entry.OriginalPath))
if original == "" {
original = path
}
pathMap[path] = original
}
return pathMap
}

// resolveOriginalPath returns the mapped original path, or name when unmapped.
func resolveOriginalPath(name string, pathMap map[string]string) string {
name = filepath.ToSlash(name)
if name == "" {
return name
}
if pathMap != nil {
if original, ok := pathMap[name]; ok && original != "" {
return original
}
}
return name
}
58 changes: 58 additions & 0 deletions lint/app_yaml_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package lint

import (
"os"
"path/filepath"
"testing"
)

func TestLoadOriginalPathMapMissingFile(t *testing.T) {
pathMap := loadOriginalPathMap(t.TempDir())
if len(pathMap) != 0 {
t.Fatalf("expected empty map for missing app.yaml, got %v", pathMap)
}
}

func TestLoadOriginalPathMapAndResolve(t *testing.T) {
tmpDir := t.TempDir()
appYaml := `
content: []
files:
- path: Module2/Folder_TRUNCATED/Constant.yaml
originalPath: Module2/Folder_very_long_name/Constant.yaml
- path: Metadata.yaml
originalPath: Metadata.yaml
`
if err := os.WriteFile(filepath.Join(tmpDir, "app.yaml"), []byte(appYaml), 0644); err != nil {
t.Fatalf("write app.yaml: %v", err)
}

pathMap := loadOriginalPathMap(tmpDir)
if got := resolveOriginalPath("Module2/Folder_TRUNCATED/Constant.yaml", pathMap); got != "Module2/Folder_very_long_name/Constant.yaml" {
t.Fatalf("mapped path = %q", got)
}
if got := resolveOriginalPath("Metadata.yaml", pathMap); got != "Metadata.yaml" {
t.Fatalf("identity mapped path = %q", got)
}
if got := resolveOriginalPath("Unmapped/Doc.yaml", pathMap); got != "Unmapped/Doc.yaml" {
t.Fatalf("unmapped fallback = %q", got)
}
}

func TestResolveOriginalPathNilMap(t *testing.T) {
if got := resolveOriginalPath("Module2/Doc.yaml", nil); got != "Module2/Doc.yaml" {
t.Fatalf("nil map fallback = %q", got)
}
}

func TestFormatTestcaseNameWithOriginalPath(t *testing.T) {
modelSource := t.TempDir()
inputFile := filepath.Join(modelSource, "Module2", "Doc.yaml")
name := formatTestcaseName(inputFile, modelSource)
pathMap := map[string]string{
"Module2/Doc.yaml": "Module2/Original Doc.yaml",
}
if got := resolveOriginalPath(name, pathMap); got != "Module2/Original Doc.yaml" {
t.Fatalf("originalPath = %q, name = %q", got, name)
}
}
11 changes: 8 additions & 3 deletions lint/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ func EvalAllWithResults(rulesPath string, modelSourcePath string, xunitReport st
// Create a mutex to safely print testsuites
var printMutex sync.Mutex

originalPathMap := loadOriginalPathMap(modelSourcePath)

maxConcurrency := effectiveLintConcurrency(len(rules))
sem := make(chan struct{}, maxConcurrency)

Expand All @@ -59,7 +61,7 @@ func EvalAllWithResults(rulesPath string, modelSourcePath string, xunitReport st
defer wg.Done()
defer func() { <-sem }()

testsuite, err := evalTestsuite(r, modelSourcePath, ignoreNoqa, useCache, changedFiles)
testsuite, err := evalTestsuite(r, modelSourcePath, ignoreNoqa, useCache, changedFiles, originalPathMap)
if err != nil {
errChan <- err
return
Expand Down Expand Up @@ -161,6 +163,8 @@ func EvalAll(rulesPath string, modelSourcePath string, xunitReport string, jsonF
// Create a mutex to safely print testsuites
var printMutex sync.Mutex

originalPathMap := loadOriginalPathMap(modelSourcePath)

maxConcurrency := effectiveLintConcurrency(len(rules))
sem := make(chan struct{}, maxConcurrency)

Expand All @@ -172,7 +176,7 @@ func EvalAll(rulesPath string, modelSourcePath string, xunitReport string, jsonF
defer wg.Done()
defer func() { <-sem }()

testsuite, err := evalTestsuite(r, modelSourcePath, ignoreNoqa, useCache, changedFiles)
testsuite, err := evalTestsuite(r, modelSourcePath, ignoreNoqa, useCache, changedFiles, originalPathMap)
if err != nil {
errChan <- err
return
Expand Down Expand Up @@ -269,7 +273,7 @@ func countTotalTestcases(testsuites []Testsuite) int {
return count
}

func evalTestsuite(rule Rule, modelSourcePath string, ignoreNoqa bool, useCache bool, changedFiles []string) (*Testsuite, error) {
func evalTestsuite(rule Rule, modelSourcePath string, ignoreNoqa bool, useCache bool, changedFiles []string, originalPathMap map[string]string) (*Testsuite, error) {

log.Debugf("evaluating rule %s", rule.Path)

Expand Down Expand Up @@ -327,6 +331,7 @@ func evalTestsuite(rule Rule, modelSourcePath string, ignoreNoqa bool, useCache

// Normalize testcase name for output consistency regardless of cache source.
testcase.Name = formatTestcaseName(inputFile, modelSourcePath)
testcase.OriginalPath = resolveOriginalPath(testcase.Name, originalPathMap)

if testcase.Failure != nil {
failuresCount++
Expand Down
22 changes: 11 additions & 11 deletions lint/lint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestEvalTestsuite_Rego(t *testing.T) {
t.Fatalf("Failed to parse rule metadata: %v", err)
}

result, err := evalTestsuite(*rule, "./../resources/modelsource-v1", false, false, nil)
result, err := evalTestsuite(*rule, "./../resources/modelsource-v1", false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand Down Expand Up @@ -67,7 +67,7 @@ errors contains "Always fails"
Language: LanguageRego,
}

result, err := evalTestsuite(rule, tempDir, false, false, nil)
result, err := evalTestsuite(rule, tempDir, false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand All @@ -85,7 +85,7 @@ func TestEvalTestsuite_Javascript(t *testing.T) {
t.Fatalf("Failed to parse rule metadata: %v", err)
}

result, err := evalTestsuite(*rule, "./../resources/modelsource-v1", false, false, nil)
result, err := evalTestsuite(*rule, "./../resources/modelsource-v1", false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand Down Expand Up @@ -134,7 +134,7 @@ function rule(input) {
Language: LanguageJavascript,
}

result, err := evalTestsuite(rule, tempDir, false, false, nil)
result, err := evalTestsuite(rule, tempDir, false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand All @@ -152,7 +152,7 @@ func TestEvalTestsuite_Typescript(t *testing.T) {
t.Fatalf("Failed to parse rule metadata: %v", err)
}

result, err := evalTestsuite(*rule, "./../resources/modelsource-v1", false, false, nil)
result, err := evalTestsuite(*rule, "./../resources/modelsource-v1", false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand Down Expand Up @@ -203,7 +203,7 @@ Name: "Test"
}

t.Run("documentation noqa is ignored", func(t *testing.T) {
result, err := evalTestsuite(rule, tempDir, false, false, nil)
result, err := evalTestsuite(rule, tempDir, false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand All @@ -217,7 +217,7 @@ Name: "Test"
})

t.Run("ignoreNoqa has no effect on documentation skip", func(t *testing.T) {
result, err := evalTestsuite(rule, tempDir, true, false, nil)
result, err := evalTestsuite(rule, tempDir, true, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand Down Expand Up @@ -275,7 +275,7 @@ function rule(input) {
Language: LanguageJavascript,
}

result, err := evalTestsuite(rule, tempDir, false, false, nil)
result, err := evalTestsuite(rule, tempDir, false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand Down Expand Up @@ -584,7 +584,7 @@ function rule(input) {
Language: LanguageJavascript,
}

result, err := evalTestsuite(rule, tempDir, false, false, nil)
result, err := evalTestsuite(rule, tempDir, false, false, nil, nil)
if err != nil {
t.Fatalf("Expected testsuite evaluation to succeed, got: %v", err)
}
Expand Down Expand Up @@ -640,7 +640,7 @@ function rule(input) {
Language: LanguageJavascript,
}

result, err := evalTestsuite(rule, tempDir, false, false, nil)
result, err := evalTestsuite(rule, tempDir, false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand Down Expand Up @@ -683,7 +683,7 @@ function rule(input) {
Language: LanguageJavascript,
}

result, err := evalTestsuite(rule, tempDir, false, false, nil)
result, err := evalTestsuite(rule, tempDir, false, false, nil, nil)
if err != nil {
t.Fatalf("Failed to evaluate testsuite: %v", err)
}
Expand Down
11 changes: 6 additions & 5 deletions lint/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ type Testsuite struct {
}

type Testcase struct {
XMLName xml.Name `xml:"testcase" json:"-"`
Name string `xml:"name,attr" json:"name"`
Time float64 `xml:"time,attr" json:"time"`
Failure *Failure `xml:"failure,omitempty" json:"failure,omitempty"`
Skipped *Skipped `xml:"skipped,omitempty" json:"skipped,omitempty"`
XMLName xml.Name `xml:"testcase" json:"-"`
Name string `xml:"name,attr" json:"name"`
OriginalPath string `xml:"originalPath,attr,omitempty" json:"originalPath,omitempty"`
Time float64 `xml:"time,attr" json:"time"`
Failure *Failure `xml:"failure,omitempty" json:"failure,omitempty"`
Skipped *Skipped `xml:"skipped,omitempty" json:"skipped,omitempty"`
}

type Failure struct {
Expand Down
Loading
Loading