using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Net; using System.Text; using System.Xml.Linq; using System.Xml.XPath; using LibGit2Sharp; namespace TCBuildConfigSync { /// /// Syncs TeamCity build configurations with Git branches. /// /// Uses libgit2sharp to read the list of branches from Git, the TeamCity REST API and HTTP POSTs to the TeamCity dashboard URLs. /// /// libgit2sharp: https://github.com/libgit2/libgit2sharp /// class Program { private const string TeamCityUrl = "http://bob/httpAuth"; static void Main(string[] args) { using (var repo = new Repository(args[0])) { // Collect all the TeamCity build configurations Dictionary tcBranches = new Dictionary(); // Name to Id map List tcBranchesToDelete = new List(); using (WebClient webClient = GetWebClient()) { XDocument doc = XDocument.Parse(webClient.DownloadString(TeamCityUrl + "/app/rest/projects/id:project9")); foreach (XElement buildTypeEl in doc.Root.XPathSelectElements("buildTypes/buildType")) { string id = buildTypeEl.Attribute("id").Value; string name = buildTypeEl.Attribute("name").Value; tcBranches.Add(name, id); tcBranchesToDelete.Add(name); } } // Collect all the branches in this repo foreach (Branch branch in repo.Branches) { // Only look at remote branches if (!branch.IsRemote) continue; // Only look at private branches if (!branch.Name.StartsWith("origin/private/")) continue; string gitBranchName = branch.Name.Substring("origin/".Length); string tcConfigName = branch.Name.Substring("origin/private/".Length).Replace('/', '-'); if (!tcBranches.ContainsKey(tcConfigName)) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("+" + tcConfigName); Console.ResetColor(); // Create a new configuration for this branch using (WebClient webClient = GetWebClient()) { NameValueCollection parameters = new NameValueCollection(); parameters.Add("buildTypeName", tcConfigName); parameters.Add("createFromTemplate", "Create"); parameters.Add("templateId", "btTemplate6"); parameters.Add("param:BRANCH_NAME", gitBranchName); byte[] responseArray = webClient.UploadValues(TeamCityUrl + "/admin/action.html", "POST", parameters); string response = Encoding.ASCII.GetString(responseArray); Console.WriteLine(" ->" + response); } } else { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine(" " + tcConfigName); Console.ResetColor(); // Remove branch from deletion list, there is a matching Git branch tcBranchesToDelete.Remove(tcConfigName); } } // Delete build configurations without Git branches foreach (string tcConfigName in tcBranchesToDelete) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("-" + tcConfigName); Console.ResetColor(); // Delete this dead configuration using (WebClient webClient = GetWebClient()) { NameValueCollection parameters = new NameValueCollection(); parameters.Add("buildTypeId", tcBranches[tcConfigName]); parameters.Add("removeBuildType", "1"); byte[] responseArray = webClient.UploadValues(TeamCityUrl + "/admin/action.html", "POST", parameters); string response = Encoding.ASCII.GetString(responseArray); Console.WriteLine(" -> " + response); } } } } private static WebClient GetWebClient() { WebClient webClient = new WebClient(); webClient.Credentials = new NetworkCredential("user", "password"); return webClient; } } }