Revertendo automaticamente as confirmações que falham na compilação

39

Um colega me disse que está pensando em fazer com que nosso servidor de IC reverta as confirmações que falharam na compilação, portanto, o HEAD in master é sempre estável (como ao passar pelo menos a compilação).

Essa é uma prática recomendada ou pode ser mais problemática do que simplesmente deixar master interrompido até que o desenvolvedor a corrija?

Meu pensamento é que reverter o commit tornará mais complexa a tarefa de ler o commit e consertar (o desenvolvedor terá que reverter o revert e então commitar a correção, que também vai bagunçar o git log ) e nós devemos apenas deixar o commit e, em seguida, confirme a correção. Embora eu veja algumas vantagens em ter master stable, essa reversão de commits com falha não me convence.

edit: Não importa se é master ou qualquer outro ramo de desenvolvimento, mas a questão permanece a mesma: o sistema de CI deve reverter um commit que falhou na construção?

outra (extensão) edit: Ok, estamos usando git de uma forma estranha. Acreditamos que o conceito de ramificações vai contra o IC real, porque o comprometimento com uma ramificação isola você dos outros desenvolvedores e suas alterações, e adiciona tempo quando você precisa reintegrar sua ramificação e lidar com possíveis conflitos. Se todos se comprometerem com master , os conflitos serão reduzidos ao mínimo e todos os commit passarão em todos os testes.

Claro, isso obriga você a empurrar apenas estáveis (ou quebrar a compilação) e programar com mais cuidado para não quebrar a compatibilidade com versões anteriores ou alternar recursos ao introduzir novos recursos.

Existem desvantagens ao fazer o CI dessa ou daquela maneira, mas isso está fora do escopo da questão (consulte pergunta relacionada para isso). Se preferir, posso reformular a pergunta: uma pequena equipe de desenvolvedores trabalha em conjunto em um ramo de recursos. Se um desenvolvedor comete algo que quebra a compilação desse ramo, o sistema de CI deve reverter o commit ou não?

    
por Carlos Campderrós 21.08.2015 / 10:03
fonte

8 respostas

52

Eu seria contra fazer isso pelas seguintes razões:

  • Sempre que você configura uma ferramenta automatizada para alterar o código em seu nome , corre-se o risco de errar ou de surgir uma situação onde você precisa Pare de fazer essa mudança (por exemplo, a versão mais recente do Google Mock tinha um bug, por isso não é o seu código falhando) e você tem que perder tempo reconfigurando-o. Além disso, há sempre um pequeno risco de que a compilação falhe por causa de um bug no sistema de compilação, em vez de um bug no seu código. Para mim, CI é sobre ganhar confiança de que meu código está correto; isso apenas a transformaria em outra fonte de possíveis problemas para eu me preocupar.

  • Os tipos de bugs que quebram "a compilação" devem ser erros tolos que levam pouco tempo para serem corrigidos (como você indicou em um comentário, isso é verdade para você) . Se bugs mais sutis e complicados estão regularmente tornando-os no master, então a solução correta não é "consertá-lo mais rápido", é ter mais cuidado ao revisar as ramificações de recursos antes que elas sejam mescladas.

  • Deixar mestre unbuildable por alguns minutos, enquanto o bug é corrigido corretamente não faz mal a ninguém. Não é como se o CEO fosse pessoalmente verificar o mestre e publicar o código diretamente para os clientes em qualquer momento aleatório (pelo menos, espero que não sem o seu envolvimento). No caso altamente improvável de você precisar liberar algo antes de poder corrigir o bug, então você pode facilmente tomar a decisão de reverter manualmente antes de publicar.

por 21.08.2015 / 13:03
fonte
26

Vamos concordar com os termos primeiro.

Eu pessoalmente uso os termos "Integração contínua" e "Integração contínua" para distinguir dois cenários diferentes:

  • Continuous Build: uma ferramenta que verifica periodicamente se o repositório mudou desde a última compilação, e compilar / testar se isso aconteceu.
  • Integração contínua: uma ferramenta que recebe solicitações de extração e as valida com o último cabeçalho anterior para torná-las visíveis.

O último, Integração Contínua, significa que o repositório que ele protege é sempre verde 1 : é estritamente melhor.

