Struttura del Mercurial Repository con comunicazioni aziendali pesanti, gestione della configurazione e requisiti di test

15

Sono ancora un altro utente di Subversion che fatica a rieducarmi nel Tao del controllo di versione distribuito.

Quando usavo Subversion, ero un grande sostenitore dell'approccio secondario al progetto e, con la maggior parte dei miei ex datori di lavoro, strutturavamo i nostri rami di deposito; tag & tronco come segue:

branches-+
         +-personal-+
         |          +-alice-+
         |          |       +-shinyNewFeature
         |          |       +-AUTOMATED-+
         |          |                   +-shinyNewFeature
         |          +-bob-+
         |                +-AUTOMATED-+
         |                            +-bespokeCustomerProject
         +-project-+
                   +-shinyNewFeature
                   +-fixStinkyBug
tags-+
     +-m20110401_releaseCandidate_0_1
     +-m20110505_release_0_1
     +-m20110602_milestone
trunk

All'interno del vero albero dei sorgenti stessi, useremmo (qualcosa di simile) la seguente struttura:

  (src)-+
        +-developmentAutomation-+
        |                       +-testAutomation
        |                       +-deploymentAutomation
        |                       +-docGeneration
        |                       +-staticAnalysis
        |                       +-systemTest
        |                       +-performanceMeasurement
        |                       +-configurationManagement
        |                       +-utilities
        +-libraries-+
        |           +-log-+
        |           |     +-build
        |           |     +-doc
        |           |     +-test
        |           +-statistics-+
        |           |            +-build
        |           |            +-doc
        |           |            +-test
        |           +-charting-+
        |           |          +-build
        |           |          +-doc
        |           |          +-test
        |           +-distributedComputing-+
        |           |                      +-build
        |           |                      +-doc
        |           |                      +-test
        |           +-widgets-+
        |                     +-build
        |                     +-doc
        |                     +-test
        +-productLines-+
        |              +-flagshipProduct-+
        |              |                 +-coolFeature
        |              |                 +-anotherCoolFeature
        |              |                 +-build
        |              |                 +-doc
        |              |                 +-test
        |              +-coolNewProduct
        +-project-+
                  +-bigImportantCustomer-+
                  |                      +-bespokeProjectOne
                  |                      +-bespokeProjectTwo
                  +-anotherImportantCustomer-+
                                             +-anotherBespokeProject

L'idea era (ed è tuttora) di utilizzare la struttura del repository per aiutare a strutturare la comunicazione tra il team di ingegneri; la parte del business rivolta al cliente e vari altri stakeholder & esperti di dominio.

Per arguzia: i documenti sorgente che si trovano in una delle directory "progetto" vengono utilizzati (e guadagnati) solo una volta. I documenti che si trovano in una delle directory "productLines" guadagnano denaro tutte le volte che viene venduto un prodotto da quella particolare linea. I documenti che si trovano in una delle directory "librerie" guadagnano denaro tutte le volte che vengono venduti i prodotti che li utilizzano.

Rende esplicita la nozione di ammortamento dei costi e aiuta a creare supporto per il riutilizzo dei documenti di origine in tutta l'azienda.

Significa anche che esiste una struttura comune sulla quale possono operare i nostri strumenti di automazione delle build. (I nostri script di costruzione percorrono l'albero dei sorgenti alla ricerca di cartelle "build" all'interno delle quali trovano i file di configurazione che specificano in che modo deve essere costruito ciascun componente, un processo simile avviene per la generazione e il test della documentazione).

Significativamente, i prodotti su cui lavoro in genere impiegano molto tempo per eseguire misurazioni e prestazioni delle prestazioni; test di caratterizzazione; da 20 a 200 ore; generare da qualche parte tra diversi GB a diversi TB di risultati di test elaborati / dati intermedi (che devono essere memorizzati e legati a una particolare configurazione di sistema in modo da poter misurare il miglioramento delle prestazioni nel tempo). Questo problema rende la gestione della configurazione un'importante considerazione e impone anche alcuni requisiti per la centralizzazione, poiché in genere le risorse di calcolo necessarie per eseguire i test di misurazione e caratterizzazione delle prestazioni sono limitate; (un piccolo cluster di 64-128 core).

Come ultima nota; il sistema di integrazione continua sa che è necessario attivare una build; analisi statica; test del fumo e amp; Il test dell'unità viene eseguito ogni volta che viene modificato il trunk, ogni volta che viene modificato un ramo "tag" e ogni volta viene modificato un ramo ramo "AUTOMATICO". In questo modo, i singoli sviluppatori possono utilizzare il sistema di CI con le loro filiali personali, un'importante capacità, IMHO.

