Skip to content

Commit c20175c

Browse files
authored
✨ Analysis Issue labels (#325)
Updates models and API to replace analysis ruleset (source, target) technologies with issue labels. Instead of filtering on technologies in the ruleset metadata, filtering is done on issue label match. As a result, the AnalysisRuleSet and AnalysisTechnology models and API resources can be removed. Removes AnalysisDependency.Type - not needed by tackle. Adds label and selector support to analysis deps. Adds RuleSet.Labels (as related to RuleBundles). The RuleSet.Metadata will be removed with the seeding [PR](#323). Adds model.intersect() method to help construct `intersect` queries needed for AND filters. Refit the tag query to use the method. closes #308 closes #313 closes #314 Requires: konveyor/analyzer-lsp#146 (and likely 1 more) --------- Signed-off-by: Jeff Ortel <[email protected]>
1 parent 1ac2e55 commit c20175c

15 files changed

+541
-478
lines changed

api/analysis.go

+190-300
Large diffs are not rendered by default.

api/filter/filter.go

+63-3
Original file line numberDiff line numberDiff line change
@@ -109,24 +109,84 @@ func (f *Filter) Resource(r string) (filter Filter) {
109109

110110
//
111111
// Where applies (root) fields to the where clause.
112-
func (f *Filter) Where(in *gorm.DB) (out *gorm.DB) {
112+
func (f *Filter) Where(in *gorm.DB, selector ...string) (out *gorm.DB) {
113113
out = in
114+
fs := FieldSelector(selector)
114115
for _, p := range f.predicates {
115116
field := Field{p}
116-
fr := field.Resource()
117-
if fr == "" {
117+
if fs.Match(&field) {
118118
out = out.Where(field.SQL())
119119
}
120120
}
121121
return
122122
}
123123

124+
//
125+
// Delete specified fields.
126+
func (f *Filter) Delete(name string) (found bool) {
127+
var wanted []Predicate
128+
for _, p := range f.predicates {
129+
if strings.ToLower(p.Field.Value) != name {
130+
wanted = append(wanted, p)
131+
} else {
132+
found = true
133+
}
134+
}
135+
f.predicates = wanted
136+
return
137+
}
138+
124139
//
125140
// Empty returns true when the filter has no predicates.
126141
func (f *Filter) Empty() bool {
127142
return len(f.predicates) == 0
128143
}
129144

145+
//
146+
// FieldSelector fields.
147+
// fields with '+' prefix are included.
148+
// fields with '-' prefix are excluded.
149+
// Fields scoped to a resource are excluded.
150+
// An empty selector includes ALL.
151+
type FieldSelector []string
152+
153+
//
154+
// Match fields by qualified name.
155+
func (r FieldSelector) Match(f *Field) (m bool) {
156+
if f.Resource() != "" {
157+
return
158+
}
159+
if len(r) == 0 {
160+
m = true
161+
return
162+
}
163+
included := make(map[string]byte)
164+
excluded := make(map[string]byte)
165+
for _, s := range r {
166+
s = strings.ToLower(s)
167+
if s != "" {
168+
switch s[0] {
169+
case '-':
170+
excluded[s[1:]] = 0
171+
case '+':
172+
included[s[1:]] = 0
173+
default:
174+
included[s] = 0
175+
}
176+
}
177+
}
178+
name := strings.ToLower(f.Field.Value)
179+
if _, found := excluded[name]; found {
180+
return
181+
}
182+
if len(included) == 0 {
183+
m = true
184+
return
185+
}
186+
_, m = included[name]
187+
return
188+
}
189+
130190
//
131191
// Field predicate.
132192
type Field struct {

api/filter/filter_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,49 @@ func TestValidation(t *testing.T) {
294294
})
295295
g.Expect(err).ToNot(gomega.BeNil())
296296
}
297+
298+
func TestFieldSelector(t *testing.T) {
299+
g := gomega.NewGomegaWithT(t)
300+
field := func(name string) (f *Field) {
301+
f = &Field{}
302+
f.Field.Value = name
303+
return
304+
}
305+
selector := FieldSelector{
306+
"zero",
307+
"-one",
308+
"-two",
309+
}
310+
g.Expect(selector.Match(field("zero"))).To(gomega.BeTrue())
311+
g.Expect(selector.Match(field("one"))).ToNot(gomega.BeTrue())
312+
g.Expect(selector.Match(field("two"))).ToNot(gomega.BeTrue())
313+
g.Expect(selector.Match(field("unknown"))).ToNot(gomega.BeTrue())
314+
315+
selector = FieldSelector{
316+
"-one",
317+
"-two",
318+
}
319+
g.Expect(selector.Match(field("Zero"))).To(gomega.BeTrue())
320+
g.Expect(selector.Match(field("unknown"))).To(gomega.BeTrue())
321+
g.Expect(selector.Match(field("one"))).ToNot(gomega.BeTrue())
322+
g.Expect(selector.Match(field("two"))).ToNot(gomega.BeTrue())
323+
324+
selector = FieldSelector{
325+
"one",
326+
"two",
327+
}
328+
g.Expect(selector.Match(field("one"))).To(gomega.BeTrue())
329+
g.Expect(selector.Match(field("two"))).To(gomega.BeTrue())
330+
g.Expect(selector.Match(field("unknown"))).ToNot(gomega.BeTrue())
331+
332+
selector = FieldSelector{}
333+
g.Expect(selector.Match(field("one"))).To(gomega.BeTrue())
334+
g.Expect(selector.Match(field("two"))).To(gomega.BeTrue())
335+
336+
selector = FieldSelector{
337+
"resource.one",
338+
"two",
339+
}
340+
g.Expect(selector.Match(field("two"))).To(gomega.BeTrue())
341+
g.Expect(selector.Match(field("resource.one"))).ToNot(gomega.BeTrue())
342+
}

api/rulebundle.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ type RuleSet struct {
292292
Resource
293293
Name string `json:"name,omitempty"`
294294
Description string `json:"description,omitempty"`
295-
Metadata interface{} `json:"metadata,omitempty"`
295+
Labels interface{} `json:"labels,omitempty"`
296296
File *Ref `json:"file,omitempty"`
297297
}
298298

@@ -301,7 +301,7 @@ type RuleSet struct {
301301
func (r *RuleSet) With(m *model.RuleSet) {
302302
r.Resource.With(&m.Model)
303303
r.Name = m.Name
304-
_ = json.Unmarshal(m.Metadata, &r.Metadata)
304+
_ = json.Unmarshal(m.Labels, &r.Labels)
305305
r.File = r.refPtr(m.FileID, m.File)
306306
}
307307

@@ -311,8 +311,8 @@ func (r *RuleSet) Model() (m *model.RuleSet) {
311311
m = &model.RuleSet{}
312312
m.ID = r.ID
313313
m.Name = r.Name
314-
if r.Metadata != nil {
315-
m.Metadata, _ = json.Marshal(r.Metadata)
314+
if r.Labels != nil {
315+
m.Labels, _ = json.Marshal(r.Labels)
316316
}
317317
m.FileID = r.idPtr(r.File)
318318
return

hack/add/all.sh

-9
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,10 @@ dir=`dirname $0`
1010
cd ${dir}
1111

1212
./settings.sh
13-
./tag.sh
1413
./identity.sh
1514
./job-function.sh
1615
./stakeholder-group.sh
1716
./stakeholder.sh
1817
./business-service.sh
1918
./application.sh
20-
./task.sh
21-
./taskgroup.sh
22-
./bucket.sh
2319
./review.sh
24-
./proxy.sh
25-
./applicationtags.sh
26-
./analysis.sh
27-
./analysis.sh
28-
./analysis.sh

hack/add/analysis.sh

+28-40
Original file line numberDiff line numberDiff line change
@@ -12,52 +12,40 @@ echo " RuleSets: ${nRuleSet}"
1212
echo " Issues: ${nIssue}"
1313

1414
#
15-
# RuleSets
15+
# Issues
1616
#
1717
echo -n "---
18-
rulesets:
18+
issues:
1919
" > ${file}
2020
for r in $(seq 1 ${nRuleSet})
21-
do
22-
echo -n "- name: Main${r}
23-
description: Testing.
24-
technologies:
25-
- name: TechA-${r}
26-
- name: TechB-${r}
27-
- name: TechC-${r}
28-
- name: TechS-${r}
29-
source: true
30-
issues:
31-
" >> ${file}
32-
#
33-
# Issues
34-
#
21+
do
3522
for i in $(seq 1 ${nIssue})
3623
do
37-
echo -n " - ruleid: Rule-${i}
38-
name: Rule-${i}-Violated
39-
description: This is a test ${r}/${i}.
40-
category: warning
41-
effort: 10
42-
labels:
43-
- RULESET-${r}
44-
- RULE-${i}
45-
incidents:
46-
- uri: http://thing.com/file:1
47-
message: Thing happend line:1
48-
facts:
49-
factA: 1.A
50-
factB: 1.B
51-
- uri: http://thing.com/file:2
52-
message: Thing happend line:2
53-
facts:
54-
factA: 1.C
55-
factB: 1.D
56-
- uri: http://thing.com/file:3
57-
message: Thing happend line:3
58-
facts:
59-
factA: 1.E
60-
factB: 1.F
24+
echo -n "- ruleset: ruleSet-${r}
25+
rule: rule-${i}
26+
name: Rule-${i}-Violated
27+
description: This is a test ${r}/${i}.
28+
category: warning
29+
effort: 10
30+
labels:
31+
- konveyor.io/target=RULESET-${r}
32+
- konveyor.io/source=RULE-${i}
33+
incidents:
34+
- uri: http://thing.com/file:1
35+
message: Thing happend line:1
36+
facts:
37+
factA: 1.A
38+
factB: 1.B
39+
- uri: http://thing.com/file:2
40+
message: Thing happend line:2
41+
facts:
42+
factA: 1.C
43+
factB: 1.D
44+
- uri: http://thing.com/file:3
45+
message: Thing happend line:3
46+
facts:
47+
factA: 1.E
48+
factB: 1.F
6149
" >> ${file}
6250
done
6351
done

0 commit comments

Comments
 (0)