Check committed file sizes
This commit is contained in:
@@ -131,6 +131,15 @@ type ValidationSettings struct {
|
||||
// Omitted or false disables the check.
|
||||
GoFormat bool `json:"go_format,omitempty"`
|
||||
ModuleDistribution ModuleDistributionSettings `json:"module_distribution,omitempty"`
|
||||
// FileSize checks the size of each committed blob. Null or omission disables
|
||||
// the check; an empty object enables the default limit.
|
||||
FileSize *FileSizeSettings `json:"file_size,omitempty"`
|
||||
}
|
||||
|
||||
// FileSizeSettings selects the maximum committed-file size and literal exclusions.
|
||||
type FileSizeSettings struct {
|
||||
LimitBytes *int64 `json:"limit_bytes,omitempty"`
|
||||
Exclusions []string `json:"exclusions,omitempty"`
|
||||
}
|
||||
|
||||
// ModuleDistributionSettings selects committed module-source distribution checks.
|
||||
@@ -236,6 +245,9 @@ func LoadSettings(repoDir, configPath string) (Settings, error) {
|
||||
}
|
||||
}
|
||||
if settings.Validation != nil {
|
||||
if fileSize := settings.Validation.FileSize; fileSize != nil && fileSize.LimitBytes != nil && *fileSize.LimitBytes < 0 {
|
||||
return Settings{}, fmt.Errorf("profile %q: validation.file_size.limit_bytes must not be negative", configPath)
|
||||
}
|
||||
for i, target := range settings.Validation.Go.CompileTargets {
|
||||
if strings.Count(target, "/") != 1 {
|
||||
return Settings{}, fmt.Errorf("profile %q: validation.go.compile_targets[%d] must be GOOS/GOARCH", configPath, i)
|
||||
|
||||
@@ -144,7 +144,7 @@ func TestLoadSettingsDefaultsRemoteAndConfigPath(t *testing.T) {
|
||||
func TestLoadSettingsReadsGoValidation(t *testing.T) {
|
||||
repoDir := t.TempDir()
|
||||
profilePath := filepath.Join(repoDir, "releasekit.json")
|
||||
if err := os.WriteFile(profilePath, []byte(`{"product":"Example","expected_push_url":"ssh://git.example/owner/repo.git","validation":{"go_format":true,"module_distribution":{"workspace_files":true,"local_replacements":true},"go":{"race":true,"full_vet":true,"compile_targets":["linux/amd64","linux/arm64","darwin/arm64"]}}}`), 0o600); err != nil {
|
||||
if err := os.WriteFile(profilePath, []byte(`{"product":"Example","expected_push_url":"ssh://git.example/owner/repo.git","validation":{"go_format":true,"module_distribution":{"workspace_files":true,"local_replacements":true},"file_size":{"limit_bytes":0,"exclusions":["assets"]},"go":{"race":true,"full_vet":true,"compile_targets":["linux/amd64","linux/arm64","darwin/arm64"]}}}`), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -155,6 +155,9 @@ func TestLoadSettingsReadsGoValidation(t *testing.T) {
|
||||
if settings.Validation == nil || !settings.Validation.GoFormat || !settings.Validation.ModuleDistribution.WorkspaceFiles || !settings.Validation.ModuleDistribution.LocalReplacements || !settings.Validation.Go.Race || !settings.Validation.Go.FullVet {
|
||||
t.Fatalf("validation settings = %#v, want Go formatting, workspace inspection, race, and full vet enabled", settings.Validation)
|
||||
}
|
||||
if settings.Validation.FileSize == nil || settings.Validation.FileSize.LimitBytes == nil || *settings.Validation.FileSize.LimitBytes != 0 || len(settings.Validation.FileSize.Exclusions) != 1 || settings.Validation.FileSize.Exclusions[0] != "assets" {
|
||||
t.Fatalf("file size settings = %#v, want explicit zero limit and exclusions", settings.Validation.FileSize)
|
||||
}
|
||||
if got, want := strings.Join(settings.Validation.Go.CompileTargets, ","), "linux/amd64,linux/arm64,darwin/arm64"; got != want {
|
||||
t.Fatalf("compile targets = %q, want %q", got, want)
|
||||
}
|
||||
@@ -163,6 +166,47 @@ func TestLoadSettingsReadsGoValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadSettingsPreservesEmptyAndNullFileSize(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
profile string
|
||||
enabled bool
|
||||
}{
|
||||
{name: "empty object", profile: `{"product":"Example","validation":{"file_size":{}}}`, enabled: true},
|
||||
{name: "default limit", profile: `{"product":"Example","validation":{"file_size":{"limit_bytes":null}}}`, enabled: true},
|
||||
{name: "null object", profile: `{"product":"Example","validation":{"file_size":null}}`},
|
||||
{name: "omitted object", profile: `{"product":"Example","validation":{}}`},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
repoDir := t.TempDir()
|
||||
profilePath := filepath.Join(repoDir, "releasekit.json")
|
||||
if err := os.WriteFile(profilePath, []byte(test.profile), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
settings, err := LoadSettings(repoDir, profilePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := settings.Validation != nil && settings.Validation.FileSize != nil
|
||||
if got != test.enabled {
|
||||
t.Fatalf("FileSize enabled = %t, want %t", got, test.enabled)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadSettingsRejectsNegativeFileSizeLimit(t *testing.T) {
|
||||
repoDir := t.TempDir()
|
||||
profilePath := filepath.Join(repoDir, "releasekit.json")
|
||||
profile := `{"product":"Example","validation":{"file_size":{"limit_bytes":-1}}}`
|
||||
if err := os.WriteFile(profilePath, []byte(profile), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := LoadSettings(repoDir, profilePath); err == nil || !strings.Contains(err.Error(), "validation.file_size.limit_bytes") {
|
||||
t.Fatalf("LoadSettings() error = %v, want invalid negative file-size limit", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExampleProfileLoads(t *testing.T) {
|
||||
repoDir, err := filepath.Abs(filepath.Join("..", "..", "..", ".."))
|
||||
if err != nil {
|
||||
|
||||
@@ -172,6 +172,17 @@ func validationSpec(settings *cli.ValidationSettings) releasekit.ValidationSpec
|
||||
CompileTargets: make([]releasekit.Target, len(settings.Go.CompileTargets)),
|
||||
},
|
||||
}
|
||||
if settings.FileSize != nil {
|
||||
var limitBytes *int64
|
||||
if settings.FileSize.LimitBytes != nil {
|
||||
limit := *settings.FileSize.LimitBytes
|
||||
limitBytes = &limit
|
||||
}
|
||||
result.FileSize = &releasekit.FileSizeValidationSpec{
|
||||
LimitBytes: limitBytes,
|
||||
Exclusions: append([]string(nil), settings.FileSize.Exclusions...),
|
||||
}
|
||||
}
|
||||
for index, target := range settings.Go.CompileTargets {
|
||||
goos, goarch, _ := strings.Cut(target, "/")
|
||||
result.Go.CompileTargets[index] = releasekit.Target{OS: goos, Arch: goarch}
|
||||
|
||||
@@ -113,6 +113,7 @@ func TestCheckCommandBindsConfiguredChecksToCapturedCandidate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCandidateRequestMapsGoValidation(t *testing.T) {
|
||||
limit := int64(2048)
|
||||
request := candidateRequest(cli.Invocation{Repository: "repository", Version: "v1.2.3"}, cli.Settings{
|
||||
Product: "Example Product",
|
||||
ExpectedPushURL: "publication-only value",
|
||||
@@ -120,6 +121,7 @@ func TestCandidateRequestMapsGoValidation(t *testing.T) {
|
||||
GoFormat: true,
|
||||
Go: cli.GoValidationSettings{Race: true, FullVet: true, CompileTargets: []string{"linux/amd64", "darwin/arm64"}},
|
||||
ModuleDistribution: cli.ModuleDistributionSettings{WorkspaceFiles: true, LocalReplacements: true},
|
||||
FileSize: &cli.FileSizeSettings{LimitBytes: &limit, Exclusions: []string{"cache"}},
|
||||
},
|
||||
}, nil)
|
||||
if !request.Validation.Go.Race || !request.Validation.Go.FullVet {
|
||||
@@ -131,6 +133,9 @@ func TestCandidateRequestMapsGoValidation(t *testing.T) {
|
||||
if !request.Validation.ModuleDistribution.WorkspaceFiles || !request.Validation.ModuleDistribution.LocalReplacements {
|
||||
t.Fatalf("candidate request module distribution = %#v, want both checks enabled", request.Validation.ModuleDistribution)
|
||||
}
|
||||
if request.Validation.FileSize == nil || request.Validation.FileSize.LimitBytes == nil || *request.Validation.FileSize.LimitBytes != limit || len(request.Validation.FileSize.Exclusions) != 1 || request.Validation.FileSize.Exclusions[0] != "cache" {
|
||||
t.Fatalf("candidate request file size = %#v, want configured limit and exclusions", request.Validation.FileSize)
|
||||
}
|
||||
if request.ExpectedPushURL != "" {
|
||||
t.Fatalf("candidate request carried publication-only expected push URL %q", request.ExpectedPushURL)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user