Ora, ecco la mia domanda: come posso replicare tutto quanto sopra (e migliorarlo, se possibile) con Mercurial.

- edit:

La mia attuale linea di pensiero è di usare un repository centrale di Subversion, per definire la struttura generale, ma per consentire l'uso di hg come client in modo che gli sviluppatori possano avere repository disponibili localmente.

    
posta William Payne 04.01.2012 - 18:22
fonte

2 risposte

9

La risposta di Spoike è eccellente, ma ci sono alcune cose che penso che varrebbe la pena aggiungere che sono troppo grande per i commenti.

Organizzazione filiale

Con Mercurial puoi tranquillamente ignorare l'intero tuo primo organigramma. Come dice Spoke, ogni repository ha il proprio set di tag, rami (nominati e anonimi) e può essere organizzato in base alle esigenze aziendali.

Se bespokeProjectTwo ha bisogno di una versione speciale della libreria charting , allora devi diramare charting , aggiungere le nuove strutture e usarlo in bespokeProjectTwo . Le nuove strutture (e i relativi bug) non sarebbero utilizzate da altri progetti che farebbero riferimento alla libreria standard charting . Se la libreria charting principale ha corretto gli errori, è possibile unire tali modifiche nel ramo. Se anche altri progetti avessero bisogno di queste strutture, potresti far sì che quei progetti usassero il ramo speciale , oppure unire il ramo nella linea principale e chiudere il ramo.

Inoltre, non c'è nulla che ti impedisca di avere una politica per strutturare i nomi dei rami per fornire strutture specifiche come i tuoi rami AUTOMATION.

Organizzazione di directory

Non vi è alcun motivo per cui non è possibile mantenere la directory di origine esattamente come con Mercurial. L'unica differenza è che mentre con Subversion hai un singolo repository monolitico (src) , con Mercurial è meglio suddividerlo in repository logicamente raggruppati. Dalla tua struttura ad albero sorgente, probabilmente estraperei ognuno dei seguenti come singoli repository:

src-+
      +-(developmentAutomation)
      +-libraries-+
      |           +-(log)
      |           +-(statistics)
      |           +-(charting)
      |           +-(distributedComputing)
      |           +-(widgets)
      +-productLines-+
      |              +-(flagshipProduct)
      |              +-(coolNewProduct)
      +-project-+
                +-bigImportantCustomer-+
                |                      +-(bespokeProjectOne)
                |                      +-(bespokeProjectTwo)
                +-anotherImportantCustomer-+
                                           +-(anotherBespokeProject)

Ciò consente a qualsiasi prodotto o progetto su misura di utilizzare qualsiasi combinazione di librerie, a qualsiasi revisione. Dai un'occhiata ai sotto-repository mercuriali per un modo semplice per gestire quali librerie sono utilizzate per una determinata versione di un prodotto o progetto.

Flusso di lavoro

Un'alternativa al flusso di lavoro suggerito da Spoike (lo sviluppatore tira su blessed repo, lavora localmente, emette una richiesta di pull e infine l'integratore estrae quelle modifiche e le unisce) sarebbe utilizzare il sistema di integrazione continua come intermediario.

Come in precedenza, lo sviluppatore attinge da repo benedetto e lavora localmente, ma una volta terminato, tira di nuovo il benedetto repo e si fonde prima di spingere verso un repository non benedetto. Eventuali modifiche al repository non benedetto vengono quindi esaminate (manualmente o automaticamente) e trasferite al repository benedetto solo se approvate.

Ciò significa che l'integratore ha solo accettato o rifiutato una modifica, non l'unione. Nella mia esperienza è quasi sempre meglio per lo sviluppatore che ha scritto il codice per eseguire l'unione piuttosto che per farlo eseguire da qualcun altro.

Come suggerito nel libro mercuriale, è possibile utilizzare hook per automatizzare questa procedura:

When someone pushes a changeset to the server that everyone pulls from, the server will test the changeset before it accepts it as permanent, and reject it if it fails to pass the test suite. If people only pull changes from this filtering server, it will serve to ensure that all changes that people pull have been automatically vetted.

Altri problemi

Il problema dei grandi set di dati di test può anche essere risolto inserendo i dati di test in un sotto-repository mercuriale . Ciò eviterà che il repository del codice si gonfia di dati di test, mantenendo i dati del test sotto controllo di revisione.

    
risposta data 05.01.2012 - 12:55
fonte
8

Va bene, prova a rispondere semplicemente.

Che cosa è necessario sapere

