Annulation automatique des commits qui échouent à la construction

44

Un de mes collègues m'a dit qu'il envisageait de faire en sorte que notre serveur d'initialisation rétablisse les validations ayant échoué lors de la compilation, de sorte que le HEADin masterest toujours stable (comme si la génération était au moins transmise).

S'agit-il d'une meilleure pratique ou cela risque-t-il de poser plus de problèmes que de laisser le masterfichier brisé jusqu'à ce que le développeur le corrige?

Ma pensée est que la révocation du commit rendra plus complexe la tâche de lecture du commit et du correctif (le développeur devra revenir sur le revert puis valider le correctif, ce qui encombrera également le git log) et nous devrions simplement laisser le commit, puis commettre le réparer. Bien que je voie certains avantages à avoir la masterstabilité, cette inversion d'échec des commits ne me convainc pas.

edit: Peu importe qu'il s'agisse d' masterune autre branche de développement ou d'une autre branche de développement, mais la question reste la même: le système CI doit-il annuler une validation ayant échoué à la construction?

une autre (longueur) edit: Ok, nous utilisons gitd'une manière étrange. Nous pensons que le concept de branche va à l’encontre du véritable IC, car s’engager dans une branche vous isole des autres développeurs et de leurs modifications, et ajoute un temps supplémentaire pour la réintégration de votre branche et le traitement des conflits éventuels. Si tout le monde s'engage dans mastercette voie, les conflits sont réduits au minimum et chaque commit réussit tous les tests.

Bien sûr, cela vous oblige à ne pousser que de manière stable (ou vous cassez la construction) et à programmer plus soigneusement pour ne pas annuler la compatibilité avec les versions antérieures ni faire basculer les fonctionnalités lors de l'introduction de nouvelles fonctionnalités.

Il y a des compromis à faire CI tel ou tel moyen, mais c'est hors de la portée de la question (voir la question connexe à ce sujet). Si vous préférez, je peux reformuler la question: une petite équipe de développeurs travaillent ensemble dans une branche. Si un développeur valide quelque chose qui rompt la construction de cette branche, le système de CI doit-il annuler le commit ou non?

Carlos Campderrós
la source
38
Les constructions échouées n'auraient jamais dû arriver masterpour commencer. C'est à cela que servent les branches de développement et de fonctionnalités. Ces modifications vont ensuite dans quelque chose comme une branche d'intégration où vous pouvez tester si toutes les nouvelles fonctionnalités de plusieurs développeurs fonctionneront ensemble et ce, uniquement si cela est testé, peut aller en master. Ou du moins c'est un flux de travail possible.
Thorsten Müller
1
@ thorstenmüller imagine bien que c’est dans une branche de développement que tous les développeurs utilisent. Le système CI doit-il rétablir les commits qui échouent à la construction?
Carlos Campderrós
7
Il semble que vous utilisiez git d'une manière étrange. En règle générale, les utilisateurs doivent travailler sur leurs propres référentiels dans leurs propres succursales et ne pousser que vers le principal une fois que CI pour leur version personnelle vérifie que les modifications sont correctes.
Wilbert
4
> "ces conflits sont réduits au minimum"; vous obtenez moins de conflits au moment de la fusion, mais vous avez des problèmes avec les mauvaises fusions beaucoup plus. La solution consiste à fusionner en permanence du maître à votre branche dans le cadre de votre processus, et non à ne pas créer de branche.
deworde
2
... Pourquoi ne pas faire en sorte que les constructions qui échouent ne soient pas acceptées dans master pour commencer?
user253751

Réponses:

56

