-
Notifications
You must be signed in to change notification settings - Fork 0
feat!: Move run logic in separate subcommand #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| package commands | ||
|
|
||
| import ( | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "log/slog" | ||
| "os" | ||
|
|
||
| "github.com/fatih/color" | ||
| "github.com/thumbrise/commitlint-scope/cmd/errs" | ||
| "github.com/thumbrise/commitlint-scope/pkg/validator" | ||
| "github.com/urfave/cli/v3" | ||
| ) | ||
|
|
||
| var ( | ||
| flagRunFrom string | ||
| flagRunTo string | ||
| flagRunVerbose bool | ||
| flagRunNoColor bool | ||
| flagRunJSON bool | ||
| ) | ||
|
|
||
| var RunCMD = &cli.Command{ | ||
| Name: "run", | ||
| Usage: "Lint commit scopes against changed files", | ||
| UsageText: "commitlint-scope run --from <sha> --to <sha>", | ||
| Description: `Validate that scopes declared in commit messages correspond to actually changed files | ||
|
|
||
| The command inspects a range of commits (from exclusive, to inclusive) and reports any scope that does not match the files modified in that commit. | ||
|
|
||
| Examples: | ||
| commitlint-scope run --from main --to feature-branch | ||
| commitlint-scope run --from HEAD~5 --to HEAD | ||
| `, | ||
| Suggest: true, | ||
| Flags: []cli.Flag{ | ||
| &cli.StringFlag{ | ||
| Name: "from", | ||
| Aliases: []string{"f"}, | ||
| Usage: "Start of the commit range (exclusive)", | ||
| Required: true, | ||
| Destination: &flagRunFrom, | ||
| }, | ||
| &cli.StringFlag{ | ||
| Name: "to", | ||
| Aliases: []string{"t"}, | ||
| Usage: "End of the commit range (inclusive)", | ||
| Required: true, | ||
| Destination: &flagRunTo, | ||
| }, | ||
| &cli.BoolFlag{ | ||
| Name: "verbose", | ||
| Aliases: []string{"v"}, | ||
| Usage: "Verbose output", | ||
| Required: false, | ||
| Destination: &flagRunVerbose, | ||
| }, | ||
| &cli.BoolFlag{ | ||
| Name: "no-color", | ||
| Usage: "Disable color output", | ||
| Required: false, | ||
| Destination: &flagRunNoColor, | ||
| }, | ||
| &cli.BoolFlag{ | ||
| Name: "json", | ||
| Usage: "Show output in JSON format", | ||
| Required: false, | ||
| Destination: &flagRunJSON, | ||
| }, | ||
| }, | ||
|
|
||
| Action: func(ctx context.Context, cmd *cli.Command) error { | ||
| color.NoColor = flagRunNoColor | ||
|
|
||
| configureLogger(os.Stderr, flagRunVerbose) | ||
|
|
||
| cfg, err := validator.LoadConfig() | ||
| if err != nil { | ||
| return fmt.Errorf("loading config: %w", err) | ||
| } | ||
|
|
||
| vld, err := validator.NewValidator(cfg, validator.Options{ | ||
| Logger: slog.Default(), | ||
| SHALength: 7, | ||
| Git: nil, | ||
| OutsiderFinder: nil, | ||
| ScopeParser: nil, | ||
| }) | ||
| if err != nil { | ||
| return fmt.Errorf("creating validator: %w", err) | ||
| } | ||
|
|
||
| violations, err := vld.Validate(ctx, flagRunFrom, flagRunTo) | ||
| if err != nil { | ||
| return fmt.Errorf("validation failed: %w", err) | ||
| } | ||
|
|
||
| if len(violations) == 0 { | ||
| return nil | ||
| } | ||
|
|
||
| if flagRunJSON { | ||
| err := jsonOutput(cmd.Writer, violations) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } else { | ||
| textOutput(cmd.Writer, violations) | ||
| } | ||
|
|
||
| return errs.NewViolationsFound(len(violations)) | ||
| }, | ||
| } | ||
|
|
||
| func textOutput(w io.Writer, violations []validator.Violation) { | ||
| shaColor := color.New(color.FgYellow, color.Bold) | ||
| for _, v := range violations { | ||
| _, _ = fmt.Fprintf(w, "%s %s\n", shaColor.Sprintf("%s", v.SHA), v.Header) | ||
| for _, o := range v.Outsiders { | ||
| _, _ = fmt.Fprintf(w, " - %s\n", o.File) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| func jsonOutput(writer io.Writer, violations []validator.Violation) error { | ||
| encoder := json.NewEncoder(writer) | ||
| encoder.SetIndent("", " ") | ||
|
|
||
| if err := encoder.Encode(violations); err != nil { | ||
| return fmt.Errorf("failed to output violations: %w", err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func configureLogger(writer io.Writer, verbose bool) { | ||
| opts := &slog.HandlerOptions{ | ||
| AddSource: false, | ||
| Level: slog.LevelInfo, | ||
| } | ||
|
|
||
| if verbose { | ||
| opts.Level = slog.LevelDebug | ||
| opts.AddSource = true | ||
| } | ||
|
|
||
| handler := slog.NewTextHandler(writer, opts) | ||
|
|
||
| logger := slog.New(handler) | ||
|
|
||
| slog.SetDefault(logger) | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,21 @@ | ||||||||||||||||||||
| package errs | ||||||||||||||||||||
|
|
||||||||||||||||||||
| import ( | ||||||||||||||||||||
| "fmt" | ||||||||||||||||||||
| ) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| type ViolationsFoundError struct { | ||||||||||||||||||||
| num int | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| func NewViolationsFound(num int) *ViolationsFoundError { | ||||||||||||||||||||
| return &ViolationsFoundError{num: num} | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
Comment on lines
+11
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate that The constructor should validate that 🛡️ Proposed fix to add validation func NewViolationsFound(num int) *ViolationsFoundError {
+ if num <= 0 {
+ panic(fmt.Sprintf("ViolationsFoundError requires num > 0, got %d", num))
+ }
return &ViolationsFoundError{num: num}
}Alternatively, return an error from the constructor: -func NewViolationsFound(num int) *ViolationsFoundError {
+func NewViolationsFound(num int) (*ViolationsFoundError, error) {
+ if num <= 0 {
+ return nil, fmt.Errorf("violations count must be positive, got %d", num)
+ }
return &ViolationsFoundError{num: num}, nil
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
|
|
||||||||||||||||||||
| func (v ViolationsFoundError) Error() string { | ||||||||||||||||||||
| return fmt.Sprintf("%d violations found", v.num) | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| func (v ViolationsFoundError) ExitCode() int { | ||||||||||||||||||||
| return 2 | ||||||||||||||||||||
| } | ||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.