Per prima cosa devi sapere: Mercurial è un controllo di versione distribuito e ha alcune proprietà che dovresti sapere sotto elencate.

  • L'origine proviene da un repository, in cui tale repository può essere clonato. Tutti i repository clonati possono condividere il codice l'uno con l'altro tramite la sincronizzazione (con i comandi pull e push, che possono essere limitati all'accesso).
  • Ogni utente che ha una copia del codice ha un clone del repository. Se vogliono un ramo, possono farlo nel loro clone locale. Ciò significa che non è necessario organizzare il modo in cui ogni utente deve diramarsi. Possono farlo da soli.
  • I tag vengono creati in mercurial da un commit (che è lo stesso dei rigidi in git). Ciò significa che non hai bisogno di una directory all'interno della struttura del tuo repository per i tag.
  • Il solito modello con cui le persone lavorano in DVCS (che è utilizzato in github e bitbucket) è di farlo semi-centralizzato.

    Ogni utente ha un repository pubblico (in alcune condivisioni o su un server sicuro) e un repository privato (nelle proprie workstation). Sono entrambi i cloni del repository "benedetto" di un integratore. Ogni volta che sentono di essere pronti a pubblicare il loro codice, possono trasferire le modifiche dal loro repository pubblico. Un integratore può quindi scegliere quali utenti inserire il codice nel repository "benedetto".

    Se l'integratore non è in grado di unire facilmente il codice di un utente, le modifiche vengono rifiutate e spetta a quel particolare utente aggiornare il proprio repository e correggere l'unione. Solitamente non è così difficile se ti unisci spesso (dato che è meno codice che deve essere unito) e solitamente quell'utente dovrebbe sapere cosa è andato storto con l'unione.

Impostazione repository per progetto

Quindi il solito set up è che per ogni progetto c'è il seguente:

  • Un repository pubblico di sola lettura di cui è responsabile l'integratore. È "benedetto".

    vale a dire. tutti gli utenti possono tirare / recuperare i contenuti ma non hanno accesso per spingerli.

  • Ogni utente può avere il proprio clone pubblico del repository.

    Impostazione più semplice inserita in un'unità di condivisione (anche se potresti considerare l'hosting come bitbucket). L'integratore riceve richieste di pull dagli utenti e tenta di estrarre il nuovo codice da questi repository. Quando le unioni vengono eseguite senza intoppi, vengono inserite nel repository di sola lettura. In caso contrario, viene chiesto agli utenti di correggere i conflitti di fusione che si verificano aggiornando e unendoli autonomamente localmente.

  • Ogni utente può avere i propri cloni privati del repository.

    La buona pratica è tirare fuori dal loro clone pubblico, ma non importa se tirano dal loro pubblico o da quello dell'integratore. Tutti i commit sono identificabili in modo univoco, quindi i commit di unione che hai dimenticato di recuperare nel pubblico sono relativamente facili da risolvere (spostando le modifiche dal privato al pubblico, vengono automaticamente apportate anche le modifiche dell'integratore).

Organizzazione del codice sorgente

Come in come organizzare la fonte del progetto stessa è qualcosa che devi riflettere. Se un artefatto deve essere controllato dalla fonte, inserirlo nel controllo del codice sorgente. Personalmente non mi piace l'idea di verificare le risorse create dal build o dal runtime (a causa dell'elevato rischio di conflitti di unione su questi tipi di risorse) come binari o file di registro.

Puoi anche controllare la configurazione, a patto che sia facile per gli sviluppatori andare avanti e non rovinare la configurazione per le versioni o l'ambiente di produzione / live (come le impostazioni dell'app / server web). Ciò porta a pensare che se la configurazione impedisse seriamente agli sviluppatori di iniziare entro cinque minuti dal momento in cui hanno estratto il codice, allora deve essere rifatto. Un altro requisito è che dovrebbe essere davvero difficile per gli sviluppatori fare confusione con il rilascio o l'ambiente di produzione / live.

Hai detto che hai dati di test che devono essere legati ad alcune versioni del codice. Ora questo è un po 'più complicato perché i sistemi DVCS come Mercurial e Git tendono a rallentare quando si registrano dati ENORME. Nella mia esperienza diventa davvero insopportabile dopo 5 GB di file binari (la tua milizia può variare, quindi dovresti provare come funziona per te). Tuttavia, ti consiglio di inserire i dati generati nel proprio repository e fare in modo che il sistema di test li tagga correttamente al momento del check in (e / o creare file di testo per gli stessi scopi dei metadati).

Spero che tutto abbia un senso. Si prega di commentare qui sotto se ho perso qualche dettaglio o se qualcosa ha bisogno di ulteriori spiegazioni e proverò a modificare.

    
risposta data 04.01.2012 - 22:14
fonte