variables:
# Version de git utilisée
GIT_VERSION: v2.30.1
# Branche cible pour les PDF (modifiable via CI/CD variables)
PDF_BRANCH: "pdf"
FILE_NAMES: 2024-2025-rapport-csi 2024-2025-presentation-csi
build_tex:
stage: build
image: registry.gitlab.com/islandoftex/images/texlive:latest
script:
- |
for FILE_NAME in $FILE_NAMES
do
echo "Compiling ${FILE_NAME}"
pdflatex --shell-escape ${FILE_NAME}.tex
if test -f ${FILE_NAME}.bcf; then
echo "Found ${FILE_NAME}.bcf, running biber"
biber ${FILE_NAME}
fi
pdflatex --shell-escape ${FILE_NAME}.tex
done
after_script:
- |
for FILE_NAME in $FILE_NAMES
do
echo "============================================"
cat ${FILE_NAME}.log
echo "============================================"
done
artifacts:
paths:
- "*.pdf"
deploy:
stage: deploy
image:
name: alpine/git:${GIT_VERSION}
entrypoint: [""]
before_script:
# Clone le repo dans un dossier temporaire
- git clone "https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "${CI_COMMIT_SHA}"
# Configure l’identité git
- git config --global user.email "${GIT_USER_EMAIL:-$GITLAB_USER_EMAIL}"
- git config --global user.name "${GIT_USER_NAME:-$GITLAB_USER_NAME}"
script:
# Déplace les PDFs compilés dans le repo cloné
- mv *.pdf "${CI_COMMIT_SHA}/"
- cd "${CI_COMMIT_SHA}"
# Crée une branche orpheline (vierge, sans historique ni fichiers)
- git checkout --orphan "${PDF_BRANCH}"
- git reset --hard
# Ajoute uniquement les PDF
- git add -f *.pdf
# Vérifie s’il y a des changements et push
- |
CHANGES=$(git status --porcelain | wc -l)
if [ "$CHANGES" -gt "0" ]; then
git commit -m "${COMMIT_MESSAGE:-Updating PDF files}"
git push --force origin "${PDF_BRANCH}" -o ci.skip
else
echo "No PDF changes to commit"
fiThe Final CI
Here is the content of one of my .gitlab-ci.yaml files
If you see any inconsistencies, contact me by email: louis.lacoste@agroparistech.fr
Let’s break down what happens!
Variables
The variables section below is used to define variables that we will reference later.
GIT_VERSION: specifies the git version to use for the Docker image we’re going to fetch.PDF_BRANCH: indicates the name of the branch on which our PDFs will be published.FILE_NAMES: declares the list of file names (without extensions). In yaml format, these are strings without quotes separated by spaces
The Steps
The compilation phase build_tex
Let’s detail the build_tex step:
build_tex:
stage: build
image: registry.gitlab.com/islandoftex/images/texlive:latest
script:
- |
for FILE_NAME in $FILE_NAMES
do
echo "Compiling ${FILE_NAME}"
pdflatex --shell-escape ${FILE_NAME}.tex
if test -f ${FILE_NAME}.bcf; then
echo "Found ${FILE_NAME}.bcf, running biber"
biber ${FILE_NAME}
fi
pdflatex --shell-escape ${FILE_NAME}.tex
done
after_script:
- |
for FILE_NAME in $FILE_NAMES
do
echo "============================================"
cat ${FILE_NAME}.log
echo "============================================"
done
artifacts:
paths:
- "*.pdf"First, we declare stage: build to qualify the step we’re performing here. There are 3 possible stages: build, test, deploy (GitLab documentation). Here we choose build since this is the compilation of our project.
Next, we load a docker image that contains the texlive tools.
Finally, the script directive defines in bash the sequence of steps we perform to compile the project.
biber
Note that we haven’t included extensions in FILE_NAMES so that we can detect here the bcf files characteristic of the bibliography.
Finally, we use the after_script directive to display the compilation log files in the CI logs.
Lastly, artifacts specifies that the artifacts we want to keep from the CI are all PDFs at the root of the repository
The deployment phase deploy
deploy:
stage: deploy
image:
name: alpine/git:${GIT_VERSION}
entrypoint: [""]
before_script:
# Clone le repo dans un dossier temporaire
- git clone "https://${GITLAB_USERNAME}:${GITLAB_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "${CI_COMMIT_SHA}"
# Configure l’identité git
- git config --global user.email "${GIT_USER_EMAIL:-$GITLAB_USER_EMAIL}"
- git config --global user.name "${GIT_USER_NAME:-$GITLAB_USER_NAME}"
script:
# Déplace les PDFs compilés dans le repo cloné
- mv *.pdf "${CI_COMMIT_SHA}/"
- cd "${CI_COMMIT_SHA}"
# Crée une branche orpheline (vierge, sans historique ni fichiers)
- git checkout --orphan "${PDF_BRANCH}"
- git reset --hard
# Ajoute uniquement les PDF
- git add -f *.pdf
# Vérifie s’il y a des changements et push
- |
CHANGES=$(git status --porcelain | wc -l)
if [ "$CHANGES" -gt "0" ]; then
git commit -m "${COMMIT_MESSAGE:-Updating PDF files}"
git push --force origin "${PDF_BRANCH}" -o ci.skip
else
echo "No PDF changes to commit"
fiFinally, we deploy our PDFs. For this, we load a lightweight Alpine Linux image with the Git version selected in the variables.
With the before_script directive, we clone the repository.
Note in the git clone that we use a GITLAB_TOKEN variable, which must be created beforehand and declared in the repository.
To do this:
- Go to your repository settings.

- Here add a new token.

- Configure the
read_repositoryandwrite_repositorypermissions to be able to clone and push our files. Then click on “Create project access token”.

Your token is now displayed, copy it as it will not be displayed again.
Now go to CI/CD settings.

- Now create the variable by clicking on “Add variable”, name it
GITLAB_TOKEN, in “value” add the copied token.
The rest of the script moves the PDFs to the cloned repository, creates the publication branch and adds the pdfs.
You should now have a CI for compiling and publishing PDFs! Now you can reference your PDFs in your README.md by entering a link like:
https://mygitlab.com/myusername/myrepo/-/raw/mypdf.pdf
which allows you to display the compilation output directly in the browser. 😄