- Azure DevOps
- Terraform
Dans ce tutoriel, nous allons configurer les policies à appliquer pour chaque repository dans notre projet Azure DevOps à l’aide de Terraform !
Ce tutoriel fait partie d’une série complète de tutoriels sur la configuration d’Azure DevOps à l’aide de Terraform. Vous pouvez télécharger le projet de la partie précédente et suivre.
Dans un tutoriel précédent vous avez créé vos repository, mais pour y contribuer en utilisant les Pull Requests, vous devez configurer une liste de bonnes pratiques pour éviter que du mauvais code ne soit déployé en production. Donc, pour y parvenir, vous pouvez utiliser le concept de policies
et l’appliquer à toutes les branches dont vous avez besoin.
Pour les besoins de ce tutoriel, nous appliquerons les policies
uniquement sur la branche par défaut, cependant il est vraiment recommandé de l’appliquer sur chaque branche qui a du sens pour votre projet.
Vous avez plusieurs policies à définir pour verrouiller et standardiser vos Pull Requests :
Voyons comment configurer les cinq premiers en créant un nouveau fichier appelé repos_policies.tf
.
Notez également dans les prochains exemples de codes, que vous devez ajouter la propriété
depends_on
pour chacune des policies déclarées, car les fichiers par défaut que vous avez ajoutés dans le repository doivent être poussés avant d’activer les policies. Si vous ne le faites pas, vous obtiendrez une erreur vous indiquant que les policies sont déjà définies et que vous ne pouvez pas pousser vos fichiers par défaut sans passer par une Pull Request, ce qui n’est pas le comportement que vous souhaitez lors de l’initialisation du repository.
## Nombre minimal de relecteurs
Comme vous pouvez le voir ci-dessous, vous définissez un azuredevops_branch_policy_min_reviewers
et parcourez une liste de repositories comme nous l’avons défini dans un tutoriel précédent.
resource "azuredevops_branch_policy_min_reviewers" "this" {
count = length(var.repositories)
project_id = azuredevops_project.this.id
enabled = true
blocking = true
settings {
reviewer_count = 1
submitter_can_vote = false
last_pusher_cannot_approve = true
allow_completion_with_rejects_or_waits = false
on_push_reset_approved_votes = false
on_last_iteration_require_vote = false
scope {
repository_id = azuredevops_git_repository.this[count.index].id
repository_ref = azuredevops_git_repository.this[count.index].default_branch
match_type = "Exact"
}
}
depends_on = [
azuredevops_git_repository_file.default_pipeline,
azuredevops_git_repository_file.default_gitignore,
]
}
resource "azuredevops_branch_policy_work_item_linking" "this" {
count = length(var.repositories)
project_id = azuredevops_project.this.id
enabled = true
blocking = true
settings {
scope {
repository_id = azuredevops_git_repository.this[count.index].id
repository_ref = azuredevops_git_repository.this[count.index].default_branch
match_type = "Exact"
}
}
depends_on = [
azuredevops_git_repository_file.default_pipeline,
azuredevops_git_repository_file.default_gitignore,
]
}
Ci-dessus, vous demandez à l’utilisateur d’ajouter le work item lié à la branche pour une Pull Request. Ceci est utile pour comprendre le code ajouté.
Maintenant, quelque chose de vraiment important concernant les Pull Requests, assurez-vous que les commentaires ont tous été résolus avant de pouvoir les fusionner :
resource "azuredevops_branch_policy_comment_resolution" "this" {
count = length(var.repositories)
project_id = azuredevops_project.this.id
enabled = true
blocking = true
settings {
scope {
repository_id = azuredevops_git_repository.this[count.index].id
repository_ref = azuredevops_git_repository.this[count.index].default_branch
match_type = "Exact"
}
}
depends_on = [
azuredevops_git_repository_file.default_pipeline,
azuredevops_git_repository_file.default_gitignore,
]
}
En fonction des règles que vous avez fixées avec votre équipe, il est important de définir le type de fusion que vous souhaitez pour chaque branche. Par exemple, le squash
peut être bon lorsque vous fusionnez une fonctionnalité sur la branche develop
. Ainsi, vous vous retrouvez avec un seul commit avec un message formaté au lieu d’avoir tous les commits de la branche de la fonctionnalité, ce qui peut être un peu brouillon.
resource "azuredevops_branch_policy_merge_types" "this" {
count = length(var.repositories)
project_id = azuredevops_project.this.id
enabled = true
blocking = true
settings {
allow_squash = true
allow_rebase_and_fast_forward = false
allow_basic_no_fast_forward = true
allow_rebase_with_merge = false
scope {
repository_id = azuredevops_git_repository.this[count.index].id
repository_ref = azuredevops_git_repository.this[count.index].default_branch
match_type = "Exact"
}
}
depends_on = [
azuredevops_git_repository_file.default_pipeline,
azuredevops_git_repository_file.default_gitignore,
]
}
Le dernier que vous verrez est probablement le plus important. L’ajout d’une validation de build garantit qu’un pipeline Azure DevOps a exécuté votre code. Ce pipeline doit avoir au minimum, l’exécution de vos tests unitaires, le build du projet et si vous le pouvez, d’autres outils de scan comme Sonar, Checkmarks, etc.. pour valider la qualité de votre code.
resource "azuredevops_branch_policy_build_validation" "this" {
count = length(var.repositories)
project_id = azuredevops_project.this.id
enabled = true
blocking = true
settings {
display_name = "Pull Request Check"
build_definition_id = azuredevops_build_definition.build_definitions[count.index].id
valid_duration = 720 # minutes => 12 hours
scope {
repository_id = azuredevops_git_repository.this[count.index].id
repository_ref = azuredevops_git_repository.this[count.index].default_branch
match_type = "Exact"
}
}
depends_on = [
azuredevops_git_repository_file.default_pipeline,
azuredevops_git_repository_file.default_gitignore,
]
}
Vous pouvez trouver toutes les policies disponibles dans la documentation de Terraform.
Vous pouvez maintenant exécuter la nouvelle commande de planification de Terraform comme ceci :
terraform plan -var-file=env.tfvars --out=plan.out
Et puis appliquez-le plan:
terraform apply plan.out
En conséquence, tous vos repositories auront des stratégies dans la branche par défaut et tout le nouveau code ne sera ajouté à cette branche que par une Pull Request.
Vous avez maintenant vos référentiels de branche par défaut protégés par certaines politiques utilisant Terraform. Vous trouverez le code source complet dans ce dépôt Github.