Super-Linter es un action de GitHub que combina una serie de linters para prevenir que código roto, que no siga las mejores prácticas y no tenga un formato que permita la fácil lectura sea integrado a una rama protegida; adicionalmente permite fácilmente automatizar el proceso de revisión para el cumplimiento de dichas prácticas. Actualmente tiene soporte para múltiples lenguajes, y usa muchos linters que nos ayudaran a mejorar la calidad de nuestro código; a continuación, les comparto una tabla que fue extraída de la documentación del action donde nos indica la amplia gama de lenguajes y los linters que aplica.
Lenguaje | Linter |
Ansible | ansible-lint |
AWS CloudFormation templates | cfn-lint |
Azure Resource Manager (Bicep)(ARM) | arm-ttk |
C++ | cpp-lint / clang-format |
C# | dotnet-format / clang-format |
CSS | stylelint |
Clojure | clj-kondo |
CoffeeScript | coffeelint |
Copy/paste detection | jscpd |
Dart | dartanalyzer |
Dockerfile | hadolint |
EditorConfig | editorconfig-checker |
ENV | dotenv-linter |
Gherkin | gherkin-lint |
GitHub Actions | actionlint |
Golang | golangci-lint |
Groovy | npm-groovy-lint |
HTML | HTMLHint |
Java | checkstyle / google-java-format |
JavaScript | ESLint / standard js |
JSON | eslint-plugin-json |
JSONC | eslint-plugin-jsonc |
Kubeval | kubeval |
Kotlin | ktlint |
LaTeX | ChkTex |
Lua | luacheck |
Markdown | markdownlint |
Natural language | textlint |
OpenAPI | spectral |
Perl | perlcritic |
PHP | PHP built-in linter / PHP CodeSniffer / PHPStan / Psalm |
PowerShell | PSScriptAnalyzer |
Protocol Buffers | protolint |
Python3 | pylint / flake8 / black / isort |
R | lintr |
Raku | Raku |
Ruby | RuboCop |
Rust | Rustfmt / Clippy |
Scala | scalafmt |
Secrets | GitLeaks |
Shell | Shellcheck / [executable bit check] / shfmt |
Snakemake | snakefmt / snakemake –lint |
SQL | sql-lint / sqlfluff |
Tekton | tekton-lint |
Terraform | tflint / terrascan |
Terragrunt | terragrunt |
TypeScript | ESLint / standard js |
XML | LibXML |
YAML | YamlLint |
Configuración de Super-Linter
Una vez dicho esto vamos a entrar en materia y ver como configurar esto en nuestros workflows de GitHub, como ejemplo estaremos utilizando un api web desarrollada en Java que nos va a saludar, no es algo complejo, pero nos ayudará a clarificar y explicar el proceso de configuración y uso de este.
El repositorio está disponible para tu consulta y se encuentra en la siguiente URL: erickdanramirez/SuperlinterDemo (github.com)
Puedes visualizar en el marketplace como integrarlo de forma sencilla, siempre es bueno leer la documentación, para entender las consideraciones de configuración, uso y exprimir al máximo las funcionalidades que nos ofrece.
Puedes acceder a la documentación completa desde la descripción del action, también te comparto la URL donde consultarla si quieres saber mas acerca de las propiedades que puedes usar (github/super-linter: Combination of multiple linters to install as a GitHub Action).
Una vez dicho esto necesitamos configurar lo más importante que son las reglas que vamos a hacer efectivas dentro de la ejecución del action. Por default detecta el lenguaje de programación que estas usando en el código y aplicar todos los estándares definidos en los linters, pero sabemos que no necesariamente aplicarían todas para nuestros aplicativos, por lo que es requerimos tener un mecanismo para personalizar cuales vamos a aplicar.
Existe un repositorio con muchos archivos plantilla que podemos usar como base para definir las reglas que aplicaran sobre nuestro código (En la siguiente URL puedes ver y utilizar el que más te convenga usar de acuerdo con el lenguaje de programación que uses en tu código super-linter/TEMPLATES at main · github/super-linter). Para este caso nuestro api esta desarrollado en java y vamos a utilizar. sun_checks.xml (super-linter/sun_checks.xml at main · github/super-linter). Es importante que almacenemos este archivo en el folder “.github/linters”.
Vamos solo a comentar una regla relacionada con Javadoc Packages, ya que nuestro objetivo es meramente didáctico, definir que reglas aplican y cuales no depende de cada equipo y organización (SuperlinterDemo/sun_checks.xml at main · erickdanramirez/SuperlinterDemo (github.com)).
Es importante mencionar si tenemos soluciones con diferentes lenguajes podemos tener mas de un archivo en este directorio.
Vamos a proceder a la configuración del action dentro de un workflow que funja como build verification test (no es limitativo ponemos ponerlo en otro tipo de workflow dependiendo de nuestro proceso de desarrollo y las necesidades del equipo); en este ejemplo no nos vamos a complicar y solo compilaremos el api y al final agregaremos el action de super-linter.
name: Build Verification Test
on:
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Super-Linter
uses: github/super-linter@v4.9.4
env:
FILTER_REGEX_INCLUDE: .*src/main/.*
VALIDATE_ALL_CODEBASE: false
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Es importante explicar las variables que seleccionamos y que efecto tendrán en la ejecución de la revisión (Adjunto liga a documentación para que tengas referencia de funcionalidades adicionales github/super-linter: Combination of multiple linters to install as a GitHub Action):
- FILTER_REGEX_INCLUDE: Permite reducir el scope de revisión del action a lo que se encuentre en un directorio o archivos con una terminación en específico.
- VALIDATE_ALL_CODEBASE: Al poner “false” solo revisara archivos nuevos o archivos que contengan cambios.
- DEFAULT_BRANCH: Define cual es la rama defecto a revisar.
- GITHUB_TOKEN: Permite el acceso a el código del repo en cuestión.
Nos falta un paso de configuración para hacer que la ejecución satisfactoria de nuestra acción dentro del workflow, forme parte de las políticas para integrar cambios nuevos a las ramas que tenemos protegidas en GitHub, para esto necesitamos agregar una regla de protección de ramas en la sección de configuración de las ramas.
Especificamos las reglas que aplicaran y al final activamos la regla “Require status checks to pass before merging” y “Require branches to be up to date before merging” agregamos el status check de Linted: JAVA (existen otros linters para Java, es posible agregarlos también), guardamos nuestros cambios.
Existen otras capacidades que permiten integrar este linter en Visual Studio code (Adjunto referencia github/super-linter: Combination of multiple linters to install as a GitHub Action), sin embargo con esto terminamos la configuración de super-linter, ahora procederemos a ver como seria la interacción una vez que se ejecuta.
Interacción día a día con la herramienta
Ahora que ya tenemos configurado super-linter, y esta protegida nuestra rama, vamos a ver como verifica nuestro código; creamos una nueva rama basada en main y agregamos un cambio en el archivo HelloController.java en el metod api, que simplemente declara una variable tipo entero y le asigna un 5.
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, String> api() {
HashMap<String, String> map = new HashMap<>();
int a=6;
map.put("greeting", greeting);
return map;
}
Una vez que hacemos el commit del cambio en nuestra rama, creamos un pull Request y esperamos a que se ejecute el workflow que validara que compile nuestro código y que ejecute super-linter
El workflow fallará ya que el action identifico varios incumplimientos de las reglas definidas en el archivo personalizado de linter que agregamos anteriormente, algo interesante es que solo fue en los archivos que modificamos en este caso en el hello Controller.
En su mayoría los errores están relacionados a falta de comentarios Javadoc en los métodos y clases, la forma en la cual declaramos algunas variables y asignamos valores.
Procedemos a realizar las correcciones en el archivo HelloController.java que modificamos, en la rama y hacemos commit de nuestros cambios.
package com.hello.hello;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HelloController {
String greeting = "Hello World!";
@RequestMapping("/")
public String index() {
return greeting;
}
@RequestMapping("/api")
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, String> api() {
HashMap<String, String> map = new HashMap<>();
map.put("greeting", greeting);
return map;
}
}
Vemos que se ejecuta el workflow que contiene la revisión estática de código y forma parte de las políticas que restringen el acceso de nuevos cambios a la rama protegida.
Vemos la ejecución de super linte en el workflow.
Y una vez que termina de revisar todos los archivos modificados y el check está cubierto, podemos integrar nuestro cambio en la rama protegida si cumple con las otras reglas establecidas.
Esto fue todo por hoy espero que te haya gustado este articulo y te sea de mucha utilidad, puedes ver más contenido que estaré generando en este medio.
¡Saludos y disfruta estar en la nube!