Uso de un formateador de código
Los formateadores de código existen para asegurar que el estilo del código escrito sea consistente en toda la base de código. Esto se utiliza en muchos proyectos importantes, desde Android hasta OpenCV. Los equipos pueden querer añadir un formateador en todo el código de su robot para asegurarse de que el código base mantiene la legibilidad y la coherencia en todo momento.
For this article, we will highlight using Spotless for Java teams and wpiformat for C++ teams.
Spotless
Configuración
Es necesario realizar los cambios necesarios en build.gradle
para que Spotless sea funcional. En el bloque plugins {}
de tu build.gradle
, añade el plugin Spotless para que aparezca de forma similar a la siguiente.
plugins {
id "java"
id "edu.wpi.first.GradleRIO" version "2024.1.1"
id 'com.diffplug.spotless' version '6.20.0'
}
A continuación, asegúrese de añadir un bloque requerido spotless {}
para configurar correctamente spotless. Esto puede colocarse al final de tu build.gradle
.
spotless {
java {
target fileTree('.') {
include '**/*.java'
exclude '**/build/**', '**/build-*/**'
}
toggleOffOn()
googleJavaFormat()
removeUnusedImports()
trimTrailingWhitespace()
endWithNewline()
}
groovyGradle {
target fileTree('.') {
include '**/*.gradle'
exclude '**/build/**', '**/build-*/**'
}
greclipse()
indentWithSpaces(4)
trimTrailingWhitespace()
endWithNewline()
}
format 'xml', {
target fileTree('.') {
include '**/*.xml'
exclude '**/build/**', '**/build-*/**'
}
eclipseWtp('xml')
trimTrailingWhitespace()
indentWithSpaces(2)
endWithNewline()
}
format 'misc', {
target fileTree('.') {
include '**/*.md', '**/.gitignore'
exclude '**/build/**', '**/build-*/**'
}
trimTrailingWhitespace()
indentWithSpaces(2)
endWithNewline()
}
}
Ejecutar Spotless
Spotless puede ser ejecutado usando ./gradlew spotlessApply
que aplicará todas las opciones de formato. También se puede especificar una tarea concreta añadiendo simplemente el nombre del formateador. Un ejemplo es ./gradlew spotlessmiscApply
.
In addition to formatting code, Spotless can also ensure the code is correctly formatted; this can be used by running ./gradlew spotlessCheck
. Thus, Spotless can be used as a CI check, as shown in the following GitHub Actions workflow:
on: [push]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
spotless:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-java@v4
with:
distribution: 'zulu'
java-version: 17
- run: ./gradlew spotlessCheck
Explicación de las opciones
Cada sección format
destaca el formato de los archivos personalizados en el proyecto. Las secciones java
y groovyGradle
son soportadas nativamente por spotless, por lo que se definen de forma diferente.
Desglosando esto, podemos dividirlo en varias partes.
Formateo de Java
Formateo de archivos Gradle
Formateo de archivos XML
Formateo de archivos varios
Todos son similares, excepto por algunas pequeñas diferencias que se explicarán. El siguiente ejemplo destacará el bloque java {}
.
java {
target fileTree('.') {
include '**/*.java'
exclude '**/build/**', '**/build-*/**'
}
toggleOffOn()
googleJavaFormat()
removeUnusedImports()
trimTrailingWhitespace()
endWithNewline()
}
Vamos a explicar qué significa cada una de las opciones.
target fileTree('.') {
include '**/*.java'
exclude '**/build/**', '**/build-*/**'
}
El ejemplo anterior le dice a spotless dónde están nuestras clases Java y que excluya el directorio build
. El resto de las opciones se explican por sí mismas.
toggleOffOn()
añade la posibilidad de que spotless ignore partes específicas de un proyecto. El uso es como el siguiente
// format:off
public void myWeirdFunction() {
}
// format:on
googleJavaFormat()
le dice a spotless que formatee según la Guía de Estilo de GoogleremoveUnusedImports()
will remove any unused imports from any of your Java classestrimTrailingWhitespace()
eliminará cualquier espacio en blanco extra al final de las líneasendWithNewline()
añadirá un carácter de nueva línea al final de tus clases
En el bloque groovyGradle
, hay una opción greclipse
. Este es el formateador que spotless utiliza para formatear los archivos gradle.
Además, hay una opción eclipseWtp
en el bloque xml
. Esto significa «Gradle Web Tools Platform» y es el formateador para formatear archivos xml
. Los equipos que no utilicen ningún archivo XML pueden desear no incluir esta configuración.
Nota
Una lista completa de configuraciones está disponible en el Spotless README
Problemas con los finales de línea
Spotless intentará aplicar finales de línea por SO, lo que significa que los diffs de Git cambiarán constantemente si dos usuarios están en diferentes SOs (Unix vs Windows). Se recomienda que los equipos que contribuyen al mismo repositorio desde múltiples sistemas operativos utilicen un archivo .gitattributes
. Lo siguiente debería ser suficiente para manejar los finales de línea.
*.gradle text eol=lf
*.java text eol=lf
*.md text eol=lf
*.xml text eol=lf
wpiformat
Requerimientos:
You can install wpiformat by typing pip3 install wpiformat
into a terminal or command prompt.
Uso
wpiformat se puede ejecutar escribiendo wpiformat
en una consola. Esto formateará con clang-format
. Se necesitan tres archivos de configuración (.clang-format
, .styleguide
, .styleguide-license
). Estos deben existir en la raíz del proyecto.
A continuación se muestra un ejemplo de guía de estilo:
cppHeaderFileInclude {
\.h$
\.hpp$
\.inc$
\.inl$
}
cppSrcFileInclude {
\.cpp$
}
modifiableFileExclude {
gradle/
}
Nota
Los equipos pueden adaptar .styleguide
y .styleguide-license
como quieran. ¡Es importante que no se eliminen, ya que son necesarios para ejecutar wpiformat!
You can turn this into a CI check by running git --no-pager diff --exit-code HEAD
, as shown in the example GitHub Actions workflow below:
name: Lint and Format
on:
pull_request:
push:
jobs:
wpiformat:
name: "wpiformat"
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch all history and metadata
run: |
git checkout -b pr
git branch -f main origin/main
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install wpiformat
run: pip3 install wpiformat==2024.45
- name: Run
run: wpiformat
- name: Check output
run: git --no-pager diff --exit-code HEAD