metodologia

todo mundo quer ser ágil

July 5th, 2010  |  Published in metodologia

Alguns dias atrás eu comentava com um colega de trabalho, sobre o meu sentimento de que o “agilismo” (ou seja lá qual for o termo) já se tornou a moda da vez. Os “xipezeiros”, “scrunzeiros” e agilistas de plantão estufam o peito pra falar dos seus “sprints”… que utilizam quadros brancos… que tem post-its colados por toda empresa… que UML  não serve pra náda… e que ser ágil é sentar e sair programando.
Tenho o sentimento que muitas pessoas e consequentemente empresas, se juntam a manáda e começam a utilizar alguma metodologia, porque alguém disse que é bom, ou porque o blog do momento falou que é “cool” ser ágil.

Qual a empresa de tecnologia hoje, ser arriscaria a dizer para seu cliente que não é “Ágil” ?
Todo mundo tenta desesperadamente ser ágil.
Até a IBM, quer ser ágil.

Tenho a impressão que essa busca incansável, é motivada principalmente por 2 coisas:

- a primeira é que já sofremos muito durante os últimos anos  tentando fazer software
Quem já trabalhou numa fábrica de software, numa consultoria de 3 letrinhas, já encarou caso de uso de mais de 100 páginas, ou quis modelar um ERP inteiro em UML antes de começar a programar, sabe bem do que estou falando. Para quem já está na labuta a pelo menos uns 10 anos e passou por tudo isso já aprendeu que algumas coisas nem sempre funcionam. E vêem o agile como a melhor opção disponível para desenvolver software atualmente.

- a segunda é a falsa idéia de que as metodologias ágeis pregam… não utilizar metodologia alguma..!!!
Isso é fato quando se vê muita gente em fóruns e afins, falando que na suas empresas não tem análise, não tem documentação ou burocracia alguma...que após uma reunião, todos os programadores se debruçam-se sobre seus teclados e se põe a codificar até que algo seja “entregável” para o cliente.
Bem, IMHO isso me parece muito mais um XGH…. ou um “Just Do-it Programming” disfarçado de scrum.
Acho que muita gente que está entrando no mercado de trabalho recentemente (a uns 3 ou 4 anos), diz que utiliza XP, Scrum, Lean ou qualquer metodolgia ágil porque tem a ilusão de que é fácil de implementar.

Se não tem documentação… não tem formalidade alguma….se é só fazer uma reunião de 15 min durante a manhã e programar durante o resto do dia… eu também posso ser ágil… vamos implementar isso aqui na nossa empresa !!!

Essa é uma das maiores falácias do desenvolvimento de software. Por experiência própria, eu posso dizer que aplicar uma metodologia como Scrum ou XP na prática numa empresa e obter resultados positivos é um trabalho árduo. É difícil e vai requerer uma paciência que você achava que não tinha. Ao contrário do que muitos pensam, aplicar algumas práticas do XP, como o TDD por exemplo, vai exigir muito mais disciplina de uma equipe, do que se ela estivesse trabalhando numa fábrica de software com CMM5.

Com tudo isso, surgiram inúmeros cursos Scrum e XP por aí… apareceram centanas de especialistas em agile, que prometem demonstrar um conjunto de práticas para tornar qualquer empresa ágil…acabando com seus problemas de escopo, prazo e relacionamento com o cliente.

A verdade é que não existe uma fórmula, ou receita de bolo pra isso. A bala de prata não existe. Cada empresa tem uma caracterísitca….cada projeto tem um contexto… que faz com que seja necessário escolher as melhores práticas em cada situação.

A melhor idéia de agile que tenho até o momento, foram as palavras de Philippe Kruchten no seu keynote no final semana passado, no agile brazil 2010:

Software development is not a Natural Science like Physics or any other. In Agile Software Develpment, we have different methods (aka: scrum, xp, lean) for diferente issues. We have to ask ourselves which practices or methods will fit better in our project context”

“Why we’re using XP ? What practices will fit better in these project ? … and why we’re doing this any way?”

Você consegue imaginar a utilização de XP no desenvolvimento do software que contola um caça F-35 ?

Xispezeiro: “Sem problemas,  nessas duas primeiras semanas vamos entregar a parte que faz ligar o motor e você já pode decolar com o avião”
Piloto: “E o controlador de vôo ?”
Xispezeiro: “O que ? O controlador de vôo ? Mas você vai precisar disso mesmo ? O mais importante agora é decolar… depois conversamos sobre o controlador de vôo…”

