Nouveau : Datasets open source gratuits disponibles !Decouvrir →
🦀
Intermediaire 25 min Rust

CI/CD pour Rust avec GitHub Actions

CI/CD pour Rust avec GitHub Actions

Pourquoi CI/CD pour Rust avec GitHub Actions ?

Dans un environnement de développement professionnel, la continuité d'intégration (CI) et la livraison continue (CD) sont des pratiques essentielles qui contribuent à une meilleure qualité du code, à une réduction des erreurs et à une acceleration du cycle de développement. Pour les développeurs Rust, GitHub Actions est un outil puissant et facile à utiliser pour mettre en place ces pratiques.

Un cas concret d'utilisation serait le déploiement automatique d'une API web Rust sur un serveur de production chaque fois qu'un commit est poussé dans la branche principale. Cela permet une mise à jour rapide et fiable de l'application, avec des tests automatisés pour s'assurer que les nouvelles fonctionnalités ne causent pas de regressions.

Prerequis

Pour suivre ce tutoriel, vous aurez besoin de :

  • Un compte GitHub
  • Un environnement Rust installé (version recommandée : 1.56 ou plus tard)
  • L'outil cargo qui est partant avec Rust
  • Node.js et npm pour le projet fil rouge (si nécessaire)

Concepts fondamentaux

Workflow

Un workflow est une séquence d'étapes automatisées exécutées par GitHub Actions. Il est défini dans un fichier YAML placé dans le répertoire .github/workflows/ de votre dépôt.

name: CI/CD Rust

on:
  push:
    branches:
      - main

Job

Un job est une série d'étapes qui s'exécutent en parallèle ou séquentiellement. Chaque job a un conteneur Docker spécifié.

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

Step

Un step est une action spécifique qui peut être exécutée dans un job. Elle peut exécuter des commandes shell, installer des dépendances, ou appeler d'autres actions.

      - name: Install dependencies
        run: |
          cargo build --release

Action

Une action est une unité réutilisable qui effectue une tâche spécifique. Par exemple, l'action actions/checkout@v2 permet de cloner le code du dépôt dans l'environnement d'exécution.

      - name: Run tests
        run: cargo test

Mise en pratique : projet fil rouge

Nous allons créer un simple gestionnaire de tâches Rust qui peut ajouter, supprimer et afficher des tâches. Ce projet sera utilisé pour mettre en œuvre le workflow GitHub Actions.

Étape 1 : Création du projet

cargo new task_manager
cd task_manager

Étape 2 : Structure du projet

Le projet aura une structure de base comme suit :

task_manager/
├── Cargo.toml
├── src/
│   ├── main.rs
│   └── task_manager.rs
└── .github/workflows/
    └── ci_cd.yml

Étape 3 : Ajout des fonctionnalités

Créez un fichier src/task_manager.rs avec le code suivant :

// src/task_manager.rs
use std::collections::HashMap;

pub struct TaskManager {
    tasks: HashMap<String, bool>,
}

impl TaskManager {
    pub fn new() -> Self {
        TaskManager { tasks: HashMap::new() }
    }

    pub fn add_task(&mut self, task_name: String) {
        self.tasks.insert(task_name, false);
    }

    pub fn complete_task(&mut self, task_name: &str) {
        if let Some(task) = self.tasks.get_mut(task_name) {
            *task = true;
        }
    }

    pub fn list_tasks(&self) -> Vec<(String, bool)> {
        self.tasks.iter().map(|(k, v)| (k.clone(), *v)).collect()
    }
}

Étape 4 : Utilisation du gestionnaire de tâches

Modifiez le fichier src/main.rs pour utiliser le gestionnaire de tâches :

// src/main.rs
mod task_manager;

use task_manager::TaskManager;

fn main() {
    let mut tm = TaskManager::new();
    tm.add_task("Write code".to_string());
    tm.complete_task("Write code");
    for (task, completed) in tm.list_tasks() {
        println!("{} - {}", task, completed);
    }
}

Étape 5 : Ajout des tests

Créez un fichier src/task_manager.rs avec le code suivant :

// src/task_manager.rs
use std::collections::HashMap;

pub struct TaskManager {
    tasks: HashMap<String, bool>,
}

impl TaskManager {
    pub fn new() -> Self {
        TaskManager { tasks: HashMap::new() }
    }

    pub fn add_task(&mut self, task_name: String) {
        self.tasks.insert(task_name, false);
    }

    pub fn complete_task(&mut self, task_name: &str) {
        if let Some(task) = self.tasks.get_mut(task_name) {
            *task = true;
        }
    }

    pub fn list_tasks(&self) -> Vec<(String, bool)> {
        self.tasks.iter().map(|(k, v)| (k.clone(), *v)).collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add_task() {
        let mut tm = TaskManager::new();
        tm.add_task("Write code".to_string());
        assert_eq!(tm.list_tasks(), vec![("Write code".to_string(), false)]);
    }

    #[test]
    fn test_complete_task() {
        let mut tm = TaskManager::new();
        tm.add_task("Write code".to_string());
        tm.complete_task("Write code");
        assert_eq!(tm.list_tasks(), vec![("Write code".to_string(), true)]);
    }
}

Étape 6 : Ajout du workflow GitHub Actions

Créez un fichier .github/workflows/ci_cd.yml avec le code suivant :

name: CI/CD Rust

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          components: rustfmt, clippy

      - name: Install dependencies
        run: cargo build --release

