The analyzer rules are a set of instructions that are used to analyze source code and detect issues. Rules are fundamental pieces that codify modernization knowledge.
The analyzer parses user provided rules, evaluates them and generates Violations for matched rules. A collection of one or more rules form a Ruleset. Rulesets provide an opionated way of organizing multiple rules that achieve a common goal. The analyzer CLI takes a set of rulesets as input arguments.
A Rule is written in YAML. It consists of metadata, conditions and actions. It instructs analyzer to take specified actions when given conditions match.
Rule metadata contains general information about a rule:
# id must be unique among a Ruleset
ruleId: "unique_id"
# violations have pre-defined categories
category: "potential|information|mandatory"
# links point to external hyperlinks
# rule authors are expected to provide
# relevant hyperlinks for quick fixes, docs etc
links:
- url: "konveyor.io"
title: "title to be shown in report"
# labels are key=value pairs attached to rules, value
# can be empty or omitted, keys can be subdomain prefixed
labels:
# key=value pair
- "label1=val1"
# valid label with value omitted
- "label2"
# valid label with empty value
- "label3="
# subdomain prefixed key
- "konveyor.io/label1=val1"
# effort is an integer value to indicate level of
# effort needed to fix this issue
effort: 1
See labels doc for more details on labels
field.
A rule has message
and tag
actions.
The message
action generates a message for every violation created when rule matches. The message also supports templating in that the custom data exported by providers can be used in the message.
# when a match is found, analyzer generates a violation with this message
message: "helpful message about the violation"
The tag
action allows generating tags for the application. Each string in the tag can be a comma separated list of tags. Optionally, tags can have categories.
# when a match is found, analyzer generates these tags for the application
tag:
# tags can be comma separated
- "tag1,tag2,tag3"
# optionally, tags can be assigned categories
- "Category=tag4,tag5"
Finally, a rule contains a when
block to specify a condition:
when:
<condition>
<nested-condition>
When
has exactly one condition. Multiple conditions can be nested within the top-level condition.
A "provider" knows how to analyse the source code of a technology. It publishes what it can do with the source code in terms of "capabilities".
A provider condition instructs the analyzer to invoke a specific "provider" and use one of its "capabilities". In general, it is of the form <provider_name>.<capability>
:
when:
<provider>.<capability>: "input"
Analyzer currently supports builtin
, java
and go
providers.
builtin
is an in-tree provider that can work with vaious different files and internal metadata generated by the engine. It has file
, filecontent
, xml
, json
and hasTags
capabilities.
file
capability enables the provider to find files in the source code that match a given pattern:
when:
builtin.file: "<regex_to_match_filenames>"
filecontent
capability enables the provider to search for content that matches a given pattern:
when:
builtin.filecontent: "<regex_to_match_filecontent>"
xml
capability enables the provider to query XPath expressions on a list of provided XML files. Unlike providers discussed so far, xml
takes two input parameters:
when:
builtin.xml:
# xpath must be a valid xpath expression
xpath: "<xpath_expressions>"
# filepaths is a list of files to scope xpath query to
filepaths:
- "/src/file1.xml"
- "/src/file2.xml"
json
capability enables the provider to query XPath expressions on a list of provided JSON files. Unlike xml
, currently json
only takes xpath as input and performs the search on all json files in the codebase:
when:
builtin.json:
# xpath must be a valid xpath expression
xpath: "<xpath_expressions>"
hasTags
enables the provider to query application tags. It doesn't deal with the source code, instead it queries the internal data structure to check whether given tags are present for the application:
when:
# when more than one tags are given, a logical AND is implied
hasTags:
- "tag1"
- "tag2"
Java provider can work with Java source code and provides capabilities referenced
and dependency
.
referenced
capability enables the provider to find references in the source code. It takes two input parameters:
when:
java.referenced:
# regex pattern to match
pattern: "<pattern>"
# location defines the exact location where
# pattern should be matched
location: CONTRUCTOR_CALL
The supported locations are:
- CONSTRUCTOR_CALL
- TYPE
- INHERITANCE
- METHOD_CALL
- ANNOTATION
- IMPLEMENTS_TYPE
- ENUM_CONSTANT
- RETURN_TYPE
- IMPORT
- VARIABLE_DECLARATION
Go provider can work with Golang source code and provides capabilities referenced
and dependency
.
referenced
capability enables the provider to find references in the source code:
when:
go.referenced: "<regex_to_find_reference>"
The dependency
capability enables the provider to find dependencies for an application:
when:
go.dependency:
# name of the dependency to search
name: "<dependency_name>"
# upper bound on version of the depedency
upperbound: "<version_string>"
# lower bound on version of the dependency
lowerbound: "<version_string>"
A match is found when the given application has a dependency that falls within the given range of versions.
Analyzers provide two basic logical conditions that are useful in making more complex queries by aggregating results of other conditions.
The And
condition takes an array of conditions and performs a logical
"and" operation on their results:
when:
and:
- <condition1>
- <condition2>
Example:
when:
and:
- java.dependency:
name: junit.junit
upperbound: 4.12.2
lowerbound: 4.4.0
- java.dependency:
name: io.fabric8.kubernetes-client
lowerbound: 5.0.100
Note that the conditions can also be nested within other conditions:
when:
and:
- and:
- go.referenced: "*CustomResourceDefinition*"
- java.referenced:
pattern: "*CustomResourceDefinition*"
- go.referenced: "*CustomResourceDefinition*"
The Or
condition takes an array of other conditions and performs a logical "or" operation on their results:
when:
or:
- <condition1>
- <condition2>
A set of Rules form a Ruleset. Rulesets are an opionated way of passing Rules to Rules Engine.
Each Ruleset is stored in its own directory with a ruleset.yaml
file at the directory root that stores metadata of the Ruleset.
# name has to be unique within the provided rulesets
# doesn't necessarily has to be unique globally
name: "Name of the ruleset"
description: "Describes the ruleset"
# additional labels for ruleset
# labels help filter rulesets
labels:
- awesome_rules1
Rulesets provide a good way of organizing multiple rules that achieve a common goal.