Disponível em 🇧🇷 / Available in 🇺🇸
Eu vinha mantendo os inputs do Blog na minha maquina e sem versionamento, mas comecei a usar um outro notebook e pensar em copiar/colar o conteúdo prebuild do blog pra conseguir escrever novos artigos era a motivação que eu precisava para fazer o CI/CD.
Neste post vamos abordar a criação de um CI/CD, commitando os inputs do blog em um repositório, criando a trigger de commit no master para popular o conteúdo em outro repositório também do Github. É uma implementação não muito convencional, já que nosso ponto de publicação é um repositório do git.
post anterior 1 post anterior 2
Apenas para dar contexto, se você chegou até aqui e não está familiariado com o termo CI/CD, de forma bem grosseira, CI trata a compilação, testes e geração do artefato válido do projeto (para o nosso caso há somente a compilação para geração do html) e o CD o deployment (que no nosso caso é o envio dos arquivos compilados para o Github Pages). O assunto é extenso, abordado num livro dedicado para esse assunto e também abordado de forma muito mais didatica em artigos na internet.
Escolha do serviço de CI/CD
No passado explorei um pouco as possibilidades de integração para hosting de páginas estáticas e há uma grande variedade de ferramentas e serviços que podem ser utilizadas, então eu tinha uma noção das possibilidades aqui. Os critérios de decisão foram:
- Serviço de uso gratuito;
- Sem necessidade de hosting para o serviço em si;
- Integração simples e possível via arquivos de configuração alocados no repositório de inputs do projeto;
E de cara pensei em utilizar o AppVeyor.
AppVeyor
O AppVeyor é a primeira opção na lista de ferramentas para deployment do Wyam na documentação da propria ferramenta. O AppVeyor no passado me chamou a atenção por disponibilizar CI/CD com build-hosts rodando Windows e de graça - não estendi minha pesquisa sobre serviços de build para projetos Windows nos dias de hoje pois não era o tópico, mas num passado antes da Microsoft entrar nessa briga com VSTS online, ao que eu me lembro esses caras eram os únicos a disponibilizarem um serviço gratuito para builds de projetos Windows.
A ferramenta possui configuração simples, o script utilizado para build pode ficar no repositório do projeto e o uso é gratuito, mas com um porém: o repositório de git utilizado no build precisa ser público. Bom, isso me trouxe uma sensação de incomodo, pois eu precisaria deixar público meus drafts e backlogs, mas não era um bloqueio para utilizar a ferramenta.
Outro ponto é o exemplo na documentação do Wyam, que expõe o token utilizado para escrever no repositório no script de build... Isso trás a necessidade de armazenar/obter o token de um local diferente do próprio repositório para evitar o problema de segurança de ter uma chave com permissionamento de escrita aberta no github.
Com certeza esse problema teria um contorno relativamente fácil como armazenar o token como variável de ambiente nas configurações de build, mas eu queria fazer essa integração da forma mais simples possível e decidi explorar outras ferramentas antes de voltar a olhar para o AppVeyor.
Azure Devops
Azure Devops, antigamente chamado de VSTS.
Lembrei que, atualmente ao criar projetos no Github, lá estava aquela mensagem de integração com o Azure Pipelines e, desde que a Microsoft adquiriu o Github, a integração para build deveria ter melhorado bastante - em 2018 não era possível escrever o arquivo de build, somente exportá-lo após passar pela interface com configuração toda visual no VSTS. Parece que as coisas haviam melhorado.
O Azure Devops me surpreendeu positivamente, a interface está muito mais limpa que era no passado e conseguiu de alguma forma manter o modelo de organização utilizado anteriormente - que diga-se de passagem era um dos únicos pontos positivos de utilizar o VSTS em relação a outras ferramentas, antes do VSTS se tornar o Azure Devops.
Dei uma pesquisada rápida para ter uma ideia se eu ia ter muito trabalho para fazer tudo que eu precisava e encontrei um artigo parecido com o que eu queria, com a diferença que neste exemplo os arquivos de input e output ficavam no mesmo repositório. Não gosto muito dessa abordagem pois deixa os commits ilegíveis (após um commit do código do blog ou a inserção de um novo arquivo de markdown, o CI/CD faria um novo commit no mesmo repositório, com o código compilado...), mas simplifica a implementação. Para quem quiser consultar o artigo do Matt Cooper, que eu me espelhei para esta implementação, ele está disponível aqui.
Bom, o que era para ser um teste de funcionamento acabou virando o serviço que já está em funcionamento para publicação do Blog - então daqui para frente, vamos falar de como implementar o CI/CD.
Criando a pipeline no Azure Devops
Antes de iniciar as configurações, precisamos de um novo repositório do github, para armazenar os arquivos de markdown utilizados antes do build do Wyam - lembre que o repositório atual contém os arquivos de output já "compilados". Não vamos passar por todo o processo de criação do repositório aqui, crie um repositório no github - no meu caso criei o projeto nilo-dev-inputs - clone-o para sua maquina, copie os arquivos da raiz do seu projeto utilizado com o Wyam para a pasta do repositório e envie os arquivos para o repositório.
Se rolar alguma dúvida sobre como enviar os arquivos... Google. Acaba sendo muito mais produtivo para fixar conteúdo aprendido, pesquisar do que copiar e colar tudo de um tutorial.
Só tome o cuidado de não enviar arquivos desnecessários para o repositório, o arquivo .gitignore que eu utilizo fica configurado da seguinte forma (e novamente, não sabe o funcionamento do .gitignore? Google it):
[Pp]ackages/
[Tt]ools/*
[Oo]utput/
nuget.exe
*.zip
/debug.log
/*.packages.xml
/*.wyam.hash
/*.wyam.dll
Logo de cara, criei um projeto privado no Azure Devops com as configurações padrões. Em Pipelines criei um nova pipeline e linkei minha conta do Github ao Azure Devops. Na próxima tela já estava disponível minha lista de repositórios, selecionei o repositório de inputs do blog e na próxima tela já estava disponível o arquivo azure-pipelines.yml para configuração do build. Adicionei apenas o step de build do Wyam, Save and run e o arquivo azure-pipelines.yml já foi commitado para o repositório no github, assim como a build do projeto iniciou. A execução da Pipeline finalizou com sucesso e, apesar de não gerar um artefato, era somente isso que precisavamos para a parte de CI.
Eu realmente não me lembro de ter uma experiência tão fluída assim com a Microsoft no passado...
Com o CI configurado, precisamos configurar o CD.
Criação da chave de deployment
Como agora temos mais componentes, é interessante ter uma ideia do desenho que queremos como estado final quando terminarmos a configuração (e desculpem os garranchos):
O projeto atual no Azure Devops possui acesso somente ao repositório nilo.dev-inputs e precisamos habilitar um acesso com permissão de escrita no repositório nilo.dev. Para isso, vamos criar uma chave de deployment no projeto. Na página do projeto no Github, em Settings, acesse Deploy Keys > Add deploy key:
Gere uma chave executando um ssh-keygen (desde 2018 o Windows possui OpenSSH nativo, não precisa baixar nada se não estiver usando linux), nomeie a chave como "deploy_key", copie o conteúdo da chave publica (deploy_key.pub) e cole no Github.
De volta na página do projeto no Azure Devops, em Pipelines > Library > Secure Files > "+ Secure File" e faça o upload da sua chave privada gerada anteriormente - pode deletar a chave de seu computador local após o upload.
Iremos utilizar o nome da chave no script de build, se por acaso mudar o nome dela no Secure Files, lembre-se de alterar o script de build utilizando o novo nome;
Feito isso, iremos alterar a pipeline de build. Poderíamos criar uma pipeline com o release ou segmentar o build em mais de uma pipeline, o que eu acho uma complexidade desnecessária para um projeto tão pequeno. Você não precisa concordar comigo, altere o projeto como preferir.
Em Pipelines, clique na única pipeline existente, clique em "Edit" e adicione o script abaixo - altere o endereço do repositório no código conforme a necessidade - clique em "Save and run" e veja a magica acontecer:
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
steps:
- task: DotNetCoreInstaller@0
displayName: Install .NET Core SDK
name: install_dotnetcore_sdk
enabled: true
inputs:
packageType: 'sdk'
version: '2.2.101'
- script: dotnet tool install -g Wyam.Tool
displayName: Install Wyam
- script: wyam
displayName: Build Site
- task: DownloadSecureFile@1
name: deployKey
displayName: 'Get the deploy key'
inputs:
secureFile: deploy_key
- script: |
echo Installing deployment key $(deployKey.secureFilePath) ...
mkdir ~/.ssh && mv $(deployKey.secureFilePath) ~/.ssh/id_rsa
chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_rsa
ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
displayName: 'Install SSH key '
- script: |
rm -rf .git
git clone git@github.com:daniloalsilva/nilo.dev.git --branch=master publish
cp -R publish/.git output/
cd output
git config --local user.name "Azure Pipelines"
git config --local user.email "azuredevops@microsoft.com"
git add .
git commit -m "Publishing GitHub Pages"
git push origin HEAD:master
displayName: 'Publish GitHub Pages'
Um alerta deve aparecer na página seguinte, solicitando o acesso da Pipeline ao arquivo deploy_key que está na Library, este alerta aparece uma única vez;
E é isso, o Azure Devops já fez seu primeiro deploy e a partir de agora, a cada commit na branch master, o Blog [nilo.dev] será atualizado automáticamente!
Extras
Para deixar o projeto no Azure Devops mais "limpo", eu prefiro desativar os itens do projeto que não são utilizados, como Boards, Repos, Test Plans e Artifacts. Basta nas configurações do projeto (UX está horrível pra isso no azure devops e eu tive que pesquisar no Google pra achar o botão... A opção está no canto lateral esquerdo, na página do projeto) e desativar os itens não utilizados.
E você pode tambêm adicionar uma badge da pipeline no seu repositório do Github ou no seu Blog informando se a ultima build do blog funcionou ou falhou, basta pegar o link da badge nas opções da pipeline:
E ativar a visualização de badges se seu projeto for privado:
Preocupações
Ainda não sei se, quando o repositório crescer em quantidade de conteúdo, vai haver perda de performance no push ou erros no build. O Github limita cada repositório individualmente à 100GB e recomenda o uso inferior a 1GB para que haja boa performance.
Vamos descobrir se/quando chegarmos lá!
Referências:
- https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/download-secure-file?view=azure-devops
- https://cloudblogs.microsoft.com/opensource/2019/04/05/publishing-github-pages-from-azure-pipelines/
- https://stackoverflow.com/questions/58674639/azure-pipelines-status-badge-not-getting-displayed-in-markdown
- https://help.github.com/pt/github/managing-large-files/what-is-my-disk-quota