      - name: Run tests
        run: cargo test

      - name: Build and publish (optional)
        if: github.ref == 'refs/heads/main'
        uses: softprops/action-gh-release@v1
        with:
          files: target/release/task_manager

Étape 7 : Exécution du workflow

Push le code sur GitHub :

git add .
git commit -m "Add task manager and CI/CD"
git push origin main

GitHub Actions exécutera automatiquement les étapes définies dans le fichier ci_cd.yml.

Erreurs frequentes et debugging

1. Erreur : Le code ne compile pas

// src/main.rs
fn main() {
    let x = 5;
    println!("The value of x is: {}", y);
}

Erreur :

error[E0425]: cannot find value `y` in this scope

Correction :

// src/main.rs
fn main() {
    let x = 5;
    println!("The value of x is: {}", x);
}

2. Erreur : Les tests ne passent pas

// src/task_manager.rs
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add_task() {
        let mut tm = TaskManager::new();
        tm.add_task("Write code".to_string());
        assert_eq!(tm.list_tasks(), vec![("Write code".to_string(), false)]);
    }

    #[test]
    fn test_complete_task() {
        let mut tm = TaskManager::new();
        tm.add_task("Write code".to_string());
        tm.complete_task("Write code");
        assert_eq!(tm.list_tasks(), vec![("Code write".to_string(), true)]);
    }
}

Erreur :

error: test failed, to rerun pass '--test task_manager'

Correction :

// src/task_manager.rs
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_add_task() {
        let mut tm = TaskManager::new();
        tm.add_task("Write code".to_string());
        assert_eq!(tm.list_tasks(), vec![("Write code".to_string(), false)]);
    }

    #[test]
    fn test_complete_task() {
        let mut tm = TaskManager::new();
        tm.add_task("Write code".to_string());
        tm.complete_task("Write code");
        assert_eq!(tm.list_tasks(), vec![("Write code".to_string(), true)]);
    }
}

3. Erreur : Le workflow ne fonctionne pas

name: CI/CD Rust

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          components: rustfmt, clippy

      - name: Install dependencies
        run: cargo build --release

      - name: Run tests
        run: cargo test

      - name: Build and publish (optional)
        if: github.ref == 'refs/heads/main'
        uses: softprops/action-gh-release@v1
        with:
          files: target/release/task_manager

Erreur :

Error: no files were uploaded, expected one or more of the following files to be present in the repository root directory: target/release/task_manager

Correction :

name: CI/CD Rust

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          components: rustfmt, clippy

      - name: Install dependencies
        run: cargo build --release

      - name: Run tests
        run: cargo test

      - name: Build and publish (optional)
        if: github.ref == 'refs/heads/main'
        uses: softprops/action-gh-release@v1
        with:
          files: target/release/task_manager

Pour aller plus loin

1. Intégration avec Docker

Utilisez un conteneur Docker pour exécuter le workflow GitHub Actions.

name: CI/CD Rust

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Docker Buildx
        id: buildx
        uses: docker/setup-buildx-action@v1

      - name: Build and publish image
        uses: docker/build-push-action@v2
        with:
          context: .
          push: $github.ref == 'refs/heads/main'

2. Utilisation de secrets GitHub

Stockez des informations sensibles comme les clés d'API dans les variables d'environnement GitHub.

name: CI/CD Rust

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          components: rustfmt, clippy

      - name: Install dependencies
        run: cargo build --release

      - name: Run tests
        run: cargo test

3. Déploiement sur AWS Elastic Beanstalk

Déployez votre application Rust sur AWS Elastic Beanstalk.

name: CI/CD Rust

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          components: rustfmt, clippy

      - name: Install dependencies
        run: cargo build --release

      - name: Run tests
        run: cargo test

      - name: Deploy to AWS Elastic Beanstalk
        uses: einaregilsson/beanstalk-deploy@v18
        with:
          aws_access_key: $secrets.AWS_ACCESS_KEY
          aws_secret_key: $secrets.AWS_SECRET_KEY
          application_name: task-manager-app
          environment_name: task-manager-env
          region: us-west-2

Défi pratique

Développez une API de blog en Rust avec les fonctionnalités suivantes :

  • Création d'un article
  • Lecture d'un article
  • Mise à jour d'un article
  • Suppression d'un article

Utilisez GitHub Actions pour automatiser le déploiement sur un serveur AWS Elastic Beanstalk.

Besoin d'aide sur Rust ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Questions frequentes

Quelles sont les principales avantages du CI/CD avec GitHub Actions pour le développement en Rust ?
Le CI/CD avec GitHub Actions offre des avantages tels que la mise en œuvre automatique des tests unitaires et de l'intégration continue, qui permettent une amélioration significative de la qualité du code. Il facilite également les déploiements réguliers vers différents environnements.
Comment configurer GitHub Actions pour un projet Rust spécifique ?
Pour configurer GitHub Actions pour un projet Rust, vous devez créer un fichier `.github/workflows/ci-cd.yml` dans votre repository. Ce fichier doit contenir des étapes pour installer les dépendances de Rust, compiler le code et exécuter les tests.
Quelle est la stratégie recommandée pour gérer les versions de Rust avec GitHub Actions ?
Il est recommandé d'utiliser une action spéciale pour définir la version de Rust à utiliser dans votre workflow. Cela vous permet de choisir précisément quelle version de Rust est utilisée pour le build et les tests, assurant ainsi la cohérence entre l'environnement local et le pipeline CI/CD.

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.