Pourquoi CI/CD pour .NET avec GitHub Actions ?
La continuité d'intégration et de déploiement (CI/CD) est un processus essentiel pour les développeurs modernes, particulièrement dans l'industrie du développement .NET. Il permet une intégration continue de code source entre les différents membres d'une équipe, et un déploiement automatisé vers des environnements de test et de production. En utilisant GitHub Actions, vous pouvez mettre en place ce processus de manière simple et efficace.
Un cas concret d'utilisation de la CI/CD pour .NET avec GitHub Actions est dans le développement d'une application web de gestion des projets. Cette application nécessite une mise à jour régulière des fonctionnalités et du code source, ainsi qu'un déploiement rapide sur un serveur de production.
Prerequis
Pour suivre ce tutoriel, vous aurez besoin des éléments suivants :
- Un compte GitHub
- Visual Studio ou tout autre éditeur de code .NET
- .NET SDK installé (version 6.0 ou ultérieure)
- Node.js et npm installés (pour les outils front-end si nécessaire)
Concepts fondamentaux
Workflow
Un workflow est un processus automatisé qui s'exécute sur GitHub Actions. Il peut être déclenché par des événements spécifiques, comme la création d'une Pull Request ou la push vers une branche.
## .github/workflows/dotnet-ci.yml
name: .NET CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0'
Actions et Jobs
Un job est une série d'étapes qui s'exécutent dans un environnement spécifique. Une action est une unité réutilisable qui peut être exécutée dans le cadre d'un workflow.
## .github/workflows/dotnet-ci.yml
name: .NET CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0'
- name: Build the project
run: dotnet build --configuration Release --no-restore
Actions personnalisées
Vous pouvez aussi utiliser des actions personnalisées pour exécuter des scripts ou des commandes spécifiques.
## .github/workflows/dotnet-ci.yml
name: .NET CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0'
- name: Build the project
run: dotnet build --configuration Release --no-restore
- name: Run custom script
run: ./scripts/run-tests.sh
Mise en pratique : projet fil rouge
Pour ce tutoriel, nous allons créer un simple gestionnaire de tâches avec .NET. Ce projet comprendra des fonctionnalités de création, de lecture, de mise à jour et de suppression de tâches.
Création du projet
Commencez par créer un nouveau projet .NET console :
dotnet new console -n TaskManager cd TaskManagerStructure des fichiers
Le projet aura une structure similaire à celle-ci :
TaskManager/ ├── Program.cs └── tasks.txtCode initial du programme
// Program.cs using System; using System.IO; class Program { static void Main(string[] args) { Console.WriteLine("Bienvenue dans le gestionnaire de tâches !"); while (true) { Console.WriteLine("Choisissez une option :"); Console.WriteLine("1. Ajouter une tâche"); Console.WriteLine("2. Lister les tâches"); Console.WriteLine("3. Quitter"); string choice = Console.ReadLine(); switch (choice) { case "1": AddTask(); break; case "2": ListTasks(); break; case "3": return; default: Console.WriteLine("Option invalide. Veuillez choisir à nouveau."); break; } } } static void AddTask() { Console.Write("Entrez le nom de la tâche : "); string taskName = Console.ReadLine(); using (StreamWriter writer = File.AppendText("tasks.txt")) { writer.WriteLine(taskName); } Console.WriteLine("Tâche ajoutée avec succès !"); } static void ListTasks() { if (!File.Exists("tasks.txt")) { Console.WriteLine("Aucune tâche enregistrée."); return; } using (StreamReader reader = File.OpenText("tasks.txt")) { string line; int index = 1; while ((line = reader.ReadLine()) != null) { Console.WriteLine($"{index}. {line}"); index++; } } } }Ajout du workflow GitHub Actions
Créez un fichier
.github/workflows/dotnet-ci.ymlavec le contenu suivant :name: .NET CI on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup .NET uses: actions/setup-dotnet@v1 with: dotnet-version: '6.0' - name: Build the project run: dotnet build --configuration Release --no-restore - name: Run tests run: dotnet test --verbosity normal
Erreurs frequentes et debugging
Erreur 1 : Problème d'accès au fichier tasks.txt
Le programme génère une erreur si le fichier tasks.txt n'existe pas.
// Program.cs
static void ListTasks()
{
if (!File.Exists("tasks.txt"))
{
Console.WriteLine("Aucune tâche enregistrée.");
return;
}
using (StreamReader reader = File.OpenText("tasks.txt"))
{
string line;
int index = 1;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine($"{index}. {line}");
index++;
}
}
}
Correction :
// Program.cs
static void ListTasks()
{
if (!File.Exists("tasks.txt"))
{
File.Create("tasks.txt").Close();
Console.WriteLine("Aucune tâche enregistrée.");
return;
}
using (StreamReader reader = File.OpenText("tasks.txt"))
{
string line;
int index = 1;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine($"{index}. {line}");
index++;
}
}
}
Erreur 2 : Problème d'exécution des tests
Les tests unitaires ne s'exécutent pas correctement.
// TaskManager.Tests/TaskManagerTests.cs
using NUnit.Framework;
[TestFixture]
public class TaskManagerTests
{
[Test]
public void AddTask_ShouldAddTask()
{
// Arrange
using (StreamWriter writer = File.CreateText("tasks.txt"))
{
writer.WriteLine();
}
// Act
Program.AddTask();
// Assert
string[] lines = File.ReadAllLines("tasks.txt");
Assert.AreEqual(2, lines.Length);
}
}
Correction :
// TaskManager.Tests/TaskManagerTests.cs
using NUnit.Framework;
[TestFixture]
public class TaskManagerTests
{
[Test]
public void AddTask_ShouldAddTask()
{
// Arrange
string originalContent = File.ReadAllText("tasks.txt");
// Act
Program.AddTask();
// Assert
string[] lines = File.ReadAllLines("tasks.txt");
Assert.AreEqual(2, lines.Length);
// Cleanup
File.WriteAllText("tasks.txt", originalContent);
}
}
Erreur 3 : Problème de configuration du workflow
Le workflow GitHub Actions ne fonctionne pas correctement.
## .github/workflows/dotnet-ci.yml
name: .NET CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0'
- name: Build the project
run: dotnet build --configuration Release --no-restore
- name: Run tests
run: dotnet test --verbosity normal
Correction :
## .github/workflows/dotnet-ci.yml
name: .NET CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0'
- name: Build the project
run: dotnet build --configuration Release --no-restore
- name: Run tests
run: dotnet test --verbosity normal
Pour aller plus loin
1. Intégration avec Azure DevOps
Si vous utilisez déjà Azure DevOps, vous pouvez combiner les avantages de GitHub Actions et d'Azure DevOps pour une intégration complète du pipeline CI/CD.
2. Utilisation des secrets
Pour gérer des informations sensibles comme des clés API ou des mots de passe dans vos workflows GitHub Actions, utilisez les secrets :
## .github/workflows/dotnet-ci.yml
name: .NET CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0'
- name: Build the project
run: dotnet build --configuration Release --no-restore
- name: Run tests
env:
API_KEY: $secrets.API_KEY
run: dotnet test --verbosity normal
3. Déploiement sur Azure App Service
Pour déployer votre application .NET sur Azure App Service, utilisez les actions suivantes :
## .github/workflows/dotnet-ci.yml
name: .NET CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0'
- name: Build the project
run: dotnet build --configuration Release --no-restore
- name: Run tests
run: dotnet test --verbosity normal
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0'
- name: Publish the project
run: dotnet publish --configuration Release --output ./publish
- name: Deploy to Azure App Service
uses: azure/webapps-deploy@v2
with:
app-name: your-app-name
slot-name: production
package: ./publish
Défi pratique
Créez un simple API de blog en utilisant ASP.NET Core. Le projet devra comprendre les fonctionnalités suivantes :
- Création d'un nouveau post
- Lecture de tous les posts
- Mise à jour d'un post existant
- Suppression d'un post
Utilisez GitHub Actions pour automatiser le build, les tests et le déploiement sur Azure App Service.