Jak radzisz sobie z plikami konfiguracyjnymi w kontroli źródła?

97

Załóżmy, że masz typową aplikację internetową z konfiguracją plików. Cokolwiek. Każdy programista pracujący nad projektem będzie miał jedną wersję dla swoich dev boxów, będą dostępne wersje dev, prod i stage. Jak sobie z tym radzisz w kontroli źródła? W ogóle nie wpisujesz tego pliku, nie sprawdzasz go pod różnymi nazwami lub nie robisz czegoś wymyślnego?

deadprogrammer
źródło

Odpowiedzi:

70

W przeszłości posiadałem domyślny plik konfiguracyjny, który jest wpisywany do kontroli źródła. Następnie każdy programista ma swój własny plik konfiguracyjny nadpisywania, który jest wykluczony z kontroli źródła. Aplikacja najpierw ładuje wartość domyślną, a następnie, jeśli plik zastępowania jest obecny, ładuje go i używa wszystkich ustawień z zastąpienia zamiast domyślnego pliku.

Ogólnie rzecz biorąc, im mniejszy plik nadpisania, tym lepiej, ale zawsze może zawierać więcej ustawień dla programisty w bardzo niestandardowym środowisku.

yukondude
źródło
24

Konfiguracja jest kodem i powinieneś go wersjonować. Nasze pliki konfiguracyjne opieramy na nazwach użytkowników; zarówno w systemie UNIX / Mac, jak i Windows możesz uzyskać dostęp do nazwy logowania użytkownika i jeśli są one unikalne dla projektu, wszystko jest w porządku. Możesz nawet zmienić to w środowisku, ale powinieneś wszystko kontrolować.

Umożliwia to również zbadanie konfiguracji innych osób, co może pomóc w diagnozowaniu problemów z kompilacją i platformą.

davetron5000
źródło
10
+1 absolutnie za podkreślenie, że konfiguracja nadal powinna być wersjonowana
Alexander Bird,
A jeśli nazwa użytkownika nie jest wiarygodna z jakiegokolwiek powodu, możesz mieć pojedynczy plik z tylko jedną linią zawierającą nazwę nadpisanego pliku konfiguracyjnego. W ten sposób jest bardzo niewiele (jak około 10 znaków), które nie są kontrolowane przez wersję. A plik README może wyjaśnić, że musisz utworzyć ten plik.
Alexander Bird
Zawsze uważam, że konfiguracje powinny być oddzielone od kodu. Pracowałem w miejscach, które wymagają tak wielu konfiguracji dla jednego repozytorium, że Git jest po prostu przytłoczony plikami konfiguracyjnymi. Nie mówiąc, że konfiguracje nie powinny być wersjonowane, należą one gdzie indziej, jak menedżer artefaktów. Konfiguracja to nie kod, to ustawienia kodu.
Thomas
Pliki konfiguracyjne mogą zawierać poufne informacje, takie jak hasła, które nie powinny być wersjonowane. A może chcesz zapewnić każdemu deweloperowi dostęp do swojego środowiska produkcyjnego? Myślę, że lepiej jest po prostu utworzyć wersję „konfiguracji głównej” i zastąpić ją w określonych środowiskach.
Christophe Weis
19

Nie wersjonuj tego pliku. Wersja szablonu lub coś w tym stylu.

Dotacja
źródło
2
Używam tego podejścia, po prostu mam plik main.php.tmpl i kiedy wyewidencjonuję nową kopię, po prostu skopiuj ją do main, php. Dodaję plik main.php do listy ignorowanych, aby uniknąć przypadkowego zatwierdzenia.
levhita,
10

Mój zespół przechowuje oddzielne wersje plików konfiguracyjnych dla każdego środowiska (web.config.dev, web.config.test, web.config.prod). Nasze skrypty wdrożeniowe kopiują poprawną wersję, zmieniając jej nazwę na web.config. W ten sposób mamy pełną kontrolę nad wersjami plików konfiguracyjnych dla każdego środowiska, możemy łatwo wykonać różnicę itp.

Brandon Wood
źródło
6

Obecnie posiadam plik konfiguracyjny „template” z dodanym rozszerzeniem np .:

web.config.rename