A sua pergunta só faz sentido para a Construção Contínua, por isso responderei assumindo que esta é a sua configuração.

1 : Causas ambientais também podem estragar uma compilação, por exemplo, um teste com um ano codificado (2015) pode começar a falhar em janeiro de 2016, um disco pode ficar cheio, .. E, claro, há a praga de testes instáveis. Eu orgulhosamente ignoro essas questões aqui; senão nunca chegaremos a lugar algum.

Se você tiver uma configuração de Construção Contínua, poderá de fato automatizar a reversão de confirmações que podem ter quebrado a compilação, no entanto, há várias sutilezas.

  • Você não pode realmente despir os commits: outros colegas de trabalho podem já tê-los verificado e vão empurrá-los de volta na próxima vez que eles tentarem confirmar. Em vez disso, uma reversão deve estar confirmando um diff reverse . Ah, e os colegas de trabalho vão odiá-lo por reverter o trabalho deles quando estiver correto, pois eles terão que encontrar uma maneira de empurrá-lo de volta ...
  • Na verdade, você não pode retirar apenas o último commit (é uma mesclagem), mas precisa remover todos os commits ... até certo ponto. Por exemplo, o último commit válido conhecido (cuidado ao inicializar o sistema).
  • Você precisa pensar sobre as causas externas (questões ambientais) e evitar uma configuração que reverta tudo para o dia 0. Felizmente, reverter para o último compromisso válido conhecido evita essa questão.
  • Você precisa pensar que a última compilação boa conhecida não pode mais ser construída (problemas de ambiente) e, nesse caso, é provável que todas as outras confirmações sejam revertidas. Idealmente, em caso de falha, e antes de reverter, você verificaria a última boa compilação conhecida e a testaria novamente. Se passar, reverta, caso contrário, levante um alerta.

Note que com este sistema, no caso de um teste instável ou um colega de trabalho muitas vezes cometendo porcaria, muitos bons commits serão revertidos. Seus colegas de trabalho vão te odiar.

Espero que meu conto de horror tenha exposto os problemas de permitir um repositório corrompido e você agora implementará um pipeline de Integração Contínua adequado, onde PR nunca será enviado diretamente para o repositório, mas enfileirado para ser mesclado em uma fila de trabalho, e integrado em um uma vez (ou por roll-ups):

  • buscar cabeçalho do repositório localmente
  • aplicar pedido (s) de solicitação
  • construir e testar
  • em caso de sucesso, envie para o repositório, caso contrário, marque como com falha
  • passar para as próximas solicitações

Tendo tentado ambos, isso é estritamente melhor.

    
por 21.08.2015 / 15:51
fonte
5

Is this a best practice or it may be more problematic than just leaving master broken until the developer fixes it?

É problemático. Uma pessoa que decide "o HEAD mestre está quebrado; vou reverter a mudança de topo" é completamente diferente do que o sistema de CI fazendo o mesmo.

Aqui estão algumas desvantagens:

  • Erros no processo de reversão automatizada atrapalharão o repositório;

  • isto assume um único changeset (o mais alto) errou a compilação (o que não é realista)

  • Os mantenedores terão mais trabalho a fazer para corrigir o problema, do que apenas investigar e confirmar (eles também precisarão analisar o histórico inverso)

We believe that the concept of branches goes against real CI, because committing to a branch isolates you from the other developers and their changes, and adds time when you have to reintegrate your branch and deal with possible conflicts.

Essa crença (ramificações vs. CI) está incorreta. Considere manter o um branch estável, onde você confirma somente changesets testados pela unidade . O restante (filiais de recursos e filiais locais) deve ser de responsabilidade de cada desenvolvedor e não parte de sua política de IC.

Nos ramos de recursos que você deseja que sejam isolados de outros desenvolvedores. Isso permite que você:

  • executar codificação exploratória

  • experimente a base de código

  • execute confirmações parciais (confirme efetivamente o código não funcional) para configurar pontos de backup (caso você tenha problemas), para criar um histórico de alterações mais significativo (por meio de mensagens de confirmação) e para fazer backup de seu trabalho e alternar completamente para outra coisa (no tempo que você leva para escrever "git commit & git checkout")

  • executa tarefas de baixa prioridade que demoram muito tempo (por exemplo, você deseja realizar uma refatoração que altere todas as 80 classes da camada de dados: você altera duas por dia, até que todas elas sejam modificadas) (mas você pode fazer isso sem afetar ninguém até que você possa fazer um único commit).