Je serais contre cela pour les raisons suivantes:

  • Chaque fois que vous configurez un outil automatisé pour modifier le code en votre nom , vous risquez de vous tromper ou de vous exposer au cas où vous en auriez besoin pour ne plus effectuer ce changement (par exemple, la dernière version de Google Mock). il y avait un bogue, donc ce n'est pas votre code qui échoue) et vous devez perdre du temps à le reconfigurer De plus, il y a toujours un risque faible que la compilation échoue à cause d'un bogue dans le système de compilation plutôt que d'un bogue dans votre code. Pour moi, CI signifie gagner la confiance que mon code est correct; cela ne ferait que le transformer en une autre source de problèmes potentiels sur lesquels je devrais m'inquiéter.

  • Les types de bugs qui cassent "la construction" devraient être des erreurs stupides qui prennent très peu de temps à corriger (comme vous l'avez indiqué dans un commentaire, cela est vrai pour vous). Si des bogues plus complexes et plus subtils parviennent régulièrement à maîtriser le fichier maître, la solution correcte consiste à ne pas "réparer le problème plus rapidement", mais à faire plus attention lors de l'examen des branches de fonctionnalités avant leur fusion.

  • Laisser le maître inconcevable pendant quelques minutes pendant que le bogue est corrigé correctement ne fait de mal à personne. Ce n'est pas comme si le chef de la direction vérifiait personnellement maître et publiait le code directement à l'intention des clients à tout moment (au moins, espérons-le, pas sans votre participation). Dans le cas très improbable que vous avez besoin de sortir quelque chose avant de pouvoir corriger le bug, alors vous pouvez facilement prendre la décision de revenir manuellement avant de publier.

Ixrec
la source
1
En outre, seules les versions réussies devraient déclencher la création d’une "copie de génération" pouvant être déployée. En cas d'échec d'une génération, il ne devrait y avoir aucune suppression de génération déployable. Par conséquent, il ne devrait y avoir aucun risque que quelqu'un publie un code incorrect pour les clients.
Mark Freedman
1
il y a certainement une autre option qui est utilisée et qui est meilleure que celle-ci et je pense qu'elle est très utilisée (nous l'utilisons sur Twitter). ne mettez pas les versions ratées sur le maître ET les erreurs idiotes sont faciles à corriger également. Voir ma réponse complète ci-dessous.
Dean Hiller
26

Mettons-nous d'accord sur les termes d'abord.

Personnellement, j’utilise les termes construction continue et intégration continue pour distinguer deux scénarios différents:

  • Construction continue: outil qui vérifie périodiquement si le référentiel a changé depuis la dernière construction et construit / teste si c'est le cas.
  • Intégration continue: un outil qui prend les demandes d'extraction et les valide par rapport à la dernière en-tête avant de les rendre visibles.

Ce dernier, Intégration continue, signifie que le référentiel qu'il protège est toujours vert 1 : il est strictement meilleur.

Votre question n’a vraiment de sens que pour la construction en continu, je vais donc vous répondre en supposant qu’il s’agit de votre configuration.

1 : Les causes environnementales peuvent également gâcher une construction, par exemple un test avec une année codée en dur (2015) peut commencer à échouer en janvier 2016, un disque peut être plein, ... et bien sûr, il y a le fléau de l'instable tests. J'ignore hautainement ces problèmes ici; sinon nous n'irons jamais nulle part.


