¿Cómo se manejan los archivos de configuración en el control de fuentes?


96

Digamos que tiene una aplicación web típica y con una configuración de archivo. Cada desarrollador que trabaje en el proyecto tendrá una versión para sus cajas de desarrollo, habrá versiones de desarrollo, producción y etapa. ¿Cómo maneja esto en el control de fuentes? ¿No verifica este archivo en absoluto, lo verifica con nombres diferentes o hace algo elegante?

Respuestas:


69

Lo que he hecho en el pasado es tener un archivo de configuración predeterminado que está registrado en el control de fuente. Luego, cada desarrollador tiene su propio archivo de configuración de anulación que está excluido del control de código fuente. La aplicación primero carga el archivo predeterminado y luego, si el archivo de anulación está presente, lo carga y usa cualquier configuración de la anulación en preferencia al archivo predeterminado.

En general, cuanto más pequeño sea el archivo de anulación, mejor, pero siempre puede contener más configuraciones para un desarrollador con un entorno muy no estándar.


24

La configuración es código, y debe versionarlo. Basamos nuestros archivos de configuración en nombres de usuario; tanto en UNIX / Mac como en Windows, puede acceder al nombre de inicio de sesión del usuario, y siempre que sean exclusivos del proyecto, está bien. Incluso puede anular esto en el entorno, pero la versión debe controlar todo.

Esto también le permite examinar las configuraciones de otros, lo que puede ayudar a diagnosticar problemas de compilación y plataforma.


10
+1 absolutamente por enfatizar que la configuración aún debe estar versionada
Alexander Bird

Y si el nombre de usuario no es confiable por alguna razón, entonces puede tener un solo archivo con una sola línea que indique el nombre del archivo de configuración de anulación. De esta manera, hay muy poco (como en unos 10 caracteres aproximadamente) que no estén controlados por la versión. Y el archivo README podría explicar que necesita crear ese archivo.
Alexander Bird

Siempre pienso que las configuraciones deben mantenerse separadas del código. He trabajado en lugares que requieren tantas configuraciones para un repositorio que Git simplemente se abruma con los archivos de configuración. Sin decir que las configuraciones no deberían ser versionadas, pertenecen a otra parte como un administrador de artefactos. La configuración no es un código, son configuraciones para el código.
Thomas

Los archivos de configuración pueden contener información confidencial, como contraseñas, que no deben ser versionadas. ¿O desea otorgar acceso a todos los desarrolladores a su entorno de producción? Creo que es mejor simplemente versionar una "configuración maestra" y anularla en entornos específicos.
Christophe Weis

19

No versiones ese archivo. Versión de una plantilla o algo así.


2
Utilizo este enfoque, solo tengo un main.php.tmpl y cuando compro una nueva copia simplemente la copio en main, php. Agrego el archivo main.php a la lista de ignorados para evitar cometerlo por accidente.
levhita

10

Mi equipo mantiene versiones separadas de los archivos de configuración para cada entorno (web.config.dev, web.config.test, web.config.prod). Nuestros scripts de implementación copian la versión correcta y le cambian el nombre a web.config. De esta manera, tenemos un control total de la versión de los archivos de configuración para cada entorno, podemos realizar fácilmente una diferencia, etc.


6

Actualmente tengo el archivo de configuración de "plantilla" con una extensión agregada, por ejemplo:

web.config.rename

Sin embargo, puedo ver un problema con este método si los cambios críticos han cambiado.


6

+1 en el enfoque de plantilla.

Pero dado que esta pregunta tiene etiqueta Git, me viene a la mente la alternativa distribuida, en la que las personalizaciones se guardan en una rama de prueba privada:

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

En este esquema, la línea principal contiene un archivo de configuración de "plantilla" genérico que requiere una cantidad mínima de ajustes para volverse funcional.

