Uma introdução a scripts de build

O processo de build é o coração das práticas de engenharia ágil: é
através dele que automatizamos todos os passos necessários para
garantir a qualidade mínima esperada.

Esse nível de garantias varia entre cada projeto e todos os passos que uma equipe madura seria capaz de executar com quase perfeição são automatizados para minimizar falhas e atingir tal objetivo.

Diversas práticas são utilizadas para garantir a qualidade necessária que nos permite executar entregas contínuas, e a maior parte delas estão presentes ou são referenciadas dentro do processo automatizado de build.

Um processo de build simples envolve a compilação – quando necessária – e geração de algum artefato final. O exemplo a seguir mostra um script do ant compilando seus arquivos java:

<project name="project-name" default="compile">
	<description>Build full</description>
	<property file="build.properties" />
	<property name="war.file" value="${war.filename}.war" />

	<path id="libs.classpath" path=".">
		<fileset dir="${libs.dir}">
			<include name="*.jar" />
		</fileset>
	</path>

	<path id="compile.classpath">
		<path refid="servlet-api.classpath" />
		<path refid="libs.classpath" />
	</path>

	<target name="compile" depends="prepare" description="--> compile the classes">
		<javac destdir="${tmp.classes.dir}" srcdir="${src.dir}" classpathref="compile.classpath" debug="true" encoding="UTF-8">
		</javac>
	</target>

</project>

Lembrando que nesse mundo para a web em Java, é bem comum que o artefato final seja um arquivo .war a ser deployado em algum servidor de aplicação ou servlet container. Para criá-lo usamos outras tags simples do ant:

<target name="war" depends="compile" description="--> generate project's war">
	<delete file="${artifacts.dir}/${war.file}" />
	<copy todir="${tmp.classes.dir}">
		<fileset dir="${resources.dir}" />
	</copy>

	<war destfile="${artifacts.dir}/${war.file}" webxml="${webapp.dir}/WEB-INF/web.production.xml" compress="true" >
		<fileset dir="${webapp.dir}">
			<exclude name="WEB-INF/web*.xml" />
			<exclude name="**/servlet*.jar" />
		</fileset>
		<classes dir="${tmp.classes.dir}" />
	</war>
</target>

E, em Ruby, o artefato comum é uma gem, que podemos criar utilizando a task GemPackage:

Rake::GemPackageTask.new(spec) do |pkg| 
  pkg.gem_spec = spec 
end

Um script completo escrito para Rake, incluindo a tag de geração de pacote e a descrição de sua gem como a seguir pode ser criada automaticamente também:

require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
require 'rake/gempackagetask'

desc 'Default: build gem.'
task :default => :package

PKG_FILES = FileList[ '[a-zA-Z]*', 'generators/**/*', 'lib/**/*', 'rails/**/*', 'tasks/**/*', 'test/**/*' ] 

spec = Gem::Specification.new do |s|
   s.name = "Relata"  
   s.version = "0.0.2"  
   s.author = "Anderson Leite, Guilherme Silveira"  
   s.email = "anderson.leite@caelum.com.br"  
   s.homepage = "http://github.com/caelum/relata"  
   s.platform = Gem::Platform::RUBY 
   s.summary = "Helps poking around with relationships when using ARel"
   s.files = PKG_FILES.to_a 
   s.require_path = "lib"  
   s.has_rdoc = false 
   s.extra_rdoc_files = ["README.markdown"] 
end 

desc 'Turn this plugin into a gem.' 
Rake::GemPackageTask.new(spec) do |pkg| 
  pkg.gem_spec = spec 
end

Para sistemas legados que ainda não possuem script, o primeiro passo é a compilação e geração de tal artefato. Dessa maneira o desenvolvedor não esqueçe de copiar arquivos de configuração durante o processo de montagem (assembly) de seu artefato, um erro muito comum em processos de build manuais. A simples adição de uma tag evita erros simples causados por descuido humano como o anterior:

<copy todir="${tmp.classes.dir}">
	<fileset dir="${resources.dir}" />
</copy>

Com o amadurecimento da equipe nesse sistema legado, ou com uma equipe qualquer trabalhando em um sistema novo – sem nenhuma restrição, green field, visamos a automatização de todas as práticas que dependem de um ser humano, um processo que inclue outros passos.

Alternativas de ferramentas de build que vêm ganhando espaço ultimamente são o gradle e o buildr, e o maven, todos correndo atrás de suportar o maior número possível de linguagens na JVM.

Com pouco esforço tanto em sistemas já existentes quanto em novos projetos, compile e gere artefatos com todos os arquivos de configuração automaticamente.

5 Comentários

  1. Élysson MR 10/11/2010 at 22:47 #

    Gostei do post, nem sabia que os arquivos de build funcionavam assim. Sempre utilizei os scripts automático que algumas IDEs oferecem. Agora eu vou dar uma pesquisada mais aprofundada neste tema para saber mais sobre como funciona e como criar scripts de build.

  2. EhEu 11/11/2010 at 17:08 #

    Nossa, e não falaram nada do maven2?

  3. Paulo Silveira 11/11/2010 at 17:21 #

    Pois é senhor anonimo. Mesmo a gente usando maven em praticamente todos os nossos projetos (inclusive nos abertos em http://www.github.com/caelum), nossa preferência tem sido ir para ant+ivy ou gradle no java.

    quem sabe agora com maven 3 podemos encarar novamente.

  4. Guilherme Silveira 12/11/2010 at 10:42 #

    Bom dia,

    Fizemos um post exclusivo para o maven 2 anos atrás, repetir exemplos de dois anos em um novo post não cairia bem nesse instante. Você pode ver sobre o assunto aqui: http://blog.caelum.com.br/2008/07/07/processo-de-build-com-o-maven

    O Maven também tem caminhado para suportar outras linguagens uma vez que a descrição dele ainda é mais pesada que outras soluções.

    Abraço

Deixe uma resposta