Come gestisci i file di configurazione nel controllo del codice sorgente?


97

Supponiamo che tu abbia una tipica app web e con una configurazione di file. Qualunque cosa. Ogni sviluppatore che lavora al progetto avrà una versione per i propri box di sviluppo, ci saranno versioni dev, prod e stage. Come gestisci questo problema nel controllo del codice sorgente? Non archiviare affatto questo file, controllarlo con nomi diversi o fare qualcosa di stravagante?

Risposte:


70

Quello che ho fatto in passato è avere un file di configurazione predefinito che viene archiviato nel controllo del codice sorgente. Quindi, ogni sviluppatore ha il proprio file di configurazione di sostituzione che è escluso dal controllo del codice sorgente. L'app carica prima il file predefinito, quindi, se è presente il file di sostituzione, lo carica e utilizza le impostazioni dell'override al posto del file predefinito.

In generale, più piccolo è il file di override, meglio è, ma può sempre contenere più impostazioni per uno sviluppatore con un ambiente molto non standard.


24

La configurazione è un codice e dovresti eseguirne la versione. Basiamo i nostri file di configurazione sui nomi utente; sia in UNIX / Mac che in Windows puoi accedere al nome di login dell'utente e, fintanto che questi sono univoci per il progetto, stai bene. Puoi persino sovrascriverlo nell'ambiente, ma dovresti controllare la versione di tutto.

Ciò consente anche di esaminare le configurazioni degli altri, che possono aiutare a diagnosticare i problemi di build e piattaforma.


10
+1 assolutamente per sottolineare che la configurazione dovrebbe essere ancora aggiornata
Alexander Bird

E se il nome utente non è affidabile per qualsiasi motivo, puoi avere un singolo file con una sola riga che fornisce il nome del file di configurazione di sostituzione. In questo modo, c'è molto poco (come in circa 10 caratteri o giù di lì) che non è controllato dalla versione. E il file README potrebbe spiegare che è necessario creare quel file.
Alexander Bird

Penso sempre che le configurazioni dovrebbero essere tenute separate dal codice. Ho lavorato in luoghi che richiedono così tante configurazioni per un repository che Git viene sopraffatto dai file di configurazione. Non sto dicendo che le configurazioni non dovrebbero essere sottoposte a controllo di versione, appartengono altrove come un gestore di artefatti. La configurazione non è un codice, sono impostazioni per il codice.
Thomas il

I file di configurazione possono contenere informazioni sensibili come password che non devono essere sottoposte a controllo di versione. O vuoi concedere a ogni sviluppatore l'accesso al tuo ambiente di produzione? Penso che sia meglio eseguire la versione di una "configurazione principale" e sovrascriverla in ambienti specifici.
Christophe Weis

19

Non eseguire la versione di quel file. Versione di un modello o qualcosa del genere.


2
Uso questo approccio, ho solo un main.php.tmpl e quando controllo una nuova copia basta copiarlo su main, php. Aggiungo il file main.php alla lista degli ignorati per evitare di commetterlo accidentalmente.
levhita

10

Il mio team mantiene versioni separate dei file di configurazione per ogni ambiente (web.config.dev, web.config.test, web.config.prod). I nostri script di distribuzione copiano la versione corretta, rinominandola in web.config. In questo modo, abbiamo il controllo completo della versione sui file di configurazione per ogni ambiente, possiamo facilmente eseguire un diff, ecc.


6

Attualmente ho il file di configurazione "modello" con un'estensione aggiunta, ad esempio:

web.config.rename

Tuttavia, posso vedere un problema con questo metodo se sono cambiate modifiche critiche.


6

+1 sull'approccio modello.

Ma poiché questa domanda ha il tag Git, viene in mente l'alternativa distribuita, in cui le personalizzazioni sono mantenute su un ramo di test privato:

A---B---C---D---           <- mainline (public)
     \       \
      B'------D'---        <- testing (private)

In questo schema, la linea principale contiene un file di configurazione "modello" generico che richiede una quantità minima di modifiche per diventare funzionale.

