Super-Linter, que es y como puedo integrarlo en mi flujo de CI – CD en GitHub

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.

LenguajeLinter
Ansibleansible-lint
AWS CloudFormation templatescfn-lint
Azure Resource Manager (Bicep)(ARM)arm-ttk
C++cpp-lint / clang-format
C#dotnet-format / clang-format
CSSstylelint
Clojureclj-kondo
CoffeeScriptcoffeelint
Copy/paste detectionjscpd
Dartdartanalyzer
Dockerfilehadolint
EditorConfigeditorconfig-checker
ENVdotenv-linter
Gherkingherkin-lint
GitHub Actionsactionlint
Golanggolangci-lint
Groovynpm-groovy-lint
HTMLHTMLHint
Javacheckstyle / google-java-format
JavaScriptESLint / standard js
JSONeslint-plugin-json
JSONCeslint-plugin-jsonc
Kubevalkubeval
Kotlinktlint
LaTeXChkTex
Lualuacheck
Markdownmarkdownlint
Natural languagetextlint
OpenAPIspectral
Perlperlcritic
PHPPHP built-in linter / PHP CodeSniffer / PHPStan / Psalm
PowerShellPSScriptAnalyzer
Protocol Buffersprotolint
Python3pylint / flake8 / black / isort
Rlintr
RakuRaku
RubyRuboCop
RustRustfmt / Clippy
Scalascalafmt
SecretsGitLeaks
ShellShellcheck / [executable bit check] / shfmt
Snakemakesnakefmt / snakemake –lint
SQLsql-lint / sqlfluff
Tektontekton-lint
Terraformtflint / terrascan
Terragruntterragrunt
TypeScriptESLint / standard js
XMLLibXML
YAMLYamlLint

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).

Descripción en el marketplace de GitHub del action Super-Linter

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”.

Archivo de definición de linters para personalizar reglas

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)).

Comentario para omitir la ejecución de la regla de JavadocPackage

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.

Configuraciones de la ramas dentro del repositorio de GitHub

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.

Reglas de protección de ramas

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.

Errores encontrados en la ejecución del workflow

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.

Check del pull request

Vemos la ejecución de super linte en el workflow.

Logs de ejecución de Super-Linter
Logs del proceso de escaneo de Super-Linter sobre los archivos modificados

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.

Checks ejecutados con exito en el pull request

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!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *