【问题标题】:TFS Execute Custom Code on a Work Item TransitionTFS 在工作项转换上执行自定义代码
【发布时间】:2012-04-25 08:37:14
【问题描述】:

我希望 TFS 2010 在发生特定工作流转换时运行一些自定义代码。这可能吗?

我找到了有关自定义操作的文档,这些操作似乎可以自动触发工作项转换(我说对了吗?)我还找到了与构建相关的自定义活动.但没有什么能满足这个特殊要求 - 我错过了什么吗?

感谢您的帮助!

【问题讨论】:

    标签: tfs workitem


    【解决方案1】:

    这是非常可行的。

    它是如此可行,以至于有很多方法可以做到。我的最爱之一是制作服务器端插件。 (注意,这只适用于 TFS 2010)

    这些博客文章展示了基础知识:

    这是我从我的开源项目TFS Aggregator修改的一些代码:

    public class WorkItemChangedEventHandler : ISubscriber
    {       
        /// <summary>
        /// This is the one where all the magic starts.  Main() so to speak.
        /// </summary>
        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext, NotificationType notificationType, object notificationEventArgs,
                                                    out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)
        {
            statusCode = 0;
            properties = null;
            statusMessage = String.Empty;
            try
            {
                if (notificationType == NotificationType.Notification && notificationEventArgs is WorkItemChangedEvent)
                {
                    // Change this object to be a type we can easily get into
                    WorkItemChangedEvent ev = notificationEventArgs as WorkItemChangedEvent;
                    // Connect to the setting file and load the location of the TFS server
                    string tfsUri = TFSAggregatorSettings.TFSUri;
                    // Connect to TFS so we are ready to get and send data.
                    Store store = new Store(tfsUri);
                    // Get the id of the work item that was just changed by the user.
                    int workItemId = ev.CoreFields.IntegerFields[0].NewValue;
                    // Download the work item so we can update it (if needed)
                    WorkItem eventWorkItem = store.Access.GetWorkItem(workItemId);
    
                    if ((string)(eventWorkItem.Fields["State"].Value) == "Done")
                        {
                            // If the estimated work was changed then revert it back.  
                            // We are in done and don't want to allow changes like that.
                            foreach (IntegerField integerField in ev.ChangedFields.IntegerFields)
                            {
                                if (integerField.Name == "Estimated Work")
                                {
                                    eventWorkItem.Open();
                                    eventWorkItem.Fields["Estimated Work"].Value = integerField.OldValue;
                                    eventWorkItem.Save();
                                }
                            }
                        }
                    }
                }
    
            }
            return EventNotificationStatus.ActionPermitted;
        }
    
        public string Name
        {
            get { return "SomeName"; }
        }
    
        public SubscriberPriority Priority
        {
            get { return SubscriberPriority.Normal; }
        }
    
        public WorkItemChangedEventHandler()
        {
            //DON"T ADD ANYTHING HERE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING.
            //TFS DOES NOT LIKE CONSTRUCTORS HERE AND SEEMS TO FREEZE WHEN YOU TRY :(
        }
    
        public Type[] SubscribedTypes()
        {
            return new Type[1] { typeof(WorkItemChangedEvent) };
        }
    }
    
    /// <summary>
    /// Singleton Used to access TFS Data.  This keeps us from connecting each and every time we get an update.
    /// </summary>
    public class Store
    {
        private readonly string _tfsServerUrl;
        public Store(string tfsServerUrl)
        {
            _tfsServerUrl = tfsServerUrl;
        }
    
        private TFSAccess _access;
        public TFSAccess Access
        {
            get { return _access ?? (_access = new TFSAccess(_tfsServerUrl)); }
        }
    }
    
    /// <summary>
    /// Don't use this class directly.  Use the StoreSingleton.
    /// </summary>
    public class TFSAccess
    {
        private readonly WorkItemStore _store;
        public TFSAccess(string tfsUri)
        {
            TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(new Uri(tfsUri));
            _store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
        }
    
        public WorkItem GetWorkItem(int workItemId)
        {
            return _store.GetWorkItem(workItemId);
        }
    }
    

    【讨论】:

    • 需要注意的重要一点是,此事件是一个通知(不是决策点)。这意味着您无法阻止它。你只能对它做出反应。
    • 这正是我想要的。非常感谢。
    • @Vaccano - 您的TFS Aggregator 项目对我们的团队很有用。只是想说声谢谢...我现在要去你的 codeplex 项目来传播赞成票!
    • @SaulDolgin - 很高兴听到它有帮助!
    • 有没有办法从上下文中获取 TFS URI 而不需要设置文件和帮助程序库?
    【解决方案2】:

    这是我的单例模式的示例

    public class TFSSingleton
    {
        private static TFSSingleton _tFSSingletonInstance;
        private TfsTeamProjectCollection _teamProjectCollection;
        private  WorkItemStore _store;
    
        public static TFSSingleton Instance
        {
            get
            {
                if (_tFSSingletonInstance == null)
                {
                    _tFSSingletonInstance = new TFSSingleton();
                }
                return _tFSSingletonInstance;
            }
        }
    
        public TfsTeamProjectCollection TeamProjectCollection
        {
            get { return _teamProjectCollection; }
        }
    
        public WorkItemStore RefreshedStore
        {
            get
            {
                _store.RefreshCache();
                return _store;
            }
        }
    
        public WorkItemStore Store
        {
            get { return _store; }
        }
    
        private TFSSingleton()
        {
            NetworkCredential networkCredential = new NetworkCredential("pivotalautomation", "*********", "***********");
    
    
            // Instantiate a reference to the TFS Project Collection
            _teamProjectCollection = new TfsTeamProjectCollection(new Uri("http://********:8080/tfs/**********"), networkCredential);
            _store = (WorkItemStore)_teamProjectCollection.GetService(typeof(WorkItemStore));
        }
    }
    

    这是它的引用方式。

    WorkItemTypeCollection workItemTypes = TFSSingleton.Instance.Store.Projects[projectName].WorkItemTypes;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-28
      • 2017-09-18
      • 2012-04-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-23
      相关资源
      最近更新 更多