Create a gist now

Instantly share code, notes, and snippets.

Sync TeamCity build configurations with Git branches
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
{
/// <summary>
/// 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
/// </summary>
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<string, string> tcBranches = new Dictionary<string, string>(); // Name to Id map
List<string> tcBranchesToDelete = new List<string>();
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;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment