Como você lida com arquivos de configuração no controle de origem?


96

Digamos que você tenha um aplicativo da web típico e com um arquivo de configuração. Cada desenvolvedor trabalhando no projeto terá uma versão para seus dev boxes, haverá versões dev, prod e stage. Como você lida com isso no controle de origem? Não verificar este arquivo, verificar com nomes diferentes ou fazer algo totalmente sofisticado?

Respostas:


69

O que eu fiz no passado é ter um arquivo de configuração padrão que é verificado no controle de origem. Então, cada desenvolvedor tem seu próprio arquivo de configuração de substituição, que é excluído do controle de origem. O aplicativo carrega primeiro o padrão e, em seguida, se o arquivo de substituição estiver presente, carrega-o e usa todas as configurações da substituição em preferência ao arquivo padrão.

Em geral, quanto menor for o arquivo de substituição, melhor, mas ele sempre pode conter mais configurações para um desenvolvedor com um ambiente muito diferente do padrão.


24

A configuração é um código e você deve criar uma versão dele. Baseamos nossos arquivos de configuração em nomes de usuário; tanto no UNIX / Mac quanto no Windows, você pode acessar o nome de login do usuário e, desde que sejam exclusivos do projeto, tudo bem. Você pode até substituir isso no ambiente, mas deve controlar a versão de tudo.

Isso também permite que você examine as configurações de outras pessoas, o que pode ajudar a diagnosticar problemas de construção e plataforma.


10
+1 absolutamente por enfatizar que a configuração ainda deve ser versionada
Alexander Bird

E se o nome de usuário não for confiável por qualquer motivo, então você pode ter um único arquivo com apenas uma linha fornecendo o nome do arquivo de configuração de substituição. Dessa forma, há muito pouco (como em cerca de 10 caracteres ou mais) sem controle de versão. E o arquivo README pode explicar que você precisa fazer esse arquivo.
Alexander Bird

Sempre acho que as configurações devem ser mantidas separadas do código. Trabalhei em locais que exigem tantas configurações para um repo que o Git fica sobrecarregado com arquivos de configuração. Não estou dizendo que as configurações não devem ser versionadas, elas pertencem a outro lugar, como um gerenciador de artefato. Config não é código, são configurações para código.
Thomas de

Os arquivos de configuração podem conter informações confidenciais, como senhas, que não devem ser versionadas. Ou você deseja conceder a cada desenvolvedor acesso ao seu ambiente de produção? Acho que é melhor apenas criar uma versão de uma "configuração principal" e substituí-la em ambientes específicos.
Christophe Weis

19

Não crie uma versão desse arquivo. Crie uma versão de um modelo ou algo assim.


2
Eu uso essa abordagem, eu só tenho um main.php.tmpl e quando eu faço o checkout de uma nova cópia apenas copio para main, php. Eu adiciono o arquivo main.php à lista de ignorados para evitar confirmá-lo por acidente.
levhita de

10

Minha equipe mantém versões separadas dos arquivos de configuração para cada ambiente (web.config.dev, web.config.test, web.config.prod). Nossos scripts de implantação copiam a versão correta, renomeando-a para web.config. Desta forma, temos total controle de versão nos arquivos de configuração de cada ambiente, podemos facilmente realizar uma diff, etc.


6

Atualmente, tenho o arquivo de configuração "template" com uma extensão adicionada, por exemplo:

web.config.rename

No entanto, posso ver um problema com este método se mudanças críticas foram alteradas.


6

1 na abordagem do modelo.

Mas, uma vez que esta questão tem tag Git, a alternativa distribuída vem à mente, em que as personalizações são mantidas em um branch de teste privado:

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

Nesse esquema, a linha principal contém um arquivo de configuração genérico de "modelo" que requer o mínimo de ajustes para se tornar funcional.

Agora, os desenvolvedores / testadores podem ajustar o arquivo de configuração da maneira que quiserem e apenas confirmar essas alterações localmente em um branch de teste privado (por exemplo, B '= personalizações B +). Cada vez que a linha principal avança, eles a mesclam sem esforço em testes, o que resulta em commits de mesclagem como D '(= D + versão mesclada das personalizações de B).

Este esquema realmente brilha quando o arquivo de configuração do "template" é atualizado: as mudanças de ambos os lados são mescladas e são extremamente prováveis ​​de resultar em conflitos (ou falhas de teste) se forem incompatíveis!


Mas quando os testadores dos desenvolvedores entram na linha principal, suas alterações no arquivo de modelo também são enviadas. Não?
Nick Zalutskiy

A menos que haja uma solução para o comentário de Nick, isso não funcionará pelo que vejo. Ou talvez explique qual modelo de fluxo você está usando que resolveria o problema.
Alexander Bird

Eu concordo com a abordagem do modelo com quaisquer ajustes necessários incluídos no momento da construção. No entanto, no tópico de ramificação ... E se houvesse vários modelos (dev, teste, etc.) e os desenvolvedores simplesmente omitissem as alterações de seus commits. Não infalível, mas poderia funcionar com cooperação.
NickSuperb,

5

A solução que usamos é ter apenas um único arquivo de configuração (web.config / app.config), mas adicionamos uma seção especial ao arquivo que contém configurações para todos os ambientes.

Existe um LOCAL, DEV, QA, PRODUÇÃO seções cada uma contendo as chaves de configuração relevantes para aquele ambiente em nosso (s) arquivo (s) de configuração.

O que faz tudo isso funcionar é um conjunto chamado xxx.Environment que é referenciado em todos os nossos aplicativos (winforms e webforms), que informa ao aplicativo em qual ambiente ele está operando.

O conjunto xxx.Environment lê uma única linha de informações do machine.config da máquina fornecida, informando que ela está em DEV, QA, etc. Essa entrada está presente em todas as nossas estações de trabalho e servidores.

Espero que isto ajude.


1
Isso funciona extremamente bem se houver apenas algumas diferenças entre o ambiente (ou seja, strings de conexão)
Eric Labashosky

e supondo que não haja centenas de desenvolvedores, todos colocando suas configurações personalizadas lá também (ainda funcionaria, mas seria muito complicado)
Alexander Bird

5

Sempre mantive todas as versões dos arquivos de configuração no controle de origem, na mesma pasta do arquivo web.config.

Por exemplo

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

Eu prefiro essa convenção de nomenclatura (em oposição a web.config.production ou production.web.config) porque

  • Ele mantém os arquivos juntos quando você classifica por nome de arquivo
  • Ele mantém os arquivos juntos quando você classifica por extensão de arquivo
  • Se o arquivo acidentalmente for colocado em produção, você não conseguirá ver o conteúdo em http porque o IIS impedirá que arquivos * .config sejam disponibilizados

O arquivo de configuração padrão deve ser configurado de forma que você possa executar o aplicativo localmente em sua própria máquina.

Mais importante ainda, esses arquivos devem ser quase 100% idênticos em todos os aspectos, até mesmo na formatação. Você não deve usar tabulações em uma versão e espaços em outra para recuar. Você deve ser capaz de executar uma ferramenta de comparação nos arquivos para ver exatamente o que é diferente entre eles. Eu prefiro usar o WinMerge para comparar os arquivos.

Quando o processo de construção cria os binários, deve haver uma tarefa que sobrescreve o web.config com o arquivo de configuração apropriado para esse ambiente. Se os arquivos forem compactados, os arquivos não relevantes devem ser excluídos dessa compilação.


4

Já usei o modelo antes, ou seja, web.dev.config, web.prod.config, etc, mas agora prefiro a técnica de 'substituir arquivo'. O arquivo web.config contém a maioria das configurações, mas um arquivo externo contém valores específicos do ambiente, como conexões db. Boa explicação no blog de Paul Wilson .

Acho que isso reduz a quantidade de duplicação entre os arquivos de configuração, o que pode causar problemas ao adicionar novos valores / atributos.


3

@Grant está certo.

Estou em uma equipe com cerca de 100 outros desenvolvedores, e nossos arquivos de configuração não são verificados no controle de origem. Temos versões dos arquivos no repositório que são extraídas a cada verificação, mas não mudam.

Funcionou muito bem para nós.


2

Eu tenho controle de versão, mas nunca envio para outros servidores. Se o servidor de produção exigir uma alteração, eu a faço diretamente no arquivo de configuração.

Pode não ser bonito, mas funciona muito bem.


2

A versão com check-in simples de app / web.config deve ser genérica o suficiente para funcionar em todas as máquinas de desenvolvedor e ser mantida atualizada com quaisquer novas alterações de configuração, etc. Se você precisar de um conjunto específico de configurações para dev / test / production settings, verifique em arquivos separados com essas configurações, como o GateKiller declarou, com algum tipo de convenção de nomenclatura, embora eu geralmente use "web.prod.config", para não alterar a extensão do arquivo.


2

Usamos um arquivo de configuração de modelo que é verificado no controle de versão e, em seguida, uma etapa em nossa construção automatizada para substituir entradas específicas no arquivo de modelo por configurações específicas do ambiente. As configurações específicas do ambiente são armazenadas em um arquivo XML separado que também está sob controle de versão.

Estamos usando o MSBuild em nossa construção automatizada, portanto, usamos a tarefa XmlUpdate das Tarefas da comunidade do MSBuild para atualizar os valores.


2

Por muito tempo, fiz exatamente o que bcwood fez. Eu mantenho cópias de web.dev.config, web.test.config, web.prod.config, etc. sob controle de origem e, em seguida, meu sistema de construção / implantação os renomeia automaticamente conforme ele implanta em vários ambientes. Você obtém uma certa quantidade de redundância entre os arquivos (especialmente com todas as coisas do asp.net lá), mas geralmente funciona muito bem. Você também deve certificar-se de que todos na equipe se lembrem de atualizar todos os arquivos quando fizerem uma alteração.

A propósito, eu gosto de manter ".config" no final como a extensão para que as associações de arquivo não sejam quebradas.

No que diz respeito às versões do desenvolvedor local do arquivo de configuração, sempre tento o meu melhor para encorajar as pessoas a usar as mesmas configurações locais, tanto quanto possível, para que não haja necessidade de ter sua própria versão. Nem sempre funciona para todos; nesse caso, as pessoas geralmente apenas substituem localmente conforme necessário e partem daí. Não é muito doloroso nem nada.


1

Em nosso projeto, temos a configuração armazenada em arquivos com um prefixo, então nosso sistema de construção puxa a configuração apropriada com base no nome de host do sistema atual. Isso funciona bem para nós em uma equipe relativamente pequena, permitindo-nos aplicar alterações de configuração aos arquivos de outras pessoas se / quando adicionarmos um novo item de configuração. Obviamente, isso definitivamente não se adapta a projetos de código aberto com um número ilimitado de desenvolvedores.


1

Temos dois problemas aqui.

  • Em primeiro lugar, temos que controlar o arquivo de configuração que acompanha o software.

    É muito fácil para um desenvolvedor fazer o check-in de uma alteração indesejada para o arquivo de configuração principal, se estiver usando o mesmo arquivo no ambiente de transferência.

    Por outro lado, se você tiver um arquivo de configuração separado que é incluído pelo instalador, é muito fácil esquecer de adicionar uma nova configuração a ele ou deixar que os comentários nele fiquem fora de sincronia com os comentários enviados configurando arquivo.

  • Então, temos o problema de que os desenvolvedores precisam manter uma cópia do arquivo de configuração atualizada enquanto outros desenvolvedores adicionam novas definições de configuração. No entanto, algumas configurações, como strings de conexão de banco de dados, são diferentes para cada desenvolvedor.

  • Há um terceiro problema que as perguntas / respostas não cobrem. Como você mescla as alterações que um cliente faz em seu arquivo de configuração ao instalar uma nova versão de seu software?

Ainda estou para ver uma boa solução que funcione bem em todos os casos, no entanto, vi algumas soluções parciais (que podem ser combinadas em combinações diferentes conforme necessário) que reduzem muito o problema.

  • Em primeiro lugar, reduza o número de itens de configuração que você tem em seu arquivo de configuração principal.

    Se você não precisa permitir que seus clientes alterem seus mapeamentos, use o Fluent NHibernate (ou outro) para mover a configuração para o código.

    Da mesma forma para configuração de injeção de depência.

  • Divida o arquivo de configuração quando possível, por exemplo, use um arquivo separado para configurar o que o Log4Net registra.

  • Não repita itens entre muitos arquivos de configuração, por exemplo, se você tiver 4 aplicativos da web que estão todos instalados na mesma máquina, tenha um arquivo de configuração geral para o qual o arquivo web.config em cada aplicativo aponta.

    (Use um caminho relativo por padrão, por isso é raro ter que alterar o arquivo web.config)

  • Processe o arquivo de configuração de desenvolvimento para obter o arquivo de configuração de remessa.

    Isso pode ser feito por ter valores padrão nos comentários Xml que são definidos no arquivo de configuração quando uma compilação é concluída. Ou ter seções que são excluídas como parte do processo de criação do instalador.

  • Em vez de ter apenas uma string de conexão de banco de dados, tenha uma por desenvolvedor.

    Por exemplo, primeiro procure por “database_ianr” (onde ianr é meu nome de usuário ou nome da máquina) no arquivo de configuração em tempo de execução, se não for encontrado, procure por “banco de dados”

    Ter um segundo nível "por exemplo, -oracle ou -sqlserver" torna mais rápido para os desenvolvedores chegarem aos dois sistemas de banco de dados.

    Isso também pode ser feito para qualquer outro valor de configuração.

    Então, todos os valores que terminam em “_userName” podem ser listados antes de enviar o arquivo de configuração.

No entanto, no final, você é um “dono do arquivo de configuração” que assume a responsabilidade de gerenciar o (s) arquivo (s) de configuração acima ou de outra forma. Ele / ela também deve fazer uma comparação no arquivo de configuração de faces do cliente antes de cada remessa.

Você não pode eliminar a necessidade de uma pessoa carinhosa, um problema tão curto.


1

Não acho que haja uma solução única que funcione para todos os casos, pois pode depender da sensibilidade dos dados nos arquivos de configuração, ou da linguagem de programação que você está usando, e tantos outros fatores. Mas acho importante manter os arquivos de configuração de todos os ambientes sob controle de origem, para que você possa sempre saber quando foi alterado e por quem, e mais importante, ser capaz de recuperá-lo se algo der errado. E eles vão.

Então é assim que eu faço. Isso geralmente é para projetos nodejs, mas acho que funciona para outros frameworks e linguagens também.

O que faço é criar um configsdiretório na raiz do projeto e, sob esse diretório, manter vários arquivos para todos os ambientes (e algumas vezes arquivos separados para cada ambiente do desenvolvedor também) que são rastreados no controle de origem. E há o arquivo real que o código usa, nomeado configna raiz do projeto. Este é o único arquivo que não é rastreado. Então fica assim

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

Quando alguém faz check-out do projeto, ele copia o arquivo de configuração que deseja usar no não rastreado config arquivo não e fica livre para editá-lo como desejar, mas também é responsável por copiar essas alterações antes de se comprometer com os outros arquivos de ambiente conforme necessário.

E nos servidores, o arquivo não rastreado pode ser simplesmente uma cópia (ou referência) do arquivo rastreado correspondente a esse ambiente. Em JS, você pode simplesmente ter 1 linha para exigir esse arquivo.

Este fluxo pode ser um pouco complicado no início, mas tem grandes vantagens: 1. Você nunca precisa se preocupar com um arquivo de configuração sendo excluído ou modificado no servidor sem ter um backup 2. O mesmo se um desenvolvedor tiver alguma configuração personalizada em seu a máquina e sua máquina param de funcionar por qualquer motivo 3. Antes de qualquer implementação, você pode comparar os arquivos de configuração developmente, stagingpor exemplo, ver se há algo faltando ou quebrado.


0

Nós apenas mantemos o arquivo de configuração de produção verificado. É responsabilidade do desenvolvedor alterar o arquivo ao retirá-lo da segurança de origem para teste ou desenvolvimento. Isso nos queimou no passado, então eu não sugeriria isso.


0

Enfrentei esse mesmo problema e encontrei uma solução para ele. Primeiro, adicionei todos os arquivos ao repositório central (também os do desenvolvedor).

Portanto, se um desenvolvedor busca os arquivos do repositório, a configuração do desenvolvedor também está lá. Ao fazer alterações neste arquivo, o Git não deve estar ciente dessas alterações. Dessa forma, as alterações não podem ser enviadas / confirmadas para o repositório, mas permanecem localmente.

Eu resolvi isso usando o comando git: update-index --assume-unchanged. Fiz um arquivo bat que é executado na pré-construção dos projetos que contêm um arquivo cujas alterações devem ser ignoradas pelo Git. Aqui está o código que coloquei no arquivo 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

No meu pré-desenvolvimento, eu faria uma chamada para o arquivo bat, por exemplo:

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

Encontrei no SO um arquivo bat que copia o arquivo de configuração correto para o web.config / app.config. Também chamo esse arquivo bat no pré-desenvolvimento. O código para este arquivo 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.

No meu pré-desenvolvimento, eu faria uma chamada para o arquivo bat, por exemplo:

call "$(ProjectDir)\..\..\copyifnewer.bat" "$(ProjectDir)web.config.$(ConfigurationName)" "$(ProjectDir)web.config
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.