Neste tutorial você vai aprender automatizar Continuous Integration para criar e publicar um Pacote NuGet em um Feed usando Azure DevOps sempre que uma branch for atualizada.
Antes de começar, gostaria de dizer para os recém chegados, que o Azure DevOps, nada mais é, que o Visual Studio Online, o VSTS. Eles mudaram o nome, mas basicamente, as funções são as mesmas.
O tutorial será dividido em 3 tópicos principais. Se preferir pode pular um tópico ou outro.
A partir desse ponto, a leitura do tutorial é de 10 minutos, e sua aplicação leva 10 minutos.
#1 – Overview do tutorial
- O tutorial será explicado em # Passo 01, # Passo 02… e assim por diante.
- Em cada Passo, as ações Acesse, Abra, Configure e outras, estarão sempre no início do texto e em negrito.
- Palavras-chave nos textos terão links a artigos deste Blog ou outros, sempre como referência.
- A minha opinião/observação será feita sempre ao final de cada tópico.
- O Pulo do gato, estará sempre em negrito e bem destacado conforme exemplo abaixo:
Pulo do Gato: Você pode baixar todo o código fonte deste tutorial sem ler absolutamente nada. Para fazer isso basta acessar meu github.
#2 – Pré-requisitos para o tutorial.
Se você não está familiarizado com o Azure DevOps, vou tentar explicar de forma que você não fique perdido. Para realizar o tutorial, você vai precisar:
- Instalar Visual Studio 2017, em qualquer versão, até mesmo a Community, que é uma versão gratuita. Hoje em dia está fácil instalar essa IDE, diferente de quando instalei pela primeira vez no UNBOXING Visual Studio 2017: Primeiras impressões no Mundo Real.
- Vincular seu e-mail a uma conta Microsoft. Se você possui conta em algum serviço Microsoft (Skype, MSN, Live, Office 365 entre outros), você não precisa fazer mais essa vinculação.
- Ter uma conta no Azure DevOps. Por exemplo, a minha conta é fabiosilvalima.visualstudio.com. Se não tem, crie uma aqui, é gratuito.
- Criar um projeto do tipo GIT no Azure DevOps. Se possível nomeá-lo como Tutorial 2 para se familiarizar com esse tutorial.
- Ter o código fonte FSL.Framework.Core no seu repositório GIT no Azure DevOps. Para mais detalhes confira meu artigo Tutorial: Controle seu Código Fonte de Graça com GIT e Azure DevOps.
- Saber criar um pacote NuGet e publicá-lo no Azure DevOps. Para mais detalhes confira meu artigo Tutorial: Criando um Pacote NuGet e Publicando no Azure DevOps.
#3 – Continuous Integration para criar e publicar Pacote NuGet no Azure DevOps
Esse ponto é o mais complexo de todos. Se você não está familiarizado com a parte de repositório de código fonte GIT no Azure DevOps, vou tentar dar uma passada geral para que você não fique perdido.
Até agora nós criamos o projeto FSL.Framework.Core em nosso computador, mas para prosseguirmos com a automação, precisamos que esse projeto esteja publicado no GIT no Azure DevOps. Então, antes de criarmos a automação para o pacote NuGet, vamos colocar o nosso projeto no GIT.
Se você não sabe colocar um projeto no GIT usando o Azure DevOps, siga os passos do meu outro artigo Tutorial: Controle seu Código Fonte de Graça com GIT no Azure DevOps e depois volte pra cá.
# Passo 01: Abra o seu projeto do Azure DevOps.
# Passo 02: Clique em Repos e Branches. Na branch master, clique no botão “…” e depois em New branch.
# Passo 03: Preencha o nome da branch como nuGet e clique em Create Branch. O nome da branch poderia ser qualquer outra coisa. Não utilizei padrão de nomenclatura de branches para esse artigo.
#A Lógica da Automação Continuous Integration
A ideia é que, sempre que a branch nuGet for atualizada, automaticamente iniciará uma série de tarefas para compilar o projeto FSL.Framework.Core, rodar testes unitários, criar pacote nuget .nupkg, publicar pacote nuget diretamente no Azure DevOps sem precisarmos rodar nenhum command line em tempo de desenvolvimento. Esse processo de automação chama-se Continuous Integration.
# Passo 04: Acesse o Azure DevOps, entre no projeto Tutorial 2 e vá em Pipelines e depois Builds. Clique em New Pipeline.
# Passo 05: Escolha a branch nuGet, pois é nela que realizaremos a configuração de Continuous Integration. Clique em Continue.
# Passo 06: Escolha Empty job, pois vamos fazer do zero, sem template pré-definidos.
Nessa tela, estão todas as configurações para automatizar todo o processo. Preencha conforme imagem ou conforme descrito abaixo:
Pipeline Continuous Integration
- Name: Build nuGet FSL.Framework.Core
Agent job
- Display name: Agent job 1
- Demands: visualstudio e msbuild
#Task: Nuget install
# Passo 07: Adicione uma task NuGet Tool Installer em Agent job. Para isso basta clicar no ícone +, localizar na lista (ou pela busca) e clicar no botão azul add. Essa será a primeira task a ser realizada, que é, instalar o NuGet. Clique na task do lado esquerdo e preencha conforme imagem ou conforme descrito abaixo:
Nuget Tool Installer
- Display name: Nuget install
#Task: Nuget restore
# Passo 08: Adicione uma task NuGet em Agent job. Para isso basta clicar no ícone +, localizar na lista (ou pela busca) e clicar no botão azul add. Essa será a segunda task, que é, restaurar os pacotes Nuget utilizados pela lib FSL.Framework.Core, que no caso são: Dapper e Newtonsoft JSON. Clique na task do lado esquerdo e preencha conforme imagem ou conforme descrito abaixo:
NuGet
- Display name: NuGet restore
- Command: restore
- Path to solution, packages.config, or project.json: **/*.sln
- Use packages from this Azure Artifacts/TFS feed: FabioSilvaLima
#Task: Visual Studio Build
# Passo 09: Adicione uma task Visual Studio Build em Agent job. Para isso basta clicar no ícone +, localizar na lista (ou pela busca) e clicar no botão azul add. Essa será a terceira task, que é, compilar o projeto FSL.Framework.Core. Clique na task do lado esquerdo e preencha conforme imagem ou conforme descrito abaixo:
Visual Studio Build
- Platform: $(BuildPlatform)
- Configuration: $(BuildConfiguration)
#Task: Nuget pack
# Passo 10: Adicione uma task NuGet em Agent job. Para isso basta clicar no ícone +, localizar na lista (ou pela busca) e clicar no botão azul add. Essa será a quarta task, que é, criar o pacote Nuget para FSL.Framework.Core. Clique na task do lado esquerdo e preencha conforme imagem ou conforme descrito abaixo:
NuGet
- Display name: NuGet pack
- Command: pack
- Path to csproj:
$(Build.SourcesDirectory)\**\*.csproj;!$(Build.SourcesDirectory)\**\*Test.csproj
- Configuration to package: $(BuildConfiguration)
- Package folder: $(Build.ArtifactStagingDirectory)
- Package Options: Marque o campo ‘Include referenced projects’
#Task: Nuget push
# Passo 11: Adicione uma task NuGet em Agent job. Para isso basta clicar no ícone +, localizar na lista (ou pela busca) e clicar no botão azul add. Essa será a quinta e última task, que é, publicar o pacote Nuget FSL.Framework.Core no repositório nuGet FabioSilvaLima do próprio Azure DevOps. Clique na task do lado esquerdo e preencha conforme imagem ou conforme descrito abaixo:
NuGet
- Display name: NuGet push
- Command: push
- Path to NuGet package(s) to publish:
$(Build.ArtifactStagingDirectory)/**/*.nupkg;!$(Build.ArtifactStagingDirectory)/**/*.symbols.nupkg
- Target feed: FabioSilvalima
- Allow duplicates to be skipped: Sim
- Control options Continue on error: Sim
#Variables
# Passo 12: Clique em Variables e forneça chave e valor para as variáveis abaixo:
- BuildConfiguration: release
- BuildPlatform: any cpu
Obs.: Para cada uma, selecione o checkbox Settable at queue time.
#Triggers
# Passo 13: Clique em Triggers, selecione o checkbox Enable continuous integration e escolha a branch nuGet.
Pulo do gato: Essa é a configuração de automação, ou seja, quando essa branch nuGet for atualizada, esse Build nuGet FSL.Framework.Core será iniciado.
# Passo 14: Clique em Options e preencha o campo Build number format para: $(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)
#Save and Build
# Passo 15: Clique no botão Save and Queue para salvar e inicializar o Build. Vai abrir um popup e então clique no botão azul Save and Queue.
O popup será fechado e vai aparecer uma mensagem e um link bem sutil no topo da tela, vide imagem acima.
# Passo 16: Clique neste link sutil, que irá te mandar para a tela de Log desse build onde você poderá acompanhar cada uma das tarefas que estão ou serão executadas. Você pode clicar em cada uma das tarefas e ver o LOG correspondente. Se ocorrer algum erro, aparecerá em vermelho e o Build irá parar a execução. Quando a execução do Build parar devido a erros, normalmente chamamos de “quebrou o build”.
#Resumo até aqui
Nós configuramos o repositório do GIT no Visual Studio na pasta C:\inetpub\wwwroot\TFS\FabioSilvaLima\Tutorial2. Configuramos que alguns arquivos e pastas sejam ignorados. Demos o primeiro commit e push, subindo esse código fonte na branch master lá no Azure DevOps. Em seguida, criamos um Build no Pipeline de automação do Azure DevOps para fazer todo o processo para compilar projeto, criar e publicar o pacote nuGet.
#7 – Testar a automação no mundo real
Finalmente!
O teste no mundo real, que é alterar o código fonte no Visual Studio criando uma nova classe/feature no FSL.Framework.Core, fazer um commit local e um push, subindo essa alteração para o GIT no Azure DevOps.
Atenção: Nós estamos usando a branch master para fazer essa demonstração. Mas, nunca devemos usar a branch master como branch de desenvolvimento. A branch master deve ser uma cópia do código de produção, ou seja, ela contem o que há de mais atualizado em produção. Mas para facilidade para esse artigo estamos usando a branch master.
Inclua a referência da biblioteca System.Configuration do .NET Framework no projeto FSL.Framework.Core.
using FSL.CsharpUsefulExtensionsMethods; using System; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Threading.Tasks; namespace FSL.Framework.Core.Repository { public abstract class SqlRepository { private string _connectionStringId; private string _connectionString; public virtual string ConnnectionStringId { get { return _connectionStringId; } } protected async Task<T> WithConnectionAsync<T>( Func<SqlConnection, Task<T>> getData, Action<Exception> onException = null) { try { using (var connection = CreateConnection()) { await connection.OpenAsync(); return await getData(connection); } } catch (TimeoutException ex) { if (onException.IsNotNull()) { onException(ex); return default(T); } throw new Exception($"{GetType().FullName}.WithConnection() experienced a SQL timeout", ex); } catch (SqlException ex) { if (onException.IsNotNull()) { onException(ex); return default(T); } throw new Exception($"{GetType().FullName}.WithConnection() experienced a SQL exception (not a timeout)", ex); } } protected T WithConnection<T>( Func<SqlConnection, T> getData, Action<Exception> onException = null) { try { using (var connection = CreateConnection()) { connection.Open(); return getData(connection); } } catch (TimeoutException ex) { if (onException.IsNotNull()) { onException(ex); return default(T); } throw new Exception($"{GetType().FullName}.WithConnection() experienced a SQL timeout", ex); } catch (SqlException ex) { if (onException.IsNotNull()) { onException(ex); return default(T); } throw new Exception($"{GetType().FullName}.WithConnection() experienced a SQL exception (not a timeout)", ex); } } public SqlRepository UseConnectionStringId( string connectionStringId) { _connectionStringId = connectionStringId; return this; } public SqlRepository UseConnectionString( string connectionString) { _connectionString = connectionString; return this; } private SqlConnection CreateConnection() { if (string.IsNullOrEmpty( _connectionString)) { _connectionString = ConfigurationManager .ConnectionStrings[ConnnectionStringId] .ConnectionString; } return new SqlConnection( _connectionString); } } }
# Passo 17: Abra o arquivo FSL.Framework.Core.nuspec, altere o campo version para 1.0.2 e o campo releaseNotes.
# Passo 18: Faça commit e push dessas alterações.
#8 – Pull Request
# Passo 19: Abra o Azure DevOps, vá até seu projeto, depois acesse Repos e Pull Requests. Clique no botão New pull request.
# Passo 20: Escolha DE / PARA (origem/destino), branch master para nuGet e depois clique em Create.
# Passo 21: Clique no botão Complete para completar o Pull Request, ou seja, o que foi feito na branch master irá para a branch nuGet. Ao fazer isso, será iniciado o Continuous Integration, que acionará o Build que fizemos no tópico anterior.
Pulo do gato: Neste tutorial é você quem cria e completa/aprova o Pull Request, mas no Mundo Real, normalmente essa tarefa é delegada a outra pessoa.
# Passo 22: Ao clicar em Complete, vai aparecer um Popup, desmarque todos os checkboxes e clique em Complete merge. Nesse momento, para ver o Build em ação, acesse o menu esquerdo Pipeline e Builds.
# Passo 23: Ao término do Build, vá em Artifacts, vai ver que aparece uma nova versão 1.0.2 disponível no pacote Nuget do FSL.Framework.Core. Essa versão 1.0.2, foi a nova versão que acabamos de entregar, ou seja, desenvolvemos a nova feature e a entregamos no Pull Request.
Ufa! Acabou! Esse tutorial deu trabalho hein!
Preciso do seu feedback para podermos melhorá-lo.
Sugestões, críticas, deixe seu comentário abaixo para esse tutorial sobre Continuous Integration.
Até a próxima.
#Tutoriais relacionados com Continuous Integration
Faça download completo do código fonte no github. |