25 Commits

Author SHA1 Message Date
d0becd4063 Support de la compilation des slides via l'intégration continue et déploiement automatique
Signed-off-by: ynerant <ynerant@crans.org>
2021-02-08 20:37:49 +01:00
560e9ee6db On ne cherche pas à couvrir ce qui n'est pas testable
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-28 18:07:42 +01:00
db413e4a35 Réparation du tri
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-28 14:50:37 +01:00
e8fc6d0816 On remplace les if en elif pour avoir un résultat correct
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-28 14:47:20 +01:00
be7efbbfa7 Pour vérifier les calculs, on commence par transformer les entrées en entiers
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-28 14:45:58 +01:00
b8161eef93 Réparation des blagues
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-28 14:44:02 +01:00
bcfd13442f Réparation du séminaire
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-28 14:42:23 +01:00
f3dd9157c7 Ajout de tests pour tester toutes les fonctions
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-27 15:46:24 +01:00
40076ad3c1 Ajout d'un README pour les badges
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 18:57:48 +01:00
60e09751da Calcul de la couverture
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 18:47:18 +01:00
1fc558a2ad On utilise une classe pour les tests
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 18:37:12 +01:00
df223bd19e La fonction d'aide renvoie le texte à afficher au lieu de l'afficher directement
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 17:45:44 +01:00
7c2d082cf4 On lint le fichier de tests également
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 17:39:54 +01:00
1ba9934438 Pytest est requis
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 17:08:30 +01:00
d4d595ed68 Ajout d'un fichier de test avec pytest
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 17:07:12 +01:00
9026dd56cc Changement dans l'exécution du script
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:52:15 +01:00
6bd2b3c66c On exécute le programme
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:50:52 +01:00
01337279fc Ajout de docstrings. Pylint est content
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:47:46 +01:00
d8c6b6e6bf Factorisation de tests
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:45:23 +01:00
ecec88e230 Il faut aussi renommer les variables dans leurs usages
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:43:18 +01:00
9018ab4996 On renomme a, b et c qui ne sont pas suffisamment explicites
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:41:07 +01:00
ca69954315 On quitte un programme avec sys.exit
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:37:48 +01:00
4c241eeb60 On ne redéfinit pas des fonctions pré-implémentées
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:35:59 +01:00
5e55a65b3f Pas d'espace entre le nom du paramètre et la valeur par défaut. flake8 est content
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:33:45 +01:00
e551f8b98d Les lignes ne doivent pas être trop longues
Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
2021-01-26 16:32:03 +01:00
8 changed files with 414 additions and 55 deletions

14
.gitignore vendored
View File

@ -1 +1,15 @@
*.pyc
.pytest_cache
.coverage
venv
*.aux
*.log
*.nav
*.out
*.pdf
*.snm
*.synctex.gz
*.toc

View File

@ -1,5 +1,7 @@
stages:
- linting
- test
- compile_slides
flake8:
@ -7,7 +9,7 @@ flake8:
image: python:3-alpine
before_script:
- pip install flake8 --no-cache-dir
script: flake8 main.py
script: flake8 main.py main_test.py
allow_failure: true
@ -16,5 +18,32 @@ pylint:
image: python:3-alpine
before_script:
- pip install pylint --no-cache-dir
script: pylint main.py
script: pylint main.py main_test.py
allow_failure: true
test:
stage: test
image: python:3-alpine
before_script:
- pip install pytest pytest-cov --no-cache-dir
script: pytest --showlocals --cov=main --cov=main_test --cov-report=term-missing .
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
artifacts:
paths:
- slides/seminaire-ci.pdf
expire_in: 1 mo

6
README.md Normal file
View File