Ahora, los desarrolladores / evaluadores pueden ajustar el archivo de configuración al contenido de su corazón y solo realizar estos cambios localmente en una rama de prueba privada (por ejemplo, personalizaciones B '= B +). Cada vez que avanza la línea principal, la fusionan sin esfuerzo en las pruebas, lo que da como resultado combinaciones de confirmaciones como D '(= D + versión fusionada de las personalizaciones de B).

Este esquema realmente brilla cuando se actualiza el archivo de configuración de la "plantilla": los cambios de ambos lados se fusionan y es muy probable que generen conflictos (o fallas en las pruebas) si son incompatibles.


Pero cuando los probadores de desarrolladores ingresan a la línea principal, sus cambios en el archivo de plantilla también se implementarán. ¿No?
Nick Zalutskiy

A menos que haya una solución al comentario de Nick, esto no funcionará por lo que veo. O tal vez explique qué modelo de flujo está utilizando para resolver el problema.
Alexander Bird

Estoy de acuerdo con el enfoque de la plantilla con los ajustes necesarios incorporados en el momento de la compilación. Sin embargo, sobre el tema de la ramificación ... ¿Qué pasaría si hubiera varias plantillas (desarrollo, prueba, etc.) y los desarrolladores simplemente omiten los cambios en sus confirmaciones? No es infalible, pero podría funcionar con la cooperación.
NickSuperb

5

La solución que usamos es tener un solo archivo de configuración (web.config / app.config), pero agregamos una sección especial al archivo que contiene la configuración para todos los entornos.

Hay secciones LOCAL, DEV, QA, PRODUCTION , cada una de las cuales contiene las claves de configuración relevantes para ese entorno en nuestros archivos de configuración.

Lo que hace que todo esto funcione es un ensamblado llamado xxx.Environment al que se hace referencia en todas nuestras aplicaciones (winforms y webforms) que le dice a la aplicación en qué entorno está operando.

El ensamblado xxx.Environment lee una sola línea de información de machine.config de la máquina dada que le dice que está en DEV, QA, etc. Esta entrada está presente en todas nuestras estaciones de trabajo y servidores.

Espero que esto ayude.


1
Esto funciona extremadamente bien si solo hay algunas diferencias entre el entorno (es decir, cadenas de conexión)
Eric Labashosky

y suponiendo que no haya cientos de desarrolladores que pongan sus configuraciones personalizadas allí también (aún funcionaría, pero sería muy engorroso)
Alexander Bird

5

Siempre he mantenido todas las versiones de los archivos de configuración en el control de código fuente, en la misma carpeta que el archivo web.config.

Por ejemplo

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

Prefiero esta convención de nomenclatura (a diferencia de web.config.production o production.web.config) porque

  • Mantiene los archivos juntos cuando los ordena por nombre de archivo
  • Mantiene los archivos juntos cuando los ordena por extensión de archivo
  • Si el archivo se envía accidentalmente a producción, no podrá ver el contenido a través de http porque IIS evitará que se sirvan archivos * .config

El archivo de configuración predeterminado debe configurarse de manera que pueda ejecutar la aplicación localmente en su propia máquina.

Lo más importante es que estos archivos deben ser casi 100% idénticos en todos los aspectos, incluso en el formato. No debe usar tabulaciones en una versión y espacios en otra para sangrar. Debería poder ejecutar una herramienta de diferencias en los archivos para ver exactamente qué es diferente entre ellos. Prefiero usar WinMerge para diferenciar los archivos.

Cuando su proceso de compilación crea los binarios, debe haber una tarea que sobrescriba el archivo web.config con el archivo de configuración apropiado para ese entorno. Si los archivos están comprimidos, los archivos no relevantes deben eliminarse de esa compilación.


4

He usado la plantilla antes, es decir, web.dev.config, web.prod.config, etc., pero ahora prefiero la técnica de "anular archivo". El archivo web.config contiene la mayoría de las configuraciones, pero un archivo externo contiene valores específicos del entorno, como conexiones db. Buena explicación en el blog de Paul Wilson .

Creo que esto reduce la cantidad de duplicación entre los archivos de configuración, lo que puede causar problemas al agregar nuevos valores / atributos.


3

@ Grant tiene razón.

Estoy en un equipo con cerca de otros 100 desarrolladores y nuestros archivos de configuración no están registrados en el control de código fuente. Tenemos versiones de los archivos en el repositorio que se extraen con cada extracción, pero no cambian.

Nos ha funcionado bastante bien.


2

Lo controlo la versión, pero nunca lo envío a otros servidores. Si el servidor de producción requiere un cambio, lo hago directamente en el archivo de configuración.

Puede que no sea bonito, pero funciona bien.


2

La versión simple y sencilla de app / web.config debe ser lo suficientemente genérica para funcionar en todas las máquinas de desarrollo y mantenerse actualizada con cualquier cambio de configuración nuevo, etc. Si necesita un conjunto específico de configuraciones para dev / prueba / configuración de producción, verifique archivos separados con esa configuración, como dijo GateKiller, con algún tipo de convención de nomenclatura, aunque normalmente uso "web.prod.config", para no cambiar la extensión del archivo.


2

Usamos un archivo de configuración de plantilla que se registra en el control de versiones y luego un paso en nuestra compilación automatizada para reemplazar entradas específicas en el archivo de plantilla con configuraciones específicas del entorno. La configuración específica del entorno se almacena en un archivo XML separado que también está bajo control de versiones.

Estamos usando MSBuild en nuestra compilación automatizada, por lo que usamos la tarea XmlUpdate de MSBuild Community Tasks para actualizar los valores.


2

Durante mucho tiempo, he hecho exactamente lo que ha hecho bcwood. Mantengo copias de web.dev.config, web.test.config, web.prod.config, etc. bajo control de código fuente, y luego mi sistema de compilación / implementación les cambia el nombre automáticamente a medida que se implementa en varios entornos. Obtiene una cierta cantidad de redundancia entre los archivos (especialmente con todas las cosas de asp.net allí), pero en general funciona muy bien. También debe asegurarse de que todos los miembros del equipo recuerden actualizar todos los archivos cuando realizan un cambio.

Por cierto, me gusta mantener ".config" al final como extensión para que las asociaciones de archivos no se rompan.

En cuanto a las versiones para desarrolladores locales del archivo de configuración, siempre hago todo lo posible por animar a las personas a que utilicen la misma configuración local tanto como sea posible para que no sea necesario tener su propia versión. No siempre funciona para todos, en cuyo caso las personas generalmente lo reemplazan localmente según sea necesario y parten de allí. No es demasiado doloroso ni nada.


1

En nuestro proyecto, tenemos la configuración almacenada en archivos con un prefijo, luego nuestro sistema de compilación extrae la configuración adecuada según el nombre de host del sistema actual. Esto funciona bien para nosotros en un equipo relativamente pequeño, lo que nos permite aplicar cambios de configuración a los archivos de otras personas si / cuando agregamos un nuevo elemento de configuración. Obviamente, esto definitivamente no se adapta a proyectos de código abierto con un número ilimitado de desarrolladores.


1

Tenemos dos problemas aquí.

  • En primer lugar, tenemos que controlar el archivo de configuración que se envía con el software.

    Es fácil para un desarrollador registrar un cambio no deseado en el archivo de configuración maestro, si está usando el mismo archivo en el entorno de desarrollo.

    Por otro lado, si tiene un archivo de configuración separado que está incluido en el instalador, es muy fácil olvidarse de agregarle una nueva configuración, o dejar que los comentarios no estén sincronizados con los comentarios en la devolución. archivo de configuración.

  • Luego tenemos el problema de que los desarrolladores tienen que mantener actualizada la copia del archivo de configuración mientras otros desarrolladores agregan nuevas configuraciones. Sin embargo, algunas configuraciones como las cadenas de conexión de la base de datos son diferentes para cada desarrollador.

  • Hay un tercer problema que la pregunta / respuesta no cubre. ¿Cómo fusiona los cambios que un cliente ha realizado en su archivo de configuración cuando instala una nueva versión de su software?

Todavía tengo que ver una buena solución que funcione bien en todos los casos, sin embargo, he visto algunas soluciones parciales (que se pueden combinar en diferentes combinaciones según sea necesario) que reducen mucho el problema.

  • En primer lugar, reduzca la cantidad de elementos de configuración que tiene en su archivo de configuración principal.

    Si no tiene la necesidad de permitir que sus clientes cambien sus asignaciones, use Fluent NHibernate (o de otra manera) para mover la configuración al código.

    Lo mismo ocurre con la configuración de inyección de dependencia.

  • Divida el archivo de configuración cuando sea posible, por ejemplo, use un archivo separado para configurar los registros de Log4Net.

  • No repita elementos entre muchos archivos de configuración, por ejemplo, si tiene 4 aplicaciones web que están todas instaladas en la misma máquina, tenga un archivo de configuración general al que apunte el archivo web.config de cada aplicación.

    (Utilice una ruta relativa de forma predeterminada, por lo que es raro tener que cambiar el archivo web.config)

  • Procese el archivo de configuración de desarrollo para obtener el archivo de configuración de envío.

    Esto se puede hacer con valores predeterminados en los comentarios XML que luego se establecen en el archivo de configuración cuando se realiza una compilación. O tener secciones que se eliminan como parte del proceso de creación del instalador.

  • En lugar de tener una sola cadena de conexión a la base de datos, tenga una por desarrollador.

    Por ejemplo, primero busque "database_ianr" (donde ianr es mi nombre de usuario o el nombre de la máquina) en el archivo de configuración en tiempo de ejecución, si no se encuentra, busque "database"

    Tener un segundo nivel "eg -oracle o -sqlserver" para que los desarrolladores accedan más rápido a ambos sistemas de base de datos.

    Por supuesto, esto también se puede hacer para cualquier otro valor de configuración.

    Luego, todos los valores que terminan en "_userName" se pueden eliminar antes de enviar el archivo de configuración.

Sin embargo, al final, lo que es usted es un "propietario del archivo de configuración" que asume la responsabilidad de administrar los archivos de configuración como se indica arriba o de otra manera. También debe hacer una diferencia en el archivo de configuración de las caras del cliente antes de cada envío.

No se puede eliminar la necesidad de una persona que se preocupe por este problema.


1

No creo que haya una solución única que funcione para todos los casos, ya que puede depender de la sensibilidad de los datos en los archivos de configuración, o del lenguaje de programación que está utilizando, y muchos otros factores. Pero creo que es importante mantener los archivos de configuración de todos los entornos bajo control de código fuente, para que siempre pueda saber cuándo se modificó y quién lo cambió, y lo que es más importante, poder recuperarlo si algo sale mal. Y lo harán.

Así que así es como lo hago. Esto es para proyectos de nodejs generalmente, pero creo que también funciona para otros marcos y lenguajes.

Lo que hago es crear un configsdirectorio en la raíz del proyecto, y debajo de ese directorio guardo varios archivos para todos los entornos (y algunas veces también archivos separados para el entorno de cada desarrollador) que se rastrean en el control de fuente. Y está el archivo real que usa el código nombrado configen la raíz del proyecto. Este es el único archivo que no se rastrea. Entonces se ve así

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

Cuando alguien revisa el proyecto, copia el archivo de configuración que desea usar en el configarchivo sin seguimiento y es libre de editarlo como desee, pero también es responsable de copiar estos cambios antes de comprometerse con los otros archivos de entorno según sea necesario.

Y en los servidores, el archivo sin seguimiento puede ser simplemente una copia (o referencia) del archivo con seguimiento correspondiente a ese entorno. En JS, simplemente puede tener 1 línea para requerir ese archivo.

Este flujo puede ser un poco complicado al principio, pero tiene grandes ventajas: 1. Nunca tendrá que preocuparse de que un archivo de configuración se elimine o modifique en el servidor sin tener una copia de seguridad 2. Lo mismo si un desarrollador tiene alguna configuración personalizada en su máquina y su máquina deja de funcionar por cualquier motivo 3. Antes de cualquier implementación, puede diferenciar los archivos de configuración developmenty, stagingpor ejemplo, ver si falta algo o está roto.


0

Simplemente mantenemos el archivo de configuración de producción registrado. Es responsabilidad del desarrollador cambiar el archivo cuando lo extraen de la fuente segura para su puesta en escena o desarrollo. Esto nos ha quemado en el pasado, así que no lo recomendaría.


0

Me enfrenté al mismo problema y encontré una solución. Primero agregué todos los archivos al repositorio central (también los del desarrollador).

Entonces, si un desarrollador recupera los archivos del repositorio, la configuración del desarrollador también está allí. Al realizar cambios en este archivo, Git no debería estar al tanto de estos cambios. De esa manera, los cambios no se pueden enviar / confirmar en el repositorio, sino que permanecen localmente.

He resuelto esto usando el comando git: update-index --assume-unchanged. Hice un archivo bat que se ejecuta en la construcción previa de los proyectos que contienen un archivo cuyos cambios deben ser ignorados por Git. Aquí está el código que puse en el archivo 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

En mi compilación previa, haría una llamada al archivo bat, por ejemplo:

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

Encontré en SO un archivo bat que copia el archivo de configuración correcto en web.config / app.config. También llamo a este archivo bat en el archivo prebuild. El código para este archivo bat es:

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

En mi compilación previa, haría una llamada al archivo bat, por ejemplo:

call "$(ProjectDir)\..\..\copyifnewer.bat" "$(ProjectDir)web.config.$(ConfigurationName)" "$(ProjectDir)web.config
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.