Skip to content

Commit

Permalink
fix: implement merging named actions and groups
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox committed Dec 5, 2024
1 parent 764b4f0 commit c9d8ceb
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 4 deletions.
160 changes: 156 additions & 4 deletions internal/config/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var (
".json": json.Parser(),
".toml": toml.Parser(),
}
withActionsMerge = koanf.WithMergeFunc(mergeActions)
)

// ConfigNotFoundError.
Expand All @@ -63,7 +64,7 @@ func loadOne(k *koanf.Koanf, filesystem afero.Fs, root string, names []string) e
continue
}

if err := k.Load(kfs.Provider(newIOFS(filesystem), config), parsers[extension]); err != nil {
if err := k.Load(kfs.Provider(newIOFS(filesystem), config), parsers[extension], withActionsMerge); err != nil {
return err
}

Expand Down Expand Up @@ -175,7 +176,7 @@ func loadRemotes(k *koanf.Koanf, filesystem afero.Fs, repo *git.Repository, remo
panic("TODO: unknown extension to parse")
}

if err := k.Load(kfs.Provider(newIOFS(filesystem), configPath), parser); err != nil {
if err := k.Load(kfs.Provider(newIOFS(filesystem), configPath), parser, withActionsMerge); err != nil {
return err
}

Expand Down Expand Up @@ -223,15 +224,15 @@ func extendRecursive(k *koanf.Koanf, filesystem afero.Fs, root string, extends [
if !ok {
panic("TODO: unknown extension for extent " + path)
}
if err := extent.Load(kfs.Provider(newIOFS(filesystem), path), parser); err != nil {
if err := extent.Load(kfs.Provider(newIOFS(filesystem), path), parser, withActionsMerge); err != nil {
return err
}

if err := extendRecursive(extent, filesystem, root, extent.Strings("extends"), visited); err != nil {
return err
}

if err := k.Merge(extent); err != nil {
if err := k.Load(koanfProvider{extent}, nil, withActionsMerge); err != nil {
return err
}
}
Expand Down Expand Up @@ -326,6 +327,20 @@ func addHook(name string, main, secondary *koanf.Koanf, c *Config) error {
default:
}

var destActions, srcActions []interface{}
switch actions := dest["actions"].(type) {
case []interface{}:
destActions = actions
default:
}
switch actions := src["actions"].(type) {
case []interface{}:
srcActions = actions
default:
}

destActions = mergeActionsSlice(srcActions, destActions)

maps.Merge(src, dest)

if len(destCommands) > 0 {
Expand All @@ -346,6 +361,9 @@ func addHook(name string, main, secondary *koanf.Koanf, c *Config) error {
default:
}
}
if len(destActions) > 0 {
dest["actions"] = destActions
}

return nil
})
Expand Down Expand Up @@ -396,3 +414,137 @@ func (k koanfProvider) Read() (map[string]interface{}, error) {
func (k koanfProvider) ReadBytes() ([]byte, error) {
panic("not implemented")
}

func mergeActions(src, dest map[string]interface{}) error {
srcActions := make(map[string][]interface{})
for name, maybeHook := range src {
switch hook := maybeHook.(type) {
case map[string]interface{}:
switch actions := hook["actions"].(type) {
case []interface{}:
srcActions[name] = actions
default:
}
default:
}
}

destActions := make(map[string][]interface{})
for name, maybeHook := range dest {
switch hook := maybeHook.(type) {
case map[string]interface{}:
switch actions := hook["actions"].(type) {
case []interface{}:
destActions[name] = actions
default:
}
default:
}
}

if len(srcActions) == 0 || len(destActions) == 0 {
maps.Merge(src, dest)
return nil
}

for hook, newActions := range srcActions {
oldActions, ok := destActions[hook]
if !ok {
destActions[hook] = newActions
continue
}

destActions[hook] = mergeActionsSlice(newActions, oldActions)
}

maps.Merge(src, dest)

for name, maybeHook := range dest {
if actions, ok := destActions[name]; ok {
switch hook := maybeHook.(type) {
case map[string]interface{}:
hook["actions"] = actions
default:
}
}
}

return nil
}

func mergeActionsSlice(src, dest []interface{}) []interface{} {
namedActions := make(map[string]map[string]interface{})
resultActions := make([]interface{}, 0, len(dest))

for _, maybeAction := range dest {
switch destAction := maybeAction.(type) {
case map[string]interface{}:
switch name := destAction["name"].(type) {
case string:
namedActions[name] = destAction
default:
}

resultActions = append(resultActions, maybeAction)
default:
}
}

for _, maybeAction := range src {
switch srcAction := maybeAction.(type) {
case map[string]interface{}:
switch name := srcAction["name"].(type) {
case string:
destAction, ok := namedActions[name]
if ok {
var srcSubActions []interface{}
var destSubActions []interface{}

switch srcGroup := srcAction["group"].(type) {
case map[string]interface{}:
switch subActions := srcGroup["actions"].(type) {
case []interface{}:
srcSubActions = subActions
default:
}
default:
}
switch destGroup := destAction["group"].(type) {
case map[string]interface{}:
switch subActions := destGroup["actions"].(type) {
case []interface{}:
destSubActions = subActions
default:
}
default:
}

if len(destSubActions) != 0 && len(srcSubActions) != 0 {
destSubActions = mergeActionsSlice(srcSubActions, destSubActions)
}

maps.Merge(srcAction, destAction)

if len(destSubActions) != 0 {
switch destGroup := destAction["group"].(type) {
case map[string]interface{}:
switch destGroup["actions"].(type) {
case []interface{}:
destGroup["actions"] = destSubActions
default:
}
default:
}
}
continue
}
default:
}

resultActions = append(resultActions, maybeAction)
default:
}
}

return resultActions
}
3 changes: 3 additions & 0 deletions internal/lefthook/runner/run_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ func (r *Runner) runActions(ctx context.Context) []Result {

results := make([]Result, 0, len(r.Hook.Actions))
resultsChan := make(chan Result, len(r.Hook.Actions))

var failed atomic.Bool
domain := &domain{failed: &failed}

for i, action := range r.Hook.Actions {
id := strconv.Itoa(i)

Expand Down Expand Up @@ -211,6 +213,7 @@ func (r *Runner) runGroup(ctx context.Context, groupName string, domain *domain,
return groupResult(groupName, results)
}

// first finds first non-empty string and returns it.
func first(args ...string) string {
for _, a := range args {
if len(a) > 0 {
Expand Down

0 comments on commit c9d8ceb

Please sign in to comment.