From 7b646c69efbd240cee32d32cd2ac3ee335d91f0a Mon Sep 17 00:00:00 2001 From: Jeff Ortel Date: Fri, 6 Oct 2023 10:27:40 -0500 Subject: [PATCH] :bug: Download ruleSets with versioned labels. (#54) fixes: #53 Signed-off-by: Jeff Ortel --- cmd/cmd_test.go | 35 +++++++++++++++ cmd/rules.go | 111 +++++++++++++++++++++++++++++++++++++++--------- go.mod | 3 +- go.sum | 1 + 4 files changed, 130 insertions(+), 20 deletions(-) diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go index b7df34a..670c0ba 100644 --- a/cmd/cmd_test.go +++ b/cmd/cmd_test.go @@ -66,3 +66,38 @@ func TestRuleSelector(t *testing.T) { expected = "(p1||p2)||(konveyor.io/target=t1||konveyor.io/target=t2)" g.Expect(selector.String()).To(gomega.Equal(expected)) } + +func TestLabelMatch(t *testing.T) { + g := gomega.NewGomegaWithT(t) + // match name + included := Label("konveyor.io/target=thing") + rule := Label("konveyor.io/target=thing") + g.Expect(rule.Match(included)).To(gomega.BeTrue()) + // name not matched. + included = "konveyor.io/target=dog" + rule = "konveyor.io/target=cat+" + g.Expect(rule.Match(included)).To(gomega.BeFalse()) + // match versioned + included = "konveyor.io/target=thing4" + rule = "konveyor.io/target=thing4" + g.Expect(rule.Match(included)).To(gomega.BeTrue()) + // match versioned plus + included = "konveyor.io/target=thing4" + rule = "konveyor.io/target=thing4+" + g.Expect(rule.Match(included)).To(gomega.BeTrue()) + // match versioned ALL + included = "konveyor.io/target=thing" + rule = "konveyor.io/target=thing4+" + g.Expect(rule.Match(included)).To(gomega.BeTrue()) + // match version greater-than + included = "konveyor.io/target=thing5" + rule = "konveyor.io/target=thing4+" + g.Expect(rule.Match(included)).To(gomega.BeTrue()) + included = "konveyor.io/target=thing4.1" + rule = "konveyor.io/target=thing4.0+" + g.Expect(rule.Match(included)).To(gomega.BeTrue()) + // match version less-than + included = "konveyor.io/target=thing3" + rule = "konveyor.io/target=thing4-" + g.Expect(rule.Match(included)).To(gomega.BeTrue()) +} diff --git a/cmd/rules.go b/cmd/rules.go index 4ef8423..2663292 100644 --- a/cmd/rules.go +++ b/cmd/rules.go @@ -3,17 +3,22 @@ package main import ( "github.com/konveyor/tackle2-addon/command" "github.com/konveyor/tackle2-addon/repository" - hub "github.com/konveyor/tackle2-hub/addon" "github.com/konveyor/tackle2-hub/api" "github.com/konveyor/tackle2-hub/nas" + "github.com/rogpeppe/go-internal/semver" "os" "path" + "regexp" "strconv" "strings" ) type History = map[uint]byte +// +// LvRegex - Label value regex. +var LvRegex = regexp.MustCompile(`(\D+)(\d(?:[\d\.]*\d)?)([\+-])?$`) + // // Rules settings. type Rules struct { @@ -83,7 +88,7 @@ func (r *Rules) addFiles() (err error) { // addRuleSets adds rulesets and their dependencies. func (r *Rules) addRuleSets() (err error) { history := make(History) - ruleSets, err := r.Labels.ruleSets() + ruleSets, err := r.Labels.RuleSets() if err != nil { return } @@ -287,22 +292,48 @@ type Labels struct { } // -// ruleSets returns list of ruleSets with these labels. -func (r *Labels) ruleSets() (matched []api.RuleSet, err error) { - var found []api.RuleSet - for _, name := range r.Included { - f := hub.Filter{} - f.And("Labels").Eq(name) - found, err = addon.RuleSet.Find(f) - if err == nil { - matched = append(matched, found...) - } else { - return +// RuleSets returns a list of ruleSets matching the 'included' labels. +func (r *Labels) RuleSets() (matched []api.RuleSet, err error) { + mapped, err := r.ruleSetMap() + if err != nil { + return + } + for _, included := range r.Included { + for rule, ruleSets := range mapped { + if Label(rule).Match(Label(included)) { + matched = append( + matched, + ruleSets...) + } + } + } + return +} + +// +// ruleSetMap returns a populated RuleSetMap. +func (r *Labels) ruleSetMap() (mp RuleSetMap, err error) { + mp = make(RuleSetMap) + ruleSets, err := addon.RuleSet.List() + if err != nil { + return + } + for _, ruleSet := range ruleSets { + for _, rule := range ruleSet.Rules { + for i := range rule.Labels { + mp[rule.Labels[i]] = append( + mp[rule.Labels[i]], + ruleSet) + } } } return } +// +// RuleSetMap is a map of labels mapped to ruleSets with those labels. +type RuleSetMap map[string][]api.RuleSet + // // Label formatted labels. // Formats: @@ -314,8 +345,8 @@ type Label string // // Namespace returns the (optional) namespace. -func (r *Label) Namespace() (ns string) { - s := string(*r) +func (r Label) Namespace() (ns string) { + s := string(r) part := strings.Split(s, "/") if len(part) > 1 { ns = part[0] @@ -325,8 +356,8 @@ func (r *Label) Namespace() (ns string) { // // Name returns the name. -func (r *Label) Name() (n string) { - s := string(*r) +func (r Label) Name() (n string) { + s := string(r) _, s = path.Split(s) n = strings.Split(s, "=")[0] return @@ -334,8 +365,8 @@ func (r *Label) Name() (n string) { // // Value returns the (optional) value. -func (r *Label) Value() (v string) { - s := string(*r) +func (r Label) Value() (v string) { + s := string(r) _, s = path.Split(s) part := strings.SplitN(s, "=", 2) if len(part) == 2 { @@ -344,6 +375,48 @@ func (r *Label) Value() (v string) { return } +// +// Match returns true when matched. +// Values may contain version expressions. +func (r Label) Match(other Label) (matched bool) { + if r.Namespace() != other.Namespace() || + r.Name() != other.Name() { + return + } + selfMatch := LvRegex.FindStringSubmatch(r.Value()) + otherMatch := LvRegex.FindStringSubmatch(other.Value()) + if len(selfMatch) != 4 { + matched = r.Value() == other.Value() + return + } + if len(otherMatch) != 4 { + matched = selfMatch[1] == other.Value() + return + } + if selfMatch[1] != otherMatch[1] { + return + } + n := semver.Compare(selfMatch[2], otherMatch[2]) + switch selfMatch[3] { + case "+": + matched = n == 0 || n == 1 + case "-": + matched = n == 0 || n == -1 + default: + matched = n == 0 + } + return +} + +// +// Eq returns true when equal. +func (r Label) Eq(other Label) (matched bool) { + matched = r.Namespace() != other.Namespace() || + r.Name() != other.Name() || + r.Value() != other.Value() + return +} + // // RuleSelector - Label-based rule selector. type RuleSelector struct { diff --git a/go.mod b/go.mod index fa69e4a..b15ed4f 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,10 @@ require ( github.com/konveyor/tackle2-addon v0.2.2-0.20230731154530-fe8643caa094 github.com/konveyor/tackle2-hub v0.2.2-0.20230731153407-22bf2d68128a github.com/onsi/gomega v1.27.6 + github.com/rogpeppe/go-internal v1.10.0 go.lsp.dev/uri v0.3.0 gopkg.in/yaml.v2 v2.4.0 + k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed ) require ( @@ -103,7 +105,6 @@ require ( k8s.io/client-go v0.25.0 // indirect k8s.io/klog/v2 v2.70.1 // indirect k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect - k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect sigs.k8s.io/controller-runtime v0.13.1 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect diff --git a/go.sum b/go.sum index aece0c9..a3d621d 100644 --- a/go.sum +++ b/go.sum @@ -203,6 +203,7 @@ github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=