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





5.00/5 (2投票s)
一个用于递增 TFS 生成编号的实用程序
引言
我的团队使用 TFS (Microsoft Team Foundation Server 2010) 进行每日构建。 使用 TFS,设置每日构建非常容易。 但是,TFS 不会自动递增构建编号,也不包含执行此操作的任何机制。 这意味着每个构建都具有相同的编号,除非开发人员更改它。 这个项目是一个实用程序,每次运行时都会递增构建编号。
递增构建编号的过程是
- 签出您的 AssemblyInfo.cs/.vb 文件
- 递增最低位数 (1.1.1.1 变为 1.1.1.2)
- 签入文件
我的团队计划在计划构建前的每天晚上运行此实用程序。 然而,我们可以选择将其包含到构建模板或工作流中。 如果我们切换到“持续集成”流程,我们将把此实用程序移到构建模板(或工作流)中。
必备组件
- 要运行此程序,您需要安装 TFS 客户端文件。
- 您需要拥有访问 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 构建工作流/模板集成。 以下是一些您可以继续阅读的资源,以涵盖更多高级主题,这些主题会添加到此概念中
- 更好的错误处理和日志记录会很好。 如果出现问题,了解什么/在哪里会有所帮助。
- 修改 TFS 构建模板 https://codeproject.org.cn/Tips/527142/TFS-Stop-running-out-of-disk-space-on-your-build-s
- 微软关于自定义构建模板的文档 (http://msdn.microsoft.com/en-us/library/dd647551(v=vs.100).aspx) 以及添加自定义活动 (http://msdn.microsoft.com/en-us/library/gg265783(v=vs.100).aspx) 听起来有点不祥,这就是本文/项目没有走那么远的原因。
贷方
我从其他项目中借用了部分代码。 这些人做了一些出色的工作,应该为我项目的一些棘手部分给予赞誉。
历史
- 版本 1.0 (原始)