65.9K
CodeProject 正在变化。 阅读更多。
Home

TFS Rev-Up, 一个用于递增构建修订版本的实用程序

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2013年8月25日

CPOL

4分钟阅读

viewsIcon

21920

downloadIcon

132

一个用于递增 TFS 生成编号的实用程序

引言

我的团队使用 TFS (Microsoft Team Foundation Server 2010) 进行每日构建。 使用 TFS,设置每日构建非常容易。 但是,TFS 不会自动递增构建编号,也不包含执行此操作的任何机制。 这意味着每个构建都具有相同的编号,除非开发人员更改它。 这个项目是一个实用程序,每次运行时都会递增构建编号。

递增构建编号的过程是

  1. 签出您的 AssemblyInfo.cs/.vb 文件
  2. 递增最低位数 (1.1.1.1 变为 1.1.1.2)
  3. 签入文件

我的团队计划在计划构建前的每天晚上运行此实用程序。 然而,我们可以选择将其包含到构建模板或工作流中。 如果我们切换到“持续集成”流程,我们将把此实用程序移到构建模板(或工作流)中。

必备组件

  1. 要运行此程序,您需要安装 TFS 客户端文件。
  2. 您需要拥有访问 TFS 和您将更改/递增的任何 TFS 路径的权限。 如果您将此项目 (EXE) 作为计划进程运行,那么调度程序(或任务)需要使用具有这些权限的帐户。

设置

项目

我创建了一个命令行项目(带有可选的 GUI)。 为此,我创建了一个“Visual C#”,Windows,“Windows 窗体应用程序”。 创建项目后,我进入了“项目属性”,在“应用程序”选项卡下,我将“输出类型”更改为“控制台应用程序”。 最后,我通过测试命令行参数来更改 Main() 函数以检测命令行模式与 UI 模式

    static void Main(string[] args)
    {
        //if no command line args then start with UI
        if (args == null || args.Length < 1)
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new frmMain());
        }
        else //run in silent mode
        {
            if (args[0].Contains("silent"))
                Console.WriteLine("Version Revved up to " + TfsRevUp.DoRevUp(
                   TfsAutoRevUp.Properties.Settings.Default.TfsServerUrl, 
                   TfsAutoRevUp.Properties.Settings.Default.AssemblyInfoFilePath));
            else
                Console.WriteLine("Use the /silent arg to run in silent mode.\n" + 
                   "Example: TfsRevUp.exe /silent");
        }
    }

引用 TFS 程序集

在 C# 项目中,需要以下 DLL(TFS 程序集)

  • Microsoft.TeamFoundation.dll
  • Microsoft.TeamFoundation.Client.dll
  • Microsoft.TeamFoundation.Common.dll
  • Microsoft.TeamFoundation.VersionControl.Client.dll
  • Microsoft.TeamFoundation.VersionControl.Common.dll

这些文件通常可以在以下文件夹中找到: c:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\

创建指向 TFS 的配置设置

我将此实用程序设置为一次处理一个项目。 设置进入 app.config 文件 (TfsRevUp.exe.config),这样我就可以在不重新编译的情况下更改它。

Using the Code

此实用程序的所有工作都在一个名为 TfsRevUp (.cs) 的类中。