Não conheço náda de aeronáutica, mas é bem provável que um projeto de desse tipo seja obrigado a ter uma fase muito detalhada de design e documentação, porque um erro de projeto, pode gerar um prejuízo estratosférico.
E gerar muita documentação nesse caso está errado? Você faria uma reunião de 4 horinhas pra modelar uma funcionalidade num F-35 ?
Claro que esse é um exemplo extremo, mas existem muitas organizações e ramos de negócio que precisam de mais formalidade e provavelmente teriam muitas dificuldades implementando métodos ágeis.
Por isso que contexto, é fundamental.

Com toda essa confusão de post-its e sprints do falso agile, os verdadeiros valores do manifesto ágil acabam ficando em segundo plano para maioria das pessoas. Acabamos desconsiderando o mais importante: o contexto no qual estamos tentando implementar agilidade.

Por que estamos utlizando essa metodologia ? Qual o problema que estamos tentando resolver ? Essas práticas se encaixam no contexto desse projeto ?

CruiseControl com SVN – Parte 02

March 17th, 2010  |  Published in metodologia, programação

Então alguém na sua empresa tem um projeto em Flex, e quer configurá-lo no CruiseControl ?!
Sei..  nós também já passamos por isso.

A primeira coisa a ser feita é colocar a lib do flex-tasks no classpath do ant, para podermos executar as tasks flex no build do nosso projeto. A forma mais fácil de fazer isso é copiando a lib {FLEX_HOME}/ant/lib/flexTasks.jar para diretório de libs da instalação do ant {ANT_HOME}/lib.
Então, para você poder utilizar as tasks flex, basta incluir as linhas abaixo no seu arquivo de build:

<taskdef resource="flexTasks.tasks" classpath="${ant.home}/lib/flexTasks.jar" />
<property name="FLEX_HOME" value="${flex.home}" />

Feito isso você já pode compilar os seus componentes, módulos e quase toda parafernália de um projeto flex tradicional. Para compilar os seus módulos flex, você pode utilizar o <mxmlc>,  indicando o seu .mxml de entrada e o .swf de saída. No meu caso ficou mais ou menos assim:

<!-- compila o modulo flex modules/WhiteboardEditModule.mxml  -->
 <target name="compile-flex-whiteboard-module" depends="compile-java">
 <echo message="${ant.project.name}: Compilando WhiteboardEditModule.mxml ..."/>
 <mxmlc  file="${project.path}/wedoWeb/flex_src/modules/WhiteboardEditModule.mxml"
 output="${project.path}/wedoWeb/output/modules/WhiteboardEditModule.swf"
 keep-generated-actionscript="false"
 incremental="true"
 debug="true"
 allow-source-path-overlap="true"
 show-actionscript-warnings="false"
 show-binding-warnings="false"
 services="${project.path}/wedoWeb/WebContent/WEB-INF/flex/services-config.xml">

 <target-player>10.0.0</target-player>
 <actionscript-file-encoding>"UTF-8"</actionscript-file-encoding>
 <load-config filename="${flex.home}/frameworks/flex-config.xml"/>

 <library-path dir="${flex.home}/frameworks/libs" append="true">
 <include name="*.swc" />
 </library-path>
 <library-path dir="${project.name}/flex_libs" append="true">
 <include name="*.swc" />
 </library-path>

 <locale>pt_BR</locale>
 <locale>en_US</locale>
 <locale>es_ES</locale>
 <source-path path-element="${project.path}/wedoWeb/flex_src" />
 <source-path path-element="${project.path}/Whiteboard/src"/>
 <source-path path-element="${project.path}/wedoWeb/locale/{locale}"/>

 <include-resource-bundles>nous</include-resource-bundles>
 <include-resource-bundles>SharedResources</include-resource-bundles>
 <include-resource-bundles>formatters</include-resource-bundles>
 </mxmlc>
 </target>

É importante indicar o arquivo services-config.xml, ele define algumas diretrizes de compilação do projeto, também relacionadas a utilização da aplicação sobre https. ( é isso né John, vc não vai me fazer passar por mentiroso aqui ?!)

services="${project.path}/wedoWeb/WebContent/WEB-INF/flex/services-config.xml">

Além de indicar o arquivo de configuração do flex, é importante configurar a versão do flashplayer sendo utilizada e o file encoding dos actions scripts. Se você não configurar essas opções… bem, nesse caso coisas estranhas vão acontecer.

<target-player>10.0.0</target-player>
 <actionscript-file-encoding>"UTF-8"</actionscript-file-encoding>
 <load-config filename="${flex.home}/frameworks/flex-config.xml"/>

