Skip to content
Draft
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
12 changes: 3 additions & 9 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,10 @@ jobs:
go-version: "1.26"

- name: Static Analysis
run: |
go vet ./...
cd pkg/validator/justfile && go vet ./...
run: go vet ./...

- name: Check Formatting
run: |
test -z "$(gofmt -s -l -e .)"
cd pkg/validator/justfile && test -z "$(gofmt -s -l -e .)"
run: test -z "$(gofmt -s -l -e .)"

- name: Check generated files are up to date
run: |
Expand Down Expand Up @@ -106,9 +102,7 @@ jobs:
go-version: "1.26"

- name: Unit test
run: |
go test -v -cover -coverprofile coverage.out ./...
cd pkg/validator/justfile && go test -v -count=1 ./...
run: go test -v -cover -coverprofile coverage.out ./...

- name: Check coverage
env:
Expand Down
8 changes: 0 additions & 8 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,3 @@ jobs:
version: v2.11.4
args: --timeout=10m
install-mode: "goinstall"

- name: golangci-lint (go-just nested module)
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
version: v2.11.4
working-directory: pkg/validator/justfile
args: --timeout=10m
install-mode: "goinstall"
7 changes: 2 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ pkg/cli/ CLI engine: wires finder → validators → reporters
pkg/schemastore/ SchemaStore catalog lookup and caching
pkg/configfile/ .cfv.toml config file parser
pkg/tools/ Small utility functions
internal/justfile/ Justfile lexer, parser, and semantic analyzer
internal/generate/ Code generators (known files from Linguist)
```

Expand All @@ -50,17 +49,15 @@ When asked to "run the pipeline", "run pre-checks", or "verify before push", run

```
go vet ./...
cd pkg/validator/justfile && go vet ./... && cd ../../..
test -z "$(gofmt -s -l -e .)"
golangci-lint run ./...
go generate ./pkg/filetype/...
go build -o /dev/null cmd/validator/validator.go
go test -cover -coverprofile coverage.out ./...
cd pkg/validator/justfile && go test -count=1 ./...
go tool cover -func coverage.out | grep total
```

The `pkg/validator/justfile` module has a separate `go.mod` and must be tested independently. Coverage must be ≥ 90%.
Coverage must be ≥ 90%.

For fast iteration on a single package, run its tests directly:

Expand Down Expand Up @@ -213,7 +210,7 @@ The project uses a strict golangci-lint config (`.golangci.yaml`). Common issues
- The project uses `go-git/go-git/v5` for gitignore pattern matching (not the git CLI).
- Schema validation uses JSON Schema (via `xeipuuv/gojsonschema`) and XSD (via `lestrrat-go/helium`).
- SchemaStore integration fetches schemas from schemastore.org with local disk caching.
- `pkg/validator/justfile` is a separate Go module (`github.com/Boeing/go-just`) embedded via `replace` directive in the root `go.mod`. It has its own `go.mod` (Go 1.23, no external deps) and its own `.golangci.yml`. The main module imports it as `github.com/Boeing/go-just` but the code lives in-tree. This is why it must be linted and tested separately.
- `pkg/validator/justfile` is a regular package (not a separate module) containing a justfile lexer, parser, and semantic analyzer. It has no external dependencies.
- Don't edit `pkg/filetype/known_files_gen.go` — generated by `go generate`.
- Don't edit `coverage.out` or `*_cov.out` — test artifacts.

Expand Down
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Documentation website at https://boeing.github.io/config-file-validator
- `--reporter=github` option that emits validation errors as GitHub Actions workflow commands so they appear as inline PR annotations, without requiring the separate `validate-configs-action` wrapper (closes #459)
- Justfile syntax validation (`.just`, `justfile`, `Justfile`, `.justfile`) via embedded [go-just](https://github.com/Boeing/go-just) parser
- Justfile syntax validation (`.just`, `justfile`, `Justfile`, `.justfile`) via embedded justfile parser (`pkg/validator/justfile`)
- Automatic file type detection from GitHub Linguist's `languages.yml` via `go generate`
- ~90 known filenames auto-detected (`.babelrc`, `tsconfig.json`, `Pipfile`, `pom.xml`, `.gitconfig`, etc.)
- SchemaStore now resolves schemas for extensionless known files (`.babelrc`, `.clangd`, etc.)
Expand All @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- External consumers of this module (e.g. `validate-configs-action`) can now resolve all dependencies without workarounds. The justfile parser was previously a separate nested module (`github.com/Boeing/go-just`) with a `replace` directive that didn't propagate to downstream `go.mod` files.
- Repeating the same `--reporter` type with different output paths now writes each requested output.
- KnownFiles now take priority over extension matching in the finder, so `tsconfig.json` resolves to JSONC (not JSON)
- Extension exclusion cache no longer prevents known files from being found
Expand All @@ -31,7 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Justfile syntax validation (`.just`, `justfile`, `Justfile`, `.justfile`) via embedded [go-just](https://github.com/Boeing/go-just) parser
- Justfile syntax validation (`.just`, `justfile`, `Justfile`, `.justfile`) via embedded justfile parser (`pkg/validator/justfile`)
- `--gitignore` flag to skip files and directories matched by `.gitignore` patterns, including nested `.gitignore` files, `.git/info/exclude`, and global git ignore config. Supported via CLI flag, `CFV_GITIGNORE` env var, and `gitignore = true` in `.cfv.toml`.
- Automatic file type detection from GitHub Linguist's `languages.yml` via `go generate`
- ~90 known filenames auto-detected (`.babelrc`, `tsconfig.json`, `Pipfile`, `pom.xml`, `.gitconfig`, etc.)
Expand Down
3 changes: 0 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ require (
)

require (
github.com/Boeing/go-just v0.0.0
github.com/agext/levenshtein v1.2.1 // indirect
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
Expand All @@ -51,5 +50,3 @@ require (
golang.org/x/tools v0.43.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)

replace github.com/Boeing/go-just => ./pkg/validator/justfile
8 changes: 4 additions & 4 deletions pkg/validator/justfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ package validator
import (
"errors"

"github.com/Boeing/go-just"
"github.com/Boeing/config-file-validator/v2/pkg/validator/justfile"
)

type JustfileValidator struct{}

var _ Validator = JustfileValidator{}

func (JustfileValidator) ValidateSyntax(b []byte) (bool, error) {
jf, err := gojust.Parse(b)
jf, err := justfile.Parse(b)
if err != nil {
var pe *gojust.ParseError
var pe *justfile.ParseError
if errors.As(err, &pe) {
return false, &ValidationError{
Err: errors.New(pe.Message),
Expand All @@ -26,7 +26,7 @@ func (JustfileValidator) ValidateSyntax(b []byte) (bool, error) {

diags := jf.Validate()
for _, d := range diags {
if d.Severity == gojust.SeverityError {
if d.Severity == justfile.SeverityError {
return false, &ValidationError{
Err: errors.New(d.Message),
Line: d.Pos.Line,
Expand Down
7 changes: 0 additions & 7 deletions pkg/validator/justfile/.golangci.yml

This file was deleted.

2 changes: 1 addition & 1 deletion pkg/validator/justfile/adversarial_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"strings"
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/analyzer.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import "fmt"

Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/analyzer_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"strings"
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/ast.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

// Justfile is the root AST node representing a parsed justfile.
type Justfile struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/ast_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"testing"
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/diagnostic.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import "fmt"

Expand Down
4 changes: 2 additions & 2 deletions pkg/validator/justfile/doc.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Package gojust parses and validates justfiles.
// Package justfile parses and validates justfiles.
//
// Use [Parse] to parse justfile content from bytes, or [ParseFile] to
// parse from disk with automatic import and module resolution.
// Call [Justfile.Validate] to run semantic analysis and get diagnostics.
package gojust
package justfile
2 changes: 1 addition & 1 deletion pkg/validator/justfile/fuzz_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"os"
Expand Down
4 changes: 2 additions & 2 deletions pkg/validator/justfile/generated_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"fmt"
Expand All @@ -15,7 +15,7 @@ type gen struct {
}

func newGen(seed int64) *gen {
return &gen{rng: rand.New(rand.NewPCG(uint64(seed), uint64(seed)))}
return &gen{rng: rand.New(rand.NewPCG(uint64(seed), uint64(seed)))} //nolint:gosec // G404: deterministic RNG is intentional for reproducible test generation
}

func (g *gen) pick(choices ...string) string {
Expand Down
3 changes: 0 additions & 3 deletions pkg/validator/justfile/go.mod

This file was deleted.

2 changes: 1 addition & 1 deletion pkg/validator/justfile/gojust.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"errors"
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/gojust_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"errors"
Expand Down
4 changes: 2 additions & 2 deletions pkg/validator/justfile/justdump.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build justdump

package gojust
package justfile

import (
"encoding/json"
Expand Down Expand Up @@ -303,7 +303,7 @@ func dumpExpression(expr Expression) interface{} {
case *Comparison:
return []interface{}{e.Operator, dumpExpression(e.Left), dumpExpression(e.Right)}
default:
panic(fmt.Sprintf("gojust: unhandled expression type %T in dumpExpression", expr))
panic(fmt.Sprintf("justfile: unhandled expression type %T in dumpExpression", expr))
}
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/justdump_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build justdump

package gojust
package justfile

import (
"encoding/json"
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/lexer.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"fmt"
Expand Down
4 changes: 2 additions & 2 deletions pkg/validator/justfile/lexer_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"testing"
Expand Down Expand Up @@ -569,7 +569,7 @@ func TestLexRecipeLineComparisonOpsInInterpolation(t *testing.T) {
{"or", "build:\n echo {{ if \"a\" == \"a\" || \"b\" == \"b\" { \"y\" } else { \"n\" } }}\n"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(_ *testing.T) {
_, err := Parse([]byte(tt.input))
// We're exercising the lexer paths, parse may or may not succeed
// depending on grammar support
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/multiline_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"testing"
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/parser.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"fmt"
Expand Down
4 changes: 2 additions & 2 deletions pkg/validator/justfile/parser_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"errors"
Expand Down Expand Up @@ -252,7 +252,7 @@ func TestParseErrorMissingColon(t *testing.T) {
if err == nil {
t.Fatal("expected error for missing colon")
}
pe, ok := err.(*ParseError)
pe, ok := err.(*ParseError) //nolint:errorlint // test intentionally checks the concrete type
if !ok {
t.Fatalf("expected *ParseError, got %T", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/realworld_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"os"
Expand Down
2 changes: 1 addition & 1 deletion pkg/validator/justfile/resolve_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"errors"
Expand Down
4 changes: 2 additions & 2 deletions pkg/validator/justfile/stress_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import (
"fmt"
Expand All @@ -15,7 +15,7 @@ type stressGen struct {
}

func newStressGen(seed int64) *stressGen {
return &stressGen{rng: rand.New(rand.NewPCG(uint64(seed), uint64(seed)))}
return &stressGen{rng: rand.New(rand.NewPCG(uint64(seed), uint64(seed)))} //nolint:gosec // G404: deterministic RNG is intentional for reproducible stress tests
}

func (g *stressGen) id() string {
Expand Down
3 changes: 2 additions & 1 deletion pkg/validator/justfile/token.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package gojust
package justfile

import "fmt"

Expand Down Expand Up @@ -93,6 +93,7 @@ const (
tokenEOF
)

//nolint:gosec // G101 false positive: tokenNames maps token types to display names, not credentials
var tokenNames = map[tokenType]string{
tokenIdentifier: "identifier",
tokenString: "string",
Expand Down
Loading