Se você tem uma aplicação sendo versionada com Git, acredito que já tenha sentido a necessidade de automatizar o processo de atualização dessa aplicação, ao invés de ter que atualizar os arquivos manualmente ou então ter que logar no servidor via SSH para rodar um git pull
toda vez que houver uma atualização.
E se assim que você fizesse a atualização local, desse um git push origin
para atualizar o repositório remoto (no Github, por exemplo) e depois desse apenas um git push servidor
para atualizar a aplicação em produção, seria muito mais simples certo?
Neste artigo, pretendo mostrar uma forma para automatizar o processo de atualização de uma aplicação, utilizando Git Hooks. Os exemplos mostrados neste artigo foram testados no Ubuntu 16.04.
Pré-requisitos
Antes de iniciar, são necessários alguns pré-requisitos no servidor de produção da sua aplicação.
- Acesso via SSH;
- Git instalado.
Criando repositório local
Primeiramente, vamos criar um repositório local em nosso computador apenas para servir de teste durante o artigo. Para isso, criaremos uma pasta chamada deploy-automatico
e adicionaremos um arquivo.
<!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Deploy automático</title> </head> <body> <h1>Deploy automático funcionando!</h1> </body> </html>
Agora vamos abrir o terminal na pasta da aplicação que foi criada, iniciar um repositório Git e dar o commit inicial.
# Iniciando repositório git init # Adicionando arquivo e commitando git add index.html git commit -m "Commit inicial"
Configurando o servidor
Agora que já temos uma aplicação para testar, vamos acessar o nosso servidor via SSH.
ssh rafael@rafaelcouto.com.br
Criando pasta do repositório
Na pasta do meu usuário, vou criar uma outra pasta que será a pasta base do nosso repositório.
mkdir /home/rafael/deploy-automatico
Vamos então entrar nesta pasta e iniciar um repositório Git com a opção --bare
.
# Entrando na pasta cd /home/rafael/deploy-automatico # Iniciando repositório bare git init --bare
Perceba na Imagem 2 que será criado uma estrutura semelhante ao que temos na pasta .git
do nosso repositório local. Um repositório bare nada mais é que um repositório sem diretório de trabalho, ou seja, é utilizado apenas para compartilhamento e não possui diretamente o código fonte da nossa aplicação.
Portanto, um repositório bare é um repositório central que nos permite atualizá-lo através do git push
. E no caso, o nosso repositório local é um repositório non-bare.
Criando hook
Dentro da pasta do repositório que criamos temos a pasta hooks
que nos permite definir gatilhos para determinados eventos. O que queremos é que, ao receber um push, nós atualizemos o código fonte da nossa aplicação, para isso vamos criar um post-receive hook.
# Entrando na pasta cd /home/rafael/deploy-automatico/hooks # Criando arquivo do hook nano post-receive
Estou utilizando o nano como editor, porém você pode utilizar o vim ou qualquer editor de sua preferência. Vamos então colocar o conteúdo no arquivo, depois basta pressionar CTRL+X e depois Y para salvar.
#!/bin/bash # Armazenando caminho do código fonte em variável worktree=/var/www/deploy-automatico # Atualizando código fonte git --work-tree="$worktree" checkout -f
Utilizamos o comando git checkout com a opção --work-tree
, que nos permite indicar a pasta do nosso código fonte. No meu caso, o código fonte da aplicação está em /var/www/deploy-automatico
que é pasta raiz de um subdominio que criei para essa aplicação. Lembrando que a pasta do código fonte deve ter permissão para o seu usuário criar arquivos e deve estar vazia para o primeiro push.
Por fim, vamos dar permissão de execução para nosso hook.
chmod +x post-receive
Pronto, agora quando recebermos um push, as alterações serão sincronizadas com a pasta do código fonte, atualizando assim a nossa aplicação. O próximo passo agora é configurar nosso repositório local.
Configurando repositório local
Agora na aplicação de teste que criamos, vamos adicionar o endereço remoto para nos permitir executar um push para nosso servidor. Para isso utilizamos o git remote add, que possui a seguinte sintaxe.
git remote add <nome> <usuario>@<endereco-remoto>:<caminho-repositorio>
Portanto, o comando no meu caso ficou da seguinte forma.
git remote add servidor rafael@rafaelcouto.com.br:deploy-automatico
O nome é apenas o identificador que você vai utilizar ao executar o push, no caso eu deixei servidor. O usuário e o endereço remoto é o mesmo que se utiliza para o acesso SSH. Como a pasta padrão do usuário rafael é /home/rafael
, eu posso informar o caminho relativo do repositório, entretanto, você também poderia utilizar o caminho completo.
git remote add servidor rafael@rafaelcouto.com.br:/home/rafael/deploy-automatico
Depois podemos executar um git remote -v
apenas para verificar se o endereço remoto foi realmente adicionado.
Vamos então fazermos um push para o servidor do branch master. Para isso fazemos da mesma forma quando, por exemplo, queremos atualizar o repositório no Github, apenas substituindo o origin por servidor.
git push servidor master
Pronto, agora basta acessarmos o endereço da aplicação para verificar se tudo funcionou.
Atualizando aplicação
Após fazer o primeiro push, vamos atualizar nosso arquivo index.html
apenas para testar se o processo de atualização está funcionando.
<!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Deploy automático</title> </head> <body> <h1>Deploy automático funcionando!</h1> <p> Acesse o artigo <a href="https://rafaelcouto.com.br/automatizando-atualizacao-de-aplicacao-com-git">clicando aqui</a>. </p> </body> </html>
Vamos então fazer o commit da nossa alteração e o push para o servidor.
# Adicionando arquivo e commitando git add index.html git commit -m "Atualizado index.html" # Atualizando servidor git push servidor master
Por fim, vamos acessar o endereço da aplicação para verificar se tudo funcionou.
Automatização completa
Agora que já temos o processo de atualização automatizado, podemos utilizar um pouco de Shell Script e automatizar ainda mais o processo. Para evento de post-receive, o Git disponibiliza alguns argumentos que são muito úteis.
#!/bin/bash # Armazenando argumentos em variáveis read oldrev newrev ref # Armazenando caminho do código fonte em variável worktree=/var/www/deploy-automatico # Atualizando código fonte git --work-tree="$worktree" checkout -f # Exibindo valores das variáveis echo "Old revision: $oldrev" echo "New revision: $newrev" echo "Reference name: $ref"
Com essas variáveis podemos, por exemplo, comparar se houve alteração em algum arquivo.
if git --work-tree="$worktree" diff --name-only $oldrev $newrev | grep "^index\.html$" -q; then echo "Arquivo index.html alterado" fi
Através do git diff conseguimos verificar os arquivos que foram alterados entre dois commits, e utilizamos a opção --name-only
, pois queremos apenas os nomes dos arquivos alterados. Tendo o nomes dos arquivos, utilizamos o comando grep para verificar se o arquivo buscado está entre eles, se estiver será exibido a mensagem. Com isso podemos fazer várias coisas, vejamos alguns exemplos.
1. Composer
Em uma aplicação PHP é muito comum utilizarmos o Composer, portanto quando você atualizar a aplicação é interessante rodar um composer update
caso alguma biblioteca tenha sido adicionada ou removida.
if git --work-tree="$worktree" diff --name-only $oldrev $newrev | grep "^composer\.json$" -q; then echo "Atualizando bibliotecas" composer --working-dir=$worktree update --no-interaction fi
Verificamos se o arquivo composer.json
foi alterado, então rodamos o composer update
utilizando a opção --working-dir
para indicar o caminho da aplicação e a opção --no-interaction
para não fazer perguntas ao usuário já que é um processo automático.
2. Laravel
Se você possuir uma aplicação Laravel, provavelmente vai querer colocar o sistema em modo de manutenção enquanto está atualizando, além de rodar as migrations.
echo "Iniciando modo de manutenção" php $worktree/artisan down echo "Atualizando código fonte" git --work-tree="$worktree" checkout -f echo "Rodando migrations"; php $worktree/artisan migrate --force echo "Finalizando modo de manutenção" php $worktree/artisan up
Utilizamos o php para chamar o artisan na pasta da nossa aplicação e então podemos utilizar os comandos disponíveis, como por exemplo, o up, down e migrate. O migrate utilizamos com o --force
para evitar confirmação que está em ambiente de produção.
3. Gulp
Caso sua aplicação possua alguma tarefa do Gulp, você pode executá-la também. Por exemplo, caso algum arquivo javascript tenha sido alterado e você quer rodar uma tarefa de build.
if git --work-tree="$worktree" diff --name-only $oldrev $newrev | grep "^public\/assets\/.*\?\.js$" -q; then echo "Refazendo build da aplicação" gulp build --cwd "$worktree" fi
Nesse caso, se qualquer arquivo javascript (.js) que esteja na pasta public/assets
tiver sido alterado, então chamamos a tarefa build registrada no Gulp.
4. Outros
Enfim, com Shell Script o céu é o limite! Portanto, você pode rodar qualquer comando disponível no servidor para automatizar ainda mais o processo de atualização, como por exemplo, algum comando para fazer backup do banco de dados, limpar algum cache, compilar alguma coisa, etc.
Conclusão
Neste artigo vimos uma forma de automatizar o processo de atualização de uma aplicação em produção de uma forma relativamente simples.
Vale ressaltar que a aplicação em produção será sempre sincronizada com a branch master, ou seja, caso haja alguma alteração incompleta ou algum bug, será liberado em produção. Entretanto, se você aplica o conceito de Git Flow em suas aplicações, deveria diminuir as chances de problemas.
E vale lembrar também que você não deve utilizar esse método para manter o versionamento, continue utilizando o Github, Bitbucket ou qualquer outro serviço para gerenciar as versões da sua aplicação.
Enfim, espero que este artigo tenha sido útil de alguma forma. Até a próxima.
Código fonte disponível em: https://github.com/rafaelcouto/automatizando-atualizacao-de-aplicacao-com-git
Referências
- Deploy com Git — Configurando e executando um deploy automatizado. <https://medium.com/agits/deploy-com-git-configurando-e-executando-um-deploy-automatizado-156e3e1bc374>. Acessado em 13 de maio de 2020.
- Deploy com Git Hooks. <https://www.andrebian.com/deploy-com-git-hooks>. Acessado em 13 de maio de 2020.
- Git Reference. <https://git-scm.com/docs>. Acessado em 13 de maio de 2020.