Louis-Philippe Véronneau - howtohttps://veronneau.org/2018-09-16T00:00:00-04:00GIMP 2.102018-09-16T00:00:00-04:002018-09-16T00:00:00-04:00Louis-Philippe Véronneautag:veronneau.org,2018-09-16:/gimp-210.html<p>GIMP 2.10 landed in Debian Testing a few weeks ago and I have to say I'm very
happy about it. The last major version of GIMP (2.8) was released in 2012 and
the new version fixes a lot of bugs and improved the user interface.</p>
<p>I've updated my …</p><p>GIMP 2.10 landed in Debian Testing a few weeks ago and I have to say I'm very
happy about it. The last major version of GIMP (2.8) was released in 2012 and
the new version fixes a lot of bugs and improved the user interface.</p>
<p>I've updated my <a href="https://libre.sogeecom.org/media/guides/intro_gimp.pdf">Beginner's Guide to GIMP</a> (sadly only in French) and in
the process I found out a few things I thought I would share:</p>
<p><img src="/media/blog/2018-09-16/gimp.svg" title="The new GIMP logo" alt="The new GIMP logo" height="30%" width="30%" style="float:right"></p>
<h2>Theme</h2>
<p>The default theme is Dark. Although it looks very nice in my opinion, I
don't feel it's a good choice for productivity. The icon pack the theme uses
is a monochrome flat 2D render and I feel it makes it hard to differentiate
the icons from one another.</p>
<p>I would instead recommend on using the Light theme with the Color icon pack.</p>
<h2>Single Window Mode</h2>
<p>GIMP now enables <em>Single Window Mode</em> by default. That means that Dockable
Dialog Windows like the Toolbar or the Layer Window cannot be moved around,
but instead are locked to two docks on the right and the left of the screen.</p>
<p>Although you can hide and show these docks using Tab, I feel <em>Single Window
Mode</em> is more suitable for larger screens. On my laptop, I still prefer
moving the windows around as I used to do in 2.8.</p>
<p>You can disable <em>Single Window Mode</em> in the Windows tab.</p>Introduction to Gitlab CI2018-09-05T00:00:00-04:002018-09-05T00:00:00-04:00Louis-Philippe Véronneautag:veronneau.org,2018-09-05:/introduction-to-gitlab-ci.html<p>I'm giving a Gitlab CI workshop on <a href="https://agendadulibre.qc.ca/events/1853">September 16th (in English)</a>
and on <a href="https://agendadulibre.qc.ca/events/1837">September 23rd (in French)</a> during our local
<a href="https://2018.sqil.info">Free Software Week</a> and I wrote a bunch of notes for the participants.</p>
<p>I thought I would publish them here so others can refer to it. Feedback is
welcome! I …</p><p>I'm giving a Gitlab CI workshop on <a href="https://agendadulibre.qc.ca/events/1853">September 16th (in English)</a>
and on <a href="https://agendadulibre.qc.ca/events/1837">September 23rd (in French)</a> during our local
<a href="https://2018.sqil.info">Free Software Week</a> and I wrote a bunch of notes for the participants.</p>
<p>I thought I would publish them here so others can refer to it. Feedback is
welcome! I also wrote a <a href="/introduction-a-gitlab-ci-fr.html">French version</a> of these notes.</p>
<h2>Why is continuous integration important?</h2>
<p>There are plenty of reasons to start doing continuous integration (CI). Here's a
few:</p>
<ol>
<li>
<p><strong>Testing your code.</strong> If you are not already testing the code you write,
starting to use a CI platform is good way to do so. Automated tests let you
find errors you would otherwise have missed. It also lets you know if the
code you wrote works.</p>
</li>
<li>
<p><strong>Testing your code in radically different environments.</strong> Having tests you
can run locally on your machine is better than nothing, but what tells you
your code will work outside of your dev environment? Using a CI platform lets
you easily test your code in environments you don't normally run.</p>
</li>
<li>
<p><strong>Automatically test your code.</strong> Using a CI that works with a git hosting
platform forces you to run your tests every time you push. If you are using
a merge/push request workflow, this means code in your <code>master</code> branch will
always have passed your tests.</p>
</li>
<li>
<p><strong>Automatically deploy your code.</strong> You can go a step further and decide to
use a CI platform to automatically publish code on archives like PyPi or NPM
if your code passes all your tests. This is known as continuous delivery (CD).</p>
</li>
</ol>
<h2>Introduction to Gitlab CI's functionalities</h2>
<h3>Outline</h3>
<p>To use Gitlab CI, you need to have a project on a Gitlab instance. When you push
a git commit to that repository, if a <code>.gitlab-ci.yml</code> file is present in your
repository, Gitlab will run a script to test your code in a runner, an external
machine used for tests.</p>
<p>Most of the Gitlab instances have shared runners everyone can use. Some people
prefer to setup private runners since the shared ones can be slow or have
restrictions on them.</p>
<p>For everyone's sake, if your tests take more than an hour to run or require a
lot of computational power, please run your own private runner.</p>
<h3>The .gitlab-ci.yml file</h3>
<p>To start using Gitlab CI, you first have to create a <code>.gitlab-ci.yml</code> file.</p>
<p>Here's a simple example of how that might look like:</p>
<pre>
---
image: debian:stable
test12345:
script:
- echo 'deb http://deb.debian.org/debian buster main contrib non-free' >> /etc/apt/sources.list
- apt-get update
- apt-get install -y -t buster rolldice
...
</pre>
<p>The first part of the file is the <code>image</code> parameter. This is the docker image
that will be used by default for your tests. This image is fetched from the
<a href="https://hub.docker.com/explore/">Docker Hub</a>. To use an image, you have to specify its full tag. Thus, the
stable version of Debian is <code>debian:stable</code>.</p>
<p>The second part of the file is the test we are running. It is possible to have
multiple tests one after another. The test in our example is called <code>test12345</code>
but we could have called it something else. <code>apt:rolldice</code> would also have been
valid.</p>
<p>Each test must have a <code>script</code>. This script is a collection of shell commands
ran by <code>bash</code>. The commands we want to run are listed one after another.</p>
<p>Here's an example with multiple tests:</p>
<pre>
---
image: debian:stable
apt:rolldice:stable:
script:
- apt-get install -y rolldice
apt:rolldice:buster:
script:
- echo 'deb http://deb.debian.org/debian buster main contrib non-free' >> /etc/apt/sources.list
- apt-get update
- apt-get install -y -t buster rolldice
...
</pre>
<p>It's also possible to change the default image in a test:</p>
<pre>
---
image: debian:stable
apt:rolldice:stable:
script:
- apt-get install -y rolldice
apt:rolldice:buster:
image: debian:buster
script:
- apt-get install -y rolldice
...
</pre>
<p>All the files in your git repository are accessible by your scripts as if you
were working directly in that directory:</p>
<p><code>> foobar.txt</code></p>
<pre>
Hello World
</pre>
<p><code>> .gitlab-ci.yml</code></p>
<pre>
---
image: debian:stable
test:hello:
script:
- cat foobar.txt
- cat foobar.txt | grep "Hello World"
...
</pre>
<h3>The service parameter</h3>
<p>For tests that are more complex, you sometime need an external service to run in
a separate docker container. The typical example is an application using a
database.</p>
<p>With Gitlab CI, you can run such a service for all your tests directly in the
CI. Those services are also Docker images. Here a simple example of a test using
a database service:</p>
<p><code>> mytest.sql</code></p>
<pre>
CREATE TABLE `table1` (randomvar VARCHAR(30) NOT NULL);
CREATE TABLE `table2` (randomvar VARCHAR(30) NOT NULL);
CREATE TABLE `table3` (randomvar VARCHAR(30) NOT NULL);
CREATE TABLE `table4` (randomvar VARCHAR(30) NOT NULL);
</pre>
<p><code>> .gitlab-ci.yml</code></p>
<pre>
---
image: debian:stable
services:
- mariadb:10.1
variables:
MYSQL_DATABASE: mytest
MYSQL_ALLOW_EMPTY_PASSWORD: 1
test:mariadb:
script:
- apt-get update && apt-get -y install mariadb-client-10.1
- mariadb -u root -h mariadb -D mytest < mytest.sql
- mariadb -u root -h mariadb -e "SELECT * FROM information_schema.columns WHERE table_schema = 'mytest'";
...
</pre>
<p>All Docker images can be used a service. If you have specific needs, you will
need to create your own Docker image.</p>
<h3>Artifacts</h3>
<p>If you want to use Gitlab CI to compile code or to create files that you want to
keep afterwards (compiling firmware is a great use case), you will need to use
the <code>artifact</code> parameter. Its function is to specify what file or directory will
be kept by Gitlab so you can download it afterwards.</p>
<p><code>> input.md</code></p>
<pre>
# Hello World
This is a markdown test. It should be rendered to HTML properly using the great
[pandoc](https://pandoc.org/MANUAL.html).
</pre>
<p><code>> .gitlab-ci.yml</code></p>
<pre>
---
image: debian:stable
build:html:
script:
- apt-get update && apt-get -y install pandoc
- pandoc -o output.html input.md
artifacts:
paths:
- output.html
...
</pre>
<h3>Multiples tests in stages</h3>
<p>By default, tests in Gitlab CI are all simultaneous. It's useful for unit tests,
but for more elaborate tests it is often useful to work step by step and create
dependencies between our tests.</p>
<p>The <code>stage</code> parameter can be used to group different tasks. These groups can
then be ordered.</p>
<p>We can also use the <code>dependencies</code> parameter to create dependencies between
tasks. The <code>artifacts</code> created in a task are automatically passed to the second
task if it depends on it.</p>
<p><code>> hello.c</code></p>
<pre>
#include <stdio.h>
int
main (void)
{
printf ("Hello, world!\n");
return 0;
}
</pre>
<p><code>> .gitlab-ci.yml</code></p>
<pre>
---
stages:
- build
- test
compile:debian:
image: debian:stable
stage: build
script:
- apt-get update && apt-get install -y build-essential
- gcc -Wall hello.c -o hello
artifacts:
paths:
- hello
compile:alpine:
image: alpine
stage: build
script:
- apk add --update build-base
- gcc -Wall hello.c -o hello
artifacts:
paths:
- hello
test:debian:
image: debian:stable
stage: test
dependencies:
- compile:debian
script:
- ./hello
test:alpine:
image: alpine
stage: test
dependencies:
- compile:alpine
script:
- ./hello
...
</pre>
<h3>Secret variables</h3>
<p>If you want to use Gitlab CI to publish your projects on platforms like PyPi or
NPM, you will need to stock authentication information somewhere.</p>
<p>You should obviously not add your passwords directly in the <code>.gitlab-ci.yml</code>
file or in your git repository: anyone could stumble upon it and compromise your
accounts.</p>
<p>Gitlab lets you stock secret variables. To add some, you have to go in the
<em>Settings > CI/CD > Variables</em> tab.</p>
<p>Once you have added a secret variable, you can refer to it in your
<code>.gitlab-ci.yml</code> file just like a normal variable.</p>
<pre>
---
image: debian:stable
test:secret-var:
:script:
- apt-get update && apt-get -y install wget
- wget https://agendadulibre.qc.ca/events/$SECRET
...
</pre>
<h3>Compile and host a static website with Gitlab CI and Gitlab Pages</h3>
<p>An interesting use case for Gitlab CI is compiling a static website. Once
compiled, this website can then be hosted directly on the Gitlab instance using
<a href="https://docs.gitlab.com/ee/user/project/pages/">Gitlab Pages</a>. This can be very useful to host a project's
documentation.</p>
<p><a href="https://salsa.debian.org/debconf-video-team/docs">Here's an example</a> using Gitlab CI and Gitlab Pages. This
project uses <a href="http://www.sphinx-doc.org/en/stable/">Sphinx</a> with the <em>Read the Docs</em> theme. The compiled website can
be seen <a href="https://debconf-video-team.pages.debian.net/docs">here</a>.</p>
<p>Once you've added a <code>.gitlab-ci.yml</code> that compiles your static website, you need
to go in the <em>Settings > Pages</em> tab in your git project to put your website
online. Gitlab also gives the option of using an external domain if you wish to.</p>
<h3>More info</h3>
<p>The complete documentation for the <code>.gitlab-ci.yml</code> can be <a href="https://docs.gitlab.com/ce/ci/yaml/README.html">found online here</a>.</p>
<h2>Collaborative workshop</h2>
<p><em>Find a project that you like and then try to create a few tests with Gitlab CI</em>.</p>
<h2>Installing Gitlab CI + Docker on a private machine (advanced)</h2>
<p><em>We want to use Docker and Gitlab CI on a Debian Stretch server. These steps
require a basic knowledge of the command line</em>.</p>
<h3>Docker</h3>
<p>The Docker executor is the most simple and flexible one. It's also the one that
the shared runners on gitlab.com use.</p>
<p>We thus start by installing Docker on our machine. Normally, you would install
Docker directly from the Debian repository. Sadly, Docker is not packaged in
Debian Stretch so we need to install it from Docker's own repository.</p>
<p>We start by adding a source file to apt:</p>
<p><code>> /etc/apt/sources.list.d/docker.sources</code></p>
<pre>
Types: deb
URIs: https://download.docker.com/linux/debian/
Suites: stretch
Architectures: amd64
Components: main
Signed-By: /usr/share/keyrings/docker-archive-keyring.gpg
</pre>
<p>We then complete the installation process by downloading Docker's GPG key and by
installing packages<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup>:</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">apt</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">apt</span><span class="o">-</span><span class="n">transport</span><span class="o">-</span><span class="n">https</span>
<span class="o">$</span><span class="w"> </span><span class="n">curl</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">download</span><span class="o">.</span><span class="n">docker</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">linux</span><span class="o">/</span><span class="n">debian</span><span class="o">/</span><span class="n">gpg</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">gpg</span><span class="w"> </span><span class="o">--</span><span class="n">dearmor</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">keyrings</span><span class="o">/</span><span class="n">docker</span><span class="o">-</span><span class="n">archive</span><span class="o">-</span><span class="n">keyring</span><span class="o">.</span><span class="n">gpg</span>
<span class="o">$</span><span class="w"> </span><span class="n">apt</span><span class="w"> </span><span class="n">update</span>
<span class="o">$</span><span class="w"> </span><span class="n">apt</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">docker</span><span class="o">-</span><span class="n">ce</span>
</code></pre></div>
<p>Docker has a <a href="https://github.com/moby/moby/issues/23270">bad bug</a> and the networking doesn't work when you
reboot the machine running it. This means our CI doesn't have networking and all
the tests people run on it fail.</p>
<p>To hotfix this, we create a <code>cron</code> file that reboots Docker 30 seconds after our
machine has booted:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s1">'@reboot root /bin/sleep 30 && /bin/systemctl restart docker'</span><span class="w"> </span>><span class="w"> </span>/etc/cron.d/docker-reboot
</code></pre></div>
<p>We also want to make sure our server doesn't fill up with the docker images
people are running for their tests. We thus add a second <code>cron</code> file to purge
Docker periodically:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s1">'0 3 * * * root /usr/bin/docker system prune -a -f > /dev/null 2>&1'</span><span class="w"> </span>><span class="w"> </span>/etc/cron.d/docker-prune
</code></pre></div>
<p>Et voilà! Docker is ready to be used in Gitlab CI!</p>
<h3>Gitlab CI</h3>
<p>Once again, instead of using the Debian repository to install Gitlab CI, we have
to use Gitlab's repository. Gitlab is still pretty young in Debian and the
runner has not been packaged for Debian Stretch yet.</p>
<p>We start by adding a source file to apt:</p>
<p><code>> /etc/apt/sources.list.d/gitlab.sources</code></p>
<pre>
Types: deb
URIs: https://packages.gitlab.com/runner/gitlab-runner/debian/
Suites: stretch
Architectures: amd64
Components: main
Signed-By: /usr/share/keyrings/gitlab-archive-keyring.gpg
</pre>
<p>We then complete the installation process by downloading Gitlab's GPG key and by
installing packages:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>curl<span class="w"> </span>https://packages.gitlab.com/gpg.key<span class="w"> </span><span class="p">|</span><span class="w"> </span>gpg<span class="w"> </span>--dearmor<span class="w"> </span>><span class="w"> </span>/usr/share/keyrings/gitlab-archive-keyring.gpg
$<span class="w"> </span>apt<span class="w"> </span>update
$<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>gitlab-runner
</code></pre></div>
<p>Once <code>gitlab-runner</code> has been installed, we can use the command line helper to
create a new runner:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>gitlab-runner<span class="w"> </span>register
Please<span class="w"> </span>enter<span class="w"> </span>the<span class="w"> </span>gitlab-ci<span class="w"> </span>coordinator<span class="w"> </span>URL<span class="w"> </span><span class="o">(</span>e.g.<span class="w"> </span>https://gitlab.com/<span class="o">)</span>:
><span class="w"> </span>https://gitlab-instance-url
Please<span class="w"> </span>enter<span class="w"> </span>the<span class="w"> </span>gitlab-ci<span class="w"> </span>token<span class="w"> </span><span class="k">for</span><span class="w"> </span>this<span class="w"> </span>runner:
><span class="w"> </span>your-project-token
Please<span class="w"> </span>enter<span class="w"> </span>the<span class="w"> </span>gitlab-ci<span class="w"> </span>description<span class="w"> </span><span class="k">for</span><span class="w"> </span>this<span class="w"> </span>runner:
><span class="w"> </span>Your<span class="w"> </span>runner<span class="err">'</span>s<span class="w"> </span>description
Please<span class="w"> </span>enter<span class="w"> </span>the<span class="w"> </span>gitlab-ci<span class="w"> </span>tags<span class="w"> </span><span class="k">for</span><span class="w"> </span>this<span class="w"> </span>runner<span class="w"> </span><span class="o">(</span>comma<span class="w"> </span>separated<span class="o">)</span>:
><span class="w"> </span>name-of-the-runner,<span class="w"> </span>docker
</code></pre></div>
<p>To get the token to create the runner, you need to go in the
<em>Settings > CI/CD > Runners</em> tab in your git project. The token can be found
in the <em>Setup a specific Runner manually</em> section.</p>
<p>If everything works correctly, your runner should show up in the
<em>Settings > CI/CD > Runners</em> tab.</p>
<h3>Pro Tip</h3>
<p>If you are using your own Gitlab CI in a production environment, it is important
to make sure it works at all times.</p>
<p>To make sure the runner works fine, you can create a git project on the Gitlab
instance you are using. This project only has to contain a basic
<code>.gitlab-ci.yml</code> file.</p>
<p>You can then run this test each day or each hour by creating a scheduled task in
the <em>CI/CD > Schedules</em> tab of your project.</p>
<pre>
---
image: debian
test-ci:
script:
- apt-get update && apt-get -y install rolldice
tags:
- name-of-your-runner
...
</pre>
<p>It's important to specify the name of the runner in the <code>tags</code> section to force
your test to run on your runner and not on a random one.</p>
<div class="footnote">
<hr>
<ol>
<li id="fn:1">
<p>This method is more secure than using <code>apt-key add</code> since this method only
authorises the external GPG key for the source we are adding and not for
all other sources. More details on this method can be
<a href="https://wiki.debian.org/DebianRepository/UseThirdParty">found here</a>. <a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
</ol>
</div>Introduction à Gitlab CI2018-08-31T00:00:00-04:002018-08-31T00:00:00-04:00Louis-Philippe Véronneautag:veronneau.org,2018-08-31:/introduction-a-gitlab-ci-fr.html<p>Voici les notes de <a href="https://agendadulibre.qc.ca/events/1837">l'atelier d'introduction à Gitlab CI</a> que je donne
le 23 septembre dans le cadre de la
<a href="https://2018.sqil.info">Semaine québécoise de l'informatique libres</a>.</p>
<h2>Pourquoi faire de l'intégration continue?</h2>
<p>Il y a plusieurs bonnes raisons pour commencer à faire de l'intégration continue
(CI). En voici quelques unes:</p>
<ol>
<li>
<p><strong>Tester son …</strong></p></li></ol><p>Voici les notes de <a href="https://agendadulibre.qc.ca/events/1837">l'atelier d'introduction à Gitlab CI</a> que je donne
le 23 septembre dans le cadre de la
<a href="https://2018.sqil.info">Semaine québécoise de l'informatique libres</a>.</p>
<h2>Pourquoi faire de l'intégration continue?</h2>
<p>Il y a plusieurs bonnes raisons pour commencer à faire de l'intégration continue
(CI). En voici quelques unes:</p>
<ol>
<li>
<p><strong>Tester son code.</strong> Souvent, l'intégration continue est une bonne manière de
commencer à tester son code. Les tests automatisés permettent de trouver des
erreurs d'inattention et forcent à vérifier si le code que l'on écrit
fonctionne réellement.</p>
</li>
<li>
<p><strong>Tester son code sur des environnements radicalement différents.</strong> Avoir des
tests que l'on peut faire rouler localement sur sa machine est une bonne
chose, mais utiliser un CI permet de tester son code sur des environnements
sur lesquels on ne travaille pas.</p>
</li>
<li>
<p><strong>Tester son code automatiquement.</strong> Utiliser un CI lié à une plateforme
d'hébergement git permet de s'assurer que les nouveaux <em>commits</em> réussissent
les tests avant d'être ajoutés à la branche <code>master</code>.</p>
</li>
<li>
<p><strong>Déployer son code automatiquement.</strong> Il est possible d'aller une étape plus
loin et d'utiliser le CI pour publier du code sur une archive comme PyPi ou
NPM automatiquement si tous les tests passent. On parle alors de déploiement
continu (CD).</p>
</li>
</ol>
<h2>Introductions aux fonctionnalités de Gitlab CI</h2>
<h3>Aperçu</h3>
<p>Pour utiliser Gitlab CI, il faut tout d'abord avoir un projet sur une instance
Gitlab. Quand on ajoute un <em>commit</em> git au dépôt, si un fichier <code>.gitlab-ci.yml</code>
est présent dans le dépôt, Gitlab suit ces instructions et roule un script dans
le runner, une machine externe qui sert à faire des tests.</p>
<p>Sur la plupart des instances Gitlab, il existe des runners partagés que tout le
monde peut utiliser. Il est également possible de monter un runner privé pour
son propre projet. Cela peut être intéressant si on a des tests qui demandent
beaucoup de ressources.</p>
<h3>Le fichier .gitlab-ci.yml</h3>
<p>Pour commencer à utiliser Gitlab CI, il faut tout d'abord créer un fichier
<code>.gitlab-ci.yml</code>. </p>
<p>Voici un exemple très simple de fichier:</p>
<pre>
---
image: debian:stable
test12345:
script:
- echo 'deb http://deb.debian.org/debian buster main contrib non-free' >> /etc/apt/sources.list
- apt-get update
- apt-get install -y -t buster rolldice
...
</pre>
<p>La première partie du fichier est le paramètre <code>image</code>. C'est l'image docker
qui va être utilisée par défaut dans les tests que l'on effectue. Cette image
est récupérée du <a href="https://hub.docker.com/explore/">Docker Hub</a>. Pour utiliser une image, on spécifie le tag
complet de l'image. Ainsi, l'image pour la version stable de Debian est
<code>debian:stable</code>.</p>
<p>La seconde partie du fichier est le test que l'on roule. Il est possible d'avoir
plusieurs tests l'un à la suite de l'autre. Le test dans notre exemple est
nommé <code>test12345</code>, mais il aurait été possible de le nommer d'une autre manière.
<code>apt:rolldice</code> aurait également été un nom valide.</p>
<p>Chaque test doit comporter un script. Ce script est un ensemble de commandes
shell de type <code>bash</code>. L'ensemble des commandes que l'on souhaite effectuer s'y
retrouvent étapes par étapes.</p>
<p>Il est possible d'avoir plusieurs tests l'un à la suite de l'autre:</p>
<pre>
---
image: debian:stable
apt:rolldice:stable:
script:
- apt-get install -y rolldice
apt:rolldice:buster:
script:
- echo 'deb http://deb.debian.org/debian buster main contrib non-free' >> /etc/apt/sources.list
- apt-get update
- apt-get install -y -t buster rolldice
...
</pre>
<p>Il est également possible de changer l'image par défaut utilisée dans un test:</p>
<pre>
---
image: debian:stable
apt:rolldice:stable:
script:
- apt-get install -y rolldice
apt:rolldice:buster:
image: debian:buster
script:
- apt-get install -y rolldice
...
</pre>
<p>Les fichiers présents dans votre dépôt git sont accessibles par vos scripts
comme si vous travailliez directement dans ce dossier:</p>
<p><code>> foobar.txt</code></p>
<pre>
Hello World
</pre>
<p><code>> .gitlab-ci.yml</code></p>
<pre>
---
image: debian:stable
test:hello:
script:
- cat foobar.txt
- cat foobar.txt | grep "Hello World"
...
</pre>
<h3>Le paramètre service</h3>
<p>Pour certains tests plus complexes, il est parfois nécessaire d'avoir un service
externe différent de notre image docker principale, par exemple une base de
données.</p>
<p>Gitlab CI permet de rouler un service externe accessible par nos tests. Ces
services sont également des images Docker. Par voici un exemple simple
d'utilisation d'une base de données:</p>
<p><code>> mytest.sql</code></p>
<pre>
CREATE TABLE `table1` (randomvar VARCHAR(30) NOT NULL);
CREATE TABLE `table2` (randomvar VARCHAR(30) NOT NULL);
CREATE TABLE `table3` (randomvar VARCHAR(30) NOT NULL);
CREATE TABLE `table4` (randomvar VARCHAR(30) NOT NULL);
</pre>
<p><code>> .gitlab-ci.yml</code></p>
<pre>
---
image: debian:stable
services:
- mariadb:10.1
variables:
MYSQL_DATABASE: mytest
MYSQL_ALLOW_EMPTY_PASSWORD: 1
test:mariadb:
script:
- apt-get update && apt-get -y install mariadb-client-10.1
- mariadb -u root -h mariadb -D mytest < mytest.sql
- mariadb -u root -h mariadb -e "SELECT * FROM information_schema.columns WHERE table_schema = 'mytest'";
...
</pre>
<p>N'importe quelle image Docker peut être utilisée comme service. Si vous avez des
besoins particuliers, il est nécessaire de créer une image Docker par vous même.</p>
<h3>Artifacts</h3>
<p>Si vous souhaitez utiliser Gitlab CI pour compiler du code ou créer des fichiers
que vous souhaitez conserver par la suite, il est nécessaire d'utiliser le
paramètre <code>artifacts</code>. Sa fonction est de spécifier un fichier ou un dossier qui
va être enregistré par Gitlab et que vous allez pouvoir récupérer par la suite.</p>
<p><code>> input.md</code></p>
<pre>
# Hello World
This is a markdown test. It should be rendered to HTML properly using the great
[pandoc](https://pandoc.org/MANUAL.html).
</pre>
<p><code>> .gitlab-ci.yml</code></p>
<pre>
---
image: debian:stable
build:html:
script:
- apt-get update && apt-get -y install pandoc
- pandoc -o output.html input.md
artifacts:
paths:
- output.html
...
</pre>
<h3>Tests à plusieurs étapes</h3>
<p>Par défaut, les tests dans Gitlab CI fonctionnent tous simultanément. Cela est
pratique pour des tests de type <em>unit test</em>. Pour des tests plus élaborés, on
peut parfois vouloir fonctionner par étapes et créer des dépendances entre nos
tests.</p>
<p>Le paramètre <code>stage</code> permet de spécifier des groupes dans lesquels on peut
placer nos différentes tâches. Ces groupes peuvent par la suite être ordonnés,
pour que les tests roulent dans un ordre précis.</p>
<p>On peut également utiliser le paramètre <code>dependencies</code> pour créer un lien de
dépendance entre différentes tâches. Les <code>artifacts</code> créés dans une tâches sont
automatiquement passés à une seconde tâche si elle en dépend.</p>
<p><code>> hello.c</code></p>
<pre>
#include <stdio.h>
int
main (void)
{
printf ("Hello, world!\n");
return 0;
}
</pre>
<p><code>> .gitlab-ci.yml</code></p>
<pre>
---
stages:
- build
- test
compile:debian:
image: debian:stable
stage: build
script:
- apt-get update && apt install -y build-essential
- gcc -Wall hello.c -o hello
artifacts:
paths:
- hello
compile:alpine:
image: alpine
stage: build
script:
- apk add --update build-base
- gcc -Wall hello.c -o hello
artifacts:
paths:
- hello
test:debian:
image: debian:stable
stage: test
dependencies:
- compile:debian
script:
- ./hello
test:alpine:
image: alpine
stage: test
dependencies:
- compile:alpine
script:
- ./hello
...
</pre>
<h3>Variables secrètes</h3>
<p>Si vous souhaitez utiliser Gitlab pour publier votre projet sur une plateforme
comme PyPi ou NPM, il est nécessaire de stocker vos informations
d'authentification quelque part.</p>
<p>Il n'est bien évidemment pas recommandé d'ajouter vos mots de passes directement
dans votre fichier <code>.gitlab-ci.yml</code> ou dans un autre fichier dans votre dépôt
git pour des raisons de sécurité: n'importe qui pourrait lire ces fichiers et
compromettre vos comptes.</p>
<p>Gitlab permet de stocker des variables secrètes. Pour ce faire, il faut aller
dans l'onglet <em>Settings > CI/CD > Variables</em> de votre projet.</p>
<p>Une fois que vous avez créé une variable secrète, il est possible d'y référer
comme une variable normale dans votre fichier <code>.gitlab-ci.yml</code>.</p>
<pre>
---
image: debian:stable
test:secret-var:
script:
- apt-get update && apt-get -y install wget
- wget https://agendadulibre.qc.ca/events/$SECRET
...
</pre>
<h3>Compiler et héberger un site web statique à l'aide de Gitlab CI et Gitlab Pages</h3>
<p>Un cas de figure intéressant pour Gitlab CI est la compilation d'un site web
statique. Une fois compilé, ce site web peut par la suite être hébergé
directement sur Gitlab grâce au projet <a href="https://docs.gitlab.com/ee/user/project/pages/">Gitlab Pages</a>. Cela peut être
utile pour héberger la documentation d'un projet.</p>
<p><a href="https://salsa.debian.org/debconf-video-team/docs">Voici un exemple</a> de projet utilisant Gitlab CI et Gitlab
Pages. Ce projet utilise <a href="http://www.sphinx-doc.org/en/stable/">Sphinx</a> avec le thème <em>Read the Docs</em>. Le site web
compilé est disponible en ligne <a href="https://debconf-video-team.pages.debian.net/docs">ici</a>.</p>
<p>Une fois que l'on a ajouté un fichier <code>.gitlab-ci.yml</code> qui compile notre site
statique, il faut aller dans l'onglet <em>Settings > Pages</em> de notre projet git
pour mettre en ligne notre projet. Gitlab offre également la possibilité
d'utiliser un domaine externe.</p>
<h3>Plus d'informations</h3>
<p>La documentation complète du fichier <code>.gitlab-ci.yml</code> est <a href="https://docs.gitlab.com/ce/ci/yaml/README.html">disponible en ligne</a>.</p>
<h2>Atelier collaboratif d'utilisation de Gitlab CI</h2>
<p><em>Trouvez un projet qui vous intéresse et tentez de créer une série de tests ầ
l'aide de Gitlab CI</em>.</p>
<h2>Instructions pour installer Gitlab CI + Docker sur une machine privée (avancé)</h2>
<p><em>On souhaite installer Docker et Gitlab CI sur un serveur Debian Stretch. Ces
étapes nécessitent une certaine connaissance de la ligne de commande.</em></p>
<h3>Docker</h3>
<p>L'executor Docker est le plus simple et le plus flexible. C'est également celui
qui est mis en place sur gitlab.com.</p>
<p>On commence donc par installer Docker sur notre machine. En temps normal, on
installerait Docker à partir du dépôt officiel Debian. Malheureusement, Docker
n'est pas packagé dans Debian alors il est nécessaire de l'installer à partir du
dépôt offert par Docker.</p>
<p>On commence par ajouter un fichier source à apt:</p>
<p><code>> /etc/apt/sources.list.d/docker.sources</code></p>
<pre>
Types: deb
URIs: https://download.docker.com/linux/debian/
Suites: stretch
Architectures: amd64
Components: main
Signed-By: /usr/share/keyrings/docker-archive-keyring.gpg
</pre>
<p>On complète l'installation en téléchargeant la clef GPG et en installant les
packets<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup>:</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">apt</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">apt</span><span class="o">-</span><span class="n">transport</span><span class="o">-</span><span class="n">https</span>
<span class="o">$</span><span class="w"> </span><span class="n">curl</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">download</span><span class="o">.</span><span class="n">docker</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">linux</span><span class="o">/</span><span class="n">debian</span><span class="o">/</span><span class="n">gpg</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">gpg</span><span class="w"> </span><span class="o">--</span><span class="n">dearmor</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">share</span><span class="o">/</span><span class="n">keyrings</span><span class="o">/</span><span class="n">docker</span><span class="o">-</span><span class="n">archive</span><span class="o">-</span><span class="n">keyring</span><span class="o">.</span><span class="n">gpg</span>
<span class="o">$</span><span class="w"> </span><span class="n">apt</span><span class="w"> </span><span class="n">update</span>
<span class="o">$</span><span class="w"> </span><span class="n">apt</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">docker</span><span class="o">-</span><span class="n">ce</span>
</code></pre></div>
<p>Docker a la fâcheuse habitude de démarrer avant que l'interface réseau ne soit
en ligne. Cela fait en sorte que quand notre machine redémarre, notre CI n'a
plus accès à internet, ce qui fait avorter nos tests.</p>
<p>Pour remédier à ce problème, on créé un fichier <code>cron</code> qui redémarre Docker 30
secondes après que notre machine ait démarrée:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s1">'@reboot root /bin/sleep 30 && /bin/systemctl restart docker'</span><span class="w"> </span>><span class="w"> </span>/etc/cron.d/docker-reboot
</code></pre></div>
<p>On souhaite également éviter que notre serveur se remplisse des instances de
test que l'on fait rouler. On ajoute donc un autre fichier <code>cron</code> pour purger
Docker périodiquement:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s1">'0 3 * * * root /usr/bin/docker system prune -a -f > /dev/null 2>&1'</span><span class="w"> </span>><span class="w"> </span>/etc/cron.d/docker-prune
</code></pre></div>
<p>Et voilà! Docker est prêt à être utilisé dans notre installation future de
Gitlab CI!</p>
<h3>Gitlab CI</h3>
<p>Encore une fois, plutôt que d'utiliser le dépôt Gitlab offert par Debian pour
installer Gitlab CI, on choisi plutôt le dépôt offert par Gitlab.</p>
<p>Gitlab est encore très jeune dans Debian et il y de nombreuses mises à jour de
sécurité. Peut-être dans le futur les paquets Debian vont être plus fiables,
mais ce n'est pas le cas pour l'instant.</p>
<p>On commence par ajouter un fichier source à apt:</p>
<p><code>> /etc/apt/sources.list.d/gitlab.sources</code></p>
<pre>
Types: deb
URIs: https://packages.gitlab.com/runner/gitlab-runner/debian/
Suites: stretch
Architectures: amd64
Components: main
Signed-By: /usr/share/keyrings/gitlab-archive-keyring.gpg
</pre>
<p>On complète l'installation en téléchargeant la clef GPG et en installant les
packets:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>curl<span class="w"> </span>https://packages.gitlab.com/gpg.key<span class="w"> </span><span class="p">|</span><span class="w"> </span>gpg<span class="w"> </span>--dearmor<span class="w"> </span>><span class="w"> </span>/usr/share/keyrings/gitlab-archive-keyring.gpg
$<span class="w"> </span>apt<span class="w"> </span>update
$<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>gitlab-runner
</code></pre></div>
<p>Une fois <code>gitlab-runner</code> installé, on peut utiliser l'outil en ligne de commande
pour créer un nouveau runner:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>sudo<span class="w"> </span>gitlab-runner<span class="w"> </span>register
Please<span class="w"> </span>enter<span class="w"> </span>the<span class="w"> </span>gitlab-ci<span class="w"> </span>coordinator<span class="w"> </span>URL<span class="w"> </span><span class="o">(</span>e.g.<span class="w"> </span>https://gitlab.com/<span class="o">)</span>:
><span class="w"> </span>https://url-de-l-instance-gitlab
Please<span class="w"> </span>enter<span class="w"> </span>the<span class="w"> </span>gitlab-ci<span class="w"> </span>token<span class="w"> </span><span class="k">for</span><span class="w"> </span>this<span class="w"> </span>runner:
><span class="w"> </span>le-token-de-votre-projet<span class="w"> </span>
Please<span class="w"> </span>enter<span class="w"> </span>the<span class="w"> </span>gitlab-ci<span class="w"> </span>description<span class="w"> </span><span class="k">for</span><span class="w"> </span>this<span class="w"> </span>runner:
><span class="w"> </span>La<span class="w"> </span>description<span class="w"> </span>du<span class="w"> </span>runner
Please<span class="w"> </span>enter<span class="w"> </span>the<span class="w"> </span>gitlab-ci<span class="w"> </span>tags<span class="w"> </span><span class="k">for</span><span class="w"> </span>this<span class="w"> </span>runner<span class="w"> </span><span class="o">(</span>comma<span class="w"> </span>separated<span class="o">)</span>:
><span class="w"> </span>nom-du-runner-gitlab-ci,<span class="w"> </span>docker
</code></pre></div>
<p>Pour obtenir le token nécessaire à la création du runner, il faut aller dans
l'onglet <em>Settings > CI/CD > Runners</em> dans votre projet git. Le token est
spécifié dans la section <em>Setup a specific Runner manually</em>.</p>
<p>Et voilà! Si tout fonctionne correctement, le runner devrait s'afficher dans la
l'onglet <em>Settings > CI/CD > Runners</em> de votre projet.</p>
<h3>Pro Tip</h3>
<p>Si vous utilisez votre propre runner Gitlab CI dans un environnement en
production, il est important de s'assurer que ce dernier fonctionne pour
s'éviter de fâcheux ennuis.</p>
<p>Pour s'assurer que notre runner est fonctionnel, on peut créer un projet git
dont le seul but est de s'assurer que le CI fonctionne. Ce dernier n'a qu'à
contenir un fichier <code>.gitlab-ci.yml</code> de base.</p>
<p>Par la suite, vous pouvez faire rouler le test à tous les jours ou à toutes les
heures en créant un nouvel item dans dans l'onglet <em>CI/CD > Schedules</em> de
votre projet.</p>
<p>Voici un exemple de fichier <code>gitlab-ci.yml</code> que l'on peut utiliser:</p>
<pre>
---
image: debian
test-ci:
script:
- apt-get update && apt-get -y install rolldice
tags:
- nom-du-runner-gitlab-ci
...
</pre>
<p>Il est bien important de spécifier le nom du runner sur lequel vous souhaitez
que le test roule dans la section <code>tags</code> pour éviter de faire le test sur une
autre machine que la vôtre.</p>
<div class="footnote">
<hr>
<ol>
<li id="fn:1">
<p>Cette méthode est bien plus sécuritaire qu'utiliser <code>apt-key add</code> car elle
elle autorise la clef GPG externe seulement pour la source que l'on
souhaite ajouter et non pour toutes les autres sources. Plus de détails
sur cette méthode <a href="https://wiki.debian.org/DebianRepository/UseThirdParty">ici</a>. <a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
</ol>
</div>