export/import 构建定义 from/to JSon 文件 (TFS 2013)
export/import build definition from/to JSon file (TFS 2013)
我正在尝试从 tfs2013 导出和导入构建定义,在此之后 and this,但其中 none 对我有用。我知道有一些 tfs 插件可以做到这一点,但由于公司政策限制,我无法使用它们中的任何一个。
GetDefinitionAsync 和 GetFullDefinitionsAsync 方法很好,但它们不检索 ProcessParameters 属性,因此我无法导出包含此重要信息的完整构建定义。我试图让这个 属性 调用 IBuildServer.QueryBuildDefinitions,但是当我尝试创建新的构建定义时我不能,因为数据类型是 Microsoft.TeamFoundation.Build.Client.IBuildDefinition 并且我无法创建新实例Microsoft.TeamFoundation.Build.Client.BuildDefinition 因为它是密封的 class。如何复制 ProcessParameters 和其他信息以导入完整的构建定义?
谢谢
对于XAML构建,您需要使用IBuildServer.GetBuildDefinition方法先获取构建定义,然后再进行复制。
首先通过调用 TfsTeamProjectCollection
实例上的 GetService
方法获取对构建服务器的引用。一旦你有了构建服务器引用,你就可以加载你正在复制的构建定义。
如果您想复制带有过程参数的构建定义,您还应该先复制模板。示例代码 sinnper
// Copy Process parameters
newBuildDefinition.Process = buildDefinitionToCopy.Process;
var processParams = WorkflowHelpers.DeserializeProcessParameters(buildDefinitionToCopy.ProcessParameters);
var copyProcessParams = WorkflowHelpers.DeserializeProcessParameters(newBuildDefinition.ProcessParameters);
foreach (KeyValuePair<string, object> entry in processParams)
{
copyProcessParams.Add(entry.Key.ToString(), entry.Value);
}
newBuildDefinition.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(copyProcessParams);
更详细的如何通过API实现复制,可以参考这篇博客--Copying a TFS Build Definition
好的,经过深入研究,我终于找到了 export/import
的方法
导出到 JSon:
public static void ExportBuildDef(Microsoft.TeamFoundation.Build.Client.IBuildDefinition buildDefinition, string project, string filePath)
{
Console.WriteLine($"Exporting build definition '{buildDefinition.Name}' from '{project}' project.");
var json = JsonConvert.SerializeObject(
buildDefinition,
Newtonsoft.Json.Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
json = removePasswords(json);
File.WriteAllText(filePath, json);
Console.WriteLine($"Build definition '{buildDefinition.Name}' succesfully exported to '{filePath}'.");
}
private static string removePasswords(string json)
{
string res = json;
var searchFor = "\"Password\":";
var startIndex = json.IndexOf(searchFor);
if (startIndex >= 0)
{
var endIndex = json.IndexOf(",", startIndex);
var pwd = json.Substring(startIndex, endIndex - startIndex);
if (pwd.IndexOf(":") > 0)
{
pwd = json.Substring(startIndex, endIndex - startIndex).Split(':')[1].Trim();
res = json.Replace(pwd, "\"{hidden}\"");
}
}
return res;
}
从 JSon
导入
注:BuildDefinitionModel class是一组"POCO"classes(不包括长文件),可以转换为来自 here
的导出 JSon 文件的 C# classes
public static void ImportBuildDefinition(IBuildServer buildServer, string projectName, string filePath, string newBuildName, string sourceProvider)
{
if (!File.Exists(filePath))
throw new FileNotFoundException("File does not exist!", filePath);
Console.WriteLine($"Importing build definition from file '{filePath}' to '{projectName}' project.");
var json = File.ReadAllText(filePath);
var buildDef = JsonConvert.DeserializeObject<BuildDefinitionModel>(json);
var newBuildDefinition = CloneBuildDefinition(buildServer, buildDef, newBuildName, projectName, sourceProvider);
Console.WriteLine($"Build definition '{buildDef.Name}' succesfully imported to '{projectName}' project.");
}
static IBuildDefinition CloneBuildDefinition(IBuildServer buildServer, BuildDefinitionModel buildDefinitionSource, string newBuildName, string projectName, string sourceProvider)
{
var buildDefinitionClone = buildServer.CreateBuildDefinition(projectName);
buildDefinitionClone.BuildController = GetBuildController(buildServer, "");
buildDefinitionClone.Process = buildServer.QueryProcessTemplates(buildDefinitionSource.TeamProject).FirstOrDefault(c=> c.Id == buildDefinitionSource.Process.Id);
buildDefinitionClone.ProcessParameters = buildDefinitionSource.ProcessParameters;
buildDefinitionClone.TriggerType = buildDefinitionSource.TriggerType;
buildDefinitionClone.ContinuousIntegrationQuietPeriod = buildDefinitionSource.ContinuousIntegrationQuietPeriod;
buildDefinitionClone.DefaultDropLocation = buildDefinitionSource.DefaultDropLocation;
buildDefinitionClone.Description = buildDefinitionSource.Description;
buildDefinitionClone.QueueStatus = Microsoft.TeamFoundation.Build.Client.DefinitionQueueStatus.Enabled;
buildDefinitionClone.BatchSize = buildDefinitionSource.BatchSize;
buildDefinitionClone.Name = newBuildName;
foreach (var schedule in buildDefinitionSource.Schedules)
{
var newSchedule = buildDefinitionClone.AddSchedule();
newSchedule.DaysToBuild = schedule.DaysToBuild;
newSchedule.StartTime = schedule.StartTime;
newSchedule.TimeZone = schedule.TimeZone;
}
foreach (var mapping in buildDefinitionSource.Workspace.Mappings)
{
buildDefinitionClone.Workspace.AddMapping(
mapping.ServerItem, mapping.LocalItem, mapping.MappingType, mapping.Depth);
}
buildDefinitionClone.RetentionPolicyList.Clear();
foreach (var policy in buildDefinitionSource.RetentionPolicyList)
{
buildDefinitionClone.AddRetentionPolicy(
policy.BuildReason, policy.BuildStatus, policy.NumberToKeep, policy.DeleteOptions);
}
//Source Provider
IBuildDefinitionSourceProvider provider = buildDefinitionClone.CreateInitialSourceProvider(sourceProvider);
if (sourceProvider == VersionControlType.TFGIT.ToString())
{
provider.Fields["RepositoryName"] = "Git";
}
buildDefinitionClone.SetSourceProvider(provider);
buildDefinitionClone.Save();
return buildDefinitionClone;
}
private static IBuildController GetBuildController(IBuildServer buildServer, string buildController)
{
if (string.IsNullOrEmpty(buildController))
return buildServer.QueryBuildControllers(false).Where(c=> c.Status == ControllerStatus.Available).First();
return buildServer.GetBuildController(buildController);
}
我正在尝试从 tfs2013 导出和导入构建定义,在此之后
GetDefinitionAsync 和 GetFullDefinitionsAsync 方法很好,但它们不检索 ProcessParameters 属性,因此我无法导出包含此重要信息的完整构建定义。我试图让这个 属性 调用 IBuildServer.QueryBuildDefinitions,但是当我尝试创建新的构建定义时我不能,因为数据类型是 Microsoft.TeamFoundation.Build.Client.IBuildDefinition 并且我无法创建新实例Microsoft.TeamFoundation.Build.Client.BuildDefinition 因为它是密封的 class。如何复制 ProcessParameters 和其他信息以导入完整的构建定义?
谢谢
对于XAML构建,您需要使用IBuildServer.GetBuildDefinition方法先获取构建定义,然后再进行复制。
首先通过调用 TfsTeamProjectCollection
实例上的 GetService
方法获取对构建服务器的引用。一旦你有了构建服务器引用,你就可以加载你正在复制的构建定义。
如果您想复制带有过程参数的构建定义,您还应该先复制模板。示例代码 sinnper
// Copy Process parameters
newBuildDefinition.Process = buildDefinitionToCopy.Process;
var processParams = WorkflowHelpers.DeserializeProcessParameters(buildDefinitionToCopy.ProcessParameters);
var copyProcessParams = WorkflowHelpers.DeserializeProcessParameters(newBuildDefinition.ProcessParameters);
foreach (KeyValuePair<string, object> entry in processParams)
{
copyProcessParams.Add(entry.Key.ToString(), entry.Value);
}
newBuildDefinition.ProcessParameters = WorkflowHelpers.SerializeProcessParameters(copyProcessParams);
更详细的如何通过API实现复制,可以参考这篇博客--Copying a TFS Build Definition
好的,经过深入研究,我终于找到了 export/import
的方法导出到 JSon:
public static void ExportBuildDef(Microsoft.TeamFoundation.Build.Client.IBuildDefinition buildDefinition, string project, string filePath)
{
Console.WriteLine($"Exporting build definition '{buildDefinition.Name}' from '{project}' project.");
var json = JsonConvert.SerializeObject(
buildDefinition,
Newtonsoft.Json.Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
json = removePasswords(json);
File.WriteAllText(filePath, json);
Console.WriteLine($"Build definition '{buildDefinition.Name}' succesfully exported to '{filePath}'.");
}
private static string removePasswords(string json)
{
string res = json;
var searchFor = "\"Password\":";
var startIndex = json.IndexOf(searchFor);
if (startIndex >= 0)
{
var endIndex = json.IndexOf(",", startIndex);
var pwd = json.Substring(startIndex, endIndex - startIndex);
if (pwd.IndexOf(":") > 0)
{
pwd = json.Substring(startIndex, endIndex - startIndex).Split(':')[1].Trim();
res = json.Replace(pwd, "\"{hidden}\"");
}
}
return res;
}
从 JSon
导入注:BuildDefinitionModel class是一组"POCO"classes(不包括长文件),可以转换为来自 here
的导出 JSon 文件的 C# classespublic static void ImportBuildDefinition(IBuildServer buildServer, string projectName, string filePath, string newBuildName, string sourceProvider)
{
if (!File.Exists(filePath))
throw new FileNotFoundException("File does not exist!", filePath);
Console.WriteLine($"Importing build definition from file '{filePath}' to '{projectName}' project.");
var json = File.ReadAllText(filePath);
var buildDef = JsonConvert.DeserializeObject<BuildDefinitionModel>(json);
var newBuildDefinition = CloneBuildDefinition(buildServer, buildDef, newBuildName, projectName, sourceProvider);
Console.WriteLine($"Build definition '{buildDef.Name}' succesfully imported to '{projectName}' project.");
}
static IBuildDefinition CloneBuildDefinition(IBuildServer buildServer, BuildDefinitionModel buildDefinitionSource, string newBuildName, string projectName, string sourceProvider)
{
var buildDefinitionClone = buildServer.CreateBuildDefinition(projectName);
buildDefinitionClone.BuildController = GetBuildController(buildServer, "");
buildDefinitionClone.Process = buildServer.QueryProcessTemplates(buildDefinitionSource.TeamProject).FirstOrDefault(c=> c.Id == buildDefinitionSource.Process.Id);
buildDefinitionClone.ProcessParameters = buildDefinitionSource.ProcessParameters;
buildDefinitionClone.TriggerType = buildDefinitionSource.TriggerType;
buildDefinitionClone.ContinuousIntegrationQuietPeriod = buildDefinitionSource.ContinuousIntegrationQuietPeriod;
buildDefinitionClone.DefaultDropLocation = buildDefinitionSource.DefaultDropLocation;
buildDefinitionClone.Description = buildDefinitionSource.Description;
buildDefinitionClone.QueueStatus = Microsoft.TeamFoundation.Build.Client.DefinitionQueueStatus.Enabled;
buildDefinitionClone.BatchSize = buildDefinitionSource.BatchSize;
buildDefinitionClone.Name = newBuildName;
foreach (var schedule in buildDefinitionSource.Schedules)
{
var newSchedule = buildDefinitionClone.AddSchedule();
newSchedule.DaysToBuild = schedule.DaysToBuild;
newSchedule.StartTime = schedule.StartTime;
newSchedule.TimeZone = schedule.TimeZone;
}
foreach (var mapping in buildDefinitionSource.Workspace.Mappings)
{
buildDefinitionClone.Workspace.AddMapping(
mapping.ServerItem, mapping.LocalItem, mapping.MappingType, mapping.Depth);
}
buildDefinitionClone.RetentionPolicyList.Clear();
foreach (var policy in buildDefinitionSource.RetentionPolicyList)
{
buildDefinitionClone.AddRetentionPolicy(
policy.BuildReason, policy.BuildStatus, policy.NumberToKeep, policy.DeleteOptions);
}
//Source Provider
IBuildDefinitionSourceProvider provider = buildDefinitionClone.CreateInitialSourceProvider(sourceProvider);
if (sourceProvider == VersionControlType.TFGIT.ToString())
{
provider.Fields["RepositoryName"] = "Git";
}
buildDefinitionClone.SetSourceProvider(provider);
buildDefinitionClone.Save();
return buildDefinitionClone;
}
private static IBuildController GetBuildController(IBuildServer buildServer, string buildController)
{
if (string.IsNullOrEmpty(buildController))
return buildServer.QueryBuildControllers(false).Where(c=> c.Status == ControllerStatus.Available).First();
return buildServer.GetBuildController(buildController);
}