Skip to content

Commit

Permalink
👻 Fast-forward release-0.3 (#364)
Browse files Browse the repository at this point in the history
Signed-off-by: Pranav Gaikwad <[email protected]>
Signed-off-by: JonahSussman <[email protected]>
Signed-off-by: Jonah Sussman <[email protected]>
Signed-off-by: John Matthews <[email protected]>
Signed-off-by: GitHub Actions <[email protected]>
Co-authored-by: Jonah Sussman <[email protected]>
Co-authored-by: John Matthews <[email protected]>
Co-authored-by: GitHub Actions <[email protected]>
  • Loading branch information
4 people committed Oct 6, 2023
1 parent 5e97160 commit 899a663
Show file tree
Hide file tree
Showing 24 changed files with 9,499 additions and 4,100 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ Flags:
## Code Base Starting Point
Using the LSP/Protocal from ACME https://github.com/fhs/acme-lsp and stripping out anything related to serving, proxy or anything. Just keeping the types for communication
Using the LSP/Protocal from Golang https://github.com/golang/tools/tree/master/gopls/internal/lsp/protocol and stripping out anything related to serving, proxy or anything. Just keeping the types for communication
Using JSONRPC2 from google.org/x/tools/internal. Copied and removed anything to do with serving.
Using JSONRPC2 from google.org/x/tools/internal. Copied and removed anything to do with serving.
## Code of Conduct
Expand Down
11 changes: 6 additions & 5 deletions docs/labels.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ labels:
- "konveyor.io/key"
```
## Reserved Labels
## Rule Labels
The analyzer defines some labels that have special meaning. Here is a list of all such labels:
The analyzer defines some labels that have special meanings:
- `konveyor.io/source`: Identifies source technology a rule or a ruleset applies to.
- `konveyor.io/target`: Identifies target technology a rule or a ruleset applies to.
- `konveyor.io/source`: Identifies source technology a rule or a ruleset applies to. The value can be a string with optional version range at the end e.g. "eap", "eap6", "eap7-" etc.
- `konveyor.io/target`: Identifies target technology a rule or a ruleset applies to. The value can be a string with optional version range at the end e.g. "eap", "eap6", "eap8+" etc.
- `konveyor.io/include`: Overrides filter behavior for a rule irrespective of the label selector used. The value can either be `always` or `never`. `always` will always filter-in this rule, `never` will always filter-out this rule.

## Label Selector
### Rule Label Selector

The analyzer CLI takes `--label-selector` as an option. It is a string expression that supports logical AND, OR and NOT operations. It can be used to filter-in/filter-out rules based on labels.

Expand Down
2 changes: 1 addition & 1 deletion docs/violations.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The analyzer rule engine creates a _Violation_ for every rule that matches excep

* **effort**: Integer value indicating story points for each incident as determined by the rule author.

See [Violation struct](../hubapi/violations.go) for more details.
See [Violation struct](../output/v1/konveyor/violations.go) for more details.

### Output Structure

Expand Down
72 changes: 68 additions & 4 deletions engine/labels/labels.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ import (
"strings"

"github.com/PaesslerAG/gval"
"github.com/hashicorp/go-version"
)

const (
LabelValueFmt = "^[a-zA-Z0-9]([-a-zA-Z0-9. ]*[a-zA-Z0-9])?$"
// a selector label takes precedance over any other label when matching
RuleIncludeLabel = "konveyor.io/include"
SelectAlways = "always"
SelectNever = "never"
)

const (
LabelValueFmt = "^[a-zA-Z0-9]([-a-zA-Z0-9. ]*[a-zA-Z0-9+-])?$"
LabelPrefixFmt = "^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?$"
exprSpecialSymbols = `!|\|\||&&|\(|\)`
// used to split string into groups of special symbols and everything else
Expand All @@ -32,6 +40,15 @@ func AsString(key, value string) string {

func (l *LabelSelector[T]) Matches(v T) (bool, error) {
ruleLabels, _ := ParseLabels(v.GetLabels())
if val, ok := ruleLabels[RuleIncludeLabel]; ok &&
val != nil && len(val) > 0 {
switch val[0] {
case SelectAlways:
return true, nil
case SelectNever:
return false, nil
}
}
expr := getBooleanExpression(l.expr, ruleLabels)
val, err := l.language.Evaluate(expr, nil)
if err != nil {
Expand Down Expand Up @@ -204,7 +221,7 @@ func getBooleanExpression(expr string, compareLabels map[string][]string) string
}
if labelVals, ok := compareLabels[exprLabelKey]; !ok {
replaceMap[toReplace] = "false"
} else if exprLabelVal != "" && !contains(exprLabelVal, labelVals) {
} else if exprLabelVal != "" && !matchesAny(exprLabelVal, labelVals) {
replaceMap[toReplace] = "false"
} else {
replaceMap[toReplace] = "true"
Expand Down Expand Up @@ -235,11 +252,58 @@ func tokenize(expr string) []string {
return tokens
}

func contains(elem string, items []string) bool {
func matchesAny(elem string, items []string) bool {
for _, item := range items {
if item == elem {
if labelValueMatches(item, elem) {
return true
}
}
return false
}

// labelValueMatches returns true when candidate matches with matchWith
// label value is divided into two parts - name and version
// version is absolute version or a range denoted by + or -
// returns true when names of values are equal and the version of
// candidate falls within the version range of matchWith
func labelValueMatches(matchWith string, candidate string) bool {
versionRegex := regexp.MustCompile(`(\d(?:[\d\.]*\d)?)([\+-])?$`)
mMatch := versionRegex.FindStringSubmatch(matchWith)
cMatch := versionRegex.FindStringSubmatch(candidate)
if len(mMatch) != 3 {
return matchWith == candidate
}
mName, mVersion, mVersionRangeSymbol :=
versionRegex.ReplaceAllString(matchWith, ""), mMatch[1], mMatch[2]
if len(cMatch) != 3 {
// when no version on candidate, match for any version
return mName == candidate
}
cName, cVersion :=
versionRegex.ReplaceAllString(candidate, ""), cMatch[1]
if mName != cName {
return false
}
if mVersion == "" {
return mVersion == cVersion
}
if cVersion == "" {
return true
}
cSemver, err := version.NewSemver(cVersion)
if err != nil {
return cVersion == mVersion
}
mSemver, err := version.NewSemver(mVersion)
if err != nil {
return cVersion == mVersion
}
switch mVersionRangeSymbol {
case "+":
return cSemver.GreaterThanOrEqual(mSemver)
case "-":
return mSemver.GreaterThanOrEqual(cSemver)
default:
return cSemver.Equal(mSemver)
}
}
153 changes: 153 additions & 0 deletions engine/labels/labels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,22 @@ func Test_getBooleanExpression(t *testing.T) {
},
want: "( true || true ) && false && true",
},
{
name: "values with version ranges",
expr: "(konveyor.io/target=Spring Beans12 && konveyor.io/target=hibernate6.1)",
compareLabels: map[string][]string{
"konveyor.io/target": {"hibernate6-", "Spring Beans11+"},
},
want: "( true && false )",
},
{
name: "values with version ranges",
expr: "(konveyor.io/target=Spring Beans12 && konveyor.io/target=hibernate6.1)",
compareLabels: map[string][]string{
"konveyor.io/target": {"hibernate6+", "Spring Beans11-"},
},
want: "( false && true )",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -159,6 +175,24 @@ func TestParseLabel(t *testing.T) {
wantKey: "konveyor.io/fact",
wantVal: "Spring Beans",
},
{
name: "absolte version in value",
label: "konveyor.io/fact=Spring Beans12",
wantKey: "konveyor.io/fact",
wantVal: "Spring Beans12",
},
{
name: "version range + in value",
label: "konveyor.io/fact=Spring Beans12+",
wantKey: "konveyor.io/fact",
wantVal: "Spring Beans12+",
},
{
name: "version range - in value",
label: "konveyor.io/fact=Spring Beans12-",
wantKey: "konveyor.io/fact",
wantVal: "Spring Beans12-",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -326,6 +360,24 @@ func Test_ruleSelector_Matches(t *testing.T) {
},
want: true,
},
{
name: "rule has a explicit include=always label",
expr: "konveyor.io/source=test",
ruleLabels: []string{
"konveyor.io/include=always",
"konveyor.io/source=noTest", // this should make the selector not match, but 'always' selector takes precedance
},
want: true,
},
{
name: "rule has a explicit include=never label",
expr: "konveyor.io/source=test",
ruleLabels: []string{
"konveyor.io/include=never",
"konveyor.io/source=test", // this should make the selector match, but 'never' selector takes precedance
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -336,3 +388,104 @@ func Test_ruleSelector_Matches(t *testing.T) {
})
}
}

func Test_labelValueMatches(t *testing.T) {
tests := []struct {
name string
candidate string
matchWith string
want bool
}{
{
name: "no version range test",
candidate: "eap",
matchWith: "eap",
want: true,
},
{
name: "name mismatch test",
candidate: "eap",
matchWith: "javaee",
want: false,
},
{
name: "absolute version test",
candidate: "eap6",
matchWith: "eap6",
want: true,
},
{
name: "version range test for '+'",
candidate: "eap6",
matchWith: "eap5+",
want: true,
},
{
name: "version range test for '+'",
candidate: "eap5",
matchWith: "eap5+",
want: true,
},
{
name: "version range test for '-'",
candidate: "eap7",
matchWith: "eap8-",
want: true,
},
{
name: "version range negative test for '-'",
candidate: "eap9",
matchWith: "eap8-",
want: false,
},
{
name: "version range negative test for '+'",
candidate: "eap7",
matchWith: "eap8+",
want: false,
},
{
name: "complex value version range test",
candidate: "Golang Version",
matchWith: "Golang Version11+",
want: true,
},
{
name: "match any version test",
candidate: "eap",
matchWith: "eap6+",
want: true,
},
{
name: "match any version test negative",
candidate: "eap6",
matchWith: "eap",
want: false,
},
{
name: "float value absolute match",
candidate: "hibernate5.1",
matchWith: "hibernate5.1",
want: true,
},
{
name: "float value range symbol '+' match",
candidate: "hibernate5.2",
matchWith: "hibernate5.1+",
want: true,
},
{
name: "float value range symbol '+' negative match",
candidate: "hibernate5.0.12",
matchWith: "hibernate5.1+",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := labelValueMatches(tt.matchWith, tt.candidate); got != tt.want {
t.Errorf("versionRangeMatches() = %v, want %v", got, tt.want)
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (p *genericServiceClient) Evaluate(ctx context.Context, cap string, conditi

incidents := []provider.IncidentContext{}
for _, s := range symbols {
references := p.GetAllReferences(ctx, s.Location)
references := p.GetAllReferences(ctx, s.Location.Value.(protocol.Location))
for _, ref := range references {
// Look for things that are in the location loaded, //Note may need to filter out vendor at some point
if strings.Contains(ref.URI, p.config.Location) {
Expand Down Expand Up @@ -100,8 +100,8 @@ func processFile(path string, regex *regexp.Regexp, positionsChan chan<- protoco
URI: fmt.Sprintf("file://%s", absPath),
},
Position: protocol.Position{
Line: float64(lineNumber),
Character: float64(loc[1]),
Line: uint32(lineNumber),
Character: uint32(loc[1]),
},
}
}
Expand Down Expand Up @@ -190,7 +190,12 @@ func (p *genericServiceClient) GetAllSymbols(ctx context.Context, query string)
fmt.Printf("Error rpc: %v", err)
}
for _, r := range res {
symbols = append(symbols, protocol.WorkspaceSymbol{Location: r})
symbols = append(symbols, protocol.WorkspaceSymbol{
Location: protocol.OrPLocation_workspace_symbol{
Value: r,
},
// Location: r
})
}
}
}
Expand Down Expand Up @@ -223,13 +228,12 @@ func (p *genericServiceClient) initialization(ctx context.Context, log logr.Logg
panic(1)
}

params := &protocol.InitializeParams{
//TODO(shawn-hurley): add ability to parse path to URI in a real supported way
RootURI: fmt.Sprintf("file://%v", abs),
Capabilities: protocol.ClientCapabilities{},
ExtendedClientCapilities: map[string]interface{}{
"classFileContentsSupport": true,
},
//TODO(shawn-hurley): add ability to parse path to URI in a real supported way
params := &protocol.InitializeParams{}
params.RootURI = fmt.Sprintf("file://%v", abs)
params.Capabilities = protocol.ClientCapabilities{}
params.ExtendedClientCapilities = map[string]interface{}{
"classFileContentsSupport": true,
}

var result protocol.InitializeResult
Expand Down
15 changes: 15 additions & 0 deletions lsp/protocol/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Protocol generator tool

Originally from: https://github.com/golang/tools/tree/master/gopls/internal/lsp/protocol
Commit id: If4c85191760baef916911130ca315773d2adda1f

## How to use

If there is an update to the LSP specification, navigate to the `protocol` directory and run `go generate`. This will generate all the types needed for the analyzer. You need to add `ExtendedClientCapilities map[string]interface{} `json:"extendedClientCapabilities"`` to XInitializeParams struct. Other than that, you should be good to go.

## Changes

- Commented out `writeclient()` and `writeserver()` in generate/main.go
- Commented out `"Or_WorkspaceFoldersServerCapabilities_changeNotifications": "string",` in generate/tables.go
- Changed `type DocumentURI string` to `type DocumentURI = string` in generate/output.go
- Need to add `ExtendedClientCapilities map[string]interface{} `json:"extendedClientCapabilities"`` to XInitializeParams struct. Need to figure out why needed. Can remove if not.
Loading

0 comments on commit 899a663

Please sign in to comment.