最近在项目总做了一个小的应用,帮助项目实现持续集成。
在这个持续集成中,用了一些TFS的API,自动生成新版本,并且调用加密程序对二进制文件进行加密,根据开发者的变更自动生成ReadMe,然后发送邮件给测试人员。大概分下面几步。
1.连接TFS
2.建立Map关系
3.生成Readme
4.取得最新代码
5.对bin和md去掉只读属性
6.讲md拷贝到bin下面
7.编译
8.加密
9.将加密后的文件放到目标路径
10.删除所有pdb文件
11.去掉只读属性
12.写版本号
1.连接TFS
tfs = new TfsTeamProjectCollection(
new Uri(InitInfo.ServerUrl),
new NetworkCredential(InitInfo.LoginName, InitInfo.Password));
2.建立Map关系
versionControlServer = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
workspace = versionControlServer.TryGetWorkspace(InitInfo.LocalFolder);
if (workspace == null)
{
workspace = versionControlServer.CreateWorkspace(InitInfo.Workspace,
(tfs.Credentials as NetworkCredential).UserName);
}
else
{
workspace = versionControlServer.GetWorkspace(InitInfo.Workspace, InitInfo.WorkspaceOwner);
}
workspace.Map("$/" + InitInfo.ProjectName, InitInfo.LocalFolder);
3.生成Readme
生成ReadMe一共分三种
(1)根据代码关联到的Task或者Bug生成ReadMe
VersionControlServer versionControlServer = (VersionControlServer)this.tfs.GetService(typeof(VersionControlServer));
if (versionControlServer == null)
{
CommentToReadme.ErrInfo = "获取不到VersionControlServer";
return;
}
var histroies = versionControlServer.QueryHistory(
InitInfo.LocalFolder,
VersionSpec.Latest,
0,
RecursionType.Full,
null,
null,
null,
Int32.MaxValue,
true,
false,
true);
foreach (Changeset pChangeset in histroies)
{
if (!this.dicErrInfo.ContainsKey(pChangeset.Committer))
{
this.dicErrInfo.Add(pChangeset.Committer, new List<string>());
}
if (!this.dicWorkItemsTitle.ContainsKey(pChangeset.Committer))
{
this.dicWorkItemsTitle.Add(pChangeset.Committer, new List<string>());
}
if (!pChangeset.CreationDate.ToShortDateString().Equals
(System.DateTime.Now.AddDays(-1).ToShortDateString()))
{
continue;
}
WorkItem[] workItems = pChangeset.WorkItems;
if (workItems.Length != 0)
{
for (int index = 0; index < workItems.Length; index++)
{
this.dicWorkItemsTitle[pChangeset.Committer].Add(workItems[index].Title);
}
}
else
{
Change[] changes = pChangeset.Changes;
if (changes.Length != 0)
{
for (int index = 0; index < changes.Length; index++)
{
this.dicErrInfo[pChangeset.Committer].Add(changes[index].Item.CheckinDate + ":" + changes[index].Item.ServerItem);
}
}
}
}
}
(2)根据开发者自己写的Comment生成ReadMe
(3)根据Bug或者Task的状态生成ReadMe
var service = tfs.GetService<WorkItemStore>();
if (service == null)
{
CommentToReadme.ErrInfo = "获取不到service";
return;
}
for (int index = 0; index < InitInfo.Developers.Count; index++)
{
if (!this.dicResolvedBugs.ContainsKey(InitInfo.Developers[index].Name))
{
this.dicResolvedBugs.Add(InitInfo.Developers[index].Name, new List<Bug>());
}
}
for (int i = 0; i < InitInfo.Developers.Count; i++)
{
string developName = InitInfo.Developers[i].Name;
DateTime dt = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
DateTime dtQuery = dt.AddDays(-1);
string query = string.Format("Select * From WorkItems " +
"Where [Work Item Type] = 'Bug' " +
"AND ([State] = 'Resolved' OR [State] = 'Closed') " +
"AND [Resolved by] = '{0}' " +
"AND [Resolved Date] >= '{1}'", developName, dtQuery);
WorkItemCollection wc = service.Query(query);
for (int j = 0; j < wc.Count; j++)
{
Bug tempBug;
tempBug.id = wc[j].Id;
tempBug.title = wc[j].Title;
this.dicResolvedBugs[developName].Add(tempBug);
}
}
4.取得最新代码
versionControlServer.DeleteWorkspace(InitInfo.Workspace, (tfs.Credentials as NetworkCredential).UserName);
Workspace ws = versionControlServer.CreateWorkspace(InitInfo.Workspace,
(tfs.Credentials as NetworkCredential).UserName);
ws.Map("$/" + InitInfo.ProjectName, InitInfo.LocalFolder);
string item = "$/" + InitInfo.ProjectName;
GetStatus s1 = ws.Get(new GetRequest(new ItemSpec(item,
RecursionType.Full), VersionSpec.Latest
), GetOptions.GetAll | GetOptions.Overwrite);
return 0;
5,6两步略过
7.编译
if (SourceXml == null)
SourceXml = new XmlDocument();
SourceXml.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"buildsort.xml"));
XmlNodeList list = SourceXml.SelectNodes("/Projects/Project");
int SuccessCount = 0;
int FailCount = 0;
int PCount = 0;
foreach (XmlNode node in list)
{
string Args = localFolder + @"\source\" + node.Attributes["Name"].Value + @"\" + node.Attributes["Name"].Value + ".csproj";
//Thread th = new Thread(() =>
//{
Process p = new Process();
p.StartInfo = new ProcessStartInfo();
p.StartInfo.FileName = buildToolUrl;
p.StartInfo.Arguments = Args + " /t:Rebuild";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
try
{
p.Start();
PCount += 1;
while (!p.StandardOutput.EndOfStream)
{
string line = p.StandardOutput.ReadLine();
if (line.Trim().Length != 0)
{
Console.WriteLine(line + Environment.NewLine);
if (line.Contains("已成功生成") || line.Contains("Build succeeded"))
{
SuccessCount += 1;
Debug.WriteLine("成功" + SuccessCount);
Console.WriteLine("正在编译第" + "【" + PCount + "/" + list.Count + "】个项目," + "成功【" + SuccessCount + "】" + "失败【" + FailCount + "】" + Environment.NewLine);
}
if (line.Contains("生成失败") || line.Contains("Build FAILED"))
{
FailCount += 1;
Debug.WriteLine("失败" + FailCount);
Console.WriteLine("正在编译第" + "【" + PCount + "/" + list.Count + "】个项目," + "成功【" + SuccessCount + "】" + "失败【" + FailCount + "】" + Environment.NewLine);
}
}
}
p.WaitForExit();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
p = null;
if (PCount == list.Count)
buildFlag = true;
}
//});
//th.Start();
}
其余的也没啥可说的了,终点是TFS的API,真是个好东西,我掌握的也不多,希望大家多多指点