@@ -125,13 +125,15 @@ struct hook_config_cache_entry {
125125 * event_hooks: event-name to list of friendly-names map.
126126 * disabled_hooks: set of friendly-names with hook.<friendly-name>.enabled = false.
127127 * parallel_hooks: friendly-name to parallel flag.
128+ * event_jobs: event-name to per-event jobs count (stored as uintptr_t, NULL == unset).
128129 * jobs: value of the global hook.jobs key. Defaults to 0 if unset (stored in r->hook_jobs).
129130 */
130131struct hook_all_config_cb {
131132 struct strmap commands ;
132133 struct strmap event_hooks ;
133134 struct string_list disabled_hooks ;
134135 struct strmap parallel_hooks ;
136+ struct strmap event_jobs ;
135137 unsigned int jobs ;
136138};
137139
@@ -231,6 +233,18 @@ static int hook_config_lookup_all(const char *key, const char *value,
231233 warning (_ ("hook.%s.parallel must be a boolean,"
232234 " ignoring: '%s'" ),
233235 hook_name , value );
236+ } else if (!strcmp (subkey , "jobs" )) {
237+ unsigned int v ;
238+ if (!git_parse_uint (value , & v ))
239+ warning (_ ("hook.%s.jobs must be a positive integer,"
240+ " ignoring: '%s'" ),
241+ hook_name , value );
242+ else if (!v )
243+ warning (_ ("hook.%s.jobs must be positive,"
244+ " ignoring: 0" ), hook_name );
245+ else
246+ strmap_put (& data -> event_jobs , hook_name ,
247+ (void * )(uintptr_t )v );
234248 }
235249
236250 free (hook_name );
@@ -276,6 +290,7 @@ static void build_hook_config_map(struct repository *r, struct strmap *cache)
276290 strmap_init (& cb_data .event_hooks );
277291 string_list_init_dup (& cb_data .disabled_hooks );
278292 strmap_init (& cb_data .parallel_hooks );
293+ strmap_init (& cb_data .event_jobs );
279294
280295 /* Parse all configs in one run, capturing hook.* including hook.jobs. */
281296 repo_config (r , hook_config_lookup_all , & cb_data );
@@ -323,8 +338,10 @@ static void build_hook_config_map(struct repository *r, struct strmap *cache)
323338 strmap_put (cache , e -> key , hooks );
324339 }
325340
326- if (r )
341+ if (r ) {
327342 r -> hook_jobs = cb_data .jobs ;
343+ r -> event_jobs = cb_data .event_jobs ;
344+ }
328345
329346 strmap_clear (& cb_data .commands , 1 );
330347 strmap_clear (& cb_data .parallel_hooks , 0 ); /* values are uintptr_t, not heap ptrs */
@@ -587,6 +604,7 @@ static void warn_non_parallel_hooks_override(unsigned int jobs,
587604/* Determine how many jobs to use for hook execution. */
588605static unsigned int get_hook_jobs (struct repository * r ,
589606 struct run_hooks_opt * options ,
607+ const char * hook_name ,
590608 struct string_list * hook_list )
591609{
592610 /*
@@ -606,16 +624,34 @@ static unsigned int get_hook_jobs(struct repository *r,
606624 */
607625 options -> jobs = 1 ;
608626 if (r ) {
609- if (r -> gitdir && r -> hook_config_cache && r -> hook_jobs )
610- options -> jobs = r -> hook_jobs ;
611- else
627+ if (r -> gitdir && r -> hook_config_cache ) {
628+ void * event_jobs ;
629+
630+ if (r -> hook_jobs )
631+ options -> jobs = r -> hook_jobs ;
632+
633+ event_jobs = strmap_get (& r -> event_jobs , hook_name );
634+ if (event_jobs )
635+ options -> jobs = (unsigned int )(uintptr_t )event_jobs ;
636+ } else {
637+ unsigned int event_jobs ;
638+ char * key ;
639+
612640 repo_config_get_uint (r , "hook.jobs" , & options -> jobs );
641+
642+ key = xstrfmt ("hook.%s.jobs" , hook_name );
643+ if (!repo_config_get_uint (r , key , & event_jobs ) && event_jobs )
644+ options -> jobs = event_jobs ;
645+ free (key );
646+ }
613647 }
614648
615649 /*
616650 * Cap to serial any configured hook not marked as parallel = true.
617651 * This enforces the parallel = false default, even for "traditional"
618652 * hooks from the hookdir which cannot be marked parallel = true.
653+ * The same restriction applies whether jobs came from hook.jobs or
654+ * hook.<event>.jobs.
619655 */
620656 for (size_t i = 0 ; i < hook_list -> nr ; i ++ ) {
621657 struct hook * h = hook_list -> items [i ].util ;
@@ -642,7 +678,7 @@ int run_hooks_opt(struct repository *r, const char *hook_name,
642678 .options = options ,
643679 };
644680 int ret = 0 ;
645- unsigned int jobs = get_hook_jobs (r , options , hook_list );
681+ unsigned int jobs = get_hook_jobs (r , options , hook_name , hook_list );
646682 const struct run_process_parallel_opts opts = {
647683 .tr2_category = "hook" ,
648684 .tr2_label = hook_name ,
0 commit comments