Por incrível que pareça, a parametrização de intercionalização do projeto, foi mais fácil do que eu esperava. No nosso caso, o sistema está disponível em 3 idiomas.  Bastaram mais umas linhas, e tudo certo.

<locale>pt_BR</locale>
 <locale>en_US</locale>
 <locale>es_ES</locale>
 <source-path path-element="${project.path}/wedoWeb/flex_src" />
 <source-path path-element="${project.path}/Whiteboard/src"/>
 <source-path path-element="${project.path}/wedoWeb/locale/{locale}"/>

<include-resource-bundles>nous</include-resource-bundles>
 <include-resource-bundles>SharedResources</include-resource-bundles>
 <include-resource-bundles>formatters</include-resource-bundles>

Para compilar os demais módulos flex do seu projeto, a história se repte, é só mandar um <mxmlc> da mesma forma como fizemos aí em cima.

Depois disso,  ainda é preciso gerar o arquivo html principal da aplicação, sim.. aquele objeto que traz consigo o .swf dentro dele: o html-wrapper. O elemento <html-wrapper> gera pra você o index.html e AC_OETags.js, que serão necessários no deploy da aplicação. Além disso ele pode gerar o resto da parafernália (adoro a pronúncia dessa palavra: pa-ra-fer-ná-li-a …), como os arquivos historyFrame.html, history.css e history.js

<!-- Gera html-wrapper  -->
 <target name="wrapper-flex-html" depends="compile-flex-wedoWeb-module">
 <echo message="${ant.project.name}: Gerando html-wrapper ..."/>
 <html-wrapper
 title=""
 file="wedoWeb.html"
 height=""
 width=""
 bgcolor=""
 application=""
 swf=""
 version-major=""
 version-minor=""
 version-revision=""
 history="true"
 template="express-installation"
 output="${project.name}/output"/>

 <html-wrapper
 title=""
 file="wedoTest.html"
 height=""
 width=""
 bgcolor=""
 application=""
 swf=""
 version-major=""
 version-minor=""
 version-revision=""
 history="true"
 template="express-installation"
 output="${project.name}/output"/>

 </target>

O problema é que no nosso caso, já temos um index.template.html, que é utilizado na geração do html principal da aplicação. Por isso eu utilizei o <html-wrapper> apenas para geração da parafernália (novamente…) de arquivos AC_OETags.js, historyFrame.html, history.css, history.js e o index.html padrão. Depois bastaram alguns ctrl-c, ctrl-v para os passar os parãmetros do template para o meu recém criado wedoWeb.html.

<target name="copy-html-template" depends="wrapper-flex-html">
 <echo message="${ant.project.name}: Gerando wedoWeb.html ..."/>
 <delete file="wedoWeb/output/wedoWeb.html"/>
 <copy file="${project.name}/html-template/index.template.html"    tofile="${project.name}/output/wedoWeb.html" />
 <replace file="${project.name}/output/wedoWeb.html" token="$${title}" value=""/>
 <replace file="${project.name}/output/wedoWeb.html" token="$${swf}" value="wedoWeb"/>
 <replace file="${project.name}/output/wedoWeb.html" token="$${width}" value="100%"/>
 <replace file="${project.name}/output/wedoWeb.html" token="$${height}" value="100%"/>
 <replace file="${project.name}/output/wedoWeb.html" token="$${bgcolor}" value="#869ca7"/>
 <replace file="${project.name}/output/wedoWeb.html" token="$${application}" value="wedoWeb"/>
 <replace file="${project.name}/output/wedoWeb.html" token="$${version_major}" value="10"/>
 <replace file="${project.name}/output/wedoWeb.html" token="$${version_minor}" value="0"/>
 <replace file="${project.name}/output/wedoWeb.html" token="$${version_revision}" value="0"/>

Claro, antes disso ainda precisei manipular alguns arquivos… uns pra lá outros pra cá…  pra poder gerar o .war do jeito que eu queria. Mas isso também vai depender muito da estrutura do seu projeto.

Bem, acho que é isso. Depois é compilar todos os componentes e módulos flex, juntar tudo com o seu código fonte java,  empacotar o .war e “voilà”, temos o um projeto flex compilável.

Logo após as primeiras tentivas e alguns java.lang.OutOfMemoryError: Java heap space , precisei configurar a quantidade de memória para utlização do ANT. No script de inicialização, ant.bat, adicionei a linha abaixo e o problema foi resolvido.

   ANT_OPTS=-Xms512m -Xmx1024m -XX:PermSize=256m -XX:MaxPermSize=256m

