Vocês devem estar se perguntando: que raio de agilista sou eu, escrevendo esse post que ensina como “colocar uma algema” nas mãos do desenvolvedor e viola, praticamente, todos os princípios ágeis? Quero deixar claro que não recomendo que vocês apliquem isso em suas empresas e que o objetivo do post é apenas demostrar como trabalhar com eventos de servidor do TFS, ok? Vamos lá!

Políticas de Check-In

Uma das primeiras configurações que as pessoas fazem assim que começam a utilizar o TFS é habilitar as políticas de check-in no source control. Isso não é por acaso, esse é um processo bastante simples e extremamente tentador, já que com apenas alguns cliques, o administrador pode habilitar políticas para:

  • Garantir que o programador não esqueça de colocar comentários no check-in;
  • Associar o check-in com algum work item;
  • Garantir que o código está seguindo o Code Analysis;
  • Garantir que o programador não suba um código com a build quebrada e dificulte ainda mais a correção da build;
  • Garantir que os testes foram executado antes do check-in;
  • E muitos outros

políticas de check-in

Legal! É uma lista bastante tentadora, mas use-a com moderação. A minha experiência em consultoria diz que quando você liga todas essas políticas, sem a aprovação e a conscientização do time de desenvolvimento, lá na máquina do desenvolvedor, o resultado será o seguinte:

sobreescrever política

Isso mesmo, ele vai sobrescrever a política e não vai dar a mínima para as políticas que ele deveria seguir.

A minha dica aqui é: um time é diferente do outro, deixe para cada time a decisão de quais políticas utilizar. Não imponha nada, no máximo peça para experimentarem e analisar os benefícios antes de decidirem se vão ou não usar alguma política.

Agora vamos imaginar que você tenha realmente um forte motivo para impedir que o desenvolvedor sobrescreva as políticas de check-in e que você queira garantir que o TFS não deixe de forma alguma que a políticas sejam violadas.

Eventos de Servidor

O TFS possui diversos eventos de servidor. Esses eventos são disparados pelos mais diversos componentes do TFS, entre eles source control, build, work item tracking, entre outros. Os eventos também possuem duas classificações: Eventos de Notificação, onde você pode disparar uma ação qualquer e Eventos de Decisão, onde você pode cancelar ações e interagir com o usuário.

Para a nossa solução, vamos basicamente criar uma classe que implemente a interface de notificação do TFS, a ISubscriber, e quetrate o evento de decisão chamado CheckinNotification. Vamos ver passo a passo como fazer isso:

  1. Instale o Visual Studio 2010 SP1 SDK, se você não o tiver instalado;
  2. Crie um projeto do tipo Class Library;
  3. Referencie os seguintes namespaces:
    using System;
    using Microsoft.TeamFoundation.Framework.Server;
    using Microsoft.TeamFoundation.Common;
    using Microsoft.TeamFoundation.VersionControl.Server;
  4. Implemente a interface ISubscriber:
    public class BloqueadorViolacaoPolitica : ISubscriber
  5. Crie uma propriedade read-only chamada Name que identifique o seu event handler:
    private const string _name = "Bloqueador de Violacao de Politica";
    
    public string Name
    {
        get { return _name; }
    }
  6. Defina a prioridade que o seu evento será tratado:
    public SubscriberPriority Priority
    {
        get { return SubscriberPriority.Normal; }
    }
  7. Defina os tipos de eventos que o seu event handler vai tratar:
    public Type[] SubscribedTypes()
    {
        return new Type[] { typeof(CheckinNotification) };
    }
  8. E por último e mais importante, implemente a regra que vá impedir o check-in caso o programador tente violar a política:
    public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext,
        NotificationType notificationType,
        object notificationEventArgs,
        out int statusCode,
        out string statusMessage,
        out ExceptionPropertyCollection properties)
    {
        statusCode = 0;
        statusMessage = string.Empty;
        properties = null;
    
        if (notificationType == NotificationType.DecisionPoint 
            && notificationEventArgs is CheckinNotification)
        {
            CheckinNotification data = notificationEventArgs as CheckinNotification;
            if (!string.IsNullOrWhiteSpace(data.PolicyOverrideInfo.Comment))
            {
                statusMessage = "Check-in nao permitido. Verifique as politicas violadas.";
    
                statusCode = -1;
                return EventNotificationStatus.ActionDenied;
            }
    
        }
        return EventNotificationStatus.ActionPermitted;
    }

Veja que o código é bastante simples. Eu tenho basicamente que verificar se o evento que estou recebendo é um CheckinNotification é do tipo de NotificationType.DecisionPoint e se for, eu devo verificar também se houve algum comentário inserido para justificar a violação. Se houve comentário, significa também que houve também uma violação de política e a partir daí é só informar ao evento que ele não deve permitir o check-in.

Isso é feito através do retorno EventNotificationStatus.ActionDenied e eu aproveito para retornar também um mensagem e um código de erro para informar ao desenvolvedor que aquela ação não é permitida.

Uma vez a dll compilada, basta eu copiá-la para o diretório de plug-ins do TFS, no C:\Program Files\Microsoft Team Foundation Server 2010\Application Tier\Web Services\bin\Plugins e pronto. Minha nova regra já está valendo e na prática, o usuário verá um tela parecida com essa:

check-in nao permitido

Abaixo você tem o código completo da classe:

using System;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.VersionControl.Server;

public class BloqueadorViolacaoPolitica : ISubscriber
{
    private const string _name = "Bloqueador de Violacao de Politica";

    public string Name
    {
        get { return _name; }
    }

    public SubscriberPriority Priority
    {
        get { return SubscriberPriority.Normal; }
    }

    public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext,
     NotificationType notificationType,
     object notificationEventArgs,
     out int statusCode,
     out string statusMessage,
     out ExceptionPropertyCollection properties)
    {
        statusCode = 0;
        statusMessage = string.Empty;
        properties = null;

        if (notificationType == NotificationType.DecisionPoint 
         && notificationEventArgs is CheckinNotification)
        {
            CheckinNotification data = notificationEventArgs as CheckinNotification;
            if (!string.IsNullOrWhiteSpace(data.PolicyOverrideInfo.Comment))
            {
                statusMessage = "Check-in nao permitido. Verifique as politicas violadas.";

                statusCode = -1;
                return EventNotificationStatus.ActionDenied;
            }

        }
        return EventNotificationStatus.ActionPermitted;
    }

    public Type[] SubscribedTypes()
    {
        return new Type[] { typeof(CheckinNotification) };
    }

}

Bom galera, é isso! Como eu disse no início do post, não recomendo que vocês implantem essa solução em produção e espero que vocês tenham entendido como tratar os eventos de servidor do TFS.

Até a próxima
André Dias