Skip to content

Commit

Permalink
feat: custom rules
Browse files Browse the repository at this point in the history
Signed-off-by: mbwhite <[email protected]>
  • Loading branch information
mbwhite committed Mar 8, 2024
1 parent 0768462 commit b1ffd92
Show file tree
Hide file tree
Showing 12 changed files with 575 additions and 7 deletions.
5 changes: 4 additions & 1 deletion .tektonlintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ rules: # error | warning | off
prefer-when-expression: warning
no-deprecated-resource: warning
no-missing-hashbang: warning


# custom:
# my_rules: custom_rules

46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ A linter for Tekton resource definitions - **v1 beta now available!!**
- [Detecting errors](#detecting-errors)
- [Best practices](#best-practices)
- [Configuring tekton-lint](#configuring-tekton-lint)
- [Creating custom rules](#custom-rules)
- [Issues?](#issues)

<!-- /TOC -->
Expand Down Expand Up @@ -228,6 +229,51 @@ Search path for `.tektonlintrc.yaml`
- current working directory
- default values used if nothing else found
## Custom Rules
In additional the default set of rules, custom rules can provided as node modules; the mechanism is similar that used by tools such as eslint.
An example is provided in [`custom_rules`](./custom_rules), and will be used in the examples below. Notes on writing rules are also in the [README.md](./custom_rules/README.md)
### Configuring
In the `.tektonrc.yaml` file add an object with names of the rules and node module that provides it.
To load rules exported by the module `custom_rules`, and named under `my_rules` add the `custom` field to the yaml file.
```yaml
---
rules:
....
external:tasks:
...
custom:
my_rules: custom_rules
# For debug and test, refer directly to the js file
# my_rules: ../customer_rules/my_rules.js
```
### Reporting
A module may report more than one rule. There is one rule in the example, and this flags up any task that starts with the work 'Task' (not meant to be serious rule, but an example!)
Running on the `example-task.yaml` file with the example configured adds a 4th report
```
./example-task.yaml
10:14 warning Invalid image: 'busybox'. Specify the image tag instead of using ':latest' no-latest-image
9:31 error Undefined param 'contextDir' at .spec.steps[0].command[2] in 'Task-without-params' no-undefined-param
11:19 error Undefined param 'contextDir' at .spec.steps[0].workingDir in 'Task-without-params' no-undefined-param
1:1 error Tasks should not start with word 'Task' my_rules#no-tasks-called-task
✖ 4 problems (3 errors, 1 warning)
```
Within the representation of the rule name here `my_rules#no-tasks-called-task`; if you want to turn off this rule, then you can adjust the list of rules in the `.tektonrc.yaml` as for another rule
```
rules:
...
my_rules#no-tasks-called-task: off
```
## Issues?
Expand Down
47 changes: 47 additions & 0 deletions custom_rules/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Tekton Lint custom rules

- Create a regular node module
- Default export from this of an object
```js
module.exports = {
rules: [
{
name: 'no-tasks-called-task',
reportDefault: 'error',
ruleFn: forbidTasksWithTaskInTheName
}
]
}
```
- Must contain a field called `rules` that is a array of objects
- Each 'rule' object, must hava name (kebab case preferred)
- Default report type (off/error/warning)
- Reference to the rules function

- Rules are implemented in a function

```js
// Example rule to check a name of a task, note this isn't meant
// to be a serious rule - rather as an example
const forbidTasksWithTaskInTheName = (docs, tekton, report) => {

// try to always code defensively
if (tekton.tasks) {
for (const t of Object.values(tekton.tasks)) {
if (t.metadata.name.startsWith("Task")) {
report("Tasks should not start with word 'Task'", t)
}
}
}
};
```

- `docs` are the full yaml docs
- `tekton` is the object with the parsed elements of the yaml files
- `report` is a fn to report rule breaks


## Development Notes:

- As well as the yaml files from the project being tested, the rule will also see the cached elements
- try and code as defensively as possible, eg a set of files might not have Tasks
25 changes: 25 additions & 0 deletions custom_rules/my_rules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

// Example rule to check a name of a task, note this isn't meant
// to be a serious rule - rather as an example
const forbidTasksWithTaskInTheName = (docs, tekton, report) => {

// try to always code defensively
if (tekton.tasks) {
for (const t of Object.values(tekton.tasks)) {
if (t.metadata.name.startsWith("Task")) {
report("Tasks should not start with word 'Task'", t)
}
}
}
};

// could export multiple rules if you wished here.
module.exports = {
rules: [
{
name: 'no-tasks-called-task',
reportDefault: 'error',
ruleFn: forbidTasksWithTaskInTheName
}
]
}
12 changes: 12 additions & 0 deletions custom_rules/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "custom_rules",
"version": "1.0.0",
"description": "Example of a custom rule",
"main": "my_rules.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
7 changes: 7 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit b1ffd92

Please sign in to comment.