Mas depois foi só correr pro abraço…

De qualquer forma, eu conheço de flex o quanto jogo de futebol, então se quiserem uma referência mais segura em desenvolvimento flex, é melhor darem uma olhada no blog do John.

CruiseControl com SVN – Parte 01

February 20th, 2010  |  Published in metodologia, programação

Esse ano estamos tentando fazer algumas mundanças na Informant. Percebemos que usar quadros magnéticos, pregar post-it’s por toda empresa e fazer reuniões diárias não estavam nos fazendo mais “ágeis”, e na prática… pouca coisa era aplicada. Agora estamos buscando realmente implementar algo ágil nos nossos projetos. Estamos dandos os primeiros passos, mas muita coisa boa está sendo planejada para este ano.

Uma das coisas que precisamos melhorar é a forma como trabalhamos com nosso repositório de fontes. Estamos modificando nossos procedimentos e nosso trabalho diário para manter nosso respositório mais confiável: A Integração Contínua é uma prática essencial do XP, que não se resume apenas a utilização de uma ferramenta, mas a automatização de build’s e deploy’s pode economizar muito tempo de desenvolvimento. Deixando o programador disponível para realizar o seu trabalho mais importante: programar.

Estamos começando a utilizar o CruiseControl, ferramenta que ainda não conhecia de perto. Apesar de já ter trabalhado com algumas ferramentas do gênero (ex.: Bamboo), o CC me impressionou bastante com relação a flexibilidade de configuração e implementação de planos de build. Para quem está perdendo muito tempo com liberação de versões, builds, deploys de aplicativos, e está pensando em utilizar o CC, vou repassar aqui os meus passos iniciais de configuração da ferramenta em ambiente Windows:

  1. Faça o download da última release do CC, que atualmente é a 2.8.3 e descompacte vvocê achar melhor, por exemplo em C:\java\cruisecontrol-bin-2.8.3
  2. O ideal é criar um diretório de trabalho configuração de seus projetos. (ex.: C:\java\work\cruise). Achei mais fácil iniciar o CC desta mesma workspace, por isso também copiei os arquivos cruisecontrol.bat, config.xml e dashboard-config.xml para o diretório /cruise. Bastando apenas fazer alguns acertos no cruisecontrol.bat, apontando o launcher do CC para o caminho correto (C:/java/cruisecontrol-bin-2.8.3/lib/cruisecontrol-launcher.jar). Nesse momento, você já poderá iniciar o CC. Apontando o seu navegador para http://localhost:8080/dashboard/tab/dashboard já será possível acessar a ferramenta. Se tudo der certo, você deverá ver o Dashboard Server, que por enquanto, não terá nenhum projeto disponível.Você deverá ter a variável JAVA_HOME também já configurada no seu Path.
  3. Agora precisamos configurar um projeto. No CC, todos os projetos são configurados a partir do arquivo config.xml. Quando trabalhamos com múltiplos projetos, é interessante manter a configuração de cada um deles em arquivos separados, para isso podemos alterar o config.xml para que fique da seguinte forma:
    <!-- config.xml -->
    <!DOCTYPE cruisecontrol [
       <!ENTITY build-informantUtils SYSTEM "projects/informantUtils-config.xml">
       <!ENTITY build-informantEJB SYSTEM "projects/informantEJB-config.xml">
    ]>
    <cruisecontrol>
        <property file="config.properties"/>
        <plugin name="svn" classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN"/>
        <plugin name="svnbootstrapper" classname="net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper"/>
        <system>
           <configuration>
               <threads count="2"/>
           </configuration>
        </system>
        &build-informantLibs;
        &build-informantEJB;
    </cruisecontrol>
    
  4. O meu objetivo inicial com a utilização do CC, era fazer o build automático das aplicações no nosso ambiente de testes sempre que alterações fosse efetivadas (commit), garantindo que nosso repositório esteja sempre compilando, e que a qualquer momento, tivéssemos uma versão disponível para liberação. Para isso, utilizamos o elemento <modificationset>, que determina como o CC procura por alterações no repositório e quando vai executar o build do projeto.
    <!-- informantEJB-config.xml -->
    <plugin name="svn" classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN"/>;
    <plugin name="svnbootstrapper" classname="net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper"/>
        <modificationset quietperiod="10">
            <svn localWorkingCopy="checkout/agil/${project.name}"
                 repositoryLocation="${svn.repository}/${svn.trunk}/InformantEJB"
                 username="${svn.user}"
                 password="${svn.passwd}">
            </svn>
        </modificationset>
    

    Assim monitoramos alterações do projeto no SVN e quando o CC deverá fazer o build do projeto. Veja que é preciso indicar o respositório local do projeto (localWorkingCopy), para onde os fontes do projetos serão copiados e compilados no momento do build. Por isso é necessário criar um diretório de checkout local para os projetos no seu diretório de trabalho (ex.: /work/cruise/checkout)
    Para tudo dar certo, ainda iremos precisar incluir os plugins do svn, conforme acima. Também será necessária instalar e garantir que o SVN esteja no seu Path.

  5. Então utlizamos o elemento <schedule> com interval=”300″, para fazer com que o CC verifique o respositório do SVN a cada 5 minutos por novas modificações.  Além disso utilizamos o atributo time=”2300″, forçando com que um build seja executado diariamente as 23:00 horas. Nestes casos, o CC irá executar o script de build do projeto:  build-file=”checkout\agil\build-${project.name.xml}”
    <!-- informantEJB-config.xml -->
    <schedule  interval="500" showProgress="true">
         <ant  antscript="${ant.home}\bin\ant.bat"
               buildfile="checkout\agil\build-${project.name}.xml"
               target="build-informantEJB"
               uselogger="true"
               usedebug="true"
               time="2300"/>
    </schedule>
    

    Será necessário ter o ant instalado. O próprio CC  já vem com a versão 1.7.0 do ant, disponível no diretório de instalação do CC (C:/java/cruisecontrol-bin-2.8.3/apache-ant-1.7.0).

  6. Precisamos agora definir o diretório de logs do projeto. Crie um diretório de logs no seu diretório de trabalho (ex.: C:/java/work/cruise/logs). Isso é importante, porque o CC controla todo o histórico de builds e status (buildstatus) dos projetos em execução, através deste diretório de logs. Dentro do diretório de logs serão criados outros vários subdiretórios, um para cada projeto.
    E acrescente a configuração de log ao projeto:
    <!-- informantEJB-config.xml -->
    <log dir="logs/${project.name}"/>
    
  7. Após cada build do projeto, geralmente um artefato é gerado. Um arquivo war, ear ou zip por exemplo. Neste caso, um arquivo .jar. Por isso é preciso definir uma diretório onde todos esses artefatos serão armazenados após um build realizado com sucesso. Crie um diretório para os artefatos gerados no seu diretório de trabalho (ex.: C:/java/work/cruise/artifacts).  Dentro do diretório de artefatos serão criados outros vários subdiretórios, um para cada projeto.
    Para dizer ao CC, onde e quais artefatos serão publicados, utilizamos o elemento <artifactpublisher>:
    <!-- informantEJB-config.xml -->
    <publishers>
        <artifactspublisher dir="checkout/agil/${project.name}/output" dest="artifacts/${project.name}"/>
    </publishers>
    
  8. Com o arquivo de configuração do projeto concluído (projects/informantEJB-config.xml), precisamos apenas do script de build do projeto, que será chamado pelo CC. No meu caso, ficou mais ou menos assim:
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <project basedir="." default="build-informantEJB" name="informantEJB">
        <echo message="Project:informantEJB: Executando..."/>
    
        <property file="build.properties"/>
        <property name="svnant.latest.url" value="${agil.svn.repository}/${agil.svn.trunk}/informantEJB"/>
        <property name="local.repository" value="informantEJB"/>
    
        <path id="informant.libs">
            <fileset dir="libs/jars">
      	   <include name="**/*.jar"/>
    	</fileset>
        </path>
    
        <path id="jboss-runtime.libs">
    	<fileset dir="../../dependencies/jboss-runtime/client">
        	    <include name="**/*.jar"/>
    	</fileset>
    	<fileset dir="../../dependencies/jboss-runtime/lib">
     	    <include name="**/*.jar"/>
    	</fileset>
        </path>
    
        <path id="ejb.libs">
            <path refid="informant.libs"/>
            <path refid="jboss-runtime.libs"/>
        </path>
    
        <taskdef  resource="svntask.properties"/>
        <target name="checkout">
    	<echo message="${ant.project.name}: Fazendo checkout do respositorio ${svnant.latest.url}..."/>
    	<svn username="${agil.svn.user}" password="${agil.svn.passwd}">
      	    <checkout url="${svnant.latest.url}" revision="HEAD" destPath="${local.repository}" />
    	</svn>
        </target>
    
        <target name="mkdir">
            <mkdir dir="informantEJB/build/classes"/>
    		<mkdir dir="informantEJB/output"/>
            <copy includeemptydirs="false" todir="informantEJB/build/classes">
                <fileset dir="informantEJB/ejbModule">
                    <exclude name="**/*.launch"/>
                    <exclude name="**/*.java"/>
                </fileset>
            </copy>
        </target>
    
        <target depends="checkout,mkdir" name="compile">
            <echo message="${ant.project.name}: ${ant.file}"/>
            <javac debug="true"
    	       debuglevel="${debug.level}"
    	       destdir="informantEJB/build/classes"
    	       source="${compile.source}"
    	       target="${compile.target}"
    	       classpathref="ejb.libs">
                <src path="informantEJB/ejbModule"/>
            </javac>
        </target>
    
        <target depends="compile" name="build-informantEJB">
    	<echo message="${ant.project.name}: Gerando informantEJB.jar..."/>
    	<jar 	destfile="informantEJB/output/informantEJB.jar"
    		basedir="informantEJB/build/classes"
    		includes="**/*.class,**/*.xml">
    		<manifest>
          		    <attribute name="Created-By" value="Agil ERP"/>
    		    <attribute name="Manifest-Version" value="1.0"/>
    		    <attribute name="Implementation-Vendor" value="Informant"/>
    		    <attribute name="Implementation-Title" value="Informant"/>
    		    <attribute name="Implementation-Version" value="1.0"/>
    		</manifest>
    	</jar>
        </target>
    </project>
    

    O plano de build do projeto agora está OK: configuramos o informantEJB-config.xml para que execute o script de build (build-informantEJB.xml) quando alguma alteração for realizada no repositório. Além disso o CC irá executar também um build diário, as 23:00 horas.

  9. Tudo certo agora?! NÃO.
    Mesmo que você faça um build manual do projeto através do CC ( http://localhost:8080/dashboard/tab/dashboard), o status do projeto continuará inativo. Isso acontece porque criamos um diretório de trabalho em C:/java/work/cruise, onde serão armazenados os logs e artefatos do projeto. Mas o CC ainda não sabe disso.Crie um arquivo override.properties em C:/java/cruisecontrol-bin-2.8.3/reporting/jsp dessa forma:
    # This should be the full path to your CruiseControl log directory.
    # If you are in multi-project mode, there will be multiple sub-directories
    # inside this log directory, one for each project.
    user.log.dir=C:/java/work/cruise/logs
    
    # This should be the path to your current build status file, # expressed relative to the project's log directory.
    user.build.status.file=C:/java/work/cruise/logs/buildstatus.txt
    
    # This should be the absolute path to the directory where # additional build artifacts are stored.
    cruise.build.artifacts.dir=C:/java/work/cruise/artifacts
    

Essa é uma configuração bem básica. Mas já dá pra ter uma idéia do que pode ser feito. O CC foi implementado para ser extensível e flexível o suficiente para que você possa customizar quase tudo. Além disso, existem vários plugins e outros add-ons que podem ser utilizados pafa aumentar ainda mais as possibilidades de uso do framework.

<!DOCTYPE cruisecontrol [
<!ENTITY build-informant SYSTEM "projects/informant-config.xml">
<!ENTITY build-informantLibs SYSTEM "projects/informantLibs-config.xml">
<!ENTITY build-informantUtils SYSTEM "projects/informantUtils-config.xml">
<!ENTITY build-displayTags SYSTEM "projects/struts2-displatTag-config.xml">
<!ENTITY build-informantWeb SYSTEM "projects/informantWeb-config.xml">
<!ENTITY build-informantEJB SYSTEM "projects/informantEJB-config.xml">
<!ENTITY build-informantEAR SYSTEM "projects/informantEAR-config.xml">
<!ENTITY deploy-informantEAR SYSTEM "projects/informantEAR-deploy-config.xml">
]>
<cruisecontrol><property file=”config.properties”/>
<plugin name=”svn” classname=”net.sourceforge.cruisecontrol.sourcecontrols.SVN”/>
<plugin name=”svnbootstrapper” classname=”net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper”/>
<system>
<configuration>
<threads count=”2″/>
</configuration>
</system>
&build-informantLibs;
&build-informantUtils;
&build-displayTags;
&build-informantWeb;
&build-informantEJB;
&build-informantEAR;
&build-informant;
&deploy-informantEAR;
</cruisecontrol>