No momento em que escrevo este post estou trabalhando em uma aplicação desktop para Windows desenvolvida na plataforma .NET. Com a primeira versão que será entregue para os usuários finais quase pronta, nossa equipe sentiu necessidade de colocar em prática o processo de Integração Contínua. Para atingir tal objetivo precisaríamos configurar uma ferramenta que nos auxiliasse a automatizar esse processo, e para isso escolhemos um servidor de Integração Contínua chamado Jenkins.
Não tenho a intenção de me aprofundar muito nos processos relacionados a Integração Contínua neste post, a ideia é documentar algumas dicas que encontrei durante a configuração do Jenkins para o nosso cenário atual. Espero que possa ser útil para mais pessoas, boa leitura. ;)
WTF is Continuous Integration?
Basicamente, Integração Contínua ou Continuous Integration (CI) é uma prática de desenvolvimento de software considerada por muitos um dos pilares das metodologias ágeis. Ela permite que a equipe encontre e elimine problemas rapidamente, agilizando os processos de build e delivery, melhorando as respostas à falhas e aumentando a qualidade do software.
De maneira simplificada, um processo de integração continua deve monitorar as mudanças de código no seu repositório de controle de versão e realizar os passos necessários para gerar um executável entregável para o cliente. O que normalmente consiste em compilar a aplicação em modo Release, rodar os testes e gerar o executável.
Apesar de no nosso caso termos implementado um processo de Integração Contínua automatizado em um estágio um pouco mais avançado do ciclo de vida do projeto, é muito recomendável adotar essa prática já no início do desenvolvimento, obtendo assim os benefícios da Integração Contínua o mais rápido possível.
The Jenkins
O Jenkins é um servidor de Integração Contínua open source, multiplataforma e que pode ser utilizado para automatizar os processos de build e delivery de muitas linguagens, como C#, Ruby, PHP, Java, dentre outras. Um dos pontos principais do Jenkins são os seus inúmeros plugins, que estendem suas funcionalidades e podem ser desenvolvidos por qualquer um. Além disso, seu processo de instalação e configuração é relativamente simples.
Qual processo queríamos automatizar?
Como citado anteriormente, estou trabalhando em uma aplicação desktop para Windows desenvolvida na plataforma .NET, o processo de integração que precisávamos automatizar consistia basicamente nos seguintes passos:
- Rebuild da aplicação em Release.
- Execução do processo de Code Analysis.
- Execução dos testes unitários.
- Criação dos setups.
Preparação do ambiente
A instalação do Jenkins no Windows é bem simples, basta baixar o instalador no site oficial, executar o mesmo e seguir o passo a passo. Ao final do processo o Jenkins estará instalado como um serviço e será executado automaticamente na inicialização do Windows. Para verificar se tudo ocorreu corretamente acesse o endereço localhost:8080 e veja se o Jenkins está rodando.
Uma dica importante para evitar dores de cabeça é forçar o serviço do Jenkins a ser executado com um usuário administrador do Windows ao invés de Local System que é o padrão. No meu caso específico o Inno Setup não funcionou corretamente como Local System, para evitar esse tipo de problema execute os seguintes passos:
- Abra o Services do Windows.
- Abra as propriedades do serviço do Jenkins.
- Clique na aba Log On.
- Marque a opção This account.
- Selecione um usuário administrador e digite a senha.
- Clique em OK e reinicie o serviço.
Além do Jenkins você precisará que todos os softwares necessários para seus processos estejam instalados, como por exemplo o MSBuild, o NUnit, o Inno Setup, etc. Como esses softwares são normalmente executados pelo Jenkins através do Command Prompt do Windows é interessante adicioná-los as variáveis de ambiente para que não seja necessário passar o caminho completo do executável, para isso siga os seguintes passos:
- Abra o System Properties do Windows.
- Clique na aba Advanced.
- Clique no botão Environment Variables.
- Em System Variables selecione a variável Path.
- Clique em Edit e ao final da linha adicione os caminhos dos diretórios dos executáveis separados por ponto e vírgula.
Estendendo o Jenkins
Antes de criarmos nosso primeiro job podemos instalar alguns plugins interessantes, para isso acesse o endereço localhost:8080/pluginManager do Jenkins, esta página é bem simples e intuitiva, para instalar novos plugins vá para a aba Available, para removê-los vá para a aba Installed e para atualizá-los vá para a aba Updates.
Logo abaixo segue uma lista de alguns dos plugins que achei interessante e que utilizamos para esse nosso projeto. Existem centenas de outros plugins, fique a vontade para procurar novos.
- BitBucket Plugin - Permite acessar um repositório no BitBucket e configurar para um job) ser iniciado quando um Push for realizado no repositório.
- MSBuild - Permite realizar o build de projects e solutions do Visual Studio.
- NUnit - Permite que o Jenkins utilize os relatórios gerados pelo NUnit.
- Disk Usage Plugin - Exibe estatísticas sobre o uso do disco.
- Timestamper - Adiciona o horário antes de cada linha do console do Jenkins, bastante útil para medir o tempo de realização de cada tarefa.
- Google Cloud Messaging Notification Plugin - Envia notificações para smartphones Android.
- Safe Restart Plugin - Permite realizar o restart do Jenkins de maneira segura.
Segurança
Uma dica que considero importante, principalmente se você vai permitir acesso externo ao seu servidor Jenkins, é desativar a funcionalidade de Sign up e controlar as permissões dos usuários, para isso siga os seguintes passos:
- Acesse o endereço localhost:8080/configureSecurity.
- Marque a opção Enable security.
- Em Security Realm selecione a opção Jenkins’ own user database e desmarque a opção Allow users to sign up.
- Em Authorization selecione a opção Matrix-based security, adicione os usuários e marque as opções que deseja que o usuário tenha permissão.
Como desativamos a permissão de Sign up você precisará criar as contas dos usuários, para isso acesse o endereço localhost:8080/securityRealm. Um detalhe importante aqui é que o Username deve ser o mesmo que foi adicionado no passo anterior para que as permissões funcionem corretamente.
Configurações
As configurações do Jenkins podem ser acessadas através do endereço localhost:8080/configure, dentre outras coisas, aqui você pode configurar o servidor SMTP de envio de e-mail, o local onde seu Git está instalado (que normalmente é reconhecido automaticamente), as configurações para o Google Cloud Messaging Notification, etc.
Criando seu primeiro job
Para criar um novo job no Jenkins, acesse o endereço localhost:8080/newJob, digite um nome para o job, marque a opção Freestyle project e clique em OK. Você será levado para a página de configuração do seu job recém criado, está página é muito importante pois é aqui que devemos configurar tudo que o nosso job irá realizar.
Custom workspace
A primeira dica aqui é alterar o workspace onde o job será realizado, por padrão ele fica dentro do diretório onde o Jenkins foi instalado, que normalmente é em C:\Program Files (x86)\Jenkins
, o que pode desencadear alguns erros relacionados a permissão de escrita se algum dos softwares utilizados pelo seu job tentar criar algum arquivo em disco. Para alterar a workspace clique no botão Advanced em Advanced Project Options, marque a opção Use custom workspace e informe o caminho do diretório, por exemplo: C:\CI\my-job\workspace
.
Git e BitBucket
Caso tenha instalado o plugin do BitBucket (e consequentemente o do Git), em Source Code Managment selecione a opção Git e configure seu repositório, sua branch e suas credenciais de acesso. Um dica importante aqui é alterar o timeout de clone e fetch do Git, o padrão é de apenas 10 minutos, o que pode não ser suficiente dependendo do tamanho do seu repositório e da velocidade de sua conexão. Até descobrir isso perdi alguns minutos, para você não passar por isso também, clique no botão Add, escolha a opção Advanced Clone Behaviors e informe um tempo que ache razoável para o timeout.
Com o plugin do BitBucket você pode configurar para que seu job ser iniciado assim que um push no repositório seja feito, para isso marque a opção Build when change is pushed to BitBucket. Para essa opção funcionar você precisará adicionar um Hook de POST apontando para seu-ip-publico:8080/bitbucket-hook nas configurações do seu repositório no BitBucket.
MSBuild
Para configurar o build do seu projeto no MSBuild clique em Add build step e na opção Build a Visual Studio project or solution using MSBuild. Em MSBuild Build File informe o caminho da solution no workspace do job, por exemplo: C:\CI\my-job\workspace\MyProject.sln
. Em Command Line Arguments você deverá informar os parâmetros do seu build, por exemplo: /t:Rebuild /p:Configuration="Release" /p:Platform=x86 /p:DevEnvDir="C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE"
. O parâmetro DevEnvDir
é importante, ele é utilizado para algumas coisas durante o processo de build, como por exemplo na execução do Code Analisys. Clicando em Advanced você também pode marcar a opção If warning set the build to Unstable.
NUnit
Os testes do NUnit serão executados através do Console, para configurá-lo clique em Add build step e na opção Execute Windows batch command, no campo Command você deverá informar o nome do executável do NUnit (ou o caminho completo caso não o tenha adicionado nas variáveis de ambiente do Windows), o caminho do teste no workspace e o nome do arquivo XML onde será salvo o relatório com os resultados dos testes. Por exemplo: "nunit-console-x86.exe" "MyTest\bin\x86\Release\MyTest.dll" /xml=MyTest.dll-nunit-result.xml
.
Para que o Jenkins exiba os resultados dos testes clique em Add post-build action e na opção Publish NUnit test result report e em Test report XMLs e informe *nunit-result.xml
.
Inno Setup
Para gerar os executáveis utilizando o Inno Setup clique novamente em Add build step e na opção Execute Windows batch command, no campo Command informe o nome do executável do Inno Setup (ou o caminho completo caso não o tenha adicionado nas variáveis de ambiente do Windows) e o caminho do seu script no workspace. Por exemplo: "Compil32.exe" /cc "setup.iss"
.
Finalizando
Como comentei no início do post, não pretendia me aprofundar nos conceitos relacionados a Integração Contínua e sim compartilhar algumas dicas que acredito serem úteis. A intenção também não era ser nenhuma receita de bolo, adapte o que for necessário para a realidade do seu projeto, o Jenkins é uma ferramenta muito poderosa, explore seus recursos.
Espero que tenha gostado do post, por favor deixe críticas, dúvidas ou sugestões nos comentários.