@ -0,0 +1,6 @@
[![pipeline status](https://gitlab.crans.org/ynerant/seminaire-ci/badges/master/pipeline.svg)](https://gitlab.crans.org/ynerant/seminaire-ci/-/commits/master)
[![coverage report](https://gitlab.crans.org/ynerant/seminaire-ci/badges/master/coverage.svg)](https://gitlab.crans.org/ynerant/seminaire-ci/-/commits/master)
# Séminaire intégration continue
Ce dépôt contient le script utilisé lors du séminaire Crans du 11 février 2021, ainsi que les slides.

127
main.py Normal file → Executable file
View File

@ -1,100 +1,121 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""
Ce script est utilisé en guise d'appui pour le séminaire Crans d'introduction
à l'intégration continue.
Le dépôt est présent sur https://gitlab.crans.org/ynerant/seminaire-ci.git
Plus d'informations sur les séminaires : https://www.crans.org/fr/seminaire/
"""
from random import choice
import sys
def main():
def main(): # pragma: nocover
"""
Fonction principale, qui va attendre les instructions de l'utilisateur.
"""
print("Bienvenue dans le chatbot du séminaire de l'intégration continue !")
print("Veuillez taper une commande. Tapez \"help\" pour afficher l'aide.")
print("Veuillez taper une commande. Tapez \"aide\" pour afficher l'aide.")
while True:
command = input("> ")
args = command.split(" ")
print(globals()[args[0]](*args[1:]))
print(commande(args[0], *args[1:]))
def help():
def commande(name: str, *args):
"""
Exécute la commande `name` avec les arguments donnés.
"""
return globals()[name](*args)
def aide():
"""
Affiche l'aide
"""
print("help\t\tAffiche l'aide")
print("seminaire\tLance le séminaire")
print("blague\t\tRaconte une blague")
print("calcul\t\tVérifie une opération arithmétique. Par exemple, check(1, 2, 3, '+') renvoie True")
print("tri\t\tTrie une liste d'entiers.")
print("quit\t\tQuitte le programme")
return "aide\t\tAffiche l'aide\n" \
"seminaire\tLance le séminaire\n" \
"blague\t\tRaconte une blague\n" \
"calcul\t\tVérifie une opération arithmétique. " \
"Par exemple, check(1, 2, 3, '+') renvoie True\n" \
"tri\t\tTrie une liste d'entiers.\n" \
"stop\t\tQuitte le programme"
def seminaire():
"""
Affiche les slides du séminaire.
"""
print("\x4c\x61\x69\x73\x73\x65\x20\x74\x6f\x6d\x62\x65\x72\x2c\x20\x74\x6f\x6e\x20\x74\x72\x75\x63\x20\x65\x73\x74\x20\x74\x72\x6f\x70\x20\x62\x65\x75\x67\x75\xe9\x2c\x20\x74\x75\x20\x64\x65\x76\x72\x61\x69\x73\x20\x70\x61\x73\x73\x65\x72\x20\x64\x75\x20\x74\x65\x6d\x70\x73\x20\xe0\x20\xe9\x63\x72\x69\x72\x65\x20\x64\x65\x73\x20\x74\x65\x73\x74\x73\x20\x65\x74\x20\x66\x61\x69\x72\x65\x20\x64\xe9\x66\x69\x6c\x65\x72\x20\x74\x65\x73\x20\x73\x6c\x69\x64\x65\x73")
return "\x4c\x61\x69\x73\x73\x65\x20\x74\x6f\x6d\x62\x65" \
"\x72\x2c\x20\x74\x6f\x6e\x20\x74\x72\x75\x63\x20" \
"\x65\x73\x74\x20\x74\x72\x6f\x70\x20\x62\x65\x75" \
"\x67\x75\xe9\x2c\x20\x74\x75\x20\x64\x65\x76\x72" \
"\x61\x69\x73\x20\x70\x61\x73\x73\x65\x72\x20\x64" \
"\x75\x20\x74\x65\x6d\x70\x73\x20\xe0\x20\xe9\x63" \
"\x72\x69\x72\x65\x20\x64\x65\x73\x20\x74\x65\x73" \
"\x74\x73\x20\x65\x74\x20\x66\x61\x69\x72\x65\x20" \
"\x64\xe9\x66\x69\x6c\x65\x72\x20\x74\x65\x73\x20" \
"\x73\x6c\x69\x64\x65\x73"
def blague():
"""
Renvoie une blague aléatoire.
"""
return choice(["Je vais vous raconter une blague sur, mais vous ne l'aurez peut-être pas.", "Connaissez-vous la différence entre la théroie et la pratique ? Il n'y en a pas, en théorie."])
return choice(
["Je vais vous raconter une blague sur UDP, mais vous "
"ne l'aurez peut-être pas.",
"Connaissez-vous la différence entre la théorie "
"et la pratique ? Il n'y en a pas, en théorie."])
def calcul(a, b, c, operation = '+'):
def calcul(left: int, right: int, res: int, operation='+'):
"""
Vérifie si a operation b == c, où a, b et c sont des entiers.
Vérifie si left operation b == c, où a, b et c sont des entiers.
L'opération peut être +, -, *, /, &, |, ^, % ou l'un de ses alias anglais.
"""
if operation == '+':
result = a + b
if operation == 'sum':
result = a + b
if operation == 'add':
result = a + b
if operation == '-':
result = a - b
if operation == 'sub':
result = a - b
if operation == '*':
result = a * b
if operation == 'mul':
result = a * b
if operation == 'prod':
result = a * b
if operation == '/':
result = a / b
if operation == 'div':
result = a / b
if operation == '&':
result = a & b
if operation == 'and':
result = a & b
if operation == '|':
result = a | b
if operation == 'or':
result = a | b
if operation == '^':
result = a ^ b
if operation == 'xor':
result = a ^ b
left = int(left)
right = int(right)
res = int(res)
if operation in ['+', 'add', 'sum']:
result = left + right
elif operation in ['-', 'sub']:
result = left - right
elif operation in ['*', 'mul', 'prod']:
result = left * right
elif operation in ['/', 'div']:
result = left / right
elif operation in ['&', 'and']:
result = left & right
elif operation in ['|', 'or']:
result = left | right
elif operation in ['^', 'xor']:
result = left ^ right
else:
result = a % b
return c == result
result = left % right
return res == result
def tri(*args):
"""
Trie les éléments donnés en argument.
"""
return sorted(args)
return sorted(int(number) for number in args)
def quit(exit_code: int = 0):
def stop(exit_code: int = 0):
"""
Stoppe le programme avec le code d'erreur donné.
"""
print("Fin du programme, merci !")
exit(exit_code)
sys.exit(exit_code)
if __name__ == '__main__':
if __name__ == '__main__': # pragma: nocover
main()

89
main_test.py Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
Exécution des tests du script.
"""
from random import randint, seed, shuffle
import unittest
import main
class TestMain(unittest.TestCase):
"""
Cette classe permet d'executer l'ensemble des scripts
"""
def test_aide(self):
"""
On essaie d'afficher l'aide,
et on vérifie si ça affiche la bonne chose.
"""
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"))
def test_seminaire(self):
"""
Test de l'affichage du "séminaire".
"""
res = main.commande("seminaire")
self.assertEqual(len(res), 114)
def test_blague(self):
"""
On teste les blagues, et on vérifie si
elles fonctionnent bien.
"""
seed(1)
res = main.commande("blague")
self.assertEqual(res, "Je vais vous raconter une blague sur UDP, "
"mais vous ne l'aurez peut-être pas.")
seed(5)
res = main.commande("blague")
self.assertEqual(res, "Connaissez-vous la différence entre la "
"théorie et la pratique ? "
"Il n'y en a pas, en théorie.")
def test_calcul(self):
"""
On vérifie que certains calculs basiques, puis aléatoires,
marchent bien.
"""
self.assertTrue(main.commande("calcul", 1, 2, 3))
self.assertFalse(main.commande("calcul", 1, 2, 2, '+'))
self.assertTrue(main.commande("calcul", 1, 2, 2, '*'))
self.assertTrue(main.commande("calcul", 42, 3, 14, 'div'))
self.assertTrue(main.commande("calcul", 16777215, 42, 42, 'and'))
self.assertTrue(main.commande("calcul", 16777213, 42, 16777215, 'or'))
self.assertFalse(main.commande("calcul", 15, 20, 35, 'xor'))
self.assertTrue(main.commande("calcul", 15, 20, 27, '^'))
self.assertTrue(main.commande("calcul", 100, 76, 24, 'unknown'))
left, right = randint(0, 0x7FFFFFFF), randint(0, 0x7FFFFFFF)
self.assertTrue(main.commande("calcul", left, right,
left - right, "-"))
def test_tri(self):
"""
À partir d'une liste donnée, on trie la liste
et on vérifie qu'elle est bien triée.
"""
my_list = ["23", "16", "234567", "-4"]
shuffle(my_list)
sorted_list = [-4, 16, 23, 234567]
self.assertEqual(main.commande("tri", *my_list), sorted_list)
def test_stop(self):
"""
On vérifie que le programme s'arrête bien.
"""
self.assertRaises(SystemExit, main.commande, "stop", 0)

132
slides/beamerthemecrans.sty Normal file
View File

@ -0,0 +1,132 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%% BEAMER THEME FOR CRANS %%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% place in same folder as your .tex
% \usetheme{ens} in preamble
% also need crans-logo.png
\NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesPackage{ensbeamer}[2019/09/04 Beamer Theme]
\RequirePackage{tikz}
\RequirePackage{xcolor}
\makeatletter
\newif\if@section\@sectionfalse
\DeclareOption{sectiontitle}{
\@sectiontrue
}
\ProcessOptions\relax
\definecolor{rougecrans}{RGB}{207,14,34} % rougecrans !
\setbeamercolor{structure}{fg=rougecrans}
%\setbeamercolor{sidebar}{fg=rougecrans,bg=white}
\setbeamercolor{sidebar}{bg=white,fg=rougecrans}
%\setbeamercolor{title in sidebar}{fg=white}
%\setbeamercolor{section in sidebar}{fg=white}
\setbeamercolor{section in sidebar shaded}{fg=rougecrans!40}
\setbeamercolor{subsection in sidebar}{fg=rougecrans}
\setbeamercolor{subsection in sidebar shaded}{fg=rougecrans!60}
\setbeamercolor{frametitle}{fg=rougecrans,bg=white}
\def\swidth{2cm}
%
% -----------------------------
% Title Page
\setbeamerfont{title}{size=\huge}
\setbeamerfont{author}{size=\large}
\setbeamerfont{institut}{size=\Large}
\setbeamerfont{subtitle}{size=\Large}
\setbeamerfont{date}{size=\Large}
\setbeamertemplate{title page}{%
\begin{tikzpicture}[remember picture,overlay]
\fill[white]
(current page.north west) rectangle (current page.south east);
\node
at ([yshift=+.15\textheight]current page.center) (title)
{\usebeamerfont{title}\textcolor{rougecrans}{\inserttitle}};
\node[below=2em]
at(title) (subtitle)
{\usebeamerfont{subtitle}\textcolor{rougecrans}{\insertsubtitle}};
\node
at ([yshift=-70pt]current page.center) (institute)
{\usebeamerfont{institute}\textcolor{rougecrans}{\insertdate}};
\node
at ([yshift=-50pt]current page.center) (author)
{\usebeamerfont{author}\textcolor{rougecrans}{\insertauthor}};
\node [opacity=.15] at (current page.center) {\includegraphics[height=0.9\textheight]{crans-logo} };
\end{tikzpicture}
}
%
% --------------------------------------
% Sidebar
\useoutertheme[height=0pt,width=\swidth, hideothersubsections]{sidebar}
\setbeamertemplate{sidebar left}
{
{\vspace{0.9em}
\hspace{-0.4em}
\begin{minipage}{\swidth}
\centering
\insertlogo
\end{minipage}
\usebeamerfont{title in sidebar}%
\vskip1em%
\usebeamercolor[fg]{title in sidebar}%
\insertshorttitle[width=\swidth,center,respectlinebreaks]\par%
\vskip.5em%
}%
\insertverticalnavigation{\swidth}%
\vfill
\hbox to2cm{\hskip0.6cm\usebeamerfont{section in sidebar} \strut\usebeamercolor[fg]{section in sidebar}\insertframenumber/\inserttotalframenumber\hfill}%
\vskip3pt%
}%
% --------------------------------------------------------------------------
% Section as frame title
\if@section
\addtobeamertemplate{frametitle}{
\let\insertframetitle\insertsectionhead}{}
\addtobeamertemplate{frametitle}{
\let\insertframesubtitle\insertsubsectionhead}{}
\makeatletter
\CheckCommand*\beamer@checkframetitle{\@ifnextchar\bgroup\beamer@inlineframetitle{}}
\renewcommand*\beamer@checkframetitle{\global\let\beamer@frametitle\relax\@ifnextchar\bgroup\beamer@inlineframetitle{}}
\fi
\setbeamertemplate{caption}{\raggedright\insertcaption\par}
\setbeamertemplate{navigation symbols}[horizontal]
% ---------------------------------------------------
% BLOC
\setbeamertemplate{blocks}[rounded][shadow=false]
\setbeamercolor{block body}{fg=black,bg=rougecrans!20}
\setbeamercolor{block title}{fg=black,bg=rougecrans!40}
\setbeamercolor{block body example}{fg=black,bg=gray!40}
\setbeamercolor{block title example}{fg=black,bg=gray}
\setbeamercolor{block body alerted}{fg=black,bg=blue!40}
\setbeamercolor{block title alerted}{fg=black,bg=blue}
\setbeamercolor{subitem}{fg=rougecrans!20}
\makeatother
% LOGO :
\logo{\includegraphics[width=\swidth]{crans-logo.png}}

BIN
slides/crans-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

68
slides/seminaire-ci.tex Normal file
View File

@ -0,0 +1,68 @@
\documentclass[handout,aspectratio=169]{beamer}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}
\usepackage[francais]{babel}
\usepackage{graphicx}
\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}
\begin{frame}
\tableofcontents[subsubsectionstyle=hide]
\end{frame}
\section{Example}
\subsection{Block}
\begin{frame}
\begin{block}{Title block}
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
\end{block}
\begin{block}{}
No title Block \\
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}
\begin{alertblock}{Alert Block}
Alert Text
\end{alertblock}
\end{frame}
\subsection{Lists}
\begin{frame}
\begin{itemize}
\item Item 1
\item Item 2
\begin{itemize}
\item Subitem 1
\item Subitem 2
\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{document}