2021-02-10 23:31:27 +00:00
|
|
|
%\documentclass[handout,aspectratio=169]{beamer}
|
|
|
|
\documentclass[aspectratio=169]{beamer}
|
2021-02-08 18:26:20 +00:00
|
|
|
|
|
|
|
\usepackage[T1]{fontenc}
|
|
|
|
\usepackage[utf8]{inputenc}
|
|
|
|
\usepackage{lmodern}
|
2021-02-10 23:31:27 +00:00
|
|
|
\usepackage[french]{babel}
|
2021-02-08 18:26:20 +00:00
|
|
|
\usepackage{graphicx}
|
2021-02-10 23:31:27 +00:00
|
|
|
\usepackage{ulem}
|
|
|
|
\usepackage{listings}
|
|
|
|
\lstset{
|
|
|
|
inputencoding=utf8,
|
|
|
|
mathescape,
|
|
|
|
basicstyle=\tiny\ttfamily,
|
|
|
|
numberstyle=\scriptsize\ttfamily\color{gray},
|
|
|
|
showstringspaces=false,
|
|
|
|
tabsize=2,
|
|
|
|
numbers=left,
|
|
|
|
xleftmargin=8mm,
|
|
|
|
frame=lines,
|
|
|
|
framexleftmargin=8mm,
|
|
|
|
framerule=1pt,
|
|
|
|
rulecolor=\color{green!50!black},
|
|
|
|
backgroundcolor=\color{green!5},
|
|
|
|
commentstyle=\color{gray},
|
|
|
|
morecomment=[l][commentstyle]{//},
|
|
|
|
classoffset=0,
|
|
|
|
keywords={Pour, allant, Si, alors, Sinon, Fin},
|
|
|
|
keywordstyle=\color{blue!75},
|
|
|
|
classoffset=1,
|
|
|
|
morekeywords={Afficher},
|
|
|
|
keywordstyle=\color{green!50!black},
|
|
|
|
classoffset=0,
|
|
|
|
morestring=[b]",
|
|
|
|
stringstyle=\color{red!75},
|
|
|
|
literate=
|
|
|
|
{é}{{\'e}}{1}%
|
|
|
|
{è}{{\`e}}{1}%
|
|
|
|
{à}{{\`a}}{1}%
|
|
|
|
{â}{{\^a}}{1}%%%
|
|
|
|
{ç}{{\c{c}}}{1}%
|
|
|
|
{œ}{{\oe}}{1}%
|
|
|
|
{ù}{{\`u}}{1}%
|
|
|
|
{É}{{\'E}}{1}%
|
|
|
|
{È}{{\`E}}{1}%
|
|
|
|
{À}{{\`A}}{1}%
|
|
|
|
{Ç}{{\c{C}}}{1}%
|
|
|
|
{Œ}{{\OE}}{1}%
|
|
|
|
{Ê}{{\^E}}{1}%
|
|
|
|
{ê}{{\^e}}{1}%
|
|
|
|
{î}{{\^i}}{1}%
|
|
|
|
{ï}{{\"i}}{1}%%%
|
|
|
|
{ô}{{\^o}}{1}%
|
|
|
|
{û}{{\^u}}{1}%
|
|
|
|
}
|
2021-02-08 18:26:20 +00:00
|
|
|
|
|
|
|
\usetheme[sectiontitle]{crans}
|
|
|
|
|
|
|
|
\title{Automatisez vos tâches avec une intégration continue}
|
|
|
|
\subtitle{Séminaire CRANS}
|
|
|
|
\author[]{\textsc{Yohann D'ANELLO}}
|
|
|
|
\date{11 février 2021}
|
|
|
|
|
|
|
|
|
|
|
|
\begin{document}
|
|
|
|
\begin{frame}
|
|
|
|
\maketitle
|
|
|
|
\end{frame}
|
|
|
|
|
2021-02-10 23:31:27 +00:00
|
|
|
\section{Introduction}
|
|
|
|
|
|
|
|
\subsection{Discussion avec un chatbot}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Introduction avec un petit chatbot}
|
|
|
|
\begin{lstlisting}[language=bash]
|
|
|
|
git clone https://gitlab.crans.org/ynerant/seminaire-ci.git
|
|
|
|
cd seminaire-ci
|
|
|
|
git checkout v1
|
|
|
|
python3 main.py
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{exampleblock}
|
2021-02-08 18:26:20 +00:00
|
|
|
\end{frame}
|
|
|
|
|
2021-02-10 23:31:27 +00:00
|
|
|
\subsection{Des erreurs}
|
2021-02-08 18:26:20 +00:00
|
|
|
|
2021-02-10 23:31:27 +00:00
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{block}{Le script ne semble pas fonctionner}
|
|
|
|
\begin{lstlisting}[language=Python]
|
|
|
|
File "/tmp/seminaire-ci/main.py", line 7
|
|
|
|
print "Bienvenue dans le chatbot du séminaire de l'intégration continue !"
|
|
|
|
^
|
|
|
|
SyntaxError: Missing parentheses in call to 'print'.
|
|
|
|
Did you mean print("Bienvenue dans le chatbot du séminaire de l'intégration continue !")?
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\includegraphics[width=180px]{img/re2o-500.png} \includegraphics[width=180px]{img/note-500.png}
|
|
|
|
\includegraphics[width=180px]{img/youtube-500.jpg}
|
|
|
|
\end{frame}
|
2021-02-08 18:26:20 +00:00
|
|
|
|
|
|
|
\begin{frame}
|
2021-02-10 23:31:27 +00:00
|
|
|
\begin{block}{Trois solutions}
|
|
|
|
Il existe différents types de développeurs
|
|
|
|
\begin{itemize}
|
|
|
|
\item Celui/celle qui fait confiance à son code
|
|
|
|
\pause
|
|
|
|
\item Celui/celle qui ne fait pas confiance à son code et qui teste tout
|
|
|
|
en permance
|
|
|
|
\pause
|
|
|
|
\item Celui/celle qui ne fait pas confiance à son code et qui embauche un
|
|
|
|
esclave pour tout tester en permanence
|
|
|
|
\end{itemize}
|
2021-02-08 18:26:20 +00:00
|
|
|
\end{block}
|
2021-02-10 23:31:27 +00:00
|
|
|
|
|
|
|
\pause
|
|
|
|
|
|
|
|
\og{} Le code prouve que ça marche \fg{}
|
|
|
|
|
|
|
|
\og{} De toute façon ce que j'ai écrit peut rien péter \fg{}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\subsection{Comment éviter les erreurs ?}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{itemize}
|
|
|
|
\item Relire 100 fois son code
|
|
|
|
\pause
|
|
|
|
\item Réfléchir avant d'écrire, prendre du recul
|
|
|
|
\pause
|
|
|
|
\item Tester son code après chaque modification
|
|
|
|
\pause
|
|
|
|
\item Utiliser un analyseur syntaxique
|
|
|
|
\pause
|
|
|
|
\item Tester automatiquement et régulièrement le code
|
|
|
|
\end{itemize}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\section{Correction des erreurs}
|
|
|
|
|
|
|
|
\subsection{Analyseur syntaxique}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Rôle d'un analyseur syntaxique}
|
|
|
|
\begin{itemize}
|
|
|
|
\item Lit le code sans l'exécuter ni le compiler
|
|
|
|
\item Vérifie que la syntaxe est cohérente
|
|
|
|
\item Repère les erreurs les plus courantes et suggère des modifications
|
|
|
|
\item S'assure de l'uniformité du code et du respect de certaines
|
|
|
|
conventions
|
|
|
|
\item Existe dans la quasi-totalité des langages
|
|
|
|
\item En Python : Flake8 et Pylint
|
|
|
|
\end{itemize}
|
2021-02-08 18:26:20 +00:00
|
|
|
\end{block}
|
2021-02-10 23:31:27 +00:00
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Installation des analyseurs}
|
|
|
|
\begin{lstlisting}[language=bash]
|
|
|
|
(sudo apt install python3-virtualenv / sudo pacman -S python-virtualenv)
|
|
|
|
(python3 -m venv venv)
|
|
|
|
(source venv/bin/activate)
|
|
|
|
pip3 install pylint flake8
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{exampleblock}
|
|
|
|
|
|
|
|
\begin{exampleblock}{Analyse du code}
|
|
|
|
En lancant \texttt{pylint main.py} :
|
|
|
|
\begin{lstlisting}[language=Python]
|
|
|
|
************* Module main
|
|
|
|
main.py:7:11: E0001: Missing parentheses in call to 'print'.
|
|
|
|
Did you mean print("Bienvenue dans le chatbot du séminaire de l'intégration continue !")?
|
|
|
|
(<unknown>, line 7) (syntax-error)
|
|
|
|
\end{lstlisting}
|
2021-02-08 18:26:20 +00:00
|
|
|
\end{exampleblock}
|
2021-02-10 23:31:27 +00:00
|
|
|
|
|
|
|
$\implies$ On n'a pas eu besoin d'exécuter le code
|
2021-02-08 18:26:20 +00:00
|
|
|
\end{frame}
|
|
|
|
|
2021-02-10 23:31:27 +00:00
|
|
|
\subsection{Intégration continue}
|
2021-02-08 18:26:20 +00:00
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{itemize}
|
2021-02-10 23:31:27 +00:00
|
|
|
\item Appeler ce script à la main $\to$ laborieux
|
|
|
|
\item Solution : utiliser \sout{un esclave} de l'intégration continue
|
2021-02-08 18:26:20 +00:00
|
|
|
\end{itemize}
|
2021-02-10 23:31:27 +00:00
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Qu'est-ce qu'une intégration continue ?}
|
|
|
|
\begin{itemize}
|
|
|
|
\item Script appelé après commit envoyé au serveur distant
|
|
|
|
\item Utile pour analyser et tester le code
|
|
|
|
\item Mais également pour déployer le projet automatiquement
|
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Analyse syntaxique automatique}
|
|
|
|
\texttt{git checkout v2}
|
|
|
|
|
|
|
|
Dans le fichier \texttt{.gitlab-ci.yml} :
|
|
|
|
\begin{lstlisting}[]
|
|
|
|
flake8:
|
|
|
|
image: python:3-alpine
|
|
|
|
before_script:
|
|
|
|
- pip install flake8 --no-cache-dir
|
|
|
|
script: flake8 main.py
|
|
|
|
|
|
|
|
pylint:
|
|
|
|
image: python:3-alpine
|
|
|
|
before_script:
|
|
|
|
- pip install pylint --no-cache-dir
|
|
|
|
script: pylint main.py
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
Résultat : \url{https://gitlab.crans.org/ynerant/seminaire-ci/-/pipelines/5595}
|
|
|
|
\end{exampleblock}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\subsection{Nettoyer son code}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Utilité d'un analyseur syntaxique}
|
|
|
|
\begin{itemize}
|
|
|
|
\item \texttt{git checkout v2.5}
|
|
|
|
\item Le script peut être lancé, mais le code n'est pas propre
|
|
|
|
\item Un code bien écrit est un code qui peut être lu et maintenu
|
|
|
|
\item Quelques règles standards :
|
|
|
|
\begin{itemize}
|
|
|
|
\item Lignes ne faisant pas plus de 79 caractères
|
|
|
|
\item Code bien indenté
|
|
|
|
\item Pas de variable inutile
|
|
|
|
\item Code bien aéré (mais pas trop)
|
|
|
|
\item Code documenté et commenté
|
|
|
|
\item Imports triés
|
|
|
|
\item Beaucoup d'options ...
|
|
|
|
\end{itemize}
|
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Analyse du code}
|
2021-02-11 17:17:28 +00:00
|
|
|
En lancant \texttt{pylint main.py} sur le tag \texttt{v2.5} :
|
2021-02-10 23:31:27 +00:00
|
|
|
\begin{lstlisting}[language=Python]
|
|
|
|
************* Module main
|
|
|
|
main.py:23:0: C0301: Line too long (104/100) (line-too-long)
|
|
|
|
main.py:32:0: C0301: Line too long (469/100) (line-too-long)
|
|
|
|
main.py:39:0: C0301: Line too long (192/100) (line-too-long)
|
|
|
|
main.py:16:0: W0622: Redefining built-in 'help' (redefined-builtin)
|
|
|
|
main.py:91:0: W0622: Redefining built-in 'quit' (redefined-builtin)
|
|
|
|
main.py:1:0: C0114: Missing module docstring (missing-module-docstring)
|
|
|
|
main.py:6:0: C0116: Missing function or method docstring (missing-function-docstring)
|
|
|
|
main.py:42:0: C0103: Argument name "a" does not conform to snake_case naming style
|
|
|
|
(invalid-name)
|
|
|
|
main.py:42:0: C0103: Argument name "b" does not conform to snake_case naming style
|
|
|
|
(invalid-name)
|
|
|
|
main.py:42:0: C0103: Argument name "c" does not conform to snake_case naming style
|
|
|
|
(invalid-name)
|
|
|
|
main.py:42:0: R0912: Too many branches (17/12) (too-many-branches)
|
|
|
|
main.py:96:4: R1722: Consider using sys.exit() (consider-using-sys-exit)
|
|
|
|
|
|
|
|
------------------------------------------------------------------
|
|
|
|
Your code has been rated at 8.03/10 (previous run: 8.03/10, +0.00)
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{exampleblock}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\subsection{Faire marcher son code}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{block}{Un code bien écrit n'est pas un code qui marche}
|
|
|
|
\texttt{git checkout v5}
|
|
|
|
|
|
|
|
En lançant \texttt{python3 main.py} :
|
|
|
|
\begin{lstlisting}
|
|
|
|
Bienvenue dans le chatbot du séminaire de l'intégration continue !
|
|
|
|
Veuillez taper une commande. Tapez "aide" pour afficher l'aide.
|
|
|
|
> calcul 1 2 3
|
|
|
|
Traceback (most recent call last):
|
|
|
|
File "/tmp/seminaire-ci/main.py", line 110, in <module>
|
|
|
|
main()
|
|
|
|
File "/tmp/seminaire-ci/main.py", line 27, in main
|
|
|
|
print(globals()[args[0]](*args[1:]))
|
|
|
|
File "/tmp/seminaire-ci/main.py", line 90, in calcul
|
|
|
|
result = left % right
|
|
|
|
TypeError: not all arguments converted during string formatting
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
$\implies$ le code est bien écrit, mais ne fait pas ce qu'on veut
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{block}{Utilisation de l'intégration continue}
|
|
|
|
\texttt{git checkout v6}
|
|
|
|
|
|
|
|
On ajoute au fichier \texttt{.gitlab-ci.yml} :
|
|
|
|
\begin{lstlisting}
|
|
|
|
test:
|
|
|
|
stage: test
|
|
|
|
image: python:3-alpine
|
|
|
|
script: python main.py
|
|
|
|
\end{lstlisting}
|
|
|
|
|
|
|
|
Le code est bien exécuté :
|
|
|
|
\url{https://gitlab.crans.org/ynerant/seminaire-ci/-/jobs/13865}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\subsection{Environnement de tests}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Utiliser un environnement de test}
|
|
|
|
\begin{itemize}
|
|
|
|
\item Impossible d'exécuter le script pas d'entrée à fournir
|
|
|
|
\item Impossible de choisir quoi tester et de vérifier la bonne
|
|
|
|
exécution du programme
|
|
|
|
\pause
|
|
|
|
\item Solution : utiliser un environnement adapté et des tests unitaires
|
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Avec Pytest}
|
|
|
|
\texttt{git checkout v8} \\
|
|
|
|
\texttt{pip3 install pytest} \\
|
|
|
|
Dans le fichier \texttt{main\_test.py} :
|
|
|
|
\begin{lstlisting}[language=Python]
|
|
|
|
import unittest
|
|
|
|
|
|
|
|
import main
|
|
|
|
|
|
|
|
|
|
|
|
def test_aide():
|
|
|
|
res = main.commande("aide")
|
|
|
|
lines = res.split("\n")
|
|
|
|
assert len(lines) == 6
|
|
|
|
assert lines[0].startswith("aide")
|
|
|
|
assert lines[1].startswith("seminaire")
|
|
|
|
assert lines[2].startswith("blague")
|
|
|
|
assert lines[3].startswith("calcul")
|
|
|
|
assert lines[4].startswith("tri")
|
|
|
|
assert lines[5].startswith("stop")
|
|
|
|
\end{lstlisting}
|
|
|
|
On a ajouté une fonction \texttt{commande}
|
|
|
|
\end{exampleblock}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Avec Pytest}
|
|
|
|
\texttt{pytest .}
|
|
|
|
\begin{lstlisting}[language=Python]
|
|
|
|
============================= test session starts =============================
|
|
|
|
platform linux -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
|
|
|
|
rootdir: /tmp/seminaire-ci
|
|
|
|
collected 1 item
|
|
|
|
main_test.py F [100%]
|
|
|
|
================================== FAILURES ===================================
|
|
|
|
__________________________________ test_aide __________________________________
|
2021-02-08 18:26:20 +00:00
|
|
|
|
2021-02-10 23:31:27 +00:00
|
|
|
def test_aide():
|
|
|
|
res = main.commande("aide")
|
|
|
|
> lines = res.split("\n")
|
|
|
|
E AttributeError: 'NoneType' object has no attribute 'split'
|
|
|
|
|
|
|
|
main_test.py:17: AttributeError
|
|
|
|
---------------------------- Captured stdout call -----------------------------
|
|
|
|
aide Affiche l aide
|
|
|
|
[...]
|
|
|
|
=========================== short test summary info ===========================
|
|
|
|
FAILED main_test.py::test_aide - AttributeError: 'NoneType' object has no at...
|
|
|
|
============================== 1 failed in 0.03s ==============================
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{exampleblock}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Avec Pytest, après réparation de l'erreur}
|
|
|
|
\texttt{git checkout v9} \\
|
|
|
|
\texttt{pytest .}
|
|
|
|
\begin{lstlisting}[language=Python]
|
|
|
|
============================= test session starts =============================
|
|
|
|
platform linux -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
|
|
|
|
rootdir: /tmp/seminaire-ci
|
|
|
|
collected 1 item
|
|
|
|
|
|
|
|
main_test.py . [100%]
|
|
|
|
|
|
|
|
============================== 1 passed in 0.01s ==============================
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{exampleblock}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Un meilleur environnement de tests}
|
|
|
|
\texttt{git checkout v10} \\
|
|
|
|
On utilise une classe pour mieux construire son environnement
|
|
|
|
\begin{lstlisting}[language=Python]
|
|
|
|
import unittest
|
|
|
|
|
|
|
|
import main
|
|
|
|
|
|
|
|
|
|
|
|
class TestMain(unittest.TestCase):
|
|
|
|
def test_aide(self):
|
|
|
|
res = main.commande("aide")
|
|
|
|
lines = res.split("\n")
|
|
|
|
self.assertEqual(len(lines), 6)
|
|
|
|
self.assertTrue(lines[0].startswith("aide"))
|
|
|
|
self.assertTrue(lines[1].startswith("seminaire"))
|
|
|
|
self.assertTrue(lines[2].startswith("blague"))
|
|
|
|
self.assertTrue(lines[3].startswith("calcul"))
|
|
|
|
self.assertTrue(lines[4].startswith("tri"))
|
|
|
|
self.assertTrue(lines[5].startswith("stop"))
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{exampleblock}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Qu'est-ce qu'un bon test unitaire ?}
|
|
|
|
\begin{itemize}
|
|
|
|
\item \og{} Unitaire \fg{} : on ne teste qu'une seule fonctionnalité à la
|
|
|
|
fois
|
|
|
|
\item Clair
|
|
|
|
\item Pertinent
|
|
|
|
\item Non-trivial
|
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\subsection{Couverture}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{block}{Couverture}
|
|
|
|
\begin{itemize}
|
|
|
|
\item Les tests unitaires exécutent une partie du code
|
|
|
|
\item Il est possible de mesurer quelle partie du code est exécutée et
|
|
|
|
testée
|
|
|
|
\item On parle de \textit{couverture} du code (\textit{coverage} en anglais)
|
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
|
|
|
|
\begin{exampleblock}{Calcul de la couverture du code}
|
|
|
|
\begin{itemize}
|
|
|
|
\item \texttt{git checkout v11}
|
|
|
|
\item \texttt{pip install pytest-cov}
|
|
|
|
\item \texttt{pytest --showlocals --cov=main --cov=main\_test --cov-report=term-missing .}
|
|
|
|
\end{itemize}
|
|
|
|
\end{exampleblock}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{exampleblock}{Calcul de couverture}
|
|
|
|
\texttt{pytest --showlocals --cov=main --cov=main\_test --cov-report=term-missing .}
|
|
|
|
\begin{lstlisting}
|
|
|
|
============================= test session starts =============================
|
|
|
|
platform linux -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
|
|
|
|
rootdir: /tmp/seminaire-ci
|
|
|
|
plugins: cov-2.11.1
|
|
|
|
collected 1 item
|
|
|
|
main_test.py . [100%]
|
|
|
|
----------- coverage: platform linux, python 3.9.1-final-0 -----------
|
|
|
|
Name Stmts Miss Cover Missing
|
|
|
|
--------------------------------------------
|
|
|
|
main.py 41 27 34% 21-27, 54, 70, 82-98, 105, 112-113, 117
|
|
|
|
main_test.py 14 0 100%
|
|
|
|
--------------------------------------------
|
|
|
|
TOTAL 55 27 51%
|
|
|
|
|
|
|
|
============================== 1 passed in 0.05s ==============================
|
|
|
|
\end{lstlisting}
|
|
|
|
Exercice pour le plaisir : couvrir et tester correctement la totalité du code
|
|
|
|
\end{exampleblock}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\subsection{Lutter contre le nazisme}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Configuration de l'analyse et des tests}
|
|
|
|
\begin{itemize}
|
|
|
|
\item \og{} Ohh vraiment je dois faire ça \fg{}, \og{} 79 caractères c'est
|
|
|
|
pas assez \fg{}, \og{} Je ne veux/peux pas couvrir cette ligne \fg{}
|
|
|
|
\item Couvrir et tester sont des très bonnes pratiques en règle générale
|
2021-02-11 17:17:28 +00:00
|
|
|
\item Vous pouvez adapter la configuration selon vos propres critères,
|
|
|
|
plus ou moins souples
|
2021-02-10 23:31:27 +00:00
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\section{Déploiement}
|
|
|
|
|
|
|
|
\subsection{Artefacts}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Rôle d'une intégration continue}
|
|
|
|
Une intégration continue permet :
|
|
|
|
\begin{itemize}
|
|
|
|
\item d'analyser automatiquement la structure du code
|
|
|
|
\item de tester automatiquement le projet
|
|
|
|
\item \textit{a fortiori} de donner un indicateur aux autres personnes de
|
|
|
|
la qualité du projet via des badges
|
|
|
|
\pause
|
|
|
|
\item De construire et de déployer automatiquement le projet
|
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{block}{Construction du projet}
|
|
|
|
\texttt{git checkout v16} \\
|
|
|
|
Un script d'intégration ne se limite pas aux tests : il peut compiler des
|
|
|
|
projets
|
|
|
|
|
|
|
|
Exemple avec la compilation automatique \LaTeX{} de ces slides :
|
|
|
|
\begin{lstlisting}
|
|
|
|
slides:
|
|
|
|
image: aergus/latex
|
|
|
|
script:
|
|
|
|
- latexmk -cd -pdf slides/seminaire-ci.tex
|
|
|
|
\end{lstlisting}
|
|
|
|
L'intégration continue génère un fichier \texttt{seminaire-ci.pdf} dans son
|
|
|
|
script
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{block}{Construction du projet}
|
|
|
|
\texttt{git checkout v16} \\
|
|
|
|
Il est possible d'exporter certains fichiers compilés :
|
|
|
|
\begin{lstlisting}
|
|
|
|
slides:
|
|
|
|
image: aergus/latex
|
|
|
|
script:
|
|
|
|
- latexmk -cd -pdf slides/seminaire-ci.tex
|
|
|
|
artifacts:
|
|
|
|
paths:
|
|
|
|
- slides/seminaire-ci.pdf
|
|
|
|
expire_in: 1 mo
|
|
|
|
\end{lstlisting}
|
|
|
|
Ici, les slides sont compilées et le fichier PDF généré est exporté et
|
|
|
|
stocké pendant 1 mois :
|
|
|
|
\url{https://gitlab.crans.org/ynerant/seminaire-ci/-/jobs/13826/artifacts/browse}
|
|
|
|
(à des fins d'exemple, la limitation d'un mois à été retirée)
|
|
|
|
|
|
|
|
Particulièrement utile pour générer des binaires à partir du code source
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\subsection{Déploiement automatisé}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Déployer son projet}
|
|
|
|
\begin{itemize}
|
|
|
|
\item Une fois le projet dans une version stable et bien testé, le projet
|
|
|
|
peut être installé
|
|
|
|
\item Si on a suffisamment confiance en ses tests, possibilité de le faire
|
|
|
|
automatiquement
|
|
|
|
\item Deux solutions principales :
|
|
|
|
\begin{itemize}
|
|
|
|
\item Envoyer un signal (\textit{webhook}) aux services concernés
|
|
|
|
\item Directement déployer le serveur ce qu'il faut $\to$ nécessite
|
|
|
|
d'être simple à déployer et d'être peu distribué (projet développé
|
|
|
|
dans un but interne : site, latex, ...)
|
|
|
|
\end{itemize}
|
|
|
|
\item Pour des gros projets, on privilégie la première option
|
|
|
|
\item Attention aux droits donnés à Gitlab
|
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\begin{frame}[containsverbatim]
|
|
|
|
\begin{block}{Déployer son projet}
|
|
|
|
Les slides de ce séminaire sont automatiquement déployées sur
|
|
|
|
\url{https://ynerant.fr/gitlab/seminaire-ci.pdf} :
|
|
|
|
\begin{lstlisting}
|
|
|
|
slides:
|
|
|
|
stage: compile_slides
|
|
|
|
image: aergus/latex
|
|
|
|
before_script:
|
|
|
|
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
|
|
|
|
- eval $$(ssh-agent -s)
|
|
|
|
- echo "$$SSH_KEY" | tr -d '\r' | ssh-add - > /dev/null
|
|
|
|
- mkdir -p ~/.ssh
|
|
|
|
- chmod 0700 ~/.ssh
|
|
|
|
- ssh-keyscan ynerant.fr >> ~/.ssh/known_hosts
|
|
|
|
- chmod 0644 ~/.ssh/known_hosts
|
|
|
|
script:
|
|
|
|
- latexmk -cd -pdf slides/seminaire-ci.tex
|
|
|
|
- scp slides/seminaire-ci.pdf gitlab-ci@ynerant.fr:gitlab-ftp/seminaire-ci.pdf
|
|
|
|
\end{lstlisting}
|
|
|
|
\end{block}
|
|
|
|
|
|
|
|
Autre exemple : \url{https://gitlab.crans.org/nounous/homepage} déploie
|
|
|
|
automatiquement \url{https://crans.org/}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\subsection{Webhooks}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{block}{Webhooks}
|
|
|
|
Un \textit{webhook} est un événement envoyé à un service externe pour
|
|
|
|
signaler un changement d'état.
|
|
|
|
|
|
|
|
Exemples de webhooks :
|
|
|
|
|
|
|
|
\begin{itemize}
|
|
|
|
\item Message sur une plateforme de communication (IRC, Matrix, Discord,
|
|
|
|
\ldots)
|
|
|
|
\item Compilation automatique de documentation
|
|
|
|
\item Traduction
|
|
|
|
\item Compilation et déploiement du projet sur un service externe (Docker,
|
|
|
|
PyPI ou autre gestionnaire de paquets, \ldots)
|
|
|
|
\end{itemize}
|
|
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
|
|
|
|
\section{Conclusion}
|
|
|
|
|
|
|
|
\begin{frame}
|
|
|
|
\begin{exampleblock}{En résumé}
|
|
|
|
\begin{itemize}
|
|
|
|
\item Analyser statiquement son code permet d'assurer qu'il est
|
|
|
|
syntaxiquement correct et qu'il est surtout lisible
|
|
|
|
\item Tester efficacement son projet assure son bon fonctionnement et
|
|
|
|
évite des erreurs imprévues
|
|
|
|
\item Ces tâches peuvent se faire automatiquement après chaque commit par
|
|
|
|
le biais d'une intégration continue
|
|
|
|
\item Il est enfin possible de construire et déployer son projet
|
|
|
|
automatiquement
|
|
|
|
\item Une intégration continue efficace est souvent signe d'un projet bien
|
|
|
|
géré
|
|
|
|
\end{itemize}
|
|
|
|
\end{exampleblock}
|
|
|
|
|
|
|
|
\pause
|
|
|
|
|
|
|
|
\begin{block}{}
|
|
|
|
\textit{Gérer} un projet n'est pas uniquement \textit{coder} un projet.
|
|
|
|
\end{block}
|
2021-02-08 18:26:20 +00:00
|
|
|
\end{frame}
|
2021-02-10 23:31:27 +00:00
|
|
|
|
2021-02-08 18:26:20 +00:00
|
|
|
\end{document}
|