Partie 2: Pipeline de CI
Lecture 7 min. âą
Table des matiĂšres
Bonjour Ă toutes et Ă tous đ
Dans lâarticle prĂ©cĂ©dent nous avons poussĂ© Ă la main des crates en utilisant curl en local.
Ce nâest pas du tout satisfaisant.
Nous allons automatiser tout ça via la CI. Et comme nous avons commencé avec la package registry de Gitlab, on va également utilisé la Gitlab CI.
Jâai un certain nombre dâexigences.
- une adresse unique pour toutes les crates, je ne veaux pas Ă avoir Ă me rappeler du chemin Ă chaque fois
- le versionnage est explicite et basé sur la version du package publié
- support des versions flottantes de dev
- ces versions de devs ont un versionnage implicite et automatique
- cela doit ĂȘtre le moins contraignant Ă utiliser, le moins de boilerplate possible
- il doit gérer les workspace Rust
Autant dire quâil y a un peu de travail.
Pipeline de CI 1o1
Commençons par la base.
Si vous crĂ©ez un fichier .gitlab-ci.yml Ă la racine dâun projet git et que vous le poussez sur Gitlab, cela va indiquer Ă Gitlab quâil faut lancer un pipeline de CI.
Son format est le suivant
.gitlab-ci.yml
stages:
- stage1
- stage2
job1:
stage: stage1
job2:
stage: stage1
job3:
stage: stage2Cela créé un graphe dâexĂ©cution qui va ressembler Ă ceci
flowchart LR
job1 -->job3
job2 --> job3
job1 et job2 doivent tous les deux rĂ©ussir si lâon veut que job3 sâexĂ©cute. Ce systĂšme de strates se nomme des stages et permettent de rĂ©aliser des checkpoints bloquants entre les diffĂ©rentes Ă©tapes.
Par exemple ne packager que si le build est un succĂšs est une bonne idĂ©e. đ
Nous nous allons dĂ©finir un stage qui sâappellera package.
Bon et maintenant, quâest ce que lâon fait de nos jobs ?.
La premiÚre chose est de définir une image qui sera notre environnement de packaging, nous faisons du rust, ça sera donc une image rust. Et de préférence versionnée.
.gitlab-ci.yml
package-crate:
image: rust:1.77
stage: packagingNous allons Ă©crire du bash, ce qui reste la meilleure façon dâintĂ©ragir avec un environnement.
Et ce bash vient se mettre dans un array nommé scripts.
.gitlab-ci.yml
package-crate:
image: rust:1.77
stage: packaging
script:
- echo "Hello World"Packaging en CI
Dâabord rĂ©capitulons ce que nous avons fait en local:
- nous avons défini un
.ssh/configcontenant le host de notre proxy - nous avons lancé les commandes de packaging
- nous avons fait du curl
Ok, mimons ce fonctionnement.
Tout dâabord occupons-nous du SSH.
La premiĂšre chose que lâon va faire câest dĂ©finir des informations sous forme de variable dâenvironnement
.gitlab-ci.yml
variables:
CRATE_PACKAGE_ENDPOINT=$CRATES_ENDPOINT
CRATE_PACKAGE_USER=personal-tokenBien maintenant le packaging en lui-mĂȘme.
Il nécessite plusieurs éléments:
- lâaddresse de lâAPI gitlab trouvable dans la variable injectĂ©e
$CI_API_V4_URL - la version du package
- le nom du package
- le chemin vers le fichier
.crateĂ gĂ©nĂ©rer Ă partier des informations prĂ©cĂ©dentes - le token que lâon possĂšde dĂ©jĂ
Pour rappel, cela Ă cette tĂȘte-lĂ :
curl --header "PRIVATE-TOKEN: $TOKEN" --upload-file target/package/${CRATE_FILE} "${ENDPOINT}/projects/${PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/$CRATE_FILE"Commençons par récupérer le nom et la version du package.
Pour cela nous pouvons utiliser un utiliser un utilitaire qui se nomme tomlq, il vient avec yq et permet de rĂ©aliser des requĂȘtes jq sur un fichier toml.
Pour cela, on se rajoute la dépendance.
apt update && apt install -y yqPuis on génÚre nos variables.
export CRATE_NAME=$(tomlq '.package.name' Cargo.toml | tr -d '"')
export CRATE_NAME=$(tomlq '.package.version' Cargo.toml | tr -d '"')On vient âtrimâ les guillemets qui vont nous ennuyer par la suite.
On peut alors constituer notre $CRATE_FILE
export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crateIl nous faut Ă©galement un $CRATE_PACKAGE_PROJECT_ID que lâon dĂ©fini dans les variables dâenvironement
Nous avons tous les ingédients, nous pouvons créer notre job.
.gitlab-ci.yml
stages:
- packaging
variables:
# gitlab token
CRATE_PACKAGE_TOKEN: $CI_JOB_TOKEN
# l'ID du projet qui supportera les crates par défaut le project du job
CRATE_PACKAGE_PROJECT_ID: $CI_PROJECT_ID
# API user
CRATE_PACKAGE_USER_API: JOB-TOKEN
package-crate:
image: rust:1.77
stage: packaging
script:
# dépendences
- apt update && apt install -y yq
# récupération des informations du paquet
- export CRATE_NAME=$(tomlq '.package.name' Cargo.toml | tr -d '"')
- export CRATE_VERSION=$(tomlq '.package.version' Cargo.toml | tr -d '"')
- export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crate
# packaging
- cargo package
- cargo metadata --format-version 1 > metadata.json
# upload
- 'curl --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file target/package/${CRATE_FILE} "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/$CRATE_FILE"'
- 'curl --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file metadata.json "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/metadata.json"'Si tout se passe bien, vous devriez voir apparaĂźtre dans la package registry de votre projet Gitlab un paquet project v0.1.0.
Maintenant intĂ©ressons nous au cas oĂč le projet nĂ©cessite une dĂ©pendence qui elle mĂȘme est privĂ©e.
On se créé un projet pour tester.
cargo init --lib need_project && cd need_project
mkdir -p .cargo && cat << EOF > .cargo/config
[registries.private-crate]
index = "ssh://noa-crates.cleverapps.io/noa-crates/project"
[net]
git-fetch-with-cli = true
EOF
echo 'project = {version="0.1.0", registry="private-crate"}' >> Cargo.tomlComme vous pouvez le voir, nous allons devoir nous authentifier.
Pour cela nous dĂ©finissons dans lâobjet variables les diffĂ©rentes informations nĂ©cessaire Ă la connexion SSH.
.gitlab-ci.yml
variables:
CRATE_PACKAGE_TOKEN: $CI_JOB_TOKEN
CRATE_PACKAGE_ENDPOINT: noa-crates.cleverapps.io
CRATE_PACKAGE_PORT: 22066
CRATE_PACKAGE_USER: personal-tokenOn créé le répertoire .ssh avec les bons droits
mkdir -p ~/.ssh && chmod -R 700 ~/.sshVia heredoc nous générons la configuration SSH:
cat << EOF > ~/.ssh/config
Host $CRATE_PACKAGE_ENDPOINT
User $CRATE_PACKAGE_USER:$CRATE_PACKAGE_TOKEN
Port $CRATE_PACKAGE_PORT
EOFMais cela nâest pas suffisant, il faut Ă©galement gĂ©nĂ©rer une clef privĂ©e pour que la connexion SSH se fasse.
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519Et finalement rĂ©cupĂ©rer la clef publique de notre proxy SSH, sinon la connexion Ă©chouera en non-intĂ©ractif car le endpoint nâest pas âconnuâ.
ssh-keyscan -p $CRATE_PACKAGE_PORT $CRATE_PACKAGE_ENDPOINT >> ~/.ssh/known_hostsOk, notre job de CI est maintenant capable de réaliser notre authentification au proxy.
Nous pouvons rassembler les piĂšces du puzzle
.gitlab-ci.yml
stages:
- packaging
variables:
# gitlab token
CRATE_PACKAGE_TOKEN: $CI_JOB_TOKEN
# l'ID du projet qui supportera les crates par défaut le project du job
CRATE_PACKAGE_PROJECT_ID: $CI_PROJECT_ID
# API user
CRATE_PACKAGE_USER_API: JOB-TOKEN
# Host du proxy SSH
CRATE_PACKAGE_ENDPOINT: noa-crates.cleverapps.io
# Port d'écoute du proxy SSH
CRATE_PACKAGE_PORT: 22066
# Utilisateur associé au token
CRATE_PACKAGE_USER: personal-token
package-crate:
image: rust:1.77
stage: packaging
script:
# dépendences
- apt update && apt install -y yq
# configuration SSH
- mkdir -p ~/.ssh && chmod -R 700 ~/.ssh
- |
cat << EOF > ~/.ssh/config
Host $CRATE_PACKAGE_ENDPOINT
User $CRATE_PACKAGE_USER:$CRATE_PACKAGE_TOKEN
Port $CRATE_PACKAGE_PORT
EOF
# création de la paire de clefs
- ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
# ajout de la clef publique du proxy
- ssh-keyscan -p $CRATE_PACKAGE_PORT $CRATE_PACKAGE_ENDPOINT >> ~/.ssh/known_hosts
# récupération des informations du paquet
- export CRATE_NAME=$(tomlq '.package.name' Cargo.toml | tr -d '"')
- export CRATE_VERSION=$(tomlq '.package.version' Cargo.toml | tr -d '"')
- export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crate
# packaging
- cargo package
- cargo metadata --format-version 1 > metadata.json
# upload
- 'curl --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file target/package/${CRATE_FILE} "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/$CRATE_FILE"'
- 'curl --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file metadata.json "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/metadata.json"'Et lĂ câest le drame đ«
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.Oui, votre $CI_JOB_TOKEN nâa de droit que sur le projet need_project pas project.
Mais heureusement, il est possible de rĂ©gler le souci en passant en paramĂštre du job un token apte Ă intĂ©ragir avec les deux projets, pour Gitlab SaaS en gratuit nous nâavons pas le choix, ça sera forcĂ©ment des token personnels, mais pour des version self-hosted, il est possible de crĂ©er des group token.
Bref, dans la configuration de la CI du projet need_project rajoutĂ© une variable dâenvironnement CRATE_PACKAGE_TOKEN avec votre token.
Il faut également redéfinir le CRATE_PACKAGE_USER_API à PRIVATE-TOKEN
On relance
Si tout est correct,
Votre pipeline devrait afficher quelque part ceci:
$ cargo package
warning: manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
Packaging need_project v0.1.0 (/builds/noa-crates/need_project2)
Verifying need_project v0.1.0 (/builds/noa-crates/need_project2)
Updating `private-crate` index
From ssh://noa-crates.cleverapps.io/noa-crates/project
* [new ref] -> origin/HEAD
Downloading crates ...
Downloaded project v0.1.0 (registry `private-crate`)
Compiling project v0.1.0 (registry `private-crate`)
Compiling need_project v0.1.0 (/builds/noa-crates/need_project2/target/package/need_project-0.1.0)
Finished dev [unoptimized + debuginfo] target(s) in 3.00sCela prouve que votre arbre de dĂ©pendences privĂ©e est bien reconstruite en CI. đ€©
SuccĂšs âïž
Oui et non, câest trĂšs contraignant de connaĂźtre toute cette mĂ©canique, on ne gĂšre pas encore les workspace et les versions de pre-release sont impossible Ă rĂ©aliser en lâĂ©tat.
Bref on repars en chasse !
Versions de pre-release
Quâest ce quâune version de pre-release pour moi ?
Une version de pre-release câest une version pas fini mais qui est nĂ©cessaire de packager pour dâautres dĂ©veloppements.
Si on se fie Ă la notation semver suivie par cargo.
Il est possible de crĂ©er des versions qui ne sont pas âfiniesâ en les suffixant dâun attribut.
par exemple 1.0.0-alpha.0, le suffixe de version alpha.0 indique la notion de pre-release de cette 1.0.0.
Mais on peut y mettre ce que lâon dĂ©sire comme le SHA1 rĂ©duit de 8 caratĂšres du commit de version.
Câest ce que jâai dĂ©cidĂ© de faire pour gĂ©nĂ©rer des versions comme 1.0.2-2e92f1ff.
Pour cela nous allons concaténer la version récupérer du Cargo.toml et la joindre au contenu de la varaible $CI_COMMIT_SHORT_SHA injecté par le job.
export CRATE_VERSION=$CRATE_VERSION-$CI_COMMIT_SHORT_SHAOk easy non ?
Alors non, si vous tentez de faire ça comme cela, la commande cargo package nâutilisera pas votre version modifiĂ©e et crĂ©era un target/package/project-0.1.0.crate au lieu du target/package/project-0.1.0-2e92f1ff.crate voulu.
Il va falloir trafiquer le Cargo.toml pour mettre Ă jour la version.
tomlq permet au moyen du paramĂštre --arg dâinjecter de lâenvironnement.
tomlq --arg VERSION $CRATE_VERSION -t '.package.version = $VERSION' Cargo.toml > Cargo.toml.modified
mv Cargo.toml.modified Cargo.tomlEt il faut également rajouter un paramÚtre --allow-dirty pour packager sans avoir à commiter.
cargo package --allow-dirtyOn est bon ?
Presque.
Il faut que lâon dĂ©couple les run entre la branche main et les autres: je veux que le package de release ne se dĂ©clenche que sur la branche main et pas ailleurs.
Et je veux également que le run du packaging de pre-release soit une tùche manuelle.
Heuresement Gitlab Ci permet de configurer tout ceci.
.gitlab-ci.yml
stages:
- packaging
release-dev:
stage: packaging
# nécessite une intervention humaine
when: manual
# si la branche n'est pas main
rules:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
release-prod:
stage: packaging
# seulement si c'est main
only:
- $CI_DEFAULT_BRANCHEt maintenant on rempli
stages:
- packaging
variables:
# gitlab token
CRATE_PACKAGE_TOKEN: $CI_JOB_TOKEN
# l'ID du projet qui supportera les crates par défaut le project du job
CRATE_PACKAGE_PROJECT_ID: $CI_PROJECT_ID
# API user
CRATE_PACKAGE_USER_API: JOB-TOKEN
# Host du proxy SSH
CRATE_PACKAGE_ENDPOINT: noa-crates.cleverapps.io
# Port d'écoute du proxy SSH
CRATE_PACKAGE_PORT: 22066
# Utilisateur associé au token
CRATE_PACKAGE_USER: personal-token
release-dev:
image: rust:1.77
stage: packaging
# nécessite une intervention humaine
when: manual
# si la branche n'est pas main
rules:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
script:
# dépendences
- apt update && apt install -y yq
# configuration SSH
- mkdir -p ~/.ssh && chmod -R 700 ~/.ssh
- |
cat << EOF > ~/.ssh/config
Host $CRATE_PACKAGE_ENDPOINT
User $CRATE_PACKAGE_USER:$CRATE_PACKAGE_TOKEN
Port $CRATE_PACKAGE_PORT
EOF
# création de la paire de clefs
- ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
# ajout de la clef publique du proxy
- ssh-keyscan -p $CRATE_PACKAGE_PORT $CRATE_PACKAGE_ENDPOINT >> ~/.ssh/known_hosts
# récupération des informations du paquet
- export CRATE_NAME=$(tomlq '.package.name' Cargo.toml | tr -d '"')
- export CRATE_VERSION=$(tomlq '.package.version' Cargo.toml | tr -d '"')
# on créé la version flottante
- export CRATE_VERSION=$CRATE_VERSION-$CI_COMMIT_SHORT_SHA
- export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crate
# On remplace la version
- tomlq --arg VERSION $CRATE_VERSION -t '.package.version = $VERSION' Cargo.toml > Cargo.toml.modified
- mv Cargo.toml.modified Cargo.toml
# packaging
- cargo package --allow-dirty
- cargo metadata --format-version 1 > metadata.json
# upload
- 'curl --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file target/package/${CRATE_FILE} "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/$CRATE_FILE"'
- 'curl --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file metadata.json "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/metadata.json"'
release-prod:
image: rust:1.77
stage: packaging
# seulement si c'est main
only:
- $CI_DEFAULT_BRANCH
script:
# dépendences
- apt update && apt install -y yq
# configuration SSH
- mkdir -p ~/.ssh && chmod -R 700 ~/.ssh
- |
cat << EOF > ~/.ssh/config
Host $CRATE_PACKAGE_ENDPOINT
User $CRATE_PACKAGE_USER:$CRATE_PACKAGE_TOKEN
Port $CRATE_PACKAGE_PORT
EOF
# création de la paire de clefs
- ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
# ajout de la clef publique du proxy
- ssh-keyscan -p $CRATE_PACKAGE_PORT $CRATE_PACKAGE_ENDPOINT >> ~/.ssh/known_hosts
# récupération des informations du paquet
- export CRATE_NAME=$(tomlq '.package.name' Cargo.toml | tr -d '"')
- export CRATE_VERSION=$(tomlq '.package.version' Cargo.toml | tr -d '"')
- export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crate
# packaging
- cargo package
- cargo metadata --format-version 1 > metadata.json
# upload
- 'curl --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file target/package/${CRATE_FILE} "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/$CRATE_FILE"'
- 'curl --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file metadata.json "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/metadata.json"'Si lâon
git checkout -b `dev
git push --set-upstream origin dev Un pipeline avec une tĂąche manuelle va apparaĂźtre
Et dedans normalement
$ cargo package --allow-dirty
Packaging need_project v0.1.0-0eb85488 (/builds/noa-crates/need_project2)
Verifying need_project v0.1.0-0eb85488 (/builds/noa-crates/need_project2)
Updating `private-crate` index
From ssh://noa-crates.cleverapps.io/noa-crates/project
* [new ref] -> origin/HEAD
Downloading crates ...
Downloaded project v0.1.0 (registry `private-crate`)
Compiling project v0.1.0 (registry `private-crate`)
Compiling need_project v0.1.0-0eb85488 (/builds/noa-crates/need_project2/target/package/need_project-0.1.0-0eb85488)
Finished dev [unoptimized + debuginfo] target(s) in 2.89s
Packaged 6 files, 4.7KiB (1.8KiB compressed)Félicitation, vous avez packagé votre version 0.1.0-0eb85488 de need_project et celle-ci peut alors se retrouver dans la package registry de need_project.
Factorisation
Tout cela câest trĂšs bien mais on voit bien que les Ă©tapes sont trĂšs semblables entre le job de release et de pre-release.
Il doit ĂȘtre possible de mettre en place un systĂšme qui permet de factoriser ces rĂ©pĂ©titions, et ce mĂ©canisme ne provient pas de Gitlab mais du format YAML, lui-mĂȘme.
Il sâagit des YAML anchors.
Quâest ce que lâon peut factoriser ?
Tout dâabord les dĂ©pendences
.dependencies: &dependencies
# dépendences
- apt update && apt install -y yqPuis la définition de la configuration SSH
.ssh-connexion: &ssh-connexion:
# configuration SSH
- mkdir -p ~/.ssh && chmod -R 700 ~/.ssh
- |
cat << EOF > ~/.ssh/config
Host $CRATE_PACKAGE_ENDPOINT
User $CRATE_PACKAGE_USER:$CRATE_PACKAGE_TOKEN
Port $CRATE_PACKAGE_PORT
EOF
# création de la paire de clefs
- ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
# ajout de la clef publique du proxy
- ssh-keyscan -p $CRATE_PACKAGE_PORT $CRATE_PACKAGE_ENDPOINT >> ~/.ssh/known_hostsEnsuite, la récupération des informations du package.
.version: &version
# récupération des informations du paquet
- export CRATE_NAME=$(tomlq '.package.name' Cargo.toml | tr -d '"')
- export CRATE_VERSION=$(tomlq '.package.version' Cargo.toml | tr -d '"')
- export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crateEt finalement, le packaging en lui-mĂȘme
.packaging: &packaging
# packaging
- cargo package --allow-dirty
- cargo metadata --format-version 1 > metadata.json
- ls target/package/$CRATE_FILE
# upload
- 'curl -i --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file target/package/${CRATE_FILE} "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/$CRATE_FILE"'
- 'curl -i --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file metadata.json "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/metadata.json"'On peut alors jouer aux lĂ©gos đ§±
.prepare: &prepare
- *dependencies
- *ssh-connexion
- *version
release-dev:
image: rust:1.77
stage: packaging
# manuel
when: manual
# si la branche n'est pas main
rules:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
script:
- *prepare
# on créé la version flottante
- export CRATE_VERSION=$CRATE_VERSION-$CI_COMMIT_SHORT_SHA
- export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crate
# On remplace la version
- tomlq --arg VERSION $CRATE_VERSION -t '.package.version = $VERSION' Cargo.toml > Cargo.toml.modified
- mv Cargo.toml.modified Cargo.toml
- *packaging
release-prod:
image: rust:1.77
stage: packaging
# seulement si c'est main
only:
- main
script:
- *prepare
- *packagingCâest quand mĂȘme plus clean comme ça đ.gitlab-ci.yml
stages:
- packaging
variables:
# gitlab token
CRATE_PACKAGE_TOKEN: $CI_JOB_TOKEN
# l'ID du projet qui supportera les crates par défaut le project du job
CRATE_PACKAGE_PROJECT_ID: $CI_PROJECT_ID
# API user
CRATE_PACKAGE_USER_API: JOB-TOKEN
# Host du proxy SSH
CRATE_PACKAGE_ENDPOINT: noa-crates.cleverapps.io
# Port d'écoute du proxy SSH
CRATE_PACKAGE_PORT: 22066
# Utilisateur associé au token
CRATE_PACKAGE_USER: personal-token
.dependencies: &dependencies
# dépendences
- apt update && apt install -y yq
.ssh-connexion: &ssh-connexion
# configuration SSH
- mkdir -p ~/.ssh && chmod -R 700 ~/.ssh
- |
cat << EOF > ~/.ssh/config
Host $CRATE_PACKAGE_ENDPOINT
User $CRATE_PACKAGE_USER:$CRATE_PACKAGE_TOKEN
Port $CRATE_PACKAGE_PORT
EOF
# création de la paire de clefs
- ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519
# ajout de la clef publique du proxy
- ssh-keyscan -p $CRATE_PACKAGE_PORT $CRATE_PACKAGE_ENDPOINT >> ~/.ssh/known_hosts
.packaging: &packaging
# packaging
- cargo package --allow-dirty
- cargo metadata --format-version 1 > metadata.json
- ls target/package/$CRATE_FILE
# upload
- 'curl -i --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file target/package/${CRATE_FILE} "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/$CRATE_FILE"'
- 'curl -i --header "$CRATE_PACKAGE_USER_API: $CRATE_PACKAGE_TOKEN" --upload-file metadata.json "${CI_API_V4_URL}/projects/${CRATE_PACKAGE_PROJECT_ID}/packages/generic/${CRATE_NAME}/${CRATE_VERSION}/metadata.json"'
.version: &version
# récupération des informations du paquet
- export CRATE_NAME=$(tomlq '.package.name' Cargo.toml | tr -d '"')
- export CRATE_VERSION=$(tomlq '.package.version' Cargo.toml | tr -d '"')
- export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crate
.prepare: &prepare
- *dependencies
- *ssh-connexion
- *version
release-dev:
image: rust:1.77
stage: packaging
# manuel
when: manual
# si la branche n'est pas main
rules:
- if: $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
script:
- *prepare
# on créé la version flottante
- export CRATE_VERSION=$CRATE_VERSION-$CI_COMMIT_SHORT_SHA
- export CRATE_FILE=${CRATE_NAME}-${CRATE_VERSION}.crate
# On remplace la version
- tomlq --arg VERSION $CRATE_VERSION -t '.package.version = $VERSION' Cargo.toml > Cargo.toml.modified
- mv Cargo.toml.modified Cargo.toml
- *packaging
release-prod:
image: rust:1.77
stage: packaging
# seulement si c'est main
only:
- main
script:
- *prepare
- *packaging
Pour le prochain, article on verra comment gérer le problÚme épineux des workspaces.