Si vous avez une configuration de construction continue, vous pouvez en effet automatiser l’inversion des validations qui ont pu rompre la construction, mais il existe plusieurs subtilités.

  • Vous ne pouvez pas réellement supprimer les commits: d’autres collègues les ont peut-être déjà extraites et les repousseront lors de la prochaine tentative de validation. Au lieu de cela, une inversion devrait être commettre un diff inverse . Oh, et vos collègues vous haïront d'avoir inversé leur travail quand c'était correct car ils devront trouver un moyen de le repousser à nouveau ...
  • En fait, vous ne pouvez pas seulement supprimer le dernier commit (il s'agit d'une fusion), mais vous devez supprimer tous les commits ... jusqu'à un certain point. Par exemple, le dernier bon commit connu (à prendre en compte lors du démarrage du système).
  • Vous devez penser aux causes externes (problèmes environnementaux) et éviter une configuration qui rétablisse tout au jour 0. Heureusement, le retour à la dernière bonne modification connue élude ce problème.
  • Vous devez penser que la dernière version correcte connue risque de ne plus être générée (problèmes d'environnement), auquel cas il est probable que tous les commits ultérieurs seront annulés. Idéalement, en cas d’échec, et avant de revenir en arrière, vous devriez extraire la dernière bonne version connue et la tester à nouveau. Si elle réussit, revenez, sinon, déclenchez une alerte.

Notez qu'avec ce système, dans le cas d'un test instable ou d'un collègue qui commet souvent de la merde, de nombreux bons commits seront inversés. Vos collègues vont alors vous haïr.


J'espère que mon récit d'horreur a exposé les problèmes liés à l'autorisation d'un référentiel endommagé. Vous allez maintenant implémenter un pipeline d'intégration continue approprié dans lequel les relations publiques ne sont jamais directement poussées dans le référentiel, mais mises en file d'attente pour être fusionnées dans une file d'attente de travail et intégrées un par un ( ou par des cumuls):

  • chercher la tête du dépôt localement
  • appliquer les demandes de tirage
  • construire et tester
  • en cas de succès, pousser vers le référentiel, sinon marquer comme ayant échoué
  • passer aux demandes suivantes

Ayant essayé les deux, c'est strictement mieux.

Matthieu M.
la source
2
C’est effectivement la bonne solution - la bonne solution consiste à éviter que de mauvais changements n’atteignent la branche principale, au lieu de la laisser atterrir, puis de la faire reculer.
Daniel Pryden
Je pense que le problème ici est que le questionneur pense que les coûts déclarés pour "vous isoler des autres développeurs et de leurs modifications" dépassent les avantages. Les coûts indiqués sont le risque accru de fusions non triviales lorsque deux personnes plus longues divergent. OMI, l'avantage d'être isolé du code erroné est évident. Le questionneur veut adopter une stratégie "optimiste", dans laquelle un code erroné est brièvement disponible master, puis corriger cette situation une fois que les tests ont échoué. Tout le monde adopte une stratégie "pessimiste", comme vous le conseillez, et ne rend disponible que le code de passage.
Steve Jessop
(où par "disponible pour tirer", je veux dire "tirer de master", ce qui est idéalement quelque chose que les développeurs peuvent faire bon gré mal gré, mais pour ce faire, vous devez retarder l'arrivée des validations masteravant leur test et leur réussite. Si un développeur veut cherry-pick code non testé ou testé et échoué c'est bien aussi, et le code est "disponible" dans ce sens-là, ce n'est tout simplement pas ce dont je parle)
Steve Jessop
La bonne solution consiste à éviter que de mauvais changements n'atteignent TOUTE succursale. Les commits échoués ne devraient jamais être rendus publics, jamais.
Miles Rout
5

S'agit-il d'une meilleure pratique ou peut-être plus problématique que de laisser master brisé jusqu'à ce que le développeur la corrige?

C'est problématique. Une personne qui décide que "le chef HEAD est cassé; je reviens sur le changement le plus élevé" est complètement différente du système CI qui fait de même.

Voici quelques inconvénients:

  • Des erreurs dans le processus d'inversion automatique vont bousiller le référentiel;

  • cela suppose un unique changeset (le plus haut) foiré la construction (ce qui est irréaliste)

  • Les mainteneurs auront plus de travail à faire pour résoudre le problème que de simples enquêtes et validations (ils devront également examiner l'historique inversé)

Nous pensons que le concept de branche va à l’encontre du véritable IC, car s’engager dans une branche vous isole des autres développeurs et de leurs modifications, et ajoute un temps supplémentaire pour la réintégration de votre branche et le traitement des conflits éventuels.

Cette croyance (branches vs CI) est incorrecte. Pensez à conserver une branche stable dans laquelle vous ne commettez que des ensembles de modifications testés par unités . Les autres (branches spécialisées et branches locales) doivent être sous la responsabilité de chaque développeur et ne doivent en aucun cas faire partie de votre stratégie CI.

Dans les branches de fonctionnalités, vous souhaitez être isolé des autres développeurs. Cela vous permet de:

  • effectuer un codage exploratoire

  • expérimenter avec la base de code

  • effectuez des validations partielles (commettez effectivement du code qui ne fonctionne pas) pour configurer des points de sauvegarde (au cas où vous feriez faillite), pour créer un historique des modifications plus significatif (via des messages de validation), pour sauvegarder votre travail et passer complètement à autre chose (dans le temps qu'il vous faut pour écrire "git commit && git checkout")

  • effectuer des tâches de faible priorité qui prennent beaucoup de temps (par exemple, vous souhaitez effectuer un refactoring qui modifie les 80 classes du calque de données: vous en modifiez deux par jour, jusqu'à ce que vous les modifiiez toutes et que le code soit compilé (mais vous pouvez le faire sans affecter personne jusqu’à ce que vous puissiez effectuer un seul commit).

Si un développeur valide quelque chose qui rompt la construction de cette branche, le système de CI doit-il annuler le commit ou non?

Cela ne devrait pas. La validation du code stable sur votre branche CI est une responsabilité du committer, pas un système automatisé.

utnapistim
la source
2

Je suggérerais d'utiliser un environnement Gerrit + Jenkins pour garder votre branche maîtresse toujours en forme. Les gens transmettent leur nouveau code à Gerrit, ce qui déclenche un travail Jenkins pour extraire le correctif, les versions, les tests, etc. Si d'autres développeurs aiment votre correctif et que Jenkins termine son travail avec succès, alors Gerrit fusionnera ce morceau de code dans votre branche principale.

C'est un environnement similaire décrit par @ brian-vandenberg

En plus de maintenir votre branche en bon état, vous ajoutez également une étape de révision du code qui améliore la qualité du code et le partage des connaissances sur votre logiciel.

[1] Jenkins https://jenkins-ci.org/

[2] Gerrit https://www.gerritcodereview.com/

Gustavo Coelho
la source
1

L'IC ne doit jamais modifier l'historique de validation du référentiel.

La solution correcte ici est de ne pas ajouter d’engagements à la branche principale s’ils n’ont pas été testés et vérifiés.

Travaillez-vous sur les branches de caractéristiques, faites-vous que le CI s’exécute automatiquement, et si les générations échouent, ne les fusionnez pas en maître.

Vous pouvez avoir une génération supplémentaire qui teste les fusions si cela pose un problème, en s'exécutant sur la branche de fonctionnalité et, au cours de la génération, en fusionnant maître / intégration / quoi que ce soit dans la branche locale, puis en exécutant des tests.

Daenyth
la source
1
Cela ne répond en aucune façon à la question. Si la construction échoue dans une branche de fonctionnalité, le CI doit-il annuler la validation?
Carlos Campderrós
Que se passe-t-il si la construction réussit sur la branche de fonctionnalité, mais échoue après la fusion?
Matthieu M.
@MatthieuM. la fusion est un commit, l’étape de CI qui fusionne doit-elle inverser la construction?
Carlos Campderrós
@ CarlosCampderrós: ​​Personnellement, je n'aurais jamais une configuration qui tente de revenir en arrière commet; beaucoup trop compliqué.
Matthieu M.
J'ai adressé les commentaires.
Daenyth
1

Nous utilisons Jenkins pour notre serveur de génération et le modèle de gatekeeper pour pousser les commits - où une combinaison de Jenkins et de déclencheurs de commit (garantissant que les relecteurs homologues ont bien fait leur travail) constitue le gatekeeper.

Les commits sont poussés indirectement via une boucle vers Jenkins, où il clone le référentiel principal, puis extrait le ou les commit (s) à fusionner et exécute toutes les générations requises (pour Linux / solaris). Si toutes les constructions sont terminées, le commit est poussé.

Cela évite beaucoup, sinon tous les problèmes discutés jusqu'à présent:

  • altération de l'histoire
  • obtenir l'histoire correcte si vous êtes le dev qui doit réparer la casse
  • l'instabilité (sous la forme de constructions brisées) n'est jamais introduite

Cela nous permet également d'appliquer directement d'autres exigences, telles que la réussite des tests unitaires.

Brian Vandenberg
la source
re: le downvote, pourriez-vous nous dire ce que vous n’avez pas aimé dans ma réponse?
Brian Vandenberg
0

Combien de fois avez-vous reçu cet e-mail automatisé disant que votre dernier commit avait cassé la construction? Combien de fois est-ce mal? Mais maintenant, vous devez vérifier si c'est bien vous-même ou quelqu'un d'autre qui a commis un autre commit à peu près au même moment. Ou peut-être que c'était quelque chose d'environnement.

Si le système ne le sait pas avec certitude, je ne souhaite certainement pas l’automatiser.

Mohair
la source
0

La question posée est imparfaite. Je respecte cette déclaration si

"Nous pensons que le concept de branches va à l'encontre de la réalité CI, car s'engager dans une branche vous isole des autres développeurs et de leurs modifications"

Ce que vous devriez faire cependant, c'est ces étapes

  • travaillez hors du maître si vous voulez (c'est bien et continuez à tirer les changements de tout le monde) MAIS ne vous engagez pas à maîtriser localement
  • AVANT DE valider vos modifications, créez une branche avec submit_XXXXXX.
  • demandez à votre compilation automatisée de récupérer toutes les branches submit_XXX
  • Option 1: construire des ruptures ou fusionner des ruptures ... le changement est rejeté et il ne tombe jamais sur le maître
  • Option 2: la compilation fonctionne, Jenkins pousse le maître et le met à jour

ALORS, ce que nous faisons est de mettre un crochet git commit à empêcher TOUT LE MONDE de s’engager réellement à maîtriser. Cela fonctionne très bien… AUCUNE construction cassée n’a jamais été prise et AUCUN retour ne sera effectué par le maître.

plus tard, Dean

Dean Hiller
la source