Eu sempre usei o Subversion pra controlar as versões de meus códigos e no começo deste mês tive a necessidade de desenvolver uma aplicação que recuperasse as revisões do SVN e disponibilizasse em um site para controle dos gerentes de um dos projetos.
Como ferramenta eu optei por usar o SharpSVN, uma biblioteca escrita para .NET. Apesar do esforço não encontrei muita coisa em português então resolvi dar uma estudada na documentação (http://docs.sharpsvn.net/current) e escrever este artigo.
Aqui eu vou mostrar uma conexão simples e como resolver o seguinte erro ao publicar o site “SharpSvn.SvnFormatException: Can’t determine the user’s config path“.
Então vamos lá. Mãos a obra.
Primeiramente temos que preparar o nosso ambiente, para isso temos que baixar os arquivos do SharpSVN http://sharpsvn.open.collab.net/files/documents/180/4381/SSvn-1.6016.1637.zip
Extraia os arquivos.
Abra o Visual Studio e cria uma nova aplicação Web.
Faça referência a dll SharpSvn.dll.
Eu vou recuperar as versões de um projeto que nós do desenvolvedores.net apoiamos e que está no Sourceforge
Página oficial do projeto: http://uninfe.com.br
Página no Sourceforge: https://uninfe.svn.sourceforge.net/svnroot/uninfe
E como sempre, prestem atenção aos comentários do código. Eu coloco informações úteis no mesmo.
<%@ Page Language="C#" AutoEventWireup="true" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Exemplo SVN</title> <script runat="server" type="text/C#"> protected void Page_Load(object sender, EventArgs e) { //definir o datasource do meu grid grdRevision.DataSource = LoadSvnRevision(); //popular os dados no grid grdRevision.DataBind(); } private System.Collections.Generic.List<object> LoadSvnRevision() { //inicar o cliente svm SharpSvn.SvnClient client = new SharpSvn.SvnClient(); //aqui iniciamos o objeto que irá receber os dados de retorno do svn. //Obrigatoriamente tem que ser deste tipo System.Collections.ObjectModel.Collection<SharpSvn.SvnLogEventArgs> //pois o parâmetro é do tipo "out" System.Collections.ObjectModel.Collection<SharpSvn.SvnLogEventArgs> logItems = new System.Collections.ObjectModel.Collection<SharpSvn.SvnLogEventArgs>(); //aqui chamamos o método responsável por trazer as revisões do SVN //no primeiro parâmetro informamos a url do repositório. (targetPath) //no segundo parâmetro informamos a nossa variável que irá receber o retorno client.GetLog(new Uri("https://uninfe.svn.sourceforge.net/svnroot/uninfe"), out logItems); //aqui eu crio uma variável que irá recuperar este retorno e converter //em uma lista de obejtos para ser usada dentro do meu grid System.Collections.Generic.List<object> data = new System.Collections.Generic.List<object>(); foreach (var item in logItems) //aqui eu uso um array nomeado do tipo Key/Value { data.Add(new { Id = item.Revision, Autor = item.Author, Data = item.Time, }); } //descarrego cliente client.Dispose(); //limpo da memória client = null; //retorno minha lista de dados return data; } </script> </head> <body> <form id="form1" runat="server"> <div> <asp:GridView runat="server" ID="grdRevision"> </asp:GridView> </div> </form> </body> </html>
Assim temos uma aplicação básica que recupera os dados de um diretório publico. Mas, e se for em um diretório privado?
Basta acrescentar estas duas linhas ao seu código. Antes de chamar o método client.GetLog();
//Limpamos a autenticação antes de começar client.Authentication.Clear(); //criamos uma autenticação de usuário usando o System.Net.NetworkCredential client.Authentication.DefaultCredentials = new System.Net.NetworkCredential("Nome do usuário", "senha");
Uma outra dica que creio ser interessante passar é a opção de filtragem dos dados que iremos receber em nosso objeto de retorno. Do modo como foi feito no código de exemplo iremos recuperar todas as revisões, isso não é interessante em um projeto grande. Aqui vou ensinar a fazer o filtro por data.
//data de início do log que vamos buscar //aqui informo +1 dia para que pegue também o dia atual DateTime startDateTime = DateTime.Today.AddDays(1); //iremos buscar 15 dias antes. Então informamos a segunda data DateTime endDateTime = startDateTime.AddDays(-15); //aqui iremos criar um "range" de datas para filtrar. //para isso usamos o tipo SharpSvn.SvnRevisionRange //o construtor do range aceita o tipo new SharpSvn.SvnRevision //que por sua vez aceita vários tipos de filtros, um deles é o tipo data //passamos então as datas de início e fim do range, //de acordo com os parâmetros do contrutor do objeto SharpSvn.SvnRevisionRange //primeiro e segundo parâmetro do construtor SharpSvn.SvnRevisionRange range = new SharpSvn.SvnRevisionRange(new SharpSvn.SvnRevision(startDateTime), new SharpSvn.SvnRevision(endDateTime)); //criamos a nossa variável do tipo SharpSvn.SvnLogArgs para passar o nosso range de datas. SharpSvn.SvnLogArgs args = new SharpSvn.SvnLogArgs(range); //aqui chamamos o método responsável por trazer as revisões do SVN //no primeiro parâmetro informamos a url do repositório. (targetPath) //no segundo parâmetro passamos os argumentos de filtragem dos dados //no terceiro parâmetro informamos a nossa variável que irá receber o retorno client.GetLog(new Uri("https://uninfe.svn.sourceforge.net/svnroot/uninfe"), args, out logItems);
Preste atenção na linha em destaque, repare que modificamos o método client.GetLog() e passamos o parâmetro args que é o nosso filtro por data.
Vamos agora à um problema conhecido quando publicamos o nosso site. “SharpSvn.SvnFormatException: Can’t determine the user’s config path“. Este erro não acontece no modo debug porque estamos executando nossa aplicação local e a nossa configuração de usuário já foi toda carregada. Mas quando publicamos podemos receber este erro, pois normalmente a aplicação web roda como um serviço no servidor e pode não ter toda a configuração de usuário carregada. Para isso temos que informar o caminho onde iremos salvar a configuração padrão do usuário. Podemos usar um caminho temporário ou um caminho fixo na sua aplicação. Fica a seu critério. Eu optei por executar eu um caminho temporário.
Para contornar este erro, iremos usar o método LoadConfiguration() que irá indicar onde iremos salvar o arquivo de configuração temporário.
client.LoadConfiguration(System.IO.Path.Combine(System.IO.Path.GetTempPath(), "Svn"), true);
Atenção: Este método deve ser chamado antes de client.GetLog();
Abaixo o código completo de nossa aplicação SVN
<%@ Page Language="C#" AutoEventWireup="true" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Exemplo SVN</title> <script runat="server" type="text/C#"> protected void Page_Load(object sender, EventArgs e) { //definir o datasource do meu grid grdRevision.DataSource = LoadSvnRevision(); //popular os dados no grid grdRevision.DataBind(); } private System.Collections.Generic.List<object> LoadSvnRevision() { //inicar o cliente svm SharpSvn.SvnClient client = new SharpSvn.SvnClient(); //aqui iniciamos o objeto que irá receber os dados de retorno do svn. //Obrigatoriamente tem que ser deste tipo System.Collections.ObjectModel.Collection<SharpSvn.SvnLogEventArgs> //pois o parâmetro é do tipo "out" System.Collections.ObjectModel.Collection<SharpSvn.SvnLogEventArgs> logItems = new System.Collections.ObjectModel.Collection<SharpSvn.SvnLogEventArgs>(); //data de início do log que vamos buscar DateTime startDateTime = DateTime.Today.AddDays(1); //iremos buscar 15 dias antes. Então informamos a segunda data DateTime endDateTime = startDateTime.AddDays(-15); //aqui iremos criar um "range" de datas para filtrar. //para isso usamos o tipo SharpSvn.SvnRevisionRange //o construtor do range aceita o tipo new SharpSvn.SvnRevision que por sua vez aceita vários tipos de filtros, um deles é o tipo data //passamos então as datas de início e fim do range, de acordo com os parâmetros do contrutor do objeto SharpSvn.SvnRevisionRange SharpSvn.SvnRevisionRange range = new SharpSvn.SvnRevisionRange(new SharpSvn.SvnRevision(startDateTime), new SharpSvn.SvnRevision(endDateTime)); //criamos a nossa variável do tipo SharpSvn.SvnLogArgs para passar o nosso range de datas. SharpSvn.SvnLogArgs args = new SharpSvn.SvnLogArgs(range); //aqui iremos dizer onde o arquivo de configuração do svn deverá ser salvo client.LoadConfiguration(System.IO.Path.Combine(System.IO.Path.GetTempPath(), "Svn"), true); //aqui chamamos o método responsável por trazer as revisões do SVN //no primeiro parâmetro informamos a url do repositório. (targetPath) //no segundo parâmetro passamos os argumentos de filtragem dos dados //no terceiro parâmetro informamos a nossa variável que irá receber o retorno client.GetLog(new Uri("https://uninfe.svn.sourceforge.net/svnroot/uninfe"), args, out logItems); //aqui eu crio uma variável que irá recuperar este retorno e converter //em uma lista de obejtos para ser usada dentro do meu grid System.Collections.Generic.List<object> data = new System.Collections.Generic.List<object>(); foreach (var item in logItems) //aqui eu uso um array nomeado do tipo Key/Value { data.Add(new { Id = item.Revision, Autor = item.Author, Data = item.Time, }); } //descarrego cliente client.Dispose(); //limpo da memória client = null; //retorno minha lista de dados return data; } </script> </head> <body> <form id="form1" runat="server"> <div> <asp:GridView runat="server" ID="grdRevision"> </asp:GridView> </div> </form> </body> </html>
É isso ai pessoal 🙂
Até o próximo
♦ Marcelo