<p>Bonjour,</p>
<p>Cloner ou copier un pipeline CI/CD dans <strong>Azure DevOps</strong> est une opération très utile pour éviter de recréer des configurations complexes depuis zéro. Que vous souhaitiez dupliquer un pipeline au sein du même projet ou le copier vers un autre projet ou organisation, plusieurs méthodes sont à votre disposition. Je vais vous présenter toutes les approches, de la plus simple à la plus avancée.</p>
<h2><a name="p-34588-vue-densemble-des-options-disponibles-1" class="anchor" href="#p-34588-vue-densemble-des-options-disponibles-1" aria-label="Heading link"></a>Vue d’ensemble des options disponibles</h2>
<div class="md-table">
<table>
<thead>
<tr>
<th>Méthode</th>
<th>Complexité</th>
<th>Fidélité</th>
<th>Idéal pour</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Clone via l’interface graphique</strong></td>
<td>Très facile</td>
<td>Haute</td>
<td>Même projet</td>
</tr>
<tr>
<td><strong>Export/Import YAML</strong></td>
<td>Facile</td>
<td>Complète</td>
<td>Entre projets/organisations</td>
</tr>
<tr>
<td><strong>Azure DevOps CLI</strong></td>
<td>Moyenne</td>
<td>Complète</td>
<td>Automatisation, scripts</td>
</tr>
<tr>
<td><strong>API REST Azure DevOps</strong></td>
<td>Avancée</td>
<td>Complète</td>
<td>Intégration programmatique</td>
</tr>
<tr>
<td><strong>Pipeline as Code (YAML)</strong></td>
<td>Bonne pratique</td>
<td>Réutilisable</td>
<td>Tous cas de figure</td>
</tr>
</tbody>
</table>
</div><h2><a name="p-34588-mthode-1-cloner-via-linterface-graphique-le-plus-simple-2" class="anchor" href="#p-34588-mthode-1-cloner-via-linterface-graphique-le-plus-simple-2" aria-label="Heading link"></a>Méthode 1 : Cloner via l’interface graphique (le plus simple)</h2>
<h3><a name="p-34588-pour-les-pipelines-classiques-interface-graphique-3" class="anchor" href="#p-34588-pour-les-pipelines-classiques-interface-graphique-3" aria-label="Heading link"></a>Pour les pipelines classiques (interface graphique)</h3>
<p>Azure DevOps offre une fonctionnalité native de clonage pour les pipelines <strong>Classic</strong> :</p>
<ol>
<li>Naviguez vers <strong>Pipelines</strong> > <strong>Pipelines</strong> dans votre projet Azure DevOps</li>
<li>Trouvez le pipeline que vous souhaitez cloner</li>
<li>Cliquez sur les <strong>trois points (…)</strong> à droite du pipeline</li>
<li>Sélectionnez <strong>“Clone”</strong> ou <strong>“Cloner”</strong></li>
<li>Le pipeline est dupliqué avec le nom <code>Copie de [Nom du pipeline]</code></li>
<li>Renommez et modifiez la copie selon vos besoins</li>
</ol>
<blockquote>
<p><strong>Note :</strong> Cette option est disponible pour les pipelines <strong>Classic Build</strong> et <strong>Classic Release</strong>. Pour les pipelines YAML, l’approche est différente (voir méthode 2).</p>
</blockquote>
<h3><a name="p-34588-pour-les-pipelines-release-cd-4" class="anchor" href="#p-34588-pour-les-pipelines-release-cd-4" aria-label="Heading link"></a>Pour les pipelines Release (CD)</h3>
<ol>
<li>Allez dans <strong>Pipelines</strong> > <strong>Releases</strong></li>
<li>Sélectionnez votre pipeline de release</li>
<li>Cliquez sur le menu <strong>“…”</strong> > <strong>“Clone”</strong></li>
<li>La copie est créée dans le même projet</li>
</ol>
<h2><a name="p-34588-mthode-2-exportimport-de-pipeline-classic-entre-projets-5" class="anchor" href="#p-34588-mthode-2-exportimport-de-pipeline-classic-entre-projets-5" aria-label="Heading link"></a>Méthode 2 : Export/Import de pipeline Classic (entre projets)</h2>
<p>Pour copier un pipeline vers un <strong>autre projet</strong> ou une <strong>autre organisation</strong> :</p>
<h3><a name="p-34588-export-6" class="anchor" href="#p-34588-export-6" aria-label="Heading link"></a>Export</h3>
<ol>
<li>Dans le pipeline Classic, cliquez sur les trois points <strong>(…)</strong> > <strong>“Export”</strong> ou <strong>“Exporter”</strong></li>
<li>Un fichier JSON est téléchargé sur votre machine</li>
</ol>
<h3><a name="p-34588-import-7" class="anchor" href="#p-34588-import-7" aria-label="Heading link"></a>Import</h3>
<ol>
<li>Dans le projet de destination, allez dans <strong>Pipelines</strong> > <strong>Pipelines</strong></li>
<li>Cliquez sur <strong>“New pipeline”</strong> > <strong>“Import a pipeline”</strong> (ou <strong>“Importer un pipeline”</strong>)</li>
<li>Sélectionnez le fichier JSON exporté</li>
<li>Le pipeline est recréé — vous devrez reconfigurer les <strong>connections de service</strong> et les <strong>agents pools</strong> qui diffèrent entre projets</li>
</ol>
<h2><a name="p-34588-mthode-3-duplication-de-pipeline-yaml-recommande-8" class="anchor" href="#p-34588-mthode-3-duplication-de-pipeline-yaml-recommande-8" aria-label="Heading link"></a>Méthode 3 : Duplication de pipeline YAML (recommandée)</h2>
<p>Pour les pipelines <strong>YAML</strong> (la méthode moderne recommandée), la duplication se fait au niveau du fichier YAML lui-même.</p>
<h3><a name="p-34588-copier-le-fichier-yaml-9" class="anchor" href="#p-34588-copier-le-fichier-yaml-9" aria-label="Heading link"></a>Copier le fichier YAML</h3>
<pre data-code-wrap="bash"><code class="lang-bash"># Dans votre dépôt Git
cp azure-pipelines.yml azure-pipelines-nouveau.yml
</code></pre>
<h3><a name="p-34588-crer-un-nouveau-pipeline-pointant-vers-le-nouveau-fichier-10" class="anchor" href="#p-34588-crer-un-nouveau-pipeline-pointant-vers-le-nouveau-fichier-10" aria-label="Heading link"></a>Créer un nouveau pipeline pointant vers le nouveau fichier</h3>
<ol>
<li>Allez dans <strong>Pipelines</strong> > <strong>New pipeline</strong></li>
<li>Sélectionnez votre dépôt</li>
<li>Choisissez <strong>“Existing Azure Pipelines YAML file”</strong></li>
<li>Sélectionnez le fichier <code>azure-pipelines-nouveau.yml</code></li>
<li>Configurez les variables et triggers selon vos besoins</li>
</ol>
<h3><a name="p-34588-utiliser-les-templates-yaml-pour-viter-la-duplication-11" class="anchor" href="#p-34588-utiliser-les-templates-yaml-pour-viter-la-duplication-11" aria-label="Heading link"></a>Utiliser les templates YAML pour éviter la duplication</h3>
<p>La vraie bonne pratique est d’utiliser les <strong>templates YAML</strong> pour partager des configurations entre pipelines :</p>
<pre data-code-wrap="yaml"><code class="lang-yaml"># templates/build-steps.yml (template réutilisable)
parameters:
- name: buildConfiguration
type: string
default: 'Release'
- name: dotnetVersion
type: string
default: '8.x'
steps:
task: UseDotNet@2
displayName: 'Installer .NET ${{ parameters.dotnetVersion }}'
inputs:
version: '${{ parameters.dotnetVersion }}'
task: DotNetCoreCLI@2
displayName: 'Build - ${{ parameters.buildConfiguration }}'
inputs:
command: 'build'
arguments: '--configuration ${{ parameters.buildConfiguration }}'
task: DotNetCoreCLI@2
displayName: 'Tests unitaires'
inputs:
command: 'test'
arguments: '--configuration ${{ parameters.buildConfiguration }} --collect:"XPlat Code Coverage"'
</code></pre>
<pre data-code-wrap="yaml"><code class="lang-yaml"># azure-pipelines-app1.yml - Pipeline pour l'application 1
trigger:
branches:
include: [main, develop]
paths:
include: ['src/App1/**']
variables:
buildConfiguration: 'Release'
pool:
vmImage: 'ubuntu-latest'
stages:
- stage: Build
jobs:
- job: BuildJob
steps:
- template: templates/build-steps.yml
parameters:
buildConfiguration: $(buildConfiguration)
dotnetVersion: '8.x'
</code></pre>
<pre data-code-wrap="yaml"><code class="lang-yaml"># azure-pipelines-app2.yml - Pipeline pour l'application 2 (réutilise le même template)
trigger:
paths:
include: ['src/App2/**']
pool:
vmImage: 'ubuntu-latest'
stages:
- stage: Build
jobs:
- job: BuildJob
steps:
- template: templates/build-steps.yml
parameters:
buildConfiguration: 'Debug'
dotnetVersion: '6.x'
</code></pre>
<h2><a name="p-34588-mthode-4-azure-devops-cli-12" class="anchor" href="#p-34588-mthode-4-azure-devops-cli-12" aria-label="Heading link"></a>Méthode 4 : Azure DevOps CLI</h2>
<p>L’Azure DevOps CLI (extension <code>az devops</code>) permet de gérer les pipelines par script.</p>
<h3><a name="p-34588-installation-et-configuration-13" class="anchor" href="#p-34588-installation-et-configuration-13" aria-label="Heading link"></a>Installation et configuration</h3>
<pre data-code-wrap="bash"><code class="lang-bash"># Installer l'extension Azure DevOps CLI
az extension add --name azure-devops
Se connecter
az devops configure --defaults organization=https://dev.azure.com/MonOrganisation project=MonProjet
az devops login
</code></pre>
<h3><a name="p-34588-lister-et-exporter-les-dfinitions-de-pipeline-14" class="anchor" href="#p-34588-lister-et-exporter-les-dfinitions-de-pipeline-14" aria-label="Heading link"></a>Lister et exporter les définitions de pipeline</h3>
<pre data-code-wrap="bash"><code class="lang-bash"># Lister tous les pipelines du projet
az pipelines list --output table
Obtenir la définition JSON d'un pipeline spécifique
az pipelines show --id 42 --output json > pipeline-backup.json
Ou par nom
az pipelines show --name "MonPipeline" --output json > pipeline-backup.json
</code></pre>
<h3><a name="p-34588-crer-un-pipeline-depuis-une-dfinition-yaml-15" class="anchor" href="#p-34588-crer-un-pipeline-depuis-une-dfinition-yaml-15" aria-label="Heading link"></a>Créer un pipeline depuis une définition YAML</h3>
<pre data-code-wrap="bash"><code class="lang-bash"># Créer un nouveau pipeline YAML
az pipelines create \
--name "MonPipeline-Copie" \
--repository "MonRepo" \
--branch "main" \
--yml-path "azure-pipelines-copie.yml" \
--repository-type tfsgit
Créer dans un autre projet
az pipelines create \
--name "MonPipeline-Copie" \
--repository "MonRepo" \
--branch "main" \
--yml-path "azure-pipelines.yml" \
--organization "https://dev.azure.com/AutreOrganisation" \
--project "AutreProjet"
</code></pre>
<h3><a name="p-34588-script-de-copie-automatise-16" class="anchor" href="#p-34588-script-de-copie-automatise-16" aria-label="Heading link"></a>Script de copie automatisée</h3>
<pre data-code-wrap="bash"><code class="lang-bash">#!/bin/bash
Script pour copier un pipeline entre projets
SOURCE_ORG="https://dev.azure.com/SourceOrganisation"
SOURCE_PROJECT="SourceProjet"
DEST_ORG="https://dev.azure.com/DestinationOrganisation"
DEST_PROJECT="DestinationProjet"
PIPELINE_NAME="MonPipeline"
echo "Récupération de la définition du pipeline source..."
az pipelines show \
--name "$PIPELINE_NAME" \
--organization "$SOURCE_ORG" \
--project "$SOURCE_PROJECT" \
--output json > /tmp/pipeline-definition.json
echo "Le pipeline a été exporté dans /tmp/pipeline-definition.json"
echo "Veuillez adapter les repository, service connections et variables, puis relancer."
</code></pre>
<h2><a name="p-34588-mthode-5-api-rest-azure-devops-17" class="anchor" href="#p-34588-mthode-5-api-rest-azure-devops-17" aria-label="Heading link"></a>Méthode 5 : API REST Azure DevOps</h2>
<p>Pour une intégration programmatique complète :</p>
<pre data-code-wrap="powershell"><code class="lang-powershell"># Script PowerShell pour cloner un pipeline via l'API REST
$organization = "MonOrganisation"
$sourceProject = "SourceProjet"
$destProject = "DestinationProjet"
$pipelineId = 42
$pat = "votre-personal-access-token" # Créez un PAT dans Azure DevOps
$headers = @{
Authorization = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$pat"))
"Content-Type" = "application/json"
}
Récupérer la définition du pipeline source
$sourceUrl = "https://dev.azure.com/$organization/$sourceProject/_apis/build/definitions/$pipelineId`?api-version=7.1"
$pipelineDef = Invoke-RestMethod -Uri $sourceUrl -Headers $headers -Method Get
Modifier pour le projet de destination
$pipelineDef.name = "$($pipelineDef.name) - Copie"
$pipelineDef.PSObject.Properties.Remove('id')
$pipelineDef.PSObject.Properties.Remove('revision')
$pipelineDef.PSObject.Properties.Remove('uri')
$pipelineDef.PSObject.Properties.Remove('url')
Créer dans le projet de destination
$destUrl = "https://dev.azure.com/$organization/$destProject/_apis/build/definitions?api-version=7.1"
$body = $pipelineDef | ConvertTo-Json -Depth 20
$newPipeline = Invoke-RestMethod -Uri $destUrl -Headers $headers -Method Post -Body $body
Write-Output "Pipeline créé avec l'ID : $($newPipeline.id)"
</code></pre>
<h2><a name="p-34588-copier-les-variables-de-pipeline-18" class="anchor" href="#p-34588-copier-les-variables-de-pipeline-18" aria-label="Heading link"></a>Copier les variables de pipeline</h2>
<p>N’oubliez pas que les <strong>variables de pipeline</strong> et les <strong>variables secrètes</strong> ne sont pas incluses dans l’export/clone automatique.</p>
<pre data-code-wrap="bash"><code class="lang-bash"># Lister les variables d'un pipeline
az pipelines variable list --pipeline-id 42
Ajouter une variable au pipeline copié
az pipelines variable create \
--pipeline-id 99 \
--name "MonVariable" \
--value "MaValeur"
Ajouter une variable secrète
az pipelines variable create \
--pipeline-id 99 \
--name "MonSecret" \
--value "ValeurSecrète" \
--secret true
</code></pre>
<h2><a name="p-34588-copier-les-environnements-et-approvals-19" class="anchor" href="#p-34588-copier-les-environnements-et-approvals-19" aria-label="Heading link"></a>Copier les environnements et approvals</h2>
<p>Si votre pipeline utilise des <strong>Environments</strong> (pour les approvals et gates) :</p>
<pre data-code-wrap="bash"><code class="lang-bash"># Lister les environnements
az devops invoke \
--area distributedtask \
--resource environments \
--organization https://dev.azure.com/MonOrganisation \
--project MonProjet \
--api-version "7.1"
Créer un environnement dans le projet de destination
az devops invoke \
--area distributedtask \
--resource environments \
--organization https://dev.azure.com/MonOrganisation \
--project DestinationProjet \
--http-method POST \
--in-file environment-definition.json \
--api-version "7.1"
</code></pre>
<h2><a name="p-34588-bonnes-pratiques-pour-la-gestion-des-pipelines-20" class="anchor" href="#p-34588-bonnes-pratiques-pour-la-gestion-des-pipelines-20" aria-label="Heading link"></a>Bonnes pratiques pour la gestion des pipelines</h2>
<h3><a name="p-34588-structurer-vos-pipelines-pour-faciliter-la-rutilisation-21" class="anchor" href="#p-34588-structurer-vos-pipelines-pour-faciliter-la-rutilisation-21" aria-label="Heading link"></a>Structurer vos pipelines pour faciliter la réutilisation</h3>
<pre data-code-wrap="yaml"><code class="lang-yaml"># Utiliser des variable groups partageables
variables:
- group: "Variables-Communes" # Groupe de variables Azure DevOps
- group: "Variables-Environnement-Prod"
- name: buildConfiguration
value: 'Release'
</code></pre>
<h3><a name="p-34588-utiliser-des-pipeline-templates-dans-un-dpt-centralis-22" class="anchor" href="#p-34588-utiliser-des-pipeline-templates-dans-un-dpt-centralis-22" aria-label="Heading link"></a>Utiliser des pipeline templates dans un dépôt centralisé</h3>
<pre data-code-wrap="yaml"><code class="lang-yaml"># Référencer un template depuis un autre dépôt
resources:
repositories:
- repository: templates
type: git
name: MonOrganisation/PipelineTemplates
ref: refs/heads/main
stages:
- template: stages/build-and-test.yml@templates
parameters:
buildConfiguration: Release
</code></pre>
<hr>
<p>En résumé, pour une copie rapide dans le même projet, utilisez la fonctionnalité <strong>Clone</strong> native de l’interface Azure DevOps. Pour copier entre projets ou automatiser la duplication, l’approche <strong>YAML avec templates</strong> est la plus robuste et maintenable à long terme.</p>
<p>Si vous pouvez préciser votre cas d’usage (pipeline Classic ou YAML, même projet ou migration vers un autre projet/organisation), je pourrai vous fournir une procédure encore plus détaillée adaptée à votre situation spécifique.</p>