Génération de mon CV LaTeX en PDF depuis Github Actions
dernière mise à jour : 06/04/2023
Suite à un récent besoin de refaire mon CV, j'ai commencé à chercher mes anciens CV. Or, j'ai changé de machines entre temps; ça s'apparente donc à une fouille minutieuse (recherche dans mes boites mail, dans les fichiers sur machines 1, fichiers sur machines 2, ...) et j'ai l'impression de réinventer la roue à chaque fois.
LaTeX
Mon CV est en LaTeX.
Dans le passé, j'ai pu les faire en word, ou avec libreoffice, mais le côté texte de LaTeX en compagnie de la puissance du langage m'ont définitivement fait adopter LaTeX, au moins pour ce besoin. Le texte formatté permet un vrai versionnement sous git ou un autre gestionnaire de version.
Je sais que pour certains, quand on fait un CV, il s'agit de réussir à se vendre, mais les CV en powerpoint, très peu pour moi, je ne fais pas du marketing (non je ne ferai pas de commentaire sur les auto-évaluations avec des étoiles ou des points)...
Vous pouvez avoir une idée de comment faire avec cet article de blog.
Les mauvaises langues diront qu'on peut faire tout aussi bien avec pandoc + markdown, et ils n'ont pas vraiment tort.
Néanmoins, je me suis mis à LaTeX bien avant que markdown soit à la mode et que pandoc permette cette conversion. De plus, les académiques ne jurent que par LaTeX et ce n'est pas un hasard. Donald Knuth, inventeur de TeX
dont LaTeX
est issu, y est presque un demi-dieu de l'informatique.
Une des forces du LaTeX est le découpage entre le contenu et l'affichage; avec le package moderncv
, je peux ainsi facilement générer un autre template qui donnera un rendu totalement différent. De manière identique, pour des présentations, on utilisera beamer
permettant la même chose (1).
L'environnement LaTeX à mettre en place, en revanche, peut être vite pénible, surtout si on fait appel à beaucoup de packages... Certes, il existe des outils qui permettent de faciliter ça, mais c'est coûteux en temps, dans tous les cas. Vous en avez souvent vite pour plusieurs Go de téléchargement.
De mon côté, j'utilise moderncv
, enumitem
, csquotes
, geometry
, babel
, hyperref
, anyfontsize
, inputenc
, fontawesome
...
Bien entendu, vous pouvez utiliser OverLeaf, mais pour un CV, j'aime bien avoir les choses en local. Overleaf a cependant un dépôt git, et rien ne vous empêche d'avoir à la fois le CV en local et sur Overleaf.
Le titre faisant mention de Github Actions
, vous comprendrez que j'ai préféré cette option. Ca m'a permis de tester cette CI et de retrouver facilement ce dépôt. J'ai mis en place un dépôt Github privé(2), pour ne pas l'ouvrir au monde entier (même si ça reste Microsoft...), synchroniser mes machines, retrouver plus facilement mon CV et versionner celui-ci. Un besoin finalement assez classique, surtout pour du code, car oui, LaTeX est un langage de programmation.
Pourquoi une CI ? J'ai besoin d'intégration continue : vous l'avez compris, l'environnement LaTeX est lourd, j'ai donc besoin d'une manière de générer le PDF sans avoir besoin de tout avoir en local. Le conteneur avec tous les packages est donc une solution toute désignée.
Github Actions
Je me suis donc mis en quête de l'exploration de Github Actions, moi, l'habitué de Gitlab-CI.
Le workflow doit pouvoir générer le PDF puis pousser ces fichiers soit vers le dépôt, soit en release.
Je découvre qu'il existe déjà de nombreux workflows, même si très peu sont proposés à l'initialisation du workflow par Github (un soucis de sponsoring ?).
Côté syntaxe, il s'agit de fichiers en yaml (oui, encore), à placer dans .github/workflows
dans votre dépôt.
NB : Au 1er pas, on a la nette impression que Github actions est moins puissant que Gitlab-CI, mais je n'ai pas assez creusé les 2 pour pouvoir faire une vraie comparaison digne de ce nom (mais ce n'est peut-être pas un hasard s'il y a autant de travis-ci sur github, même si travis-ci était là avant...) Voir aussi.
Premier essai
Parmi les worflows existants, Oh miracle (!), je trouve un github actions avec pdflatex
! pdflatex
est un binaire permettant de générer du pdf depuis un fichier .tex
. L'image utilisée dans le workflow comprend aussi lualatex
ou xelatex
permettant aussi de générer du PDF à partir de fichiers .tex
.
Le workflow se nomme "latex-actions". La documentation propose même des exemples pour pousser ensuite les PDF vers le dépôt. Je l'adapte (je rapelle, je débute avec Github Actions), je le teste, et au bout de peu de temps, incroyable (!), je commence à avoir quelque chose qui semble fonctionner. Je dis "semble" car je me rends vite compte qu'il y a un problème...
# This is a basic workflow to help you get started with Actions
name: LaTeX Build CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Set up Git repository
uses: actions/checkout@v3
- name: LaTeX Build
uses: xu-cheng/latex-action@v2
with:
root_file: "*.tex"
glob_root_file: true
- name: Upload Full En PDF file
uses: actions/upload-artifact@v3
with:
name: PDF
path: full_ac_resume_en.pdf
- name: Upload Std En PDF file
uses: actions/upload-artifact@v3
with:
name: PDF
path: std_resume_en.pdf
- name: Upload Std Fr PDF file
uses: actions/upload-artifact@v3
with:
name: PDF
path: std_cv_fr.pdf
Ce workflow est facile à décomposer. On définit sur quelles actions il se déclenche, ici sur un pull request ou un push, puis un ou plusieurs jobs, découpés en étapes, steps
.
On définit sur quelle image le job va tourner, à savoir ubuntu-latest
. Le choix offert par Github Actions est assez limité à ce niveau; je vous invite à consulter les choix possibles ici.
Puis les étapes sont les suivantes :
- un checkout du dépôt,
- l'utilisation du workflow
latex-actions
avec (uses: xu-cheng/latex-action@v2
), et sur quoi on l'applique, - la génération de fichiers PDF qu'on pousse vers notre dépôt (ici, en 3 étapes distinctes).
Lors de l'exécution de ce workflow, mon CV version fr est correctement généré, mais pas la version dans la langue de Shakespeare. Un comble ! Habituellement, c'est l'inverse à cause de la gestion des caractères français.
Le package qui pose problème est fontawesome
.
full_ac_resume_en.tex:16: Package fontawesome5 Error: Incompatible version of Font Awesome already
(fontawesome5) loaded
Visiblement, le conteneur utilisé par ce workflow est sous Alpine Linux et il y a un soucis de compatibilité de version pour ce package...
J'ai essayé un peu de bidouiller l'image afin de rajouter les fichiers manquants, mais j'ai abandonné rapidement : Je comprends évidemment l'idée d'avoir une image la plus petite possible pour un conteneur, d'où l'utilisation de Alpine Linux. Néanmoins, l'image fait déjà plusieurs Go, la faute à l'environnement complet LaTeX. Bref, autant avoir une distribution chez qui ça fonctionne directement (c'est mon cas en local avec Fedora 37).
Je me lance donc dans la création d'un conteneur Fedora 37 comprenant LaTeX et tous mes packages. Facile, je reprends mon historique shell, en local, et l'adapte dans un Dockerfile (ne me demandez pas pourquoi la coloration syntaxique est foireuse...) :
FROM fedora:37
RUN dnf update -y && \
dnf -y install texlive-chktex texlive-moderncv texlive-documentation \
texlive-anyfontsize texlive-geometry texlive-babel \
texlive-fontawesome texlive-enumitem \
texlive-inputenx texlive-latex-uni8 texlive-autopdf \
texlive-texlive-scripts texlive-mkjobtexmf texlive-metafont \
texlive-latex-fonts texlive-collection-fontsrecommended \
texlive-collection-fontsextra texlive-multirow texlive-arydshln \
texlive-babel-french texlive-xcolor texlive-csquotes && \
dnf clean all
ENTRYPOINT [ "/usr/bin/pdflatex" ]
C'est du "quick & dirty". Au final, l'image du conteneur est assez volumineuse, puisqu'elle fait 2.98Go, mais elle reste inférieur à celle utilisée dans le Github Actions latex-actions
, dont l'image pèse 4.27Go (à cause de l'environnement complet LaTeX) !
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/remyd1/fedora-moderncv 37 90fb73ad115d 3 days ago 2.98 GB
registry.fedoraproject.org/fedora 37 38b8a6c320f3 3 weeks ago 190 MB
ghcr.io/xu-cheng/texlive-full latest a624d3388c1a 4 weeks ago 4.27 GB
Cette dernière faite, je la pousse sur le dockerhub (oui, il est possible de faire ça aussi avec github actions, mais je ne le savais pas encore et l'image ne devrait pas bouger (ou alors de manière exceptionnelle...)).
Version corrigée du Yaml
Voici à quoi ressemble désormais mon fichier yaml de github actions :
# This is a basic workflow to help you get started with Actions
name: LaTeX Build CI
defaults:
run:
shell: bash
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the "main" branch
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
runs-on: ubuntu-latest
container: remyd1/fedora-moderncv:37
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Set up Git repository
uses: actions/checkout@v3
- name: LaTeX Build
run: for texfile in $(ls *.tex); do pdflatex ${texfile}; done
- name: Upload Full En PDF file
uses: actions/upload-artifact@v3
with:
name: PDF
path: full_ac_resume_en.pdf
- name: Upload Std En PDF file
uses: actions/upload-artifact@v3
with:
name: PDF
path: std_resume_en.pdf
- name: Upload Std Fr PDF file
uses: actions/upload-artifact@v3
with:
name: PDF
path: std_cv_fr.pdf
J'avais tenté de séparer ce workflow en plusieurs jobs, mais il faut alors récupérer l'environnement précédent (conteneur, espace de travail, etc), et gérer l'enchainement de ceux-ci (sinon, ils sont exécutés en parallèle). J'ai donc finalement préféré opter pour un seul gros job.
A propos de l'automatisation
Maintenant, si je voulais être encore plus feignant, serait-il possible d'automatiser encore plus tout ça... ?
La réponse est "oui", bien sûr, mais le temps que je devrais y consacrer ne sera pas rentabilisé (...).
On peut imaginer, par exemple, un code qui va lire un fichier CSV, le parser, et, en fonction du contenu, va générer le code LaTeX approprié... Oui, du code qui génère du code. C'est moche, mais ça fonctionne. On pourrait même envisager de tout coder en LaTeX..... De manière similaire, si je remplissais suffisamment ce blog, je pourrai aussi scrapper le contenu, et, en fonction des catégories, je générerai le LaTeX correspondant....
J'ai vu un code de ce type, à base de "dataframe", en R, ici (pour ceux qui ne prennent pas peur au mot "R" (avec des packages très puissants derrière (knitr
, etc...))) ! Sinon, un autre code en python, à partir de notebook Jupyter.
Pour finir
En conclusion, j'espère que cet article vous permettra de gagner du temps dans la création et la mise à jour de vos CV. Pour ceux qui souhaitent utiliser le workflow ou l'image, évidemment, la licence est libre, mais je ne suis pas contre un remerciement ou une mention dans votre dépôt (pas dans le CV !) ! Je suis aussi disponible sur mastodon pour ceux qui souhaitent en discuter ou mettre à jour tout ça.
Enfin, attention à la facturation chez Github. C'est un point que je n'ai pas mentionné, mais si vous faites tourner beaucoup de jobs (pensez à utiliser max-parallel: 1
dans votre workflow) ou si vous stockez beaucoup de données, vous pourriez avoir des surprises ! Un passage à un autre gestionnaire de CI sera sûrement nécessaire si vous n'avez pas d'autre choix et/ou un budget serré.
Notes
A ce sujet, je préfère désormais utiliser markdown
avec marp
, pour lequel j'ai forké le thème dracula afin d'avoir un résultat plus sobre.
Ce blog statique (dont le contenu est généré par Zola depuis markdown) est également géré par un dépôt github privé connecté à Netlify.