Ripristina automaticamente i commit che falliscono la compilazione

39

Un mio collega mi ha detto che sta pensando di fare in modo che il nostro server CI ripristini i commit che hanno fallito la build, quindi il HEAD in master è sempre stabile (come nel passare almeno la build).

Questa è una best practice o potrebbe essere più problematica di lasciare solo master interrotta finché lo sviluppatore non la risolve?

Il mio pensiero è che il ripristino del commit renderà più complesso il compito di leggere il commit e la correzione (lo sviluppatore dovrà ripristinare il ripristino e quindi eseguire il commit della correzione, che ingombra anche il git log ) e dovremmo partire il commit e quindi esegue il commit della correzione. Anche se vedo alcuni vantaggi nell'avere master stabile, questo ripristino di commit non riuscite non mi convince.

modifica: non importa se è master o qualsiasi altro ramo di sviluppo, ma la domanda rimane la stessa: il sistema CI dovrebbe ripristinare un commit che ha fallito la compilazione?

un'altra modifica (lenghty): Ok, stiamo usando git in un modo strano. Crediamo che il concetto di filiali vada contro l'IC reale, perché il commit su una filiale ti isola dagli altri sviluppatori e dai loro cambiamenti e aggiunge tempo quando devi reintegrare la tua filiale e affrontare possibili conflitti. Se tutti si impegnano a master , questi conflitti vengono ridotti al minimo e ogni commit passa tutti i test.

Ovviamente, questo ti costringe a spingere solo stable (o interrompi la build) e programmare più attentamente per non rompere la compatibilità all'indietro o per attivare o disattivare le funzionalità quando introduci nuove funzionalità.

Ci sono dei compromessi nel fare CI in questo o in quel modo, ma questo è fuori dallo scopo della domanda (vedi domanda correlata per questo). Se preferisci, potrei riformulare la domanda: un piccolo team di sviluppatori lavora insieme in un branch di funzionalità. Se uno sviluppatore commette qualcosa che interrompe la compilazione per quel ramo, dovrebbe il sistema CI ripristinare il commit o no?

    
posta Carlos Campderrós 21.08.2015 - 10:03
fonte

8 risposte

52

Sarei contrario a farlo per i seguenti motivi:

  • Ogni volta che imposti uno strumento automatico per modificare il codice per tuo conto , c'è il rischio che possa sbagliare o che si verifichi una situazione in cui è necessario smettila di fare quel cambiamento (ad esempio, l'ultima versione di Google Mock aveva un bug in esso, quindi non è il tuo codice in errore) e devi perdere tempo riconfigurandolo. Inoltre, c'è sempre un leggero rischio che la compilazione fallisca a causa di un bug nel sistema di build, piuttosto che un bug nel codice. Per quanto mi riguarda, CI sta guadagnando la certezza che il mio codice è corretto; questo lo trasformerebbe semplicemente in un'altra fonte di potenziali problemi di cui preoccuparmi.

  • I tipi di bug che interrompono "la build" dovrebbero essere degli errori stupidi che richiedono pochissimo tempo per risolverli (come hai indicato in un commento, questo è vero per te) . Se più bug sottili e complicati lo fanno regolarmente su master, allora la soluzione corretta non è quella di "aggiustarlo più velocemente", è meglio fare attenzione quando si riesaminano i branch delle feature prima che vengano unite.

  • Lasciare il master non gestibile per alcuni minuti mentre il bug viene corretto correttamente non fa male a nessuno. Non è come se il CEO controllasse personalmente il master e pubblicasse il codice direttamente ai clienti in qualsiasi momento casuale (almeno, si spera non senza il tuo coinvolgimento). Nell'improbabile eventualità che tu debba rilasciare qualcosa prima di poter correggere il bug, allora puoi facilmente decidere di tornare manualmente prima di pubblicare.

risposta data 21.08.2015 - 13:03
fonte
26

Prima mettiamo d'accordo sui termini.

Personalmente uso i termini Build continuo e Integrazione continua per distinguere due diversi scenari:

  • Build continuo: uno strumento che controlla periodicamente se il repository è cambiato dall'ultima build e crea / verifica se lo ha fatto.
  • Integrazione continua: uno strumento che richiama le richieste di pull e le convalida contro l'ultima versione precedente per renderle visibili.

Quest'ultimo, Integrazione continua, significa che il repository che protegge è sempre verde 1 : è strettamente migliore.

