<div class="page">
<div class="cover text-center">
<img class="mx-auto" src=/itb/images/logo_mislata.png alt="logo">
# CI/CD - GitHub Actions
<div class="text-end fit-content ms-auto my-3 mt-auto pt-3">
<p><strong>Autor:</strong> Joan Puigcerver Ibáñez</p>
<p><strong>Correu electrònic:</strong> j.puigcerveribanez@edu.gva.es</p>
<p><strong>Curs:</strong> 2024/2025</p>
</div>
<div>
<p class="fw-bold mb-0">Llicència: BY-NC-SA</p>
<p class="d-none d-md-block">(Reconeixement - No Comercial - Compartir Igual)</p>
<a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.ca" target="_blank">
<img class="mx-auto" src="/itb/images/license.png" alt="Licence"/>
</a>
</div><!--license-->
</div><!--cover-->
</div><!--page-->
{:toc}
## Introducció
En enginyeria del software, __CI/CD__ es coneix com a la combinació de les pràctiques
d'__integració contínua (_continuous integration_ o CI)__ i de
__distribució contínua (_continuous delivery_ o CD)__.
- [CI/CD - Wikipedia](https://en.wikipedia.org/wiki/Continuous_integration)
La __integració contínua__ consisteix a _integrar_ els canvis
en desenvolupament a la branca _main_ d'una manera freqüent.
- [Continuous integration - Wikipedia](https://en.wikipedia.org/wiki/Continuous_integration)
La __distribució contínua__ consisteix a proporcionar una versió
del software en períodes curts de temps, comprovant que el software
pot ser posat en producció en qualsevol moment utilitzant
una __canonada o _pipeline___ que s'encarrega de desplegar
el software automàticament sense interacció humana.
- [Continuous delivery - Wikipedia](https://en.wikipedia.org/wiki/Continuous_delivery)
## Configurar Maven
__Maven__ és el software de gestió de projectes que utilitzem en el nostre projecte
d'IntelliJ. Fins ara l'hem utilitzat per instal·lar llibreries i dependències del
projecte.
Anem a configurar-lo per poder executar els tests.
En el fitxer __pom.xml__, hem d'afegir el següent contingut:
- __Plugin__ `maven-surefire-plugin`: Aquest plugin ve inclòs per defecte en la configuració de
Maven que realitza IntelliJ. No obstant, com estem utilitzant __JUnit5__, hem d'actualitzar
el plugin a la versió 2.22.0.
```xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<!-- JUnit 5 requires Surefire version 2.22.0 or higher -->
<version>2.22.0</version>
</plugin>
</plugins>
</build>
```
- __Dependència__ `junit-jupiter-engine`: Dependència de __JUnit5__ que necessitem.
```xml
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
```
### Exemple pom.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>PuigcerverJoan-DAW1-ED-solutions</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<!-- JUnit 5 requires Surefire version 2.22.0 or higher -->
<version>2.22.0</version>
</plugin>
</plugins>
</build>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.2.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
```
Una vegada actualitzat el __pom.xml__, sols cal actualitzar el projecte amb __Maven > Reload Project__.
__Maven__ proporciona diferents accions, com compilar, empaquetar o provar el codi.
En la finestra __Maven__ (barra dreta d'IntelliJ) podeu seleccionar les diferents
accions (_Goals_) a exectuar.
En aquest cas, volem utilitzar el _goal_ ___verify___, que compila i llança els
tests del nostre projecte.
## GitHub Actions
Com hem exposat abans, comprovar el funcionament del software d'una manera
freqüent i __automàtica__ és una part de la __distribució contínua (CD)__.
En aquest apartat s'explicarà com podem configurar el nostre repositori
per llançar els tests automàticament mitjançant __GitHub Actions__.
__GitHub Actions__ és una característica que ens ofereix GitHub, que permet
automatitzar accions en certs events del repositori. _Per exemple, la publicació
de una web estàtica mitjançant GitHub Pages es realitza mitjançant Actions_.
Podeu accedir a les accions del vostre repositori en la pestanya __Actions__.
En aquesta pàgina, podeu consultar les accions creades o configurar una nova acció.
{.center}
### New Workflow
Anem a crear una nova acció mitjançant el botó __New Workflow__, i anem a seleccionar
la plantilla __Java With Maven__. Això ens obrira un editor amb el següent contingut:
```yaml
name: Java CI with Maven
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- 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
```
### Adaptar la plantilla
Anem a desxifrar el seu contingut.
Primer que res, especifiquem el nom del workflow amb l'etiqueta `name`. Anem a modificar el nom.
```yaml
name: Test Java with Maven
```
La següent etiqueta és `on`, que especifica en quines circustàncies o events
s'executarà aquesta acció. En aquest cas, s'executarà al fer un `push` o crear una
`pull_request` a la branca `main`. També podem afegir `workflow_dispatch:` per
poder llançar l'acció manualment.
```yaml
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
workflow_dispatch:
```
L'última etiqueta de l'àrrel és `jobs`, que especifica quines tasques ha de dur a terme
l'acció.
- La etiqueta `build` és el nom de la primera tasca, que la podem modificar a `test`.
- L'etiqueta `runs-on` especifica quin entorn s'ha de configurar en el contenedor per executar les tasques.
- L'etiqueta `steps` conté una llista amb els passos que s'han de seguir per completar aquesta tasca.
```yaml
jobs:
test: # Abans era build:
runs-on: ubuntu-latest
steps:
- ...
- ...
```
En aquest cas, s'executen els següents passos:
1. Es còpia el contingut del repositori al contenidor on s'executarà la tasca.
- `uses` indica que utilitza una acció predefinida. En aques cas s'utilitza l'acció [actions/checkout@v4](https://github.com/actions/checkout)
```yaml
- uses: actions/checkout@v4
```
2. Es configura la versió de Java que s'utilitzarà. En aquest cas, utilitzarem la versió 17
que hem especificat en el __pom.xml__.
- `name` indica el nom de aquest pas.
- `uses` indica que utilitza una acció predefinida. En aques cas s'utilitza l'acció [actions/setup-java@v3](https://github.com/actions/setup-java)
- `with` serveix per establir el valor de les variables d'alguna acció predefinida.
```yaml
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
```
- __pom.xml__:
```xml
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
```
3. Per últim, compilem i llançem els tests mitjançant el _goal_ `verify` de __Maven__.
- `run` serveix per establir quina comanda es vol executar en el contenedor.
```yaml
- name: Verify with Maven
run: mvn --batch-mode --update-snapshots verify
```
4. Hem eliminat l'últim pas opcional de la plantilla.
### Workflow final
El fitxer del workflow quedaria d'aquesta manera:
```yaml
name: Test Java with Maven
on:
workflow_dispatch:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Verify with Maven
run: mvn --batch-mode --update-snapshots verify
```
Una vegada configurat, podem incloure l'acció realitzant un _commit_. Aquest
fitxer es guardarà en la carpeta dedicada a les accions `.github/workflows`.
## Execució
### Workflow-dispatch
Des de la pàgina __Actions__, podem navegar a l'acció "Test Java with Maven" i llançar-la manualment,
gràcies a que hem establert `workflow_dispatch` en la configuració de l'acció.
{.center}
### Push a `main`
Si realitzem un `push` a la branca `main`, podem observar com s'executa l'acció.
Una vegada realizada, veurem un tick verd si s'ha executat correctament o una creu
roja si ha fallat.
{.center}
### Pull request a `main`
El mateix passa quan creem una __Pull Request__. En aquest cas, el resultat
de les comprovacions apareix en la pàgina des d'on es pot aprovar o rebutjar
els canvis. D'aquesta manera és fàcil identificar si els tests no passen
i podem decidir si volem o no incloure els canvis proposats.
{.center}
## Bibliografia
- https://stackoverflow.com/questions/8180315/output-failed-test-details-to-stdout-using-maven-surefire