Pipeline CI
Un pipeline CI en trois étapes s’exécutant entièrement sur des conteneurs cloud provisionnés : build (binaire Rust en release), test (cargo test avec un sidecar Postgres), package (archive tar.gz). Les étapes 1 et 2 s’exécutent en parallèle ; l’étape 3 ne démarre qu’après la fin des deux.
Exécution
melodium run 16_ci_pipeline/Compo.toml \
--api_token "my-api-token" \
--repo_url "https://github.com/my-org/my-project.git"[…] info: ci: pipeline started
[…] info: build: build succeeded
[…] info: test: all tests passed
[…] info: ci: pipeline complete — artifact writtenFonctionnement
Un seul modèle CicdDispatchEngine gère toute l’infrastructure :
model Dispatcher(const api_token: string) : CicdDispatchEngine {
api_token = |wrap<string>(api_token)
}Chaque étape est un sous-traitement encapsulant simpleStep ou simpleStepWithInput, qui abstraient le provisionnement, l’exécution, les E/S de fichiers et le nettoyage en un seul appel.
Étapes concurrentes avec fork-join
Les étapes 1 et 2 démarrent toutes les deux depuis startup.trigger :
startup.trigger -> build.trigger
startup.trigger -> test.triggerL’étape 3 attend que les deux se terminent grâce à flock<void>(), qui collecte deux signaux Block<void> et émet un Stream<void> une fois les deux reçus. Un trigger<void>() convertit ce flux en un seul Block<void> pour déclencher package :
bothFinished: flock<void>()
build.finished -> bothFinished.a
test.finished -> bothFinished.b
bothTrigger: trigger<void>()
bothFinished.stream -> bothTrigger.stream
bothTrigger.start -> package.triggerBinaire pipé entre les étapes
Le binaire compilé produit par l’étape 1 est pipé directement dans l’étape 3 sans passer par le disque local :
build.data -> package.datasimpleStepWithInput stream les octets reçus dans /mnt/data/binary sur le conteneur distant avant d’exécuter les commandes.
Sidecar de service
L’étape test attache un conteneur Postgres 16 comme sidecar accessible par le nom d’hôte postgres :
service_containers = [
|service_container(
"postgres", 512, 1000, 2048, |amd64(), [],
"postgres:16", _,
|wrap<StringMap>(|map([
|entry<string>("POSTGRES_USER", "ci"),
|entry<string>("POSTGRES_PASSWORD", "ci"),
|entry<string>("POSTGRES_DB", "ci_test")
])), _
)
]DATABASE_URL est définie sur postgres://ci:ci@postgres/ci_test dans l’environnement du conteneur de test.
Fusion des erreurs
Si l’étape 1 ou 2 échoue ou produit une erreur, un message est journalisé et l’étape 3 se déclenche quand même (sur bothFinished) — permettant au pipeline de continuer jusqu’à la tentative de packaging. Pour annuler à la place, connectez oneAnyFailed.value à un traitement qui annule le pipeline explicitement.
Dépendances
[dependencies]
std = "0.10.1" # flux de base, journalisation, structures de données
fs = "0.10.1" # lecture/écriture de fichiers locaux
process = "0.10.1" # exécution de commandes shell
work = "0.10.1" # provisionnement de runners cloud
distrib = "0.10.1" # distribution de flux entre runners
cicd = "0.10.1" # dispatch et orchestration d'étapes CI/CD