Jednak widzę problem z tą metodą, jeśli krytyczne zmiany uległy zmianie.

GateKiller
źródło
6

+1 w podejściu szablonowym.

Ale ponieważ to pytanie ma tag Git, przychodzi na myśl rozproszona alternatywa, w której dostosowania są przechowywane w prywatnej gałęzi testowej:

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

W tym schemacie główna linia zawiera ogólny plik konfiguracyjny „szablonu” wymagający minimalnej ilości dostosowań, aby działał.

Teraz programiści / testerzy mogą dostosować plik konfiguracyjny do swoich potrzeb i zatwierdzać te zmiany tylko lokalnie w jednej prywatnej gałęzi testowej (np. Dostosowania B '= B +). Za każdym razem, gdy główna linia się rozwija, bez wysiłku łączą ją z testowaniem, co skutkuje zatwierdzeniami scalającymi, takimi jak D '(= D + scalona wersja dostosowań B).

Schemat ten naprawdę błyszczy, gdy aktualizowany jest plik konfiguracyjny „szablonu”: zmiany z obu stron są łączone i są bardzo prawdopodobne, że spowodują konflikty (lub niepowodzenia testów), jeśli są niekompatybilne!

Damien Diederen
źródło
Ale kiedy testerzy deweloperów wpychają się do głównej linii, ich zmiany w pliku szablonu również zostaną wprowadzone. Nie?
Nick Zalutskiy
Jeśli nie ma rozwiązania komentarza Nicka, to nie zadziała z tego, co widzę. A może wyjaśnij, jakiego modelu przepływu używasz, który rozwiązałby problem.
Alexander Bird
Zgadzam się z podejściem opartym na szablonie z wszelkimi niezbędnymi korektami wprowadzonymi w czasie kompilacji. Jednak w temacie rozgałęziania ... Co by było, gdyby było wiele szablonów (programowanie, testowanie itp.), A programiści po prostu pomijali zmiany w swoich zatwierdzeniach. Nie jest niezawodny, ale może współpracować.
NickSuperb
5

Rozwiązaniem, którego używamy, jest posiadanie tylko jednego pliku konfiguracyjnego (web.config / app.config), ale dodajemy specjalną sekcję do pliku zawierającą ustawienia dla wszystkich środowisk.

Istnieją sekcje LOCAL, DEV, QA, PRODUCTION, z których każda zawiera klucze konfiguracyjne odpowiednie dla tego środowiska w naszych plikach konfiguracyjnych.

To, co sprawia, że ​​to wszystko działa, to zestaw o nazwie xxx.Environment którego odwołujemy się we wszystkich naszych aplikacjach (winForms i webforms), który informuje aplikację, w jakim środowisku działa.

Zespół xxx.Environment odczytuje pojedynczą linię informacji z pliku machine.config danej maszyny, która mówi mu, że jest na DEV, QA itp. Ten wpis jest obecny na wszystkich naszych stacjach roboczych i serwerach.

Mam nadzieję że to pomoże.

Jason Stevenson
źródło
1
Działa to wyjątkowo dobrze, jeśli istnieje tylko kilka różnic między środowiskiem (np.
Ciągami
i zakładając, że nie ma setek programistów, którzy również umieszczają tam swoje dostosowane ustawienia (to nadal działałoby, ale byłoby bardzo uciążliwe)
Alexander Bird,
5

Zawsze trzymałem wszystkie wersje plików konfiguracyjnych w kontroli źródła, w tym samym folderze co plik web.config.

Na przykład

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

Wolę tę konwencję nazewnictwa (w przeciwieństwie do web.config.production lub production.web.config), ponieważ

  • Utrzymuje pliki razem podczas sortowania według nazwy pliku
  • Utrzymuje pliki razem podczas sortowania według rozszerzenia pliku
  • Jeśli plik przypadkowo zostanie przesłany do produkcji, nie będzie można zobaczyć jego zawartości za pośrednictwem protokołu http, ponieważ usługi IIS uniemożliwi udostępnienie plików * .config

Domyślny plik konfiguracyjny należy skonfigurować w taki sposób, aby można było uruchomić aplikację lokalnie na własnym komputerze.

Co najważniejsze, pliki te powinny być prawie w 100% identyczne pod każdym względem, nawet formatowania. Nie należy używać tabulatorów w jednej wersji i spacji w innej do tworzenia wcięć. Powinieneś być w stanie uruchomić narzędzie porównujące do plików, aby zobaczyć dokładnie, co się między nimi różni. Wolę używać WinMerge do porównywania plików.

Kiedy proces budowania tworzy pliki binarne, powinno być zadanie, które nadpisze plik web.config plikiem konfiguracyjnym odpowiednim dla tego środowiska. Jeśli pliki są spakowane, nieistotne pliki powinny zostać usunięte z tej kompilacji.

JackAce
źródło
4

Używałem tego szablonu wcześniej, tj. Web.dev.config, web.prod.config itp., Ale teraz wolę technikę „override file”. Plik web.config zawiera większość ustawień, ale plik zewnętrzny zawiera wartości specyficzne dla środowiska, takie jak połączenia db. Dobre wyjaśnienie na blogu Paula Wilsona .

Myślę, że zmniejsza to ilość duplikatów między plikami konfiguracyjnymi, co może powodować ból podczas dodawania nowych wartości / atrybutów.

Andy Whitfield
źródło
3

@Grant ma rację.

Jestem w zespole z blisko 100 innymi programistami, a nasze pliki konfiguracyjne nie są sprawdzane w kontroli źródła. Mamy wersje plików w repozytorium, które są pobierane przy każdym wyewidencjonowaniu, ale się nie zmieniają.

U nas wyszło całkiem nieźle.

Tomek
źródło
2

Kontroluję wersję, ale nigdy nie wysyłam jej na inne serwery. Jeśli serwer produkcyjny wymaga zmiany, wprowadzam tę zmianę bezpośrednio w pliku konfiguracyjnym.

Może nie jest ładny, ale działa dobrze.

EndangeredMassa
źródło
2

Zaewidencjonowana, zwykła wersja pliku app / web.config powinna być wystarczająco ogólna, aby działać na wszystkich komputerach deweloperskich i być na bieżąco z wszelkimi nowymi zmianami ustawień itp. Jeśli potrzebujesz określonego zestawu ustawień dla programistów / test / production settings, odkładaj osobne pliki z tymi ustawieniami, jak stwierdził GateKiller, z jakąś konwencją nazewnictwa, chociaż zwykle używam "web.prod.config", aby nie zmieniać rozszerzenia pliku.

Greg Hurlman
źródło
2

Używamy pliku konfiguracyjnego szablonu, który jest wpisywany do kontroli wersji, a następnie kroku w naszej automatycznej kompilacji w celu zastąpienia określonych wpisów w pliku szablonu ustawieniami specyficznymi dla środowiska. Ustawienia specyficzne dla środowiska są przechowywane w oddzielnym pliku XML, który również podlega kontroli wersji.

Używamy programu MSBuild w naszej zautomatyzowanej kompilacji, więc do aktualizowania wartości używamy zadania XmlUpdate z zadań społeczności MSBuild .

Sean Carpenter
źródło
2

Przez długi czas robiłem dokładnie to, co zrobił bcwood. Trzymam kopie plików web.dev.config, web.test.config, web.prod.config itp. Pod kontrolą źródła, a następnie mój system kompilacji / wdrażania zmienia ich nazwy automatycznie podczas wdrażania w różnych środowiskach. Otrzymujesz pewną redundancję między plikami (szczególnie ze wszystkimi zawartymi w nich elementami asp.net), ale ogólnie działa to naprawdę dobrze. Musisz także upewnić się, że wszyscy w zespole pamiętają o zaktualizowaniu wszystkich plików, gdy wprowadzają zmiany.

Nawiasem mówiąc, lubię pozostawić „.config” na końcu jako rozszerzenie, aby skojarzenia plików nie zostały zerwane.

Jeśli chodzi o wersje pliku konfiguracyjnego dla lokalnych programistów, zawsze staram się zachęcać ludzi do korzystania z tych samych ustawień lokalnych tak często, jak to możliwe, aby nie było potrzeby posiadania własnej wersji. Nie zawsze działa to dla wszystkich, w takim przypadku ludzie zwykle po prostu zastępują go lokalnie w razie potrzeby i stamtąd. To nie jest zbyt bolesne ani nic takiego.

jeremcc
źródło
1

W naszym projekcie mamy konfigurację zapisaną w plikach z prefiksem, a następnie nasz system kompilacji pobiera odpowiednią konfigurację na podstawie nazwy hosta bieżącego systemu. Działa to dobrze dla nas w stosunkowo małym zespole, umożliwiając nam wprowadzanie zmian konfiguracyjnych do plików innych osób, jeśli / kiedy dodamy nowy element konfiguracji. Oczywiście to zdecydowanie nie daje się skalować do projektów open source z nieograniczoną liczbą programistów.

Rob Oxspring
źródło
1

Mamy tutaj dwa problemy.

  • Po pierwsze musimy kontrolować plik konfiguracyjny, który jest dostarczany z oprogramowaniem.

    Deweloperowi łatwo jest wprowadzić niechcianą zmianę w głównym pliku konfiguracyjnym, jeśli używa tego samego pliku w środowisku devolvement.

    Z drugiej strony, jeśli masz osobny plik konfiguracyjny, który jest dołączony przez instalator, bardzo łatwo jest zapomnieć o dodaniu do niego nowego ustawienia lub pozwolić, aby komentarze w nim nie były zsynchronizowane z komentarzami w procesie decyzyjnym plik konfiguracyjny.

  • Następnie pojawia się problem polegający na tym, że programiści muszą na bieżąco aktualizować kopię pliku konfiguracyjnego, gdy inni programiści dodają nowe ustawienia konfiguracyjne. Jednak niektóre ustawienia, takie jak parametry połączenia z bazą danych, są różne dla każdego dewelopera.

  • Jest trzeci problem, którego pytanie / odpowiedzi nie obejmują. W jaki sposób scalisz zmiany wprowadzone przez klienta w pliku konfiguracyjnym podczas instalowania nowej wersji oprogramowania?

Nie widziałem jeszcze dobrych rozwiązań, które działają dobrze we wszystkich przypadkach, jednak widziałem kilka rozwiązań częściowych (które w razie potrzeby można łączyć w różne kombinacje), które znacznie zmniejszają problem.

  • Po pierwsze, zmniejsz liczbę elementów konfiguracyjnych, które masz w głównym pliku konfiguracyjnym.

    Jeśli nie musisz pozwalać swoim klientom na zmianę mapowań, użyj Fluent NHibernate (lub w inny sposób), aby przenieść konfigurację do kodu.

    Podobnie w przypadku konfiguracji wtrysku depencji.

  • Jeśli to możliwe, podziel plik konfiguracyjny, np. Użyj oddzielnego pliku, aby skonfigurować dzienniki Log4Net.

  • Nie powtarzaj elementów między wieloma plikami konfiguracyjnymi, np. Jeśli masz 4 aplikacje internetowe, które są wszystkie zainstalowane na tym samym komputerze, miej ogólny plik konfiguracyjny, na który wskazuje plik web.config w każdej aplikacji.

    (Domyślnie użyj ścieżki względnej, więc rzadko trzeba zmieniać plik web.config)

  • Przetwórz plik konfiguracji programistycznej, aby uzyskać plik konfiguracji wysyłki.

    Można to zrobić, mając domyślne wartości w komentarzach XML, które są następnie ustawiane w pliku konfiguracyjnym po zakończeniu kompilacji. Lub posiadanie sekcji, które są usuwane w ramach procesu tworzenia instalatora.

  • Zamiast jednego ciągu połączenia z bazą danych, należy mieć jeden na programistę.

    Np. Najpierw poszukaj „database_ianr” (gdzie ianr to moja nazwa użytkownika lub nazwa komputera) w pliku konfiguracyjnym w czasie wykonywania, jeśli nie zostanie znaleziony, a następnie poszukaj „bazy danych”

    Miej „np. -Oracle lub -sqlserver” drugiego poziomu, aby programiści mogli szybciej dostać się do obu systemów baz danych.

    Można to oczywiście zrobić dla każdej innej wartości konfiguracyjnej.

    Następnie wszystkie wartości kończące się na „_userName” można usunąć przed wysłaniem pliku konfiguracyjnego.

Jednak ostatecznie to Ty jesteś „właścicielem pliku konfiguracyjnego”, który bierze odpowiedzialność za zarządzanie plikami konfiguracyjnymi, jak powyżej lub w inny sposób. Powinien także zrobić różnicę w pliku konfiguracyjnym twarzy klienta przed każdą wysyłką.

Nie możesz wyeliminować potrzeby opiekuńczej osoby, która ma tak krótki problem.

Ian Ringrose
źródło
1

Nie sądzę, aby istniało jedno rozwiązanie, które działa we wszystkich przypadkach, ponieważ może zależeć od wrażliwości danych w plikach konfiguracyjnych lub używanego języka programowania i wielu innych czynników. Ale myślę, że ważne jest, aby zachować pliki konfiguracyjne dla wszystkich środowisk pod kontrolą źródła, aby zawsze wiedzieć, kiedy zostało zmienione i przez kogo, a co ważniejsze, móc je odzyskać, jeśli coś pójdzie nie tak. I będą.

Oto jak to robię. Zwykle jest to przeznaczone dla projektów nodejs, ale myślę, że działa również dla innych frameworków i języków.

Robię configskatalog w katalogu głównym projektu i przechowuję w nim wiele plików dla wszystkich środowisk (a czasami także oddzielne pliki dla każdego środowiska programisty), które są śledzone w kontroli źródła. I jest rzeczywisty plik, którego używa kod o nazwie configw katalogu głównym projektu. To jedyny plik, który nie jest śledzony. Więc to wygląda tak

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

Kiedy ktoś sprawdza projekt, kopiuje plik konfiguracyjny, którego chce użyć, do nieśledzonego configpliku i może go dowolnie edytować, ale jest również odpowiedzialny za skopiowanie tych zmian przed zatwierdzeniem do innych plików środowiska, jeśli jest to potrzebne.

Na serwerach nieśledzony plik może być po prostu kopią (lub odniesieniem) śledzonego pliku odpowiadającego temu środowisku. W JS możesz po prostu mieć 1 linię, aby wymagać tego pliku.

Ten przepływ może na początku być trochę skomplikowany, ale ma wielkie zalety: 1. Nigdy nie musisz się martwić, że plik konfiguracyjny zostanie usunięty lub zmodyfikowany na serwerze bez kopii zapasowej 2. To samo, jeśli programista ma na swoim maszyna i jego maszyna przestają działać z jakiegoś powodu. 3. Przed wdrożeniem możesz porównać pliki konfiguracyjne dla developmenti stagingna przykład sprawdzić, czy czegoś brakuje lub jest uszkodzone.

gafi
źródło
0

Po prostu zachowujemy plik konfiguracji produkcyjnej zaewidencjonowany. To programista jest odpowiedzialny za zmianę pliku, gdy wyciąga go z bezpiecznego źródła do przemieszczania lub programowania. Spaliło nas to w przeszłości, więc nie sugerowałbym tego.

Ryan
źródło
0

Napotkałem ten sam problem i znalazłem rozwiązanie. Najpierw dodałem wszystkie pliki do centralnego repozytorium (również deweloperskiego).

Więc jeśli programista pobiera pliki z repozytorium, konfiguracja programisty również tam jest. Podczas zmiany dokonanej w tym pliku Git nie powinien być świadomy tych zmian. W ten sposób zmiany nie mogą być wypychane / zatwierdzane do repozytorium, ale pozostają lokalnie.

I rozwiązać to za pomocą polecenia git: update-index --assume-unchanged. Zrobiłem plik bat, który jest wykonywany podczas kompilacji wstępnej projektów zawierających plik, którego zmiany powinny być ignorowane przez Git. Oto kod, który umieściłem w pliku 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

W moim prebuild wykonałem wywołanie pliku bat, na przykład:

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

Znalazłem na SO plik bat, który kopiuje poprawny plik konfiguracyjny do web.config / app.config. Nazywam ten plik bat w prebuild. Kod tego pliku bat to:

@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.

W moim prebuild wykonałem wywołanie pliku bat, na przykład:

call "$(ProjectDir)\..\..\copyifnewer.bat" "$(ProjectDir)web.config.$(ConfigurationName)" "$(ProjectDir)web.config
Benny Emmers
źródło