Écriture des slides

Signed-off-by: ynerant <ynerant@crans.org>
This commit is contained in:
ynerant 2021-02-11 00:31:27 +01:00
parent d0becd4063
commit 143aae2e48
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
5 changed files with 618 additions and 38 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@ venv
*.nav *.nav
*.out *.out
*.pdf *.pdf
*.pyg
*.snm *.snm
*.synctex.gz *.synctex.gz
*.toc *.toc

BIN
slides/img/note-500.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

BIN
slides/img/re2o-500.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 KiB

BIN
slides/img/youtube-500.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@ -1,10 +1,58 @@
\documentclass[handout,aspectratio=169]{beamer} %\documentclass[handout,aspectratio=169]{beamer}
\documentclass[aspectratio=169]{beamer}
\usepackage[T1]{fontenc} \usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc} \usepackage[utf8]{inputenc}
\usepackage{lmodern} \usepackage{lmodern}
\usepackage[francais]{babel} \usepackage[french]{babel}
\usepackage{graphicx} \usepackage{graphicx}
\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}%
}
\usetheme[sectiontitle]{crans} \usetheme[sectiontitle]{crans}
@ -19,50 +67,581 @@
\maketitle \maketitle
\end{frame} \end{frame}
\begin{frame} \section{Introduction}
\tableofcontents[subsubsectionstyle=hide]
\end{frame}
\section{Example} \subsection{Discussion avec un chatbot}
\subsection{Block} \begin{frame}[containsverbatim]
\begin{exampleblock}{Introduction avec un petit chatbot}
\begin{frame} \begin{lstlisting}[language=bash]
\begin{block}{Title block} git clone https://gitlab.crans.org/ynerant/seminaire-ci.git
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. cd seminaire-ci
\end{block} git checkout v1
\begin{block}{} python3 main.py
No title Block \\ \end{lstlisting}
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
\end{block}
\begin{exampleblock}{Example Block}
Example text (ugly)
\end{exampleblock} \end{exampleblock}
\begin{alertblock}{Alert Block}
Alert Text
\end{alertblock}
\end{frame} \end{frame}
\subsection{Lists} \subsection{Des erreurs}
\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}
\begin{frame}
\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}
\end{block}
\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{frame}
\begin{itemize} \begin{itemize}
\item Item 1 \item Relire 100 fois son code
\item Item 2 \pause
\begin{itemize} \item Réfléchir avant d'écrire, prendre du recul
\item Subitem 1 \pause
\item Subitem 2 \item Tester son code après chaque modification
\end{itemize} \pause
\item Utiliser un analyseur syntaxique
\pause
\item Tester automatiquement et régulièrement le code
\end{itemize} \end{itemize}
\begin{enumerate}
\item item 1
\begin{enumerate}
\item item 1.1
\end{enumerate}
\item
\item
\item
\end{enumerate}
\end{frame} \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}
\end{block}
\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}
\end{exampleblock}
$\implies$ On n'a pas eu besoin d'exécuter le code
\end{frame}
\subsection{Intégration continue}
\begin{frame}
\begin{itemize}
\item Appeler ce script à la main $\to$ laborieux
\item Solution : utiliser \sout{un esclave} de l'intégration continue
\end{itemize}
\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}
En lancant \texttt{pylint main.py} sur le commit \texttt{v2.5} :
\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 __________________________________
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
\item Tout est configurable, y compris pour ajouter des exceptions
\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}
\end{frame}
\end{document} \end{document}