diff --git a/cmd/run.go b/cmd/run.go index 22a9b614..2f4aad04 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -94,6 +94,11 @@ func (run) New(opts *lefthook.Options) *cobra.Command { "run only specified commands", ) + runCmd.Flags().StringSliceVar( + &runArgs.RunOnlyJobs, "jobs", nil, + "run only specified jobs", + ) + err := runCmd.Flags().MarkDeprecated("files", "use --file flag instead") if err != nil { log.Warn("Unexpected error:", err) diff --git a/internal/lefthook/run.go b/internal/lefthook/run.go index 2d41798c..3331de63 100644 --- a/internal/lefthook/run.go +++ b/internal/lefthook/run.go @@ -33,6 +33,7 @@ type RunArgs struct { SkipLFS bool Files []string RunOnlyCommands []string + RunOnlyJobs []string } func Run(opts *Options, args RunArgs, hookName string, gitArgs []string) error { @@ -170,6 +171,7 @@ func (l *Lefthook) Run(hookName string, args RunArgs, gitArgs []string) error { Files: args.Files, Force: args.Force, RunOnlyCommands: args.RunOnlyCommands, + RunOnlyJobs: args.RunOnlyJobs, SourceDirs: sourceDirs, }, ) diff --git a/internal/lefthook/runner/run_jobs.go b/internal/lefthook/runner/run_jobs.go index 827eeccb..30ea77cc 100644 --- a/internal/lefthook/runner/run_jobs.go +++ b/internal/lefthook/runner/run_jobs.go @@ -4,6 +4,7 @@ import ( "context" "errors" "path/filepath" + "slices" "strconv" "sync" "sync/atomic" @@ -24,8 +25,9 @@ var ( type domain struct { failed *atomic.Bool - glob string - root string + glob string + root string + onlyJobs []string } func (r *Runner) runJobs(ctx context.Context) []Result { @@ -35,7 +37,7 @@ func (r *Runner) runJobs(ctx context.Context) []Result { resultsChan := make(chan Result, len(r.Hook.Jobs)) var failed atomic.Bool - domain := &domain{failed: &failed} + domain := &domain{failed: &failed, onlyJobs: r.RunOnlyJobs} for i, job := range r.Hook.Jobs { id := strconv.Itoa(i) @@ -81,6 +83,10 @@ func (r *Runner) runJob(ctx context.Context, domain *domain, id string, job *con } if len(job.Run) != 0 || len(job.Script) != 0 { + if len(domain.onlyJobs) != 0 && !slices.Contains(domain.onlyJobs, job.Name) { + return skipped(job.PrintableName(id)) + } + return r.runSingleJob(ctx, domain, id, job) } @@ -89,6 +95,11 @@ func (r *Runner) runJob(ctx context.Context, domain *domain, id string, job *con inheritedDomain.glob = first(job.Glob, domain.glob) inheritedDomain.root = first(job.Root, domain.root) groupName := first(job.Name, "["+id+"]") + + if len(domain.onlyJobs) != 0 && slices.Contains(domain.onlyJobs, job.Name) { + inheritedDomain.onlyJobs = []string{} + } + return r.runGroup(ctx, groupName, &inheritedDomain, job.Group) } diff --git a/internal/lefthook/runner/runner.go b/internal/lefthook/runner/runner.go index db383a3d..d545fade 100644 --- a/internal/lefthook/runner/runner.go +++ b/internal/lefthook/runner/runner.go @@ -41,6 +41,7 @@ type Options struct { Force bool Files []string RunOnlyCommands []string + RunOnlyJobs []string SourceDirs []string } diff --git a/testdata/cli_run_only.txt b/testdata/cli_run_only.txt new file mode 100644 index 00000000..4226df53 --- /dev/null +++ b/testdata/cli_run_only.txt @@ -0,0 +1,34 @@ +exec git init +exec git config user.email "you@example.com" +exec git config user.name "Your Name" +exec git add -A +exec lefthook install +exec lefthook run hook --jobs a --jobs c --jobs db --commands lint +stdout '\s*a\s*ca\s*cb\s*db\s*lint\s*' + +-- lefthook.yml -- +output: + - execution_out +hook: + jobs: + - name: a + run: echo a + - name: b + run: echo b + - name: c + group: + jobs: + - run: echo ca + - run: echo cb + - name: d + group: + jobs: + - name: da + run: echo da + - name: db + run: echo db + commands: + lint: + run: echo lint + test: + run: echo test