If one developer commits something that breaks the build for that branch, should the CI system revert the commit or not?

Não deveria. Confirmar o código estável em sua ramificação de IC é uma responsabilidade do committer, não de um sistema automatizado.

    
por 21.08.2015 / 13:47
fonte
2

Eu sugeriria usar um ambiente Gerrit + Jenkins para manter seu branch master sempre em boa forma. As pessoas empurram seu novo código para Gerrit, o que aciona um trabalho de Jenkins para obter o patch, os builds, os testes e assim por diante. Se outros desenvolvedores como o seu patch e o Jenkins concluírem o seu trabalho com sucesso, então o Gerrit vai fundir esse pedaço de código com o seu branch master.

É um ambiente similar descrito por @ brian-vandenberg

Além de manter sua filial em bom estado, você também adiciona uma etapa de revisão de código que melhora a qualidade do código e o compartilhamento de conhecimento sobre o seu software.

[1] Jenkins link

[2] Gerrit link

    
por 27.08.2015 / 22:58
fonte
1

O IC nunca deve alterar o histórico de commits do repositório.

A solução correta aqui é que nenhum commit seja adicionado ao branch master se eles não tiverem sido testados e verificados.

Você trabalha em ramificações de recursos, faz com que o CI seja executado automaticamente nelas e, se as compilações falharem, não as mescle no mestre.

Você pode ter uma compilação adicional que testa as mesclagens se isso for uma preocupação, executando na ramificação do recurso e durante a compilação do mestre / integração / o que quer que seja na ramificação local e, em seguida, executando os testes.

    
por 21.08.2015 / 14:19
fonte
1

Usamos o Jenkins para o nosso servidor de compilação e usamos o modelo do gatekeeper para empurrar commits - onde uma combinação de Jenkins e commit triggers (que garantem que os revisores tenham feito o trabalho) é o gatekeeper.

As confirmações são enviadas indiretamente por meio de um curl para Jenkins, onde é clonado o repo master e, em seguida, puxa o (s) commit (s) a ser mesclado e executa todas as compilações necessárias (para Linux / solaris). Se todas as compilações forem concluídas, o commit será enviado.

Isso evita muitos, se não todos os problemas discutidos até agora:

  • alteração da história
  • obtendo histórico correto se você for o desenvolvedor que precisa consertar a quebra
  • instabilidade (na forma de construções quebradas) nunca é introduzida

Ele também nos permite aplicar diretamente outros requisitos, como testes de unidade, concluídos com êxito.

    
por 21.08.2015 / 18:12
fonte
0

Quantas vezes você recebeu esse e-mail automático dizendo que seu último commit quebrou a compilação? Quantas vezes está errado? Mas agora você precisa verificar se realmente era você ou alguém que fez outro commit na mesma época. Ou talvez fosse algo ambiental.

Se o sistema não sabe ao certo, então certamente não quero automatizá-lo.

    
por 21.08.2015 / 17:52
fonte
0

A pergunta feita é falho. Eu respeito esta declaração embora

"Acreditamos que o conceito de ramificações vai contra o IC real, porque o comprometimento com uma ramificação isola você dos outros desenvolvedores e suas alterações"

O que você deve fazer, porém, é essas etapas

  • trabalhe off master se você gostar (tudo bem e continue puxando as alterações de todos) MAS NÃO se comprometa a masterizar localmente
  • APENAS ANTES de confirmar suas alterações no master, crie uma ramificação com submit_XXXXXX
  • faça sua criação automatizada atender a todas as ramificações submit_XXX criadas
  • Opção 1: criar quebras ou mesclar quebras ... alterar rejeitada e nunca chegar ao mestre
  • Opção 2: construir obras, jenkins empurra o mestre e atualiza-o

ENTÃO, o que fazemos é colocar um hook de commit do git para impedir que TODOS se comprometam com o master. Ele funciona muito bem .... SEM construções quebradas nunca e NÃO revertendo commits do mestre também.

mais tarde, Dean

    
por 30.09.2016 / 02:58
fonte