Ora, gli sviluppatori / tester possono modificare il file di configurazione a proprio piacimento e applicare queste modifiche solo localmente su un ramo di test privato (ad esempio B '= B + personalizzazioni). Ogni volta che la linea principale avanza, la uniscono facilmente in test, il che si traduce in commit di unione come D '(= D + versione fusa delle personalizzazioni di B).

Questo schema brilla davvero quando il file di configurazione "modello" viene aggiornato: le modifiche da entrambi i lati vengono unite ed è estremamente probabile che si traducano in conflitti (o errori di test) se incompatibili!


Ma quando i tester degli sviluppatori inseriscono la linea principale, verranno inserite anche le loro modifiche al file modello. No?
Nick Zalutskiy

A meno che non ci sia una soluzione al commento di Nick, questo non funzionerà da quello che vedo. O forse spiega quale modello di flusso stai utilizzando per risolvere il problema.
Alexander Bird

Sono d'accordo con l'approccio del modello con tutte le modifiche necessarie introdotte in fase di costruzione. Tuttavia, sull'argomento delle ramificazioni ... E se ci fossero più modelli (dev, test, ecc.) E gli sviluppatori semplicemente omettessero le modifiche dai loro commit. Non infallibile ma potrebbe funzionare con la cooperazione.
NickSuperb

5

La soluzione che utilizziamo è quella di avere solo il singolo file di configurazione (web.config / app.config), ma aggiungiamo una sezione speciale al file che contiene le impostazioni per tutti gli ambienti.

Esistono sezioni LOCAL, DEV, QA, PRODUCTION , ciascuna contenente le chiavi di configurazione relative a quell'ambiente nei nostri file di configurazione.

Ciò che fa funzionare tutto questo è un assembly denominato xxx.Environment a cui si fa riferimento in tutte le nostre applicazioni (winforms e webforms) che indica all'applicazione in quale ambiente sta operando.

L'assembly xxx.Environment legge una singola riga di informazioni dal machine.config della macchina data che le dice che è su DEV, QA, ecc. Questa voce è presente su tutte le nostre workstation e server.

Spero che questo ti aiuti.


1
Funziona molto bene se ci sono solo poche differenze tra l'ambiente (cioè le stringhe di connessione)
Eric Labashosky,

e supponendo che non ci siano centinaia di sviluppatori che inseriscono anche le loro impostazioni personalizzate (funzionerebbe comunque, ma sarebbe molto macchinoso)
Alexander Bird

5

Ho sempre mantenuto tutte le versioni dei file di configurazione nel controllo del codice sorgente, nella stessa cartella del file web.config.

Per esempio

web.config
web.qa.config
web.staging.config
web.production.config

Preferisco questa convenzione di denominazione (al contrario di web.config.production o production.web.config) perché

  • Mantiene insieme i file quando si ordina per nome file
  • Mantiene insieme i file quando si ordina per estensione
  • Se il file viene accidentalmente inviato alla produzione, non sarai in grado di vedere i contenuti su http perché IIS impedirà ai file * .config di essere serviti

Il file di configurazione predefinito dovrebbe essere configurato in modo da poter eseguire l'applicazione localmente sulla propria macchina.

Ancora più importante, questi file dovrebbero essere quasi identici al 100% in ogni aspetto, anche la formattazione. Non dovresti usare le tabulazioni in una versione e gli spazi in un'altra per il rientro. Dovresti essere in grado di eseguire uno strumento di differenza sui file per vedere esattamente cosa c'è di diverso tra loro. Preferisco usare WinMerge per differenziare i file.

Quando il processo di compilazione crea i binari, dovrebbe esserci un'attività che sovrascrive web.config con il file di configurazione appropriato per quell'ambiente. Se i file sono compressi, i file non rilevanti dovrebbero essere eliminati da quella build.


4

Ho già utilizzato il modello in precedenza, ad esempio web.dev.config, web.prod.config, ecc., Ma ora preferisco la tecnica "sovrascrivi file". Il file web.config contiene la maggior parte delle impostazioni, ma un file esterno contiene valori specifici dell'ambiente come le connessioni db. Buona spiegazione sul blog di Paul Wilson .

Penso che questo riduca la quantità di duplicazioni tra i file di configurazione che possono causare problemi quando si aggiungono nuovi valori / attributi.


3

@ Grant ha ragione.

Faccio parte di un team con quasi 100 altri sviluppatori e i nostri file di configurazione non vengono archiviati nel controllo del codice sorgente. Abbiamo versioni dei file nel repository che vengono estratte ad ogni estrazione ma non cambiano.

Ha funzionato abbastanza bene per noi.


2

Controllo la versione, ma non lo spingo mai sugli altri server. Se il server di produzione richiede una modifica, apporto tale modifica direttamente al file di configurazione.

Potrebbe non essere carino, ma funziona benissimo.


2

La versione check-in e semplice di app / web.config dovrebbe essere abbastanza generica da funzionare su tutte le macchine degli sviluppatori ed essere aggiornata con eventuali nuove modifiche alle impostazioni, ecc. Se hai bisogno di un set specifico di impostazioni per lo sviluppo / test / impostazioni di produzione, controlla in file separati con quelle impostazioni, come ha affermato GateKiller, con una sorta di convenzione di denominazione, anche se di solito vado con "web.prod.config", per non cambiare l'estensione del file.


2

Usiamo un file di configurazione del modello che viene archiviato per il controllo della versione e quindi un passaggio nella nostra build automatizzata per sostituire voci specifiche nel file modello con impostazioni specifiche dell'ambiente. Le impostazioni specifiche dell'ambiente vengono memorizzate in un file XML separato che è anche sotto il controllo della versione.

Stiamo usando MSBuild nella nostra build automatizzata, quindi usiamo l'attività XmlUpdate da MSBuild Community Tasks per aggiornare i valori.


2

Per molto tempo ho fatto esattamente quello che ha fatto bcwood. Tengo copie di web.dev.config, web.test.config, web.prod.config, ecc. Sotto il controllo del codice sorgente, quindi il mio sistema di compilazione / distribuzione le rinomina automaticamente durante la distribuzione in vari ambienti. Ottieni una certa quantità di ridondanza tra i file (specialmente con tutte le cose di asp.net lì dentro), ma generalmente funziona molto bene. Devi anche assicurarti che tutti i membri del team si ricordino di aggiornare tutti i file quando apportano una modifica.

A proposito, mi piace mantenere ".config" alla fine come estensione in modo che le associazioni di file non vengano interrotte.

Per quanto riguarda le versioni per sviluppatori locali del file di configurazione, faccio sempre del mio meglio per incoraggiare le persone a utilizzare le stesse impostazioni locali il più possibile in modo che non sia necessario disporre della propria versione. Non sempre funziona per tutti, nel qual caso le persone di solito lo sostituiscono localmente secondo necessità e vanno da lì. Non è troppo doloroso o altro.


1

Sul nostro progetto abbiamo la configurazione memorizzata in file con un prefisso, quindi il nostro sistema di compilazione inserisce la configurazione appropriata in base al nome host del sistema corrente. Questo funziona bene per noi in un team relativamente piccolo, permettendoci di applicare le modifiche alla configurazione ai file di altre persone se / quando aggiungiamo un nuovo elemento di configurazione. Ovviamente questo sicuramente non si adatta ai progetti open source con un numero illimitato di sviluppatori.


1

Abbiamo due problemi qui.

  • Per prima cosa dobbiamo controllare il file di configurazione fornito con il software.

    È facile per uno sviluppatore archiviare una modifica indesiderata nel file di configurazione principale, se utilizza lo stesso file nell'ambiente di trasferimento.

    D'altro canto, se si dispone di un file di configurazione separato incluso dall'installer, è molto facile dimenticarsi di aggiungere una nuova impostazione o lasciare che i commenti in esso non siano sincronizzati con i commenti nella devoluzione file di configurazione.

  • Quindi abbiamo il problema che gli sviluppatori devono mantenere una copia del file di configurazione aggiornata mentre altri sviluppatori aggiungono nuove impostazioni di configurazione. Tuttavia, alcune impostazioni come le stringhe di connessione al database sono diverse per ogni sviluppatore.

  • C'è un terzo problema che la domanda / le risposte non coprono. Come puoi unire le modifiche che un cliente ha apportato al tuo file di configurazione quando installi una nuova versione del tuo software?

Devo ancora vedere una buona soluzione che funzioni bene in tutti i casi, tuttavia ho visto alcune soluzioni parziali (che possono essere combinate in diverse combinazioni secondo necessità) che riducono molto il problema.

  • Innanzitutto riduci il numero di elementi di configurazione che hai nel tuo file di configurazione principale.

    Se non hai la necessità di consentire ai tuoi clienti di modificare i tuoi mapping, usa Fluent NHibernate (o altro) per spostare la configurazione nel codice.

    Allo stesso modo per la configurazione dell'iniezione di dipendenza.

  • Suddividere il file di configurazione quando possibile, ad esempio utilizzare un file separato per configurare ciò che Log4Net registra.

  • Non ripetere elementi tra molti file di configurazione, ad esempio se hai 4 applicazioni web installate tutte sulla stessa macchina, disponi di un file di configurazione generale a cui punta il file web.config in ciascuna applicazione.

    (Utilizza un percorso relativo per impostazione predefinita, quindi è raro dover modificare il file web.config)

  • Elaborare il file di configurazione dello sviluppo per ottenere il file di configurazione della spedizione.

    Potrebbe essere fatto con valori predefiniti nei commenti Xml che vengono poi impostati nel file di configurazione quando viene eseguita una compilazione. O avere sezioni che vengono eliminate come parte del processo di creazione del programma di installazione.

  • Invece di avere solo una stringa di connessione al database, creane una per sviluppatori.

    Ad esempio, prima cerca "database_ianr" (dove ianr è il mio nome utente o il nome della macchina) nel file di configurazione in fase di esecuzione, se non viene trovato, cerca "database"

    Avere un 2 ° livello "eg -oracle o -sqlserver" per rendere più veloce per gli sviluppatori l'accesso a entrambi i sistemi di database.

    Ovviamente questo può essere fatto anche per qualsiasi altro valore di configurazione.

    Quindi tutti i valori che terminano con "_userName" possono essere eliminati prima di inviare il file di configurazione.

Tuttavia, alla fine, ciò che sei è un "proprietario del file di configurazione" che si assume la responsabilità di gestire i file di configurazione come sopra o in altro modo. Lui / lei dovrebbe anche fare una differenza sul file di configurazione del fronte del cliente prima di ogni spedizione.

Non puoi eliminare la necessità di una persona premurosa per questo problema.


1

Non credo che ci sia un'unica soluzione che funzioni per tutti i casi in quanto potrebbe dipendere dalla sensibilità dei dati nei file di configurazione, o dal linguaggio di programmazione che stai utilizzando e da tanti altri fattori. Ma penso che sia importante mantenere i file di configurazione per tutti gli ambienti sotto il controllo del codice sorgente, in modo da poter sempre sapere quando è stato modificato e da chi e, cosa più importante, essere in grado di ripristinarlo se le cose vanno male. E lo faranno.

Quindi ecco come lo faccio. Questo di solito è per i progetti nodejs, ma penso che funzioni anche per altri framework e linguaggi.

Quello che faccio è creare una configsdirectory alla radice del progetto e in quella directory mantenere più file per tutti gli ambienti (e alcune volte anche file separati per l'ambiente di ogni sviluppatore) che sono tutti tracciati nel controllo del codice sorgente. E c'è il file effettivo che il codice utilizza denominato confignella radice del progetto. Questo è l'unico file che non viene tracciato. Quindi sembra così

root
|
|- config (not tracked)
|
|- configs/ (all tracked)
    |- development
    |- staging
    |- live
    |- James

Quando qualcuno fa il check out del progetto, copia il file di configurazione che vuole usare in untracked config file non ed è libero di modificarlo come desidera, ma è anche responsabile di copiare queste modifiche prima di eseguire il commit negli altri file di ambiente, se necessario.

E sui server, il file non tracciato può essere semplicemente una copia (o un riferimento) del file tracciato corrispondente a quell'ambiente. In JS puoi semplicemente avere 1 riga per richiedere quel file.

Questo flusso può essere un po 'complicato all'inizio ma ha grandi vantaggi: 1. Non devi mai preoccuparti che un file di configurazione venga cancellato o modificato sul server senza avere un backup 2. Lo stesso se uno sviluppatore ha qualche configurazione personalizzata sul suo la macchina e la sua macchina smettono di funzionare per qualsiasi motivo 3. Prima di qualsiasi distribuzione puoi diffondere i file di configurazione developmente, stagingad esempio, vedere se c'è qualcosa che manca o non funziona.


0

Manteniamo semplicemente archiviato il file di configurazione di produzione. È responsabilità dello sviluppatore modificare il file quando lo estrae dal codice sorgente in modo sicuro per lo staging o lo sviluppo. Questo ci ha bruciato in passato quindi non lo suggerirei.


0

Ho affrontato lo stesso problema e ho trovato una soluzione. Ho prima aggiunto tutti i file al repository centrale (anche quelli per sviluppatori).

Quindi, se uno sviluppatore recupera i file dal repository, è presente anche la configurazione dello sviluppatore. Quando si apportano modifiche a questo file, Git non dovrebbe essere a conoscenza di queste modifiche. In questo modo le modifiche non possono essere inviate / salvate nel repository ma rimangono in locale.

Ho risolto questo utilizzando il comando git: update-index --assume-unchanged. Ho creato un file bat che viene eseguito nella pre-compilazione dei progetti che contengono un file le cui modifiche dovrebbero essere ignorate da Git. Ecco il codice che ho inserito nel file bat:

IF NOT EXIST %2%\.git GOTO NOGIT
set fileName=%1
set fileName=%fileName:\=/%
for /f "useback tokens=*" %%a in ('%fileName%') do set fileName=%%~a
set "gitUpdate=git update-index --assume-unchanged"
set parameter= "%gitUpdate% %fileName%"
echo %parameter% as parameter for git
"C:\Program Files (x86)\Git\bin\sh.exe" --login -i -c %parameter%
echo Make FIleBehaveLikeUnchangedForGit Done.
GOTO END
:NOGIT
echo no git here.
echo %2%
:END

Nella mia pre-compilazione avrei effettuato una chiamata al file bat, ad esempio:

call "$(ProjectDir)\..\..\MakeFileBehaveLikeUnchangedForGit.bat" "$(ProjectDir)Web.config.developer" "$(SolutionDir)"

Ho trovato su SO un file bat che copia il file di configurazione corretto in web.config / app.config. Chiamo anche questo file bat nel file pre-compilato. Il codice per questo file bat è:

@echo off
echo Comparing two files: %1 with %2
if not exist %1 goto File1NotFound
if not exist %2 goto File2NotFound
fc %1 %2 
if %ERRORLEVEL%==0 GOTO NoCopy
echo Files are not the same.  Copying %1 over %2
copy %1 %2 /y & goto END
:NoCopy
echo Files are the same.  Did nothing
goto END
:File1NotFound
echo %1 not found.
goto END
:File2NotFound
copy %1 %2 /y
goto END
:END
echo Done.

Nella mia pre-compilazione avrei effettuato una chiamata al file bat, ad esempio:

call "$(ProjectDir)\..\..\copyifnewer.bat" "$(ProjectDir)web.config.$(ConfigurationName)" "$(ProjectDir)web.config
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.