namespace TfsRevUp
{
    class TfsRevUp
    {
       public static string DoRevUp(string TfsServerUrl, string AssemblyInfoFilePath)
       {

这两个参数的值将来自 app.config 文件(上面的“项目设置”)

包含

为了实现我的目标,我需要同时使用两个不同的 TFS 库。 一个用于 TFS 服务器,一个用于 TFS 客户端。 名称很长,所以我为客户端命名空间使用了别名

using TFS=Microsoft.TeamFoundation.VersionControl.Client;

屏幕截图(UI 或命令行)

- 或 -

连接到 TFS

TFS 旨在托管多个服务。 源代码控制只是其中之一。 所以我需要两个连接

Microsoft.TeamFoundation.Client.TeamFoundationServer tfServer;
TFS.VersionControlServer verServer;
 
//connect to the TFS server
tfServer = new Microsoft.TeamFoundation.Client.TeamFoundationServer(TfsServerUrl);
 
//connect to the Source Control service
verServer = tfServer.GetService<TFS.VersionControlServer>();
 

创建工作区

//TFS needs a workspace to do any check-in/out stuff 
const string cWorkspaceName = "RevUp-TempWorkspace";
TFS.Workspace[] workspaces = verServer.QueryWorkspaces
(cWorkspaceName, verServer.AuthorizedUser, System.Environment.MachineName);
TFS.Workspace wsp;
 
if (workspaces == null || workspaces.Length < 1)
   wsp = verServer.CreateWorkspace(cWorkspaceName, verServer.AuthorizedUser);
else
   wsp = workspaces[0];

将工作区映射到本地 HDD 路径

string strLocalPath = System.IO.Directory.GetCurrentDirectory() + "\\Temp\\";
 
//if the local path (temp) doesn’t exist, create it now
if (!System.IO.Directory.Exists(strLocalPath)) 
   System.IO.Directory.CreateDirectory(strLocalPath);
//map to a local path for editing (unless it already is mapped)
if (!wsp.IsServerPathMapped(AssemblyInfoFilePath))
   wsp.Map(AssemblyInfoFilePath, strLocalPath);

签出文件

//make sure I have permissions to check-out the file
if (!wsp.HasCheckInPermission)
{
   return "You do not have permissions to rev-up the project";
}
string strLocalFileName = strLocalPath + "AssemblyInfo.cs";
 
//make sure no one else has the assemblyinfo.cs file checked-out exclusively
TFS.PendingSet[] sets = wsp.QueryPendingSets(new string[] { strLocalFileName }, 
TFS.RecursionType.None, cWorkspaceName, verServer.AuthorizedUser, false);
if (sets.Length < 1)
{
   //get the file
   wsp.Get();
 
   //check-out the file for edit
   wsp.PendEdit(new string[] { strLocalFileName }, 
   TFS.RecursionType.None, null, TFS.LockLevel.CheckOut);
 
   //update the contents of the file
   strNewRev = UpdateAssemblyInfoFile(strLocalFileName);

解析并增加修订版本

一旦我获得了 Assembly 信息文件的本地副本,我找到版本号,加 1,更新文件并保存它。

private static string UpdateAssemblyInfoFile(string filename)
{
   System.Text.RegularExpressions.MatchCollection matches;
   const string cRxMask = "\\\"[0-9]+.[0-9]+.[0-9]+.[0-9]+\\\"";
   string newVer = "";
 
   //read-in the whole AssemblyInfo file
   string strFileContent = System.IO.File.ReadAllText(filename);
 
   //use a regular expression to find the version text(s)
   matches=System.Text.RegularExpressions.Regex.Matches(strFileContent, cRxMask);
   foreach (System.Text.RegularExpressions.Match match in matches)
   {
      //increment the lowest segment (in the format: 001)
      newVer = IncrementVer(match.Value);
 
      //replace the old ver with the newer ver
      strFileContent = System.Text.RegularExpressions.Regex.Replace(
      strFileContent, match.Value, newVer);
   }
 
   //write the new content to the AssemblyInfo file
   System.IO.File.WriteAllText(filename, strFileContent);
 
   return newVer;
}
private static string IncrementVer(string oldVer)
{
   string newVer = oldVer.Replace("\"", ""); //strip string delimiters
   char[] dot = { '.' };
 
   string[] segments = newVer.Split(dot);
 
   //increment the lowest segment (in the format: 001)
   segments[3] = (int.Parse(segments[3]) + 1).ToString("000"); //3 digits
   newVer = String.Join(".", segments);
 
   return "\"" + newVer + "\""; //restore string delimiters
}

签入

//...function DoRevUp() continued…
   //check-in the file
   wsp.CheckIn(changes, "Daily rev up");
}

删除工作区

   //remove the workspace so it doesn't honk-up TFS
   verServer.DeleteWorkspace(cWorkspaceName, verServer.AuthorizedUser);
 
   return strNewRev;
}

备用方案

有时,我团队中的某人会签出 AssemblyInfo 文件并忘记签入,或者此实用程序会遇到错误等。 因此,我在顶部附近添加了“if”块来“QueryPendingSets”,如果它找到一些,它会尝试重新提交或响应错误消息,表明有人已签出此文件。

else
{
   //if something goes wrong, replace re
   string re="Previous rev-up is being re-tried, successful"; 
   //if there was an error last time RevUp ran, then check-in the change now
   for (int x = 0; x < sets.Length; x++)
   {
      if (sets[x].Name == cWorkspaceName)
      {
         wsp.CheckIn(sets[x].PendingChanges, "Daily rev up retry");
         break;
      }
      else //if someone else has pending changes on the file, we should be concerned
      {
         re= "Cannot rev-up because someone else has the project checked-out " +
         "exclusively";
      }
   }
 
   return re;
}

安装/运行

我的团队的构建每天凌晨 1 点开始,所以我使用任务计划程序(在 TFS 服务器上)在半小时前,即凌晨 12:30 运行 TfsRevUp。 在项目中的文件 Program.cs 中,我检查了命令行开关 /silent。 它将作为命令行应用程序运行该程序,它将“rev-up”并退出。

结论

这就是签入/签出 TFS 文件并递增构建编号所需要做的所有事情。

高级选项

本文涵盖了一种非常简单的方法来递增 TFS 项目的构建编号。 但是,您可能希望将其与 TFS 构建或 TFS 构建工作流/模板集成。 以下是一些您可以继续阅读的资源,以涵盖更多高级主题,这些主题会添加到此概念中

贷方

我从其他项目中借用了部分代码。 这些人做了一些出色的工作,应该为我项目的一些棘手部分给予赞誉。

历史

  • 版本 1.0 (原始)
© . All rights reserved.