La tua domanda ha senso solo per la creazione continua, quindi risponderò assumendo che questa sia la tua impostazione.

1 : Le cause ambientali possono anche rovinare una build, ad esempio un test con un anno hard-coded (2015) potrebbe iniziare a fallire a gennaio del 2016, un disco può diventare pieno, .. E naturalmente c'è la piaga dei test instabili. Ignoro altezzosamente questi problemi qui; altrimenti non arriveremo mai da nessuna parte.

Se hai una configurazione di Build continuo, puoi effettivamente automatizzare l'inversione dei commit che potrebbero aver infranto la build, tuttavia ci sono diverse sottigliezze.

  • In realtà non puoi eliminare i commit: altri colleghi potrebbero averli già controllati e li respingeranno di nuovo nel tentativo successivo di eseguire il commit. Invece, un'inversione dovrebbe commettere un reverse diff. Oh, e i colleghi ti odieranno per ripristinare il loro lavoro quando è stato corretto in quanto dovranno trovare un modo per respingerlo di nuovo ...
  • In realtà non puoi solo rimuovere l'ultimo commit (è un'unione), ma devi rimuovere tutti i commit ... fino a un certo punto. Ad esempio, l'ultimo commit valido noto (attenzione quando si esegue il bootstrap del sistema).
  • Devi pensare a cause esterne (problemi ambientali) ed evitare un'impostazione che ritorni tutto al giorno 0. Fortunatamente, tornare all'ultima commit conosciuta bene aggira questo problema.
  • Devi pensare che l'ultima build valida nota potrebbe non essere più costruita (problemi di ambiente), nel qual caso è probabile che tutti gli ulteriori commit saranno invertiti. Idealmente, in caso di errore, e prima di tornare, verificherebbe l'ultima build valida e la testare nuovamente. Se passa, ripristina, altrimenti, genera un avviso.

Si noti che con questo sistema, nel caso di un test instabile o di un collega che spesso commette una cagata, molti buoni commit si invertiranno. I tuoi collaboratori ti odieranno.

Speriamo che il mio racconto dell'orrore abbia esposto i problemi di consentire un repository rotto e ora implementerai una pipeline di Continuous Integration corretta dove PR non viene mai direttamente spinto nel repository ma invece accodato per unire in una coda di lavoro e integrato a un tempo (o per roll-up):

  • recupera localmente il repository
  • applica le richieste di pull
  • costruisci e prova
  • in caso di successo, spingere nel repository, altrimenti contrassegnare come non soddisfacente
  • passa alle richieste successive

Dopo aver provato entrambi, questo è strettamente migliore.

    
risposta data 21.08.2015 - 15:51
fonte
5

Is this a best practice or it may be more problematic than just leaving master broken until the developer fixes it?

È problematico. Una persona che decide "il capo HEAD è rotto, io ripristinerò il massimo cambiamento" è completamente diverso dal sistema CI che fa lo stesso.

Ecco alcuni svantaggi:

  • Gli errori nel processo di annullamento automatico rovineranno il repository;

  • questo presuppone che un singolo changeset (il più in alto) abbia rovinato la build (che non è realistico)

  • I manutentori avranno più lavoro da fare per risolvere il problema, piuttosto che solo indagini e commit (dovranno anche consultare la cronologia inversa)

We believe that the concept of branches goes against real CI, because committing to a branch isolates you from the other developers and their changes, and adds time when you have to reintegrate your branch and deal with possible conflicts.

Questa convinzione (rami vs. CI) non è corretta. Prendi in considerazione il mantenimento di un ramo stabile one , in cui si impegnano solo i changeset unità testati . Il resto (feature branch e filiali locali) dovrebbe essere la responsabilità di ogni sviluppatore e non parte della politica di CI in alcun modo.

