TFS实现持续集成
最近在项目总做了一个小的应用,帮助项目实现持续集成。
在这个持续集成中,用了一些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,真是个好东西,我掌握的也不多,希望大家多多指点