diff --git a/check.go b/check.go index d9f9024..d7da521 100644 --- a/check.go +++ b/check.go @@ -59,7 +59,7 @@ type ReleaseRequest struct { // module and shared-file inputs. Independent nested modules form automatic // input boundaries; vendored files remain included. Referenced destinations // remain available for targeted inspection without expanding the input set. -// UntrackedFiles checks explicitly selected repository paths independently of +// ForbiddenFiles checks explicitly selected repository paths independently of // those file inputs. type ValidationSpec struct { // SharedFiles adds repository-relative committed files to optional file @@ -68,10 +68,10 @@ type ValidationSpec struct { // Explicit files replace the defaults and must exist even when file checks // are off. SharedFiles []string - // UntrackedFiles lists literal repository-relative file paths that must be + // ForbiddenFiles lists literal repository-relative file paths that must be // absent from the captured commit, independently of module/shared inputs. // An empty list disables the check. File contents and history are not read. - UntrackedFiles []string + ForbiddenFiles []string Go GoValidationSpec // GoFormat checks the formatting of committed regular Go source files. It // does not modify repository contents and is disabled when false. @@ -143,7 +143,7 @@ type GoValidationSpec struct { // of test-time vet, and Validation.Go.CompileTargets compiles all packages for // each selected GOOS/GOARCH pair after tests and vet with cgo disabled. Package // compilation produces no artifacts and does not execute target binaries. -// Validation.UntrackedFiles checks that selected repository-relative files are +// Validation.ForbiddenFiles checks that selected repository-relative files are // absent from the captured commit after Go checks and before other file checks. // Validation.GoFormat checks regular committed Go source after those selected // Go checks and before AdditionalChecks. Its zero value disables formatting. @@ -197,7 +197,7 @@ func candidateRequest(request ReleaseRequest) candidate.Request { FullVet: request.Validation.Go.FullVet, CompileTargets: make([]validation.Target, len(request.Validation.Go.CompileTargets)), SharedFiles: copyStringSlice(request.Validation.SharedFiles), - UntrackedFiles: copyStringSlice(request.Validation.UntrackedFiles), + ForbiddenFiles: copyStringSlice(request.Validation.ForbiddenFiles), GoFormat: request.Validation.GoFormat, Markdown: internalMarkdownSettings(request.Validation.Markdown), ModuleDistribution: validation.ModuleDistributionSettings{ diff --git a/cmd/releasekit/internal/cli/config.go b/cmd/releasekit/internal/cli/config.go index c533cd3..983a057 100644 --- a/cmd/releasekit/internal/cli/config.go +++ b/cmd/releasekit/internal/cli/config.go @@ -154,7 +154,7 @@ type ValidationSettings struct { // SharedFiles selects committed files relative to the repository root. // Nil uses optional defaults; a non-nil empty slice selects no shared files. SharedFiles []string `json:"shared_files"` - UntrackedFiles []string `json:"untracked_files,omitempty"` + ForbiddenFiles []string `json:"forbidden_files,omitempty"` Go GoValidationSettings `json:"go,omitempty"` // GoFormat checks the formatting of committed regular Go source files. // Omitted or false disables the check. diff --git a/cmd/releasekit/main.go b/cmd/releasekit/main.go index a7ca2a2..500c97c 100644 --- a/cmd/releasekit/main.go +++ b/cmd/releasekit/main.go @@ -182,7 +182,7 @@ func validationSpec(settings *cli.ValidationSettings) releasekit.ValidationSpec } result := releasekit.ValidationSpec{ SharedFiles: copyStringsPreservingEmpty(settings.SharedFiles), - UntrackedFiles: copyStringsPreservingEmpty(settings.UntrackedFiles), + ForbiddenFiles: copyStringsPreservingEmpty(settings.ForbiddenFiles), GoFormat: settings.GoFormat, ModuleDistribution: releasekit.ModuleDistributionValidationSpec{ WorkspaceFiles: settings.ModuleDistribution.WorkspaceFiles, diff --git a/cmd/releasekit/token_file_test.go b/cmd/releasekit/token_file_test.go index 919aabc..ed3db8e 100644 --- a/cmd/releasekit/token_file_test.go +++ b/cmd/releasekit/token_file_test.go @@ -53,11 +53,11 @@ func TestDeliveryTokenFileSelection(t *testing.T) { } } -func TestCheckReadsUntrackedFilesSelectionFromProfile(t *testing.T) { +func TestCheckReadsForbiddenFilesSelectionFromProfile(t *testing.T) { repository := newCLIRepository(t) writeDeliveryProfile(t, repository, cli.Settings{ Product: "Example Product", - Validation: &cli.ValidationSettings{UntrackedFiles: []string{"token-file"}}, + Validation: &cli.ValidationSettings{ForbiddenFiles: []string{"token-file"}}, Delivery: &cli.DeliverySettings{BaseURL: "https://gitea.example", Owner: "owner", Repository: "example", TokenFile: "missing-token-file"}, }) writeRepositoryFile(t, repository, "token-file", "fixture-secret\n") @@ -65,7 +65,7 @@ func TestCheckReadsUntrackedFilesSelectionFromProfile(t *testing.T) { cliGitRun(t, repository, "commit", "-m", "capture a selected token path") var stdout, stderr bytes.Buffer status := run(context.Background(), []string{"check", "--repo", repository, "v1.2.3"}, &stdout, &stderr) - if status != 1 || !strings.Contains(stderr.String(), "untracked-files") || !strings.Contains(stderr.String(), "token-file") { + if status != 1 || !strings.Contains(stderr.String(), "forbidden-files") || !strings.Contains(stderr.String(), "token-file") { t.Fatalf("check status=%d output=%s diagnostics=%s", status, &stdout, &stderr) } if strings.Contains(stdout.String()+stderr.String(), "fixture-secret") { diff --git a/docs/config.md b/docs/config.md index 70b4687..b05e658 100644 --- a/docs/config.md +++ b/docs/config.md @@ -141,9 +141,9 @@ symlink size is the committed link text. Gitlinks have no measured size. Only the captured candidate is checked, one offending file is reported at a time, and historical or aggregate repository size is not measured. -`validation.untracked_files` is an optional list of literal repository-relative +`validation.forbidden_files` is an optional list of literal repository-relative file paths that must be absent from the captured commit. It runs after the Go -checks and before other file checks, using the `untracked-files` identity and +checks and before other file checks, using the `forbidden-files` identity and reporting selected committed paths. Omission, `null`, or `[]` disables it. Paths use slash separators and ordinary relative normalization and must stay within the repository. They are checked against the whole captured repository, @@ -166,7 +166,7 @@ the absence of both credential sources, returns status 2. Omission of Credential loading runs only for `deliver` and `ci-deliver`. `check`, `publish`, and `build` do not read the token file or require a token. The CLI passes the resolved value explicitly to the library operation. Selecting a token file and -selecting the optional untracked-file validator are independent settings. +selecting the optional forbidden-file validator are independent settings. `expected_push_url`, when nonempty, is compared exactly with Git's resolved effective push URL during `publish`, before candidate validation. It applies diff --git a/docs/consumers/check.md b/docs/consumers/check.md index 367577d..3ee3383 100644 --- a/docs/consumers/check.md +++ b/docs/consumers/check.md @@ -98,9 +98,9 @@ The `Candidate` supplies both `RepositoryDir` and `ModuleDir`, plus the declared module-local product checks. ReleaseKit calls `AdditionalChecks` once after shared validation when supplied. -For local token files, set `Validation.UntrackedFiles` to the repository-relative +For local token files, set `Validation.ForbiddenFiles` to the repository-relative paths that should stay out of the committed candidate, such as -`[]string{".releasekit/gitea-token"}`. Failures use `untracked-files` and carry the +`[]string{".releasekit/gitea-token"}`. Failures use `forbidden-files` and carry the selected committed paths in `ValidationError.Findings`. This selection is independent of module and shared-file inputs; see [GoDoc](../../check.go) for the API contract and the [configuration reference](../config.md) for CLI use. diff --git a/docs/consumers/delivery.md b/docs/consumers/delivery.md index 562d192..51f06d0 100644 --- a/docs/consumers/delivery.md +++ b/docs/consumers/delivery.md @@ -90,7 +90,7 @@ as `.releasekit/gitea-token` and configure: { "product": "Example", "validation": { - "untracked_files": [".releasekit/gitea-token"] + "forbidden_files": [".releasekit/gitea-token"] }, "delivery": { "base_url": "https://gitea.example", diff --git a/docs/internal/validation.md b/docs/internal/validation.md index eff7550..4e3703e 100644 --- a/docs/internal/validation.md +++ b/docs/internal/validation.md @@ -59,9 +59,9 @@ workspace-file check using the same candidate inventory. Resolved module bodies are parsed once per blob object ID; only owned filesystem-replacement targets and line numbers remain cached. Each declaration path receives findings from that summary in its own path context. -The optional untracked-file check uses the captured tree's full path lookup +The optional forbidden-file check uses the captured tree's full path lookup before the other file checks. It normalizes the explicitly selected -repository-relative names and reports matching entries through `untracked-files` +repository-relative names and reports matching entries through `forbidden-files` without loading their blobs. Candidate-tree cleanup covers this failure path. The optional file-size check applies normalized literal file/directory exclusions with path-boundary matching, then requests local Git sizes for the diff --git a/docs/release.md b/docs/release.md index a10e280..a71b0ba 100644 --- a/docs/release.md +++ b/docs/release.md @@ -18,7 +18,7 @@ For local hosted-page delivery, save a Gitea personal access token in `.releasekit/gitea-token` with owner-only file permissions. The file contains only the token. ReleaseKit's profile selects this file as a fallback to `RELEASEKIT_GITEA_TOKEN`; `.releasekit/` is already ignored. Its optional -`validation.untracked_files` selection checks that this path is absent from the +`validation.forbidden_files` selection checks that this path is absent from the committed candidate. Source publication requires no delivery token. The [configuration reference](config.md) owns credential selection and validator semantics. diff --git a/internal/validation/diagnostic.go b/internal/validation/diagnostic.go index e7aea60..928d6f5 100644 --- a/internal/validation/diagnostic.go +++ b/internal/validation/diagnostic.go @@ -27,8 +27,8 @@ const ( MarkdownLinks Check = "markdown-links" // SharedFiles identifies a requested shared file that is unavailable. SharedFiles Check = "shared-files" - // UntrackedFiles identifies selected paths present in the committed source. - UntrackedFiles Check = "untracked-files" + // ForbiddenFiles identifies selected paths present in the committed source. + ForbiddenFiles Check = "forbidden-files" ) // Finding describes a validation observation at an optional source location. diff --git a/internal/validation/untracked_files.go b/internal/validation/forbidden_files.go similarity index 82% rename from internal/validation/untracked_files.go rename to internal/validation/forbidden_files.go index c9db5bf..86b7a43 100644 --- a/internal/validation/untracked_files.go +++ b/internal/validation/forbidden_files.go @@ -5,7 +5,7 @@ import ( "strings" ) -func checkUntrackedFiles(tree *CandidateTree, names []string) error { +func checkForbiddenFiles(tree *CandidateTree, names []string) error { var findings []Finding for _, name := range names { clean := path.Clean(name) @@ -20,5 +20,5 @@ func checkUntrackedFiles(tree *CandidateTree, names []string) error { if len(findings) == 0 { return nil } - return &Failure{Check: UntrackedFiles, Findings: findings} + return &Failure{Check: ForbiddenFiles, Findings: findings} } diff --git a/internal/validation/untracked_files_test.go b/internal/validation/forbidden_files_test.go similarity index 80% rename from internal/validation/untracked_files_test.go rename to internal/validation/forbidden_files_test.go index fdc6c10..bc1e040 100644 --- a/internal/validation/untracked_files_test.go +++ b/internal/validation/forbidden_files_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -func TestUntrackedFilesUsesCapturedRepositoryPaths(t *testing.T) { +func TestForbiddenFilesUsesCapturedRepositoryPaths(t *testing.T) { repository := newTreeRepository(t) writeTreeFile(t, repository, "go.mod", []byte("module example.com/root\n")) writeTreeFile(t, repository, "nested/go.mod", []byte("module example.com/nested\n")) @@ -27,21 +27,21 @@ func TestUntrackedFilesUsesCapturedRepositoryPaths(t *testing.T) { if err := Run(context.Background(), request); err != nil { t.Fatal(err) } - request.Settings.UntrackedFiles = []string{".releasekit/token", "absent-token"} + request.Settings.ForbiddenFiles = []string{".releasekit/token", "absent-token"} if err := Run(context.Background(), request); err != nil { t.Fatal(err) } - request.Settings.UntrackedFiles = []string{"nested/./token"} + request.Settings.ForbiddenFiles = []string{"nested/./token"} err := Run(context.Background(), request) failure, ok := err.(*Failure) - if !ok || failure.Check != UntrackedFiles || len(failure.Findings) != 1 || failure.Findings[0].Path != "nested/token" { - t.Fatalf("untracked-files error = %v, want committed nested path despite worktree deletion", err) + if !ok || failure.Check != ForbiddenFiles || len(failure.Findings) != 1 || failure.Findings[0].Path != "nested/token" { + t.Fatalf("forbidden-files error = %v, want committed nested path despite worktree deletion", err) } if strings.Contains(err.Error(), "fixture-secret") { t.Fatal("validation exposed committed token bytes") } for _, invalid := range []string{"", "../token", "/token"} { - request.Settings.UntrackedFiles = []string{invalid} + request.Settings.ForbiddenFiles = []string{invalid} if err := Run(context.Background(), request); err == nil { t.Fatalf("invalid path %q was accepted", invalid) } diff --git a/internal/validation/validation.go b/internal/validation/validation.go index 2403418..65790fb 100644 --- a/internal/validation/validation.go +++ b/internal/validation/validation.go @@ -21,7 +21,7 @@ type Settings struct { FullVet bool CompileTargets []Target SharedFiles []string - UntrackedFiles []string + ForbiddenFiles []string GoFormat bool Markdown *MarkdownSettings ModuleDistribution ModuleDistributionSettings @@ -135,7 +135,7 @@ func Run(ctx context.Context, request Request) (result error) { } } needsSharedSelection := len(request.Settings.SharedFiles) != 0 - if request.Settings.GoFormat || request.Settings.ModuleDistribution.WorkspaceFiles || request.Settings.ModuleDistribution.LocalReplacements || request.Settings.FileSize != nil || request.Settings.Markdown != nil || needsSharedSelection || len(request.Settings.UntrackedFiles) != 0 { + if request.Settings.GoFormat || request.Settings.ModuleDistribution.WorkspaceFiles || request.Settings.ModuleDistribution.LocalReplacements || request.Settings.FileSize != nil || request.Settings.Markdown != nil || needsSharedSelection || len(request.Settings.ForbiddenFiles) != 0 { tree, err := request.ReadCandidateTree(ctx) if err != nil { var failure *Failure @@ -155,8 +155,8 @@ func Run(ctx context.Context, request Request) (result error) { if request.Settings.GoFormat { check = GoFormat } - if len(request.Settings.UntrackedFiles) != 0 { - check = UntrackedFiles + if len(request.Settings.ForbiddenFiles) != 0 { + check = ForbiddenFiles } return &Failure{Check: check, Cause: err} } @@ -170,7 +170,7 @@ func Run(ctx context.Context, request Request) (result error) { } } }() - if err := checkUntrackedFiles(tree, request.Settings.UntrackedFiles); err != nil { + if err := checkForbiddenFiles(tree, request.Settings.ForbiddenFiles); err != nil { return err } if request.Settings.GoFormat { diff --git a/releasekit.json b/releasekit.json index 9912e30..f2e3313 100644 --- a/releasekit.json +++ b/releasekit.json @@ -2,7 +2,7 @@ "product": "ReleaseKit", "remote": "origin", "validation": { - "untracked_files": [".releasekit/gitea-token"] + "forbidden_files": [".releasekit/gitea-token"] }, "delivery": { "base_url": "https://forge.maximumdirect.net", diff --git a/token_validation_test.go b/token_validation_test.go index 9f47b43..a3620c4 100644 --- a/token_validation_test.go +++ b/token_validation_test.go @@ -16,7 +16,7 @@ func TestCommittedTokenFilePreventsCheckAndPublication(t *testing.T) { gitRun(t, repo.work, "add", "local-token") gitRun(t, repo.work, "commit", "-m", "capture token path") request := releasekit.ReleaseRequest{RepositoryDir: repo.work, Product: "Sample App", Version: "v1.2.3", - Validation: releasekit.ValidationSpec{UntrackedFiles: []string{"local-token"}}, + Validation: releasekit.ValidationSpec{ForbiddenFiles: []string{"local-token"}}, } var err error if operation == "check" { @@ -27,8 +27,8 @@ func TestCommittedTokenFilePreventsCheckAndPublication(t *testing.T) { _, err = releasekit.Publish(context.Background(), request) } var failure *releasekit.ValidationError - if !errors.As(err, &failure) || failure.Check != "untracked-files" || len(failure.Findings) != 1 || failure.Findings[0].Path != "local-token" { - t.Fatalf("operation error=%v, want public untracked-files diagnostic", err) + if !errors.As(err, &failure) || failure.Check != "forbidden-files" || len(failure.Findings) != 1 || failure.Findings[0].Path != "local-token" { + t.Fatalf("operation error=%v, want public forbidden-files diagnostic", err) } if gitText(t, repo.work, "tag", "--list", "v1.2.3") != "" { t.Fatal("token-file validation created a release tag") diff --git a/validation_error.go b/validation_error.go index 68b4581..d9b7576 100644 --- a/validation_error.go +++ b/validation_error.go @@ -9,7 +9,7 @@ import ( // ValidationCheck identifies a shared validation check that failed. // Current checks include "go-test", "go-vet", "package-compile", "go-format", -// "workspace-files", "local-replacements", "untracked-files", "file-size", +// "workspace-files", "local-replacements", "forbidden-files", "file-size", // and "markdown-links". type ValidationCheck string