Compare commits
2 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 69220079b6 | |||
|
|
6806b20651 |
6 changed files with 99 additions and 11 deletions
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"forge.lthn.ai/core/cli/pkg/cli"
|
"forge.lthn.ai/core/cli/pkg/cli"
|
||||||
|
coreio "forge.lthn.ai/core/go-io"
|
||||||
coreerr "forge.lthn.ai/core/go-log"
|
coreerr "forge.lthn.ai/core/go-log"
|
||||||
lint "forge.lthn.ai/core/lint"
|
lint "forge.lthn.ai/core/lint"
|
||||||
lintpkg "forge.lthn.ai/core/lint/pkg/lint"
|
lintpkg "forge.lthn.ai/core/lint/pkg/lint"
|
||||||
|
|
@ -66,7 +67,7 @@ func addLintCommands(root *cli.Command) {
|
||||||
|
|
||||||
var allFindings []lintpkg.Finding
|
var allFindings []lintpkg.Finding
|
||||||
for _, p := range paths {
|
for _, p := range paths {
|
||||||
info, err := os.Stat(p)
|
info, err := coreio.Local.Stat(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coreerr.E("cmd.check", "stat "+p, err)
|
return coreerr.E("cmd.check", "stat "+p, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"forge.lthn.ai/core/cli/pkg/cli"
|
"forge.lthn.ai/core/cli/pkg/cli"
|
||||||
|
coreio "forge.lthn.ai/core/go-io"
|
||||||
"forge.lthn.ai/core/go-i18n"
|
"forge.lthn.ai/core/go-i18n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -235,7 +236,7 @@ func expandPatterns(patterns []string) ([]string, error) {
|
||||||
|
|
||||||
// hasGoFiles checks if a directory contains Go files.
|
// hasGoFiles checks if a directory contains Go files.
|
||||||
func hasGoFiles(dir string) bool {
|
func hasGoFiles(dir string) bool {
|
||||||
entries, err := os.ReadDir(dir)
|
entries, err := coreio.Local.List(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,13 @@ package qa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"forge.lthn.ai/core/cli/pkg/cli"
|
"forge.lthn.ai/core/cli/pkg/cli"
|
||||||
"forge.lthn.ai/core/go-i18n"
|
i18n "forge.lthn.ai/core/go-i18n"
|
||||||
"forge.lthn.ai/core/lint/locales"
|
"forge.lthn.ai/core/lint/locales"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cli.RegisterCommands(AddQACommands, locales.FS)
|
i18n.RegisterLocales(locales.FS, ".")
|
||||||
|
cli.RegisterCommands(AddQACommands)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Style aliases from shared package
|
// Style aliases from shared package
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
// Package detect identifies project types by examining filesystem markers.
|
// Package detect identifies project types by examining filesystem markers.
|
||||||
package detect
|
package detect
|
||||||
|
|
||||||
import "os"
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
coreio "forge.lthn.ai/core/go-io"
|
||||||
|
)
|
||||||
|
|
||||||
// ProjectType identifies a project's language/framework.
|
// ProjectType identifies a project's language/framework.
|
||||||
type ProjectType string
|
type ProjectType string
|
||||||
|
|
@ -13,14 +17,12 @@ const (
|
||||||
|
|
||||||
// IsGoProject returns true if dir contains a go.mod file.
|
// IsGoProject returns true if dir contains a go.mod file.
|
||||||
func IsGoProject(dir string) bool {
|
func IsGoProject(dir string) bool {
|
||||||
_, err := os.Stat(dir + "/go.mod")
|
return coreio.Local.Exists(filepath.Join(dir, "go.mod"))
|
||||||
return err == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPHPProject returns true if dir contains a composer.json file.
|
// IsPHPProject returns true if dir contains a composer.json file.
|
||||||
func IsPHPProject(dir string) bool {
|
func IsPHPProject(dir string) bool {
|
||||||
_, err := os.Stat(dir + "/composer.json")
|
return coreio.Local.Exists(filepath.Join(dir, "composer.json"))
|
||||||
return err == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DetectAll returns all detected project types in the directory.
|
// DetectAll returns all detected project types in the directory.
|
||||||
|
|
|
||||||
|
|
@ -209,6 +209,89 @@ func TestScanDir_Good_Subdirectories(t *testing.T) {
|
||||||
require.Len(t, findings, 1)
|
require.Len(t, findings, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLanguagesFromRules_Good(t *testing.T) {
|
||||||
|
rules := []Rule{
|
||||||
|
{Languages: []string{"go", "php"}},
|
||||||
|
{Languages: []string{"go", "ts"}},
|
||||||
|
{Languages: []string{"py"}},
|
||||||
|
}
|
||||||
|
langs := languagesFromRules(rules)
|
||||||
|
assert.Equal(t, []string{"go", "php", "py", "ts"}, langs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLanguagesFromRules_Good_Empty(t *testing.T) {
|
||||||
|
langs := languagesFromRules(nil)
|
||||||
|
assert.Empty(t, langs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsExcludedDir_Good(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{"vendor", true},
|
||||||
|
{"node_modules", true},
|
||||||
|
{".git", true},
|
||||||
|
{"testdata", true},
|
||||||
|
{".core", true},
|
||||||
|
{".hidden", true}, // any dot-prefixed dir
|
||||||
|
{".idea", true}, // any dot-prefixed dir
|
||||||
|
{"src", false},
|
||||||
|
{"pkg", false},
|
||||||
|
{"cmd", false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equal(t, tt.want, IsExcludedDir(tt.name))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScanFile_Bad_UnrecognisedExtension(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
file := filepath.Join(dir, "readme.txt")
|
||||||
|
require.NoError(t, os.WriteFile(file, []byte("TODO: fix this"), 0o644))
|
||||||
|
|
||||||
|
rules := []Rule{
|
||||||
|
{
|
||||||
|
ID: "test-001",
|
||||||
|
Title: "Found TODO",
|
||||||
|
Severity: "low",
|
||||||
|
Languages: []string{"go"},
|
||||||
|
Pattern: `TODO`,
|
||||||
|
Fix: "Remove TODO",
|
||||||
|
Detection: "regex",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := NewScanner(rules)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
findings, err := s.ScanFile(file)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Empty(t, findings, "should not match unrecognised extensions")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestScanFile_Bad_NonexistentFile(t *testing.T) {
|
||||||
|
rules := []Rule{
|
||||||
|
{
|
||||||
|
ID: "test-001",
|
||||||
|
Title: "Test",
|
||||||
|
Severity: "low",
|
||||||
|
Languages: []string{"go"},
|
||||||
|
Pattern: `TODO`,
|
||||||
|
Fix: "Fix",
|
||||||
|
Detection: "regex",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := NewScanner(rules)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = s.ScanFile("/nonexistent/test.go")
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestScanDir_Bad_NonexistentDir(t *testing.T) {
|
func TestScanDir_Bad_NonexistentDir(t *testing.T) {
|
||||||
rules := []Rule{
|
rules := []Rule{
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
coreio "forge.lthn.ai/core/go-io"
|
||||||
coreerr "forge.lthn.ai/core/go-log"
|
coreerr "forge.lthn.ai/core/go-log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fileExists reports whether the named file or directory exists.
|
// fileExists reports whether the named file or directory exists.
|
||||||
func fileExists(path string) bool {
|
func fileExists(path string) bool {
|
||||||
_, err := os.Stat(path)
|
return coreio.Local.Exists(path)
|
||||||
return err == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatOptions configures PHP code formatting.
|
// FormatOptions configures PHP code formatting.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue