feat: enforce proto generation freshness
This commit is contained in:
parent
f968cb31d9
commit
936a7e7ef9
@ -42,7 +42,37 @@ func init() {
|
|||||||
fmt.Println(" SKIP: no sqlc or buf codegen targets found")
|
fmt.Println(" SKIP: no sqlc or buf codegen targets found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protoFreshness, protoFreshnessErr := checkProtoGeneratedFreshness(ctx.repoRoot)
|
||||||
|
if protoFreshnessErr != nil {
|
||||||
|
fmt.Printf(" ERROR: failed to run make proto freshness check: %v\n", protoFreshnessErr)
|
||||||
|
if protoFreshness.output != "" {
|
||||||
|
for line := range strings.SplitSeq(protoFreshness.output, "\n") {
|
||||||
|
fmt.Printf(" %s\n", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rep.Fail()
|
||||||
|
} else if protoFreshness.changed() {
|
||||||
|
fmt.Println(" FAIL: make proto changed generated outputs; run make proto and commit the generated files.")
|
||||||
|
fmt.Println(" before:")
|
||||||
|
printIndentedStatus(protoFreshness.beforeStatus)
|
||||||
|
fmt.Println(" after:")
|
||||||
|
printIndentedStatus(protoFreshness.afterStatus)
|
||||||
|
rep.Fail()
|
||||||
|
} else if protoFreshness.checked {
|
||||||
|
fmt.Println(" OK: make proto freshness check clean")
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printIndentedStatus(status string) {
|
||||||
|
if strings.TrimSpace(status) == "" {
|
||||||
|
fmt.Println(" (clean)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for line := range strings.SplitSeq(status, "\n") {
|
||||||
|
fmt.Printf(" %s\n", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -138,6 +138,12 @@ func checkPlaceholderLanguage(roots []todoScanRoot) []comingSoonViolation {
|
|||||||
if strings.HasSuffix(path, "_test.go") || strings.HasSuffix(path, ".test.tsx") {
|
if strings.HasSuffix(path, "_test.go") || strings.HasSuffix(path, ".test.tsx") {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
slashPath := filepath.ToSlash(path)
|
||||||
|
if strings.Contains(slashPath, "/generated/") ||
|
||||||
|
strings.HasSuffix(slashPath, ".pb.go") ||
|
||||||
|
strings.HasSuffix(slashPath, ".connect.go") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if strings.Contains(filepath.ToSlash(path), "cmd/check-safety/") {
|
if strings.Contains(filepath.ToSlash(path), "cmd/check-safety/") {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,13 @@ type protoOwnershipViolation struct {
|
|||||||
coreProto string
|
coreProto string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type protoFreshnessResult struct {
|
||||||
|
checked bool
|
||||||
|
beforeStatus string
|
||||||
|
afterStatus string
|
||||||
|
output string
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bufModulePathPattern = regexp.MustCompile(`^(?:-\s*)?path:\s*"?([^"\s]+)"?\s*$`)
|
bufModulePathPattern = regexp.MustCompile(`^(?:-\s*)?path:\s*"?([^"\s]+)"?\s*$`)
|
||||||
protoPackagePattern = regexp.MustCompile(`^\s*package\s+([A-Za-z0-9_.]+)\s*;\s*$`)
|
protoPackagePattern = regexp.MustCompile(`^\s*package\s+([A-Za-z0-9_.]+)\s*;\s*$`)
|
||||||
@ -729,6 +736,52 @@ func countRBACRoles(protoMethods []string, roleByMethod map[string]string) map[s
|
|||||||
return counts
|
return counts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkProtoGeneratedFreshness(repoRoot string) (protoFreshnessResult, error) {
|
||||||
|
result := protoFreshnessResult{}
|
||||||
|
if !samePath(repoRoot, blockNinjaRepoRoot()) {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
if !fileExists(filepath.Join(repoRoot, "Makefile")) || !fileExists(filepath.Join(repoRoot, "buf.gen.yaml")) {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result.checked = true
|
||||||
|
before, err := protoGeneratedStatus(repoRoot)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
result.beforeStatus = before
|
||||||
|
|
||||||
|
output, runErr := runCommand(repoRoot, "make", "proto")
|
||||||
|
result.output = output
|
||||||
|
|
||||||
|
after, statusErr := protoGeneratedStatus(repoRoot)
|
||||||
|
if statusErr != nil {
|
||||||
|
return result, statusErr
|
||||||
|
}
|
||||||
|
result.afterStatus = after
|
||||||
|
|
||||||
|
if runErr != nil {
|
||||||
|
return result, fmt.Errorf("make proto failed: %w", runErr)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r protoFreshnessResult) changed() bool {
|
||||||
|
return r.checked && r.beforeStatus != r.afterStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
func protoGeneratedStatus(repoRoot string) (string, error) {
|
||||||
|
paths := []string{
|
||||||
|
"backend/internal/api",
|
||||||
|
"backend/internal/mcpserver/generated",
|
||||||
|
"packages/api/src",
|
||||||
|
}
|
||||||
|
args := []string{"status", "--porcelain=v1", "--untracked-files=all", "--"}
|
||||||
|
args = append(args, paths...)
|
||||||
|
return runCommand(repoRoot, "git", args...)
|
||||||
|
}
|
||||||
|
|
||||||
func printRoleBreakdown(roleCounts map[string]int) {
|
func printRoleBreakdown(roleCounts map[string]int) {
|
||||||
orderedRoles := []string{"public", "viewer", "user", "admin", "superadmin", "cms"}
|
orderedRoles := []string{"public", "viewer", "user", "admin", "superadmin", "cms"}
|
||||||
printed := make(map[string]bool)
|
printed := make(map[string]bool)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user