In feature branch vuoi essere isolato da altri sviluppatori. Questo ti permette di:

  • esegue la codifica esplorativa

  • sperimentare con la base di codice

  • esegue commit parziali (efficacemente il codice non funzionante) per impostare i punti di backup (nel caso si rovini), per creare una cronologia delle modifiche più significativa (tramite messaggi di commit) e per eseguire il backup del lavoro e passare completamente a qualcos'altro (nel tempo necessario per scrivere "git commit & git checkout")

  • esegui attività a bassa priorità che richiedono molto tempo (ad esempio, vuoi eseguire un refactoring che altera tutte le 80 classi del livello dati: ne cambi due al giorno, finché non le cambi tutte e un codice compila (ma puoi farlo senza interessare nessuno finché non puoi fare un singolo commit).

If one developer commits something that breaks the build for that branch, should the CI system revert the commit or not?

Non dovrebbe. La registrazione di codice stabile sul ramo CI è responsabilità del committer, non di un sistema automatizzato.

    
risposta data 21.08.2015 - 13:47
fonte
2

Suggerirei di utilizzare un ambiente Gerrit + Jenkins per mantenere sempre il tuo ramo master in buona forma. Le persone spingono il loro nuovo codice a Gerrit che fa scattare un lavoro a Jenkins per ritirare patch, build, test e così via. Se altri sviluppatori come la tua patch e Jenkins completano il suo lavoro con successo, Gerrit unirà quella parte di codice al tuo ramo principale.

È un ambiente simile descritto da @ brian-vandenberg

Oltre a mantenere la tua filiale in una buona forma, aggiungi anche una fase di revisione del codice che migliora la qualità del codice e la condivisione della conoscenza del tuo software.

[1] Jenkins link

[2] Gerrit link

    
risposta data 27.08.2015 - 22:58
fonte
1

L'elemento della configurazione non dovrebbe mai alterare la cronologia del commit del repository.

La soluzione corretta qui è che nessun commit deve essere aggiunto al ramo principale se non sono stati testati e verificati.

Lavori su rami di funzionalità, fai in modo che l'elemento di configurazione funzioni automaticamente su questi e, se le build falliscono, non unirli a master.

Puoi avere un'ulteriore build che verifica i fusioni se questi sono un problema, eseguendo il ramo della funzione e durante la fusione di master / integrazione / qualsiasi cosa nel ramo locale, quindi eseguendo i test.

    
risposta data 21.08.2015 - 14:19
fonte
1

Usiamo Jenkins per il nostro server di build e usiamo il modello gatekeeper per spingere i commit - dove una combinazione di Jenkins e trigger di commit (che assicurano che i revisori peer abbiano fatto il loro lavoro) è il gatekeeper.

I commit vengono spinti indirettamente attraverso un arricciamento a Jenkins, dove clona il master repo quindi inserisce i commit da unire ed esegue tutte le build richieste (per Linux / solaris). Se tutte le build sono complete, il commit viene inviato.

Questo evita molti se non tutti i problemi discussi finora:

  • alterazione della cronologia
  • ottenere la cronologia corretta se sei lo sviluppatore che deve correggere la rottura
  • l'instabilità (sotto forma di build non funzionanti) non viene mai introdotta

Ci consente anche di applicare direttamente altri requisiti, come il completamento dei test unitari.

    
risposta data 21.08.2015 - 18:12
fonte
0

Quante volte hai ricevuto quell'e-mail automatica dicendo che il tuo ultimo commit ha rotto la build? Quante volte è sbagliato? Ma ora devi controllare se sei davvero tu o qualcun altro che ha fatto un altro commit nello stesso tempo. O forse era qualcosa di ambientale.

Se il sistema non lo sa per certo, allora certamente non voglio automatizzarlo.

    
risposta data 21.08.2015 - 17:52
fonte
0

La domanda posta è errata. Rispetto comunque questa affermazione

"Crediamo che il concetto di rami vada contro l'IC reale, perché impegnarsi in un ramo ti isola dagli altri sviluppatori e dalle loro modifiche"

Ciò che dovresti fare sono questi passaggi

  • elimina il master se preferisci (va bene e continua a tirare le modifiche da tutti) MA NON impegnarsi a padroneggiare localmente
  • SOLO PRIMA che imposti le modifiche al master, crea un ramo con submit_XXXXXX
  • fai in modo che la tua build automatizzata riprenda tutte le filiali submit_XXX create
  • Opzione 1: crea interruzioni o unisci interruzioni ... cambia respinta e non atterra mai sul master
  • Opzione 2: crea opere, jenkins invia il master e lo aggiorna

ALLORA, ciò che facciamo è mettere un git commit hook nell'impedire a EVERYONE di impegnarsi realmente a dominare. Funziona alla grande .... NESSUNA generazione fallita mai e NESSUN ripristino si impegna dal master.

dopo, Dean

    
risposta data 30.09.2016 - 02:58
fonte

Leggi altre domande sui tag