Mês: junho 2013

TDC 2013

É com grande alegria que anuncio que minha palestra foi aceita no TDC 2013!

Estarei palestrando na trilha Arquitetura .NET no dia 10/07. Pretendo também comparecer no sábado, 13/07 para prestigiar outras temas interessantes do evento.

Quem me encontrar por lá e acompanhar o blog, fiquem à vontade para perguntar, trocar idéias, criticar, etc. O objetivo é esse mesmo.

Neste ano, estarei apresentando o tema “Integrações entre Sistemas”, onde abordarei muito do aprendizado que tive realizando esta série aqui no blog e também a correlação deste tema com SOA e arquitetura corporativa.

Espero vocês por lá!!

Anúncios

Automatizando o versionamento no Build – Parte 2

Objetivo

Na parte 1, entendemos como o .NET faz para marcar a versão nos binários e como criar um arquivo para centralizar as propriedades comuns entre os assemblies.

Agora vamos brincar um pouco de como automatizar isso com o MSBuild. Se vc não sabe o que é o MSBuild, sugiro a leitura de MSBuild in a nutshell.

Automatizando o versionamento

A parte legal de utilizar uma ferramenta como o MSBuild é que é muito simples customizar a ferramenta e tem muita gente que contribui com tasks customizadas.

Nessa linha existe um projeto chamado MSBuild Community Tasks. Esse projeto possui além de uma centena de tasks, uma que iremos utilizar, a chamada AssemblyInfo.

Essa task nada mais faz do que gerar um arquivo com os atributos de versionamento. Ela tem a seguinte estrutura:

		<AssemblyInfo CodeLanguage="CS" OutputFile="$(MSBuildProjectDirectory)\..\src\SharedAssemblyInfo.cs"
			AssemblyProduct="MSBuildCodeMetrics - $(Branch) - $(CommitHash)" AssemblyCopyright="Copyright © 2013 Eric Lemes de Godoy Cintra" AssemblyTrademark=""
			AssemblyVersion="$(Version)" AssemblyConfiguration="$(Configuration)" AssemblyDescription="MSBuildCodeMetrics - $(Branch) - $(CommitHash)" />

Neste exemplo (usado no MSBuildCodeMetrics), gerarei um arquivo que sobrescreve o SharedAssemblyInfo.cs. No atributo AssemblyProduct, jogaremos além do nome do produto o valor das propriedades $(Branch) e $(CommitHash). A idéia é substituir estes valores neste e em outros atributos com valores gerados automaticamente pelo build.

Integrando com Git Hub

Seguindo a linha de contribuições, o MSBuild Community Tasks possui uma task que integra com o Git. A propriedade CommitHash pode ser obtida da seguinte maneira:

		<GitVersion>
			<Output TaskParameter="CommitHash" PropertyName="CommitHash" />			
		</GitVersion>

Esse trecho faz com que a task GitVersion pegue o valor do último commit hash e jogue na propriedade.

Aproveitando o conceito, mandei uma contribuição lá para o projeto, criando uma Task GitBranch. Essa task pegará o nome do branch do GitHub. Segue o exemplo:

		<GitBranch>
			<Output TaskParameter="Branch" PropertyName="Branch" />			
		</GitBranch>

Com essas combinações, podemos chegar no seguinte resultado final:

	<Target Name="assemblyinfo">
		<GitBranch>
			<Output TaskParameter="Branch" PropertyName="Branch" />			
		</GitBranch>
		<GitVersion>
			<Output TaskParameter="CommitHash" PropertyName="CommitHash" />			
		</GitVersion>
		<CreateProperty Value="0.0.0.0">
			<Output TaskParameter="Value" PropertyName="Version" Condition="$(Branch) == 'master'" />
		</CreateProperty>
		<CreateProperty Value="$(Branch)">
			<Output TaskParameter="Value" PropertyName="Version" Condition="($(Branch) != 'master')" />
		</CreateProperty>
	
		<AssemblyInfo CodeLanguage="CS" OutputFile="$(MSBuildProjectDirectory)\..\src\SharedAssemblyInfo.cs"
			AssemblyProduct="MSBuildCodeMetrics - $(Branch) - $(CommitHash)" AssemblyCopyright="Copyright © 2013 Eric Lemes de Godoy Cintra" AssemblyTrademark=""
			AssemblyVersion="$(Version)" AssemblyConfiguration="$(Configuration)" AssemblyDescription="MSBuildCodeMetrics - $(Branch) - $(CommitHash)" />
	</Target>

A idéia é simples. Pegamos o CommitHash e o Branch do GitHub. Se estamos no branch master, vamos carimbar a versão com “0.0.0.0” e no AssemblyDescription e ProductName ficaremos com algo parecido com: MSBuildCodeMetrics – master – b1e4cbf.

Se estivermos num branch ou numa tag, este número será utilizado para carimbar a versão. Por exemplo, para o meu branch 0.1, ficaremos com a versão da seguinte forma: MSBuildCodeMetrics – 0.1 – b1e4cbf. No AssemblyVersion, ficaremos com “0.1”, porém, infelizmente ao inspecionar pelo Windows, veremos a versão como 0.1.0.0. Ele sempre arredonda e coloca no formato de 4 dígitos. Eu particularmente não gosto, mas consigo ainda identificar minha versão pelo AssemblyDescription e ProductName.

Conclusão

Com um pouquinho de automação, como feito no MSBuildCodeMetrics, eu consigo com uma única execução da minha task “pack”, fazer um processo de automação do build de ponta a ponta. Eu gero o SharedAssemblyInfo.cs, realizo o build, monto a documentação e faço o pacote zip final, apertando o único botão. Acho que eu já consegui os três primeiros passos do The Joel Test.

Agora a cada vez que eu quero fazer um release de uma versão, basta criar uma nova tag e rodar o “pack” do meu build e está tudo pronto.

Segue código completo do script de build: MSBuildCodeMetrics.build

Automatizando o versionamento no Build – Parte 1

Objetivo

Conforme comentei no post anterior sobre a documentação do MSBuildCodeMetrics, uma outra coisa que eu queria fazer era automatizar o versionamento durante o Build.

O que eu quero dizer com isso é que eu queria “carimbar” meus binários com a localização em que eles estão no controle de versão.

A idéia deste post (ou série) é ilustrar como fazer isso na prática.

Adotando uma política de versionamento

O que eu chamo de política de versionamento é estruturar a organização de branches da aplicação, conforme explicado no post “Gestão de configuração e versões (SCM)”.

Apesar do projeto estar no GitHub adotei a política de branches de estabilização. Meu branch “master” possuirá a maior quantidade de features e será mais instável, e de tempos em tempos cortarei branches para “congelar” e estabilizar as features. No caso criei um branch 0.0 quando ainda não tinha nem documentação, e um branch 0.1 quando concluí o “básico” para soltar meu primeiro release.

A cada release que fizer, gerarei uma nova tag e o fonte compilado e publicado partirá desta tag. No meu caso, a versão 0.1.0 é a primeira tag e o primeiro release.

AssemblyInfo.cs

Muitos de vocês já devem ter visto o arquivo AssemblyInfo.cs. Geralmente ele fica jogado na pasta Properties e ninguém dá bola pra ele.

Ele tem mais ou menos essa estrutura:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("EricLemes.MSBuildTasks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("EricLemes.MSBuildTasks")]
[assembly: AssemblyCopyright("Copyright ©  2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("dabe2f23-a2e2-4249-ad24-f597d0bd36eb")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Na verdade essas propriedades no final das contas ficam em locais especiais nos binários e podem ser inspecionadas ao clicarmos com o botão direito num arquivo no Windows Explorer e depois em detalhes:

AssemblyInfo

Centralizando propriedades comuns a diversos assemblies

A primeira coisa interessante a fazer para automatizar a geração destes números é centralizar algumas das propriedades entre todos os assemblies. Pra mim essa idéia faz sentido porque sempre que lançamos uma nova versão do produto, queremos que todos os artefatos dessa versão sejam carimbados com a versão. Em outras palavras, nosso produto não é composto por um único binário e sim por um conjunto de binários.

Para tornarmos isso possível, primeiro devemos criar um novo arquivo em nossa solution. Eu achei interessante deixá-lo junto com os “Solution Items”. Clique com o botão direito, Add | New Item | Visual C# Class. No meu caso, chamei o arquivo de SharedAssemblyInfo.cs.

O arquivo contém a seguinte estrutura:

[assembly: System.Reflection.AssemblyProduct("MSBuildCodeMetrics - master - b1e4cbf")]
[assembly: System.Reflection.AssemblyCopyright("Copyright © 2013 Eric Lemes de Godoy Cintra")]
[assembly: System.Reflection.AssemblyVersion("0.0.0.0")]
[assembly: System.Reflection.AssemblyConfiguration("Release")]
[assembly: System.Reflection.AssemblyDescription("MSBuildCodeMetrics - master - b1e4cbf")]

Os atributos contidos neste arquivos são aqueles que devem ser iguais para todos os assemblies do projeto.

Em seguida, em cada um dos projetos (.csproj), clicamos com o botão direito, Add | Existing Item e escolhemos o SharedAssemblyInfo.cs. Invés de clicarmos em “Add”, clicamos na setinha de drop down e escolhemos “Add as Link”. Será adicionada somente uma referência do arquivo para o projeto. Por convenção a deixei dentro da pasta “Properties”.

Em seguida, cada um dos AssemblyInfo.cs contém a seguinte estrutura:

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("MSBuildCodeMetrics.Core")]
[assembly: AssemblyCulture("")]
[assembly: Guid("4c6e2a2c-9e70-4b9f-a2fa-01bfdfdc577b")]
[assembly: ComVisible(false)]

Esses atributos, eu entendo que são de cada um dos assemblies.

Ao compilar o projeto agora, perceberemos que o Assembly possuirá todas as propriedades, mas apenas um arquivo precisa ser alterado para mexer no identificador de versão.

Por enquanto era isso.