Skip to content

Commit

Permalink
feature: hooks filtering can be done by require_env and match_context
Browse files Browse the repository at this point in the history
  • Loading branch information
RaVbaker committed Jan 23, 2021
1 parent 16b860b commit 0af95aa
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 9 deletions.
89 changes: 81 additions & 8 deletions internal/hooks/hook.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,101 @@
package hooks

import (
"log"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/mitchellh/mapstructure"

"github.com/ravbaker/pact-contractor/internal/parts"
"github.com/ravbaker/pact-contractor/internal/speccontext"
)

type Hook struct {
Type string
PathFilter string `mapstructure:"path_filter"`
Spec interface{}
Type string
PathFilter string `mapstructure:"path_filter"`
MatchContext map[string]string `mapstructure:"match_context"`
RequireEnv []string `mapstructure:"require_env"`
Spec interface{}
}

type Spec interface {
Run(path string) error
}

func (h *Hook) CanRun(path string) bool {
if len(h.PathFilter) == 0 {
return true
// CanRun ensures the hook can be executed. It checks that the path matches what specified in path_filter
// checks that match_context rules are satisfied. If the match defined with "/" as prefix and suffix it
// matches it as a regexp. To execute hook for a part upload you have to specify the match_context["part"]
// require_env matches can be a full line, specified like: "CI=true" or only with a name of the variable "CI"
func (h *Hook) CanRun(path string, ctx speccontext.GitContext, partsCtx parts.Context) (matched bool) {
if len(h.PathFilter) > 0 {
var err error
matched, err = filepath.Match(h.PathFilter, path)
if err != nil || !matched {
return
}
}

for key, value := range h.MatchContext {
var field string
switch key {
case "branch":
field = ctx.Branch
case "author":
field = ctx.Author
case "tag":
field = ctx.SpecTag
case "origin":
field = ctx.Origin
case "commitSHA":
field = ctx.CommitSHA
case "part":
field = partsCtx.Name()
}
matched = compareMatch(value, field)
if !matched {
return
}
}
_, partRequirement := h.MatchContext["part"]
if partsCtx.Defined() && !partsCtx.Merged() && !partRequirement {
return false
}

for _, envDefinition := range h.RequireEnv {
fullLine := strings.Contains(envDefinition, "=")
if fullLine {
matched = envInclude(envDefinition)
} else {
_, matched = os.LookupEnv(envDefinition)
}
if !matched {
return
}
}

return true
}

func envInclude(definition string) (matched bool) {
for _, envLine := range os.Environ() {
matched = matched || envLine == definition
}
return
}

func compareMatch(value, contextValue string) bool {
if strings.HasPrefix(value, "/") && strings.HasSuffix(value, "/") {
pattern := value[1 : len(value)-1]
matched, err := regexp.MatchString(pattern, contextValue)
if err != nil {
log.Fatalf("Cannot match pattern: %q to %q, %v", value, contextValue, err)
}
return matched
}
matched, err := filepath.Match(h.PathFilter, path)
return err == nil && matched
return value == contextValue
}

func (h *Hook) Definition() Spec {
Expand Down
2 changes: 1 addition & 1 deletion internal/hooks/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

func Runner(path, filename string, ctx speccontext.GitContext, partsCtx parts.Context) error {
for _, hook := range config.Hooks {
if hook.CanRun(path) {
if hook.CanRun(path, ctx, partsCtx) {
err := hook.Definition().Run(path)
if err != nil {
return err
Expand Down

0 comments on commit 0af95aa

Please sign in to comment.