diff --git a/README.md b/README.md index 50944530..3f310b17 100644 --- a/README.md +++ b/README.md @@ -108,34 +108,72 @@ Each area has its own list of methods available ### Builds - Builds GetFields(string fields); - List SuccessfulBuildsByBuildConfigId(string buildConfigId, List param = null); - Build LastSuccessfulBuildByBuildConfigId(string buildConfigId, List param = null); - List FailedBuildsByBuildConfigId(string buildConfigId, List param = null); - Build LastFailedBuildByBuildConfigId(string buildConfigId, List param = null); - Build LastBuildByBuildConfigId(string buildConfigId, List param = null); - List ErrorBuildsByBuildConfigId(string buildConfigId, List param = null); - Build LastErrorBuildByBuildConfigId(string buildConfigId, List param = null); - Build LastBuildByAgent(string agentName, List param = null); Build ById(string id); + Build LastBuildByAgent(string agentName, List param = null); + Build LastBuildByBuildConfigId(string buildConfigId, List param = null); + Build LastErrorBuildByBuildConfigId(string buildConfigId, List param = null); + Build LastFailedBuildByBuildConfigId(string buildConfigId, List param = null); + Build LastSuccessfulBuildByBuildConfigId(string buildConfigId, List param = null); + Builds GetFields(string fields); + List AffectedProject(string projectId, long count = 100, List param = null); + List AllBuildsOfStatusSinceDate(DateTime date, BuildStatus buildStatus); + List AllRunningBuild(); + List AllSinceDate(DateTime date, long count = 100, List param = null); + List ByBranch(string branchName); List ByBuildConfigId(string buildConfigId); - List RunningByBuildConfigId(string buildConfigId); - List ByBuildConfigId(string buildConfigId, List param); - List ByBuildLocator(BuildLocator locator, List param); + List ByBuildConfigId(string buildConfigId, List param); + List ByBuildLocator(BuildLocator locator); + List ByBuildLocator(BuildLocator locator, List param); List ByConfigIdAndTag(string buildConfigId, string tag); List ByUserName(string userName); - List ByBuildLocator(BuildLocator locator); - List AllSinceDate(DateTime date, long count = 100, List param = null); - List AllBuildsOfStatusSinceDate(DateTime date, BuildStatus buildStatus); + List ErrorBuildsByBuildConfigId(string buildConfigId, List param = null); + List FailedBuildsByBuildConfigId(string buildConfigId, List param = null); + List NextBuilds(string buildId, long count = 100, List param = null); List NonSuccessfulBuildsForUser(string userName); - List ByBranch(string branchName); - void Add2QueueBuildByBuildConfigId(string buildConfigId); - List AllRunningBuild(); List RetrieveEntireBuildChainFrom(string buildConfigId, bool includeInitial = true, List param = null); List RetrieveEntireBuildChainTo(string buildConfigId, bool includeInitial = true, List param = null); - List NextBuilds(string buildid, long count = 100, List param = null); - List AffectedProject(string projectId, long count = 100, List param = null); + List RunningByBuildConfigId(string buildConfigId); + List SuccessfulBuildsByBuildConfigId(string buildConfigId, List param = null); + void Add2QueueBuildByBuildConfigId(string buildConfigId); void DownloadLogs(string projectId, bool zipped, Action downloadHandler); + void PinBuildByBuildNumber(string buildConfigId, string buildNumber, string comment); + void UnPinBuildByBuildNumber(string buildConfigId, string buildNumber); + + // Async + Task ByIdAsync(string id); + Task LastBuildByAgentAsync(string agentName, List param = null); + Task LastBuildByBuildConfigIdAsync(string buildConfigId, List param = null); + Task LastErrorBuildByBuildConfigIdAsync(string buildConfigId, List param = null); + Task LastFailedBuildByBuildConfigIdAsync(string buildConfigId, List param = null); + Task LastSuccessfulBuildByBuildConfigIdAsync(string buildConfigId, List param = null); + Task> AffectedProjectAsync(string projectId, long count = 100, List param = null); + Task> AllBuildsOfStatusSinceDateAsync(DateTime date, BuildStatus buildStatus); + Task> AllRunningBuildAsync(); + Task> AllSinceDateAsync(DateTime date, long count = 100, List param = null); + Task> ByBranchAsync(string branchName); + Task> ByBuildConfigIdAsync(string buildConfigId); + Task> ByBuildConfigIdAsync(string buildConfigId, List param); + Task> ByBuildLocatorAsync(BuildLocator locator); + Task> ByBuildLocatorAsync(BuildLocator locator, List param); + Task> ByConfigIdAndTagAsync(string buildConfigId, string tag); + Task> ByUserNameAsync(string userName); + Task> ErrorBuildsByBuildConfigIdAsync(string buildConfigId, List param = null); + Task> FailedBuildsByBuildConfigIdAsync(string buildConfigId, List param = null); + Task> NextBuildsAsync(string buildId, long count = 100, List param = null); + Task> NonSuccessfulBuildsForUserAsync(string userName); + Task> RetrieveEntireBuildChainFromAsync(string buildConfigId, bool includeInitial = true, List param = null); + Task> RetrieveEntireBuildChainToAsync(string buildConfigId, bool includeInitial = true, List param = null); + Task> RunningByBuildConfigIdAsync(string buildConfigId); + Task> SuccessfulBuildsByBuildConfigIdAsync(string buildConfigId, List param = null); + Task Add2QueueBuildByBuildConfigIdAsync(string buildConfigId); + Task DownloadLogsAsync(string projectId, bool zipped, Action downloadHandler); + Task PinBuildByBuildNumberAsync(string buildConfigId, string buildNumber, string comment); + Task UnPinBuildByBuildNumberAsync(string buildConfigId, string buildNumber); + Task CancelBuildByIdAsync(string buildId, string comment = "", bool reAddIntoQueue = false); + Task CancelBuildAsync(BuildLocator locator, string comment = "", bool reAddIntoQueue = false); + Task SetBuildCommentAsync(BuildLocator locator, string comment = ""); + Task DeleteBuildCommentAsync(BuildLocator locator); + Task GetCanceledInfoAsync(BuildLocator locator); ### BuildConfigs @@ -149,55 +187,124 @@ Each area has its own list of methods available BuildConfig ByProjectIdAndConfigurationId(string projectId, string buildConfigId); List ByProjectId(string projectId); List ByProjectName(string projectName); - bool ModifTrigger(string format, string oldTriggerConfigurationId, string id); + bool ModifyTrigger(string buildTypeId, string triggerId, string newBt); BuildConfig CreateConfiguration(BuildConfig buildConfig); BuildConfig CreateConfiguration(string projectName, string configurationName); BuildConfig CreateConfigurationByProjectId(string projectId, string configurationName); BuildConfig Copy(string buildConfigId, string buildConfigName, string destinationProjectId, string newBuildTypeId = ""); - - void SetConfigurationSetting(BuildTypeLocator locator, string settingName, string settingValue); bool GetConfigurationPauseStatus(BuildTypeLocator locator); void SetConfigurationPauseStatus(BuildTypeLocator locator, bool isPaused); - void PostRawArtifactDependency(BuildTypeLocator locator, string rawXml); void PostRawBuildStep(BuildTypeLocator locator, string rawXml); void PutRawBuildStep(BuildTypeLocator locator, string rawXml); BuildSteps GetRawBuildStep(BuildTypeLocator locator); void PostRawBuildTrigger(BuildTypeLocator locator, string rawXml); + void SetTrigger(BuildTypeLocator locator, BuildTrigger trigger); void SetConfigurationParameter(BuildTypeLocator locator, string key, string value); void PostRawAgentRequirement(BuildTypeLocator locator, string rawXml); void DeleteBuildStep(BuildTypeLocator locator, string buildStepId); - void DeleteArtifactDependency(BuildTypeLocator locator, string artifactDependencyId); void DeleteAgentRequirement(BuildTypeLocator locator, string agentRequirementId); void DeleteParameter(BuildTypeLocator locator, string parameterName); void DeleteBuildTrigger(BuildTypeLocator locator, string buildTriggerId); + + /// DEPRECATED: After 2017.2 Please use AttachTemplates void SetBuildTypeTemplate(BuildTypeLocator locatorBuildType, BuildTypeLocator locatorTemplate); - void DeleteSnapshotDependency(BuildTypeLocator locator, string snapshotDependencyId); - void PostRawSnapshotDependency(BuildTypeLocator locator, XmlElement rawXml); + BuildConfig BuildType(BuildTypeLocator locator); void SetBuildTypeVariable(BuildTypeLocator locatorBuildType, string nameVariable, string value); void DeleteConfiguration(BuildTypeLocator locator); + + /// 8.0 + void DeleteAllBuildTypeParameters(BuildTypeLocator locator); + + /// 8.0 + void PutAllBuildTypeParameters(BuildTypeLocator locator, IDictionary parameters); void DownloadConfiguration(BuildTypeLocator locator, Action downloadHandler); Template CopyTemplate(string templateId, string templateName, string destinationProjectId, string newTemplateId = ""); - Template GetTemplate(BuildTypeLocator locator); + Template GetTemplate(BuildTypeLocator locator); + + /// Supports version 2017.2 and higher + Templates GetTemplates(BuildTypeLocator locator); + void AttachTemplate(BuildTypeLocator locator, string templateId); + + /// Supports version 2017.2 and higher + void AttachTemplates(BuildTypeLocator locator, Templates templateList); + void DetachTemplate(BuildTypeLocator locator); - ArtifactDependencies GetArtifactDependencies(string buildTypeId); - SnapshotDependencies GetSnapshotDependencies(string buildTypeId); - bool ModifArtifactDependencies(string format, string oldDendencyConfigurationId, string id); - bool ModifSnapshotDependencies(string format, string oldDendencyConfigurationId, string id); - /// 8.0 - void DeleteAllBuildTypeParameters(BuildTypeLocator locator); - void PutAllBuildTypeParameters(BuildTypeLocator locator, IDictionary parameters); + /// Supports version 2017.2 and higher + void DetachTemplates(BuildTypeLocator locator); - // 2017.1 Branches GetBranchesByBuildConfigurationId(string buildTypeId, BranchLocator locator = null); - - /// 2017.2 - Templates GetTemplates(BuildTypeLocator locator); - void AttachTemplates(BuildTypeLocator locator, Templates templateList); - void DetachTemplates(BuildTypeLocator locator); + ArtifactDependencies GetArtifactDependencies(string buildTypeId); + SnapshotDependencies GetSnapshotDependencies(string buildTypeId); + void PostRawSnapshotDependency(BuildTypeLocator locator, XmlElement rawXml); + void PostRawArtifactDependency(BuildTypeLocator locator, string rawXml); + void SetArtifactDependency(BuildTypeLocator locator, ArtifactDependency dependency); + void SetSnapshotDependency(BuildTypeLocator locator, SnapshotDependency dependency); + void DeleteArtifactDependency(BuildTypeLocator locator, string artifactDependencyId); + void DeleteSnapshotDependency(BuildTypeLocator locator, string snapshotDependencyId); + bool ModifyArtifactDependencies(string format, string oldDependencyConfigurationId, string id); + bool ModifySnapshotDependencies(string format, string oldDependencyConfigurationId, string id); + + // Async + Task AddBuildTemplateAsync(BuildTypeLocator locator, Template template, bool optimizeSettings = false); + Task RemoveTemplateAsync(BuildTypeLocator locator, BuildTypeLocator template); + Task GetBuildTemplateAsync(BuildTypeLocator locator, BuildTypeLocator template); + Task> AllAsync(); + Task ByConfigurationNameAsync(string buildConfigName); + Task ByConfigurationIdAsync(string buildConfigId); + Task ByProjectNameAndConfigurationNameAsync(string projectName, string buildConfigName); + Task ByProjectIdAndConfigurationNameAsync(string projectId, string buildConfigName); + Task ByProjectNameAndConfigurationIdAsync(string projectName, string buildConfigId); + Task ByProjectIdAndConfigurationIdAsync(string projectId, string buildConfigId); + Task> ByProjectIdAsync(string projectId); + Task> ByProjectNameAsync(string projectName); + Task CreateConfigurationAsync(BuildConfig buildConfig); + Task CreateConfigurationAsync(string projectName, string configurationName); + + Task CopyAsync(string buildConfigId, string buildConfigName, string destinationProjectId, string newBuildTypeId = ""); + Task SetConfigurationSettingAsync(BuildTypeLocator locator, string settingName, string settingValue); + Task GetConfigurationPauseStatusAsync(BuildTypeLocator locator); + Task SetConfigurationPauseStatusAsync(BuildTypeLocator locator, bool isPaused); + Task PostRawArtifactDependencyAsync(BuildTypeLocator locator, string rawXml); + Task PostRawBuildStepAsync(BuildTypeLocator locator, string rawXml); + Task PutRawBuildStepAsync(BuildTypeLocator locator, string rawXml); + Task GetRawBuildStepAsync(BuildTypeLocator locator); + Task PostRawBuildTriggerAsync(BuildTypeLocator locator, string rawXml); + Task SetArtifactDependencyAsync(BuildTypeLocator locator, ArtifactDependency dependency); + Task SetSnapshotDependencyAsync(BuildTypeLocator locator, SnapshotDependency dependency); + Task SetTriggerAsync(BuildTypeLocator locator, BuildTrigger trigger); + Task SetConfigurationParameterAsync(BuildTypeLocator locator, string key, string value); + Task DeleteConfigurationAsync(BuildTypeLocator locator); + Task DeleteAllBuildTypeParametersAsync(BuildTypeLocator locator); + Task PutAllBuildTypeParametersAsync(BuildTypeLocator locator, IDictionary parameters); + Task DownloadConfigurationAsync(BuildTypeLocator locator, Action downloadHandler); + Task PostRawAgentRequirementAsync(BuildTypeLocator locator, string rawXml); + Task DeleteBuildStepAsync(BuildTypeLocator locator, string buildStepId); + Task DeleteArtifactDependencyAsync(BuildTypeLocator locator, string artifactDependencyId); + Task DeleteAgentRequirementAsync(BuildTypeLocator locator, string agentRequirementId); + Task DeleteParameterAsync(BuildTypeLocator locator, string parameterName); + Task DeleteBuildTriggerAsync(BuildTypeLocator locator, string buildTriggerId); + Task SetBuildTypeTemplateAsync(BuildTypeLocator locatorBuildType, BuildTypeLocator locatorTemplate); + Task DeleteSnapshotDependencyAsync(BuildTypeLocator locator, string snapshotDependencyId); + Task PostRawSnapshotDependencyAsync(BuildTypeLocator locator, XmlElement rawXml); + Task BuildTypeAsync(BuildTypeLocator locator); + Task SetBuildTypeVariableAsync(BuildTypeLocator locatorBuildType, string nameVariable, string value); + Task ModifyTriggerAsync(string buildTypeId, string triggerId, string newBt); + Task ModifySnapshotDependenciesAsync(string buildTypeId, string oldDependencyConfigurationId, string newBt); + Task ModifyArtifactDependenciesAsync(string buildTypeId, string oldDependencyConfigurationId, string newBt); + Task GetBranchesByBuildConfigurationIdAsync(string buildTypeId, BranchLocator locator = null); + Task GetArtifactDependenciesAsync(string buildTypeId); + Task GetSnapshotDependenciesAsync(string buildTypeId); + Task GetTemplatesAsync(BuildTypeLocator locator); + [Obsolete("use AddBuildTemplateAsync instead.")] + Task AttachTemplateAsync(BuildTypeLocator locator, string templateId); + Task AttachTemplatesAsync(BuildTypeLocator locator, Templates templateList); + [Obsolete("use RemoveTemplate instead.")] + Task DetachTemplateAsync(BuildTypeLocator locator); + Task RemoveAllTemplatesAsync(BuildTypeLocator locator); ### BuildInvestigation @@ -205,6 +312,10 @@ Each area has its own list of methods available BuildInvestigations GetFields(string fields); List InvestigationsByBuildTypeId(string buildTypeId); + // Async + Task> AllAsync(); + Task> InvestigationsByBuildTypeIdAsync(string buildTypeId); + ### BuildQueue List All(); @@ -212,6 +323,14 @@ Each area has its own list of methods available List ByBuildTypeLocator(BuildTypeLocator locator); List ByProjectLocater(ProjectLocator projectLocator); + // Async + Task> AllAsync(); + Task> ByBuildTypeLocatorAsync(BuildTypeLocator locator); + Task> ByProjectLocatorAsync(ProjectLocator projectLocator); + + Task CancelQueuedBuildAsync(BuildLocator locator, string comment = "", bool reAddIntoQueue = false); + Task CancelQueuedBuildByIdAsync(string buildId, string comment = "", bool reAddIntoQueue = false); + ### Projects List All(); @@ -222,14 +341,14 @@ Each area has its own list of methods available Project Create(string projectName); Project Create(string projectName, string sourceId, string projectId = ""); Project Move(string projectId, string destinationId); - Project Copy(string projectid, string projectName, string newProjectId, string parentProjectId = ""); + Project Copy(string sourceProjectId, string newProjectName, string newProjectId, string parentProjectId = ""); string GenerateID(string projectName); void Delete(string projectName); void DeleteById(string projectId); void DeleteProjectParameter(string projectName, string parameterName); void SetProjectParameter(string projectName, string settingName, string settingValue); - bool ModifParameters(string projectId, string mainprojectbranch, string variablePath); - bool ModifSettings(string projectId, string description, string fullProjectName); + bool ModifyParameters(string projectId, string mainProjectBranch, string variablePath); + bool ModifySettings(string projectId, string description, string fullProjectName); ProjectFeatures GetProjectFeatures(string projectLocatorId); ProjectFeature GetProjectFeatureByProjectFeature(string projectLocatorId, string projectFeatureId); ProjectFeature CreateProjectFeature(string projectId, ProjectFeature projectFeature); @@ -238,6 +357,28 @@ Each area has its own list of methods available // 2017.1 Branches GetBranchesByBuildProjectId(string projectId, BranchLocator locator = null); + // Asyc + Task GetProjectTemplatesAsync(ProjectLocator locator); + Task> AllAsync(); + Task ByNameAsync(string projectLocatorName); + Task ByIdAsync(string projectLocatorId); + Task DetailsAsync(Project project); + Task CreateAsync(string projectName); + Task CreateAsync(string projectName, string sourceId, string projectId = ""); + Task MoveAsync(string projectId, string destinationId); + Task CopyAsync(string sourceProjectId, string newProjectName, string newProjectId, string parentProjectId = ""); + Task DeleteAsync(string projectName); + Task DeleteByIdAsync(string projectId); + Task DeleteProjectParameterAsync(string projectName, string parameterName); + Task SetProjectParameterAsync(string projectName, string settingName, string settingValue); + Task ModifyParametersAsync(string projectId, string mainProjectBranch, string variablePath); + Task ModifySettingsAsync(string projectId, string description, string fullProjectName); + Task GetBranchesByBuildProjectIdAsync(string projectId, BranchLocator locator = null); + Task GetProjectFeaturesAsync(string projectLocatorId); + Task GetProjectFeatureByProjectFeatureAsync(string projectLocatorId, string projectFeatureId); + Task CreateProjectFeatureAsync(string projectId, ProjectFeature projectFeature); + Task DeleteProjectFeatureAsync(string projectId, string projectFeatureId); + ### ServerInformation Server ServerInfo(); @@ -245,6 +386,12 @@ Each area has its own list of methods available string TriggerServerInstanceBackup(BackupOptions backupOptions); string GetBackupStatus(); + // Async + Task ServerInfoAsync(); + Task> AllPluginsAsync(); + Task TriggerServerInstanceBackupAsync(BackupOptions backupOptions); + Task GetBackupStatusAsync(); + ### Users List All(); @@ -259,11 +406,26 @@ Each area has its own list of methods available bool AddPassword(string username, string password); bool IsAdministrator(string username); + // Async + Task> AllAsync(); + Task DetailsAsync(string userName); + Task> AllRolesByUserNameAsync(string userName); + Task> AllGroupsByUserNameAsync(string userName); + Task> AllUserGroupsAsync(); + Task> AllUsersByUserGroupAsync(string userGroupName); + Task> AllUserRolesByUserGroupAsync(string userGroupName); + Task CreateAsync(string username, string name, string email, string password); + Task AddPasswordAsync(string username, string password); + Task IsAdministratorAsync(string username); + ### Agents List All(bool includeDisconnected = false, bool includeUnauthorized = false); Agents GetFields(string fields); + // Async + Task> AllAsync(bool includeDisconnected = false, bool includeUnauthorized = false); + ### VcsRoots VcsRoots GetFields(string fields); @@ -271,12 +433,23 @@ Each area has its own list of methods available VcsRoot ById(string vcsRootId); VcsRoot AttachVcsRoot(BuildTypeLocator locator, VcsRoot vcsRoot); void DetachVcsRoot(BuildTypeLocator locator, string vcsRootId); - void SetVcsRootField(VcsRoot vcsRoot, VcsRootField field, object value); + void SetVcsRootValue(VcsRoot vcsRoot, VcsRootValue field, object value); VcsRoot CreateVcsRoot(VcsRoot configurationName, string projectId); void SetConfigurationProperties(VcsRoot vcsRootId, string key, string value); void DeleteProperties(VcsRoot vcsRootId, string parameterName); void DeleteVcsRoot(VcsRoot vcsRoot); + // Async + Task> AllAsync(); + Task ByIdAsync(string vcsRootId); + Task AttachVcsRootAsync(BuildTypeLocator locator, VcsRoot vcsRoot); + Task DetachVcsRootAsync(BuildTypeLocator locator, string vcsRootId); + Task SetVcsRootValueAsync(VcsRoot vcsRoot, VcsRootValue field, object value); + Task CreateVcsRootAsync(VcsRoot configurationName, string projectId); + Task SetConfigurationPropertiesAsync(VcsRoot vcsRootId, string key, string value); + Task DeletePropertiesAsync(VcsRoot vcsRootId, string parameterName); + Task DeleteVcsRootAsync(VcsRoot vcsRoot); + ### Changes List All(); @@ -284,16 +457,33 @@ Each area has its own list of methods available Change LastChangeDetailByBuildConfigId(string buildConfigId); List ByBuildConfigId(string buildConfigId); + // Async + Task> AllAsync(); + Task ByChangeIdAsync(string id); + Task LastChangeDetailByBuildConfigIdAsync(string buildConfigId); + Task> ByBuildConfigIdAsync(string buildConfigId); + ### BuildArtifacts void DownloadArtifactsByBuildId(string buildId, Action downloadHandler); - ArtifactWrapper ByBuildConfigId(string buildConfigId, string param=""); + ArtifactWrapper ByBuildConfigId(string buildConfigId, string param = ""); + + // Async + Task DownloadArtifactsByBuildIdAsync(string buildId, Action downloadHandler); + Task GetArtifactsAsync(string buildId, string subPath = ""); + Task GetArtifactsByLocatorAsync(BuildLocator locator, string subPath = ""); + Task GetArtifactsAsync(ArtifactItem item); + Task DownloadArtifactAsync(string href); + Task DownloadArtifactAsync(ArtifactItem item); ### Statistics Statistics GetFields(string fields); Properties GetByBuildId(string buildId); + // Async + Task GetByBuildIdAsync(string buildId); + ## Credits Copyright (c) 2013 Paul Stack (@stack72) @@ -310,3 +500,4 @@ Thanks to the following contributors: * Marc-Andre Vezeau (@exfo) * Bassem Mawassi (@exfo) * Tusman Akhter (@exfo) +* Ulysses Wu diff --git a/src/TeamCitySharp/ActionTypes/ActionHelper.cs b/src/TeamCitySharp/ActionTypes/ActionHelper.cs index 12ed6e04..cff9b5d3 100644 --- a/src/TeamCitySharp/ActionTypes/ActionHelper.cs +++ b/src/TeamCitySharp/ActionTypes/ActionHelper.cs @@ -1,6 +1,8 @@ -namespace TeamCitySharp.ActionTypes +using System.Text.RegularExpressions; + +namespace TeamCitySharp.ActionTypes { - public class ActionHelper + public static class ActionHelper { /// /// Create a url with fields @@ -20,5 +22,12 @@ public static string CreateFieldUrl(string url, string fields) } return url; } + public static string RemoveRestApiFromURL(string url) + { + var pattern = @"^(/httpAuth/app/rest|/app/rest)"; + var substitution = @""; + var regex = new Regex(pattern); + return regex.Replace(url, substitution); + } } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/Agents.cs b/src/TeamCitySharp/ActionTypes/Agents.cs index 1eb1025a..85a7220a 100644 --- a/src/TeamCitySharp/ActionTypes/Agents.cs +++ b/src/TeamCitySharp/ActionTypes/Agents.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using TeamCitySharp.Connection; using TeamCitySharp.DomainEntities; +using System.Threading.Tasks; namespace TeamCitySharp.ActionTypes { @@ -18,7 +19,7 @@ internal Agents(ITeamCityCaller caller) public Agents GetFields(string fields) { - var newInstance = (Agents) MemberwiseClone(); + var newInstance = (Agents)MemberwiseClone(); newInstance.m_fields = fields; return newInstance; } @@ -34,5 +35,17 @@ public List All(bool includeDisconnected = true, bool includeUnauthorized return agentWrapper.Agent; } + + public async Task> AllAsync(bool includeDisconnected = true, bool includeUnauthorized = true) + { + var url = + string.Format( + ActionHelper.CreateFieldUrl("/agents?includeDisconnected={0}&includeUnauthorized={1}", m_fields), + includeDisconnected.ToString().ToLower(), includeUnauthorized.ToString().ToLower()); + + var agentWrapper = await m_caller.GetAsync(url); + + return agentWrapper.Agent; + } } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/BackupOptions.cs b/src/TeamCitySharp/ActionTypes/BackupOptions.cs index 407719dd..990cf8e3 100644 --- a/src/TeamCitySharp/ActionTypes/BackupOptions.cs +++ b/src/TeamCitySharp/ActionTypes/BackupOptions.cs @@ -2,7 +2,7 @@ { public class BackupOptions { - public string Filename { get; set; } + public string FileName { get; set; } public bool IncludeDatabase { get; set; } diff --git a/src/TeamCitySharp/ActionTypes/BuildArtifacts.cs b/src/TeamCitySharp/ActionTypes/BuildArtifacts.cs index 1c870025..d42daf52 100644 --- a/src/TeamCitySharp/ActionTypes/BuildArtifacts.cs +++ b/src/TeamCitySharp/ActionTypes/BuildArtifacts.cs @@ -5,26 +5,69 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; -using System.Xml; using TeamCitySharp.Connection; +using System.Threading.Tasks; +using TeamCitySharp.DomainEntities; +using TeamCitySharp.Locators; +using File = System.IO.File; namespace TeamCitySharp.ActionTypes { internal class BuildArtifacts : IBuildArtifacts { private readonly ITeamCityCaller m_caller; + private string m_fields; public BuildArtifacts(ITeamCityCaller caller) { m_caller = caller; } + public BuildArtifacts GetFields(string fields) + { + var newInstance = (BuildArtifacts)MemberwiseClone(); + newInstance.m_fields = fields; + return newInstance; + } public void DownloadArtifactsByBuildId(string buildId, Action downloadHandler) { m_caller.GetDownloadFormat(downloadHandler, "/downloadArtifacts.html?buildId={0}", false, buildId); } - public ArtifactWrapper ByBuildConfigId(string buildConfigId, string param="") + public async Task DownloadArtifactsByBuildIdAsync(string buildId, Action downloadHandler) + { + await m_caller.GetDownloadFormatAsync(downloadHandler, "/downloadArtifacts.html?buildId={0}", false, buildId); + } + + public async Task GetArtifactsAsync(string buildId, string subPath = "") + { + var artifacts = await m_caller.GetAsync($"/builds/{buildId}/artifacts/children/{subPath}"); + return artifacts; + } + + public async Task GetArtifactsByLocatorAsync(BuildLocator locator, string subPath = "") + { + var artifacts = await m_caller.GetAsync($"/builds/{locator}/artifacts/children/{subPath}"); + return artifacts; + } + + public async Task GetArtifactsAsync(ArtifactItem item) + { + var artifacts = await m_caller.GetAsync(item.Href, false); + return artifacts; + } + + public async Task DownloadArtifactAsync(string href) + { + return await m_caller.GetByteArrayAsync(href); + } + + public async Task DownloadArtifactAsync(ArtifactItem item) + { + return await m_caller.GetByteArrayAsync(item.Content.Href); + } + + public ArtifactWrapper ByBuildConfigId(string buildConfigId, string param = "") { return new ArtifactWrapper(m_caller, buildConfigId, param); } @@ -35,57 +78,129 @@ public class ArtifactWrapper private readonly ITeamCityCaller m_caller; private readonly string m_buildConfigId; private readonly string m_param; + private const string m_url_download = "/builds/{0}{1}/artifacts"; - internal ArtifactWrapper(ITeamCityCaller caller, string buildConfigId,string param) + internal ArtifactWrapper(ITeamCityCaller caller, string buildConfigId, string param) { m_caller = caller; m_buildConfigId = buildConfigId; m_param = param; } - public ArtifactCollection LastFinished() + private string CreateParam(string[] param=null) + { + var result = ""; + if (param == null) + { + if (!string.IsNullOrEmpty(m_param)) + result = "," + m_param; + return result; + } + else + { + result = string.Join(",", param); + if (!String.IsNullOrEmpty(result)) + result = "," + result; + } + return result; + } + public ArtifactCollection LastFinished(string[] param=null) + { + var list = GetFileNameChildren(string.Format(m_url_download, BuildLocator.WithDimensions(BuildTypeLocator.WithId(m_buildConfigId), maxResults: 1).ToString(), CreateParam(param)), new List()); + + return new ArtifactCollection(m_caller, list); + } + + public async Task LastFinishedAsync(string[] param=null) { - return Specification(".lastFinished"); + var list = await GetFileNameChildrenAsync(string.Format(m_url_download, BuildLocator.WithDimensions(BuildTypeLocator.WithId(m_buildConfigId), maxResults: 1).ToString(), CreateParam(param)), new List()); + + return new ArtifactCollection(m_caller, list); } - public ArtifactCollection LastPinned() + public ArtifactCollection LastPinned(string[] param=null) { - return Specification(".lastPinned"); + var list = GetFileNameChildren(string.Format(m_url_download, BuildLocator.WithDimensions(BuildTypeLocator.WithId(m_buildConfigId), pinned: true, maxResults: 1).ToString(), CreateParam(param)), new List()); + + return new ArtifactCollection(m_caller, list); } - public ArtifactCollection LastSuccessful() + public async Task LastPinnedAsync(string[] param=null) { - return Specification(".lastSuccessful"); + var list = await GetFileNameChildrenAsync(string.Format(m_url_download, BuildLocator.WithDimensions(BuildTypeLocator.WithId(m_buildConfigId), pinned: true, maxResults: 1).ToString(), CreateParam(param)), new List()); + + return new ArtifactCollection(m_caller, list); } - public ArtifactCollection Tag(string tag) + public ArtifactCollection LastSuccessful(string[] param = null) { - return Specification(tag + ".tcbuildid"); + var list = GetFileNameChildren(string.Format(m_url_download, BuildLocator.WithDimensions(BuildTypeLocator.WithId(m_buildConfigId), status: BuildStatus.SUCCESS, maxResults: 1).ToString(), CreateParam(param)), new List()); + + return new ArtifactCollection(m_caller, list); } - public ArtifactCollection Specification(string buildSpecification) + public async Task LastSuccessfulAsync(string[] param=null) { - var url = $"/repository/download/{m_buildConfigId}/{buildSpecification}/teamcity-ivy.xml"; - var xml = m_caller.GetRaw(string.IsNullOrEmpty(m_param) ? url : $"{url}?{m_param}", false); - - var document = new XmlDocument(); - document.LoadXml(xml); - var artifactNodes = document.SelectNodes("//artifact"); - if (artifactNodes == null) - return null; - var list = new List(); - foreach (XmlNode node in artifactNodes) + var list = await GetFileNameChildrenAsync(string.Format(m_url_download, BuildLocator.WithDimensions(BuildTypeLocator.WithId(m_buildConfigId), status: BuildStatus.SUCCESS, maxResults: 1).ToString(), CreateParam(param)), new List()); + + return new ArtifactCollection(m_caller, list); + } + + public ArtifactCollection LastTag(string[] tags, string[] param=null) + { + var list = GetFileNameChildren(string.Format(m_url_download, BuildLocator.WithDimensions(BuildTypeLocator.WithId(m_buildConfigId), tags: tags, maxResults: 1).ToString(), CreateParam(param)), new List()); + + return new ArtifactCollection(m_caller, list); + } + + public async Task LastTagAsync(string[] tags, string[] param=null) + { + var list = await GetFileNameChildrenAsync(string.Format(m_url_download, BuildLocator.WithDimensions(BuildTypeLocator.WithId(m_buildConfigId), tags: tags, maxResults: 1).ToString(), CreateParam(param)), new List()); + + return new ArtifactCollection(m_caller, list); + } + + protected List GetFileNameChildren(string url, List list) + { + var artifacts = m_caller.GetFormat(ActionHelper.CreateFieldUrl(url,"")); + foreach (DomainEntities.File artifact in artifacts.File) { - var nameNode = node.SelectSingleNode("@name"); - var extensionNode = node.SelectSingleNode("@ext"); - var artifact = string.Empty; - if (nameNode != null) - artifact = nameNode.Value; - if (extensionNode != null) - artifact += "." + extensionNode.Value; - list.Add($"/repository/download/{m_buildConfigId}/{buildSpecification}/{artifact}"); + if (artifact.Children is not null && artifact.Children.Href != string.Empty) + { + list = GetFileNameChildren(ActionHelper.RemoveRestApiFromURL(artifact.Children.Href), list); + } + if (artifact.Content is not null && artifact.Content.Href != string.Empty) + list.Add($"{ActionHelper.RemoveRestApiFromURL(artifact.Content.Href)}"); + } + return list; + } + protected async Task> GetFileNameChildrenAsync(string url, List list) + { + var artifacts = m_caller.GetFormat(ActionHelper.CreateFieldUrl(url,"")); + foreach (DomainEntities.File artifact in artifacts.File) + { + if (artifact.Children is not null && artifact.Children.Href != string.Empty) + { + list = await GetFileNameChildrenAsync(ActionHelper.RemoveRestApiFromURL(artifact.Children.Href), list); + } + if (artifact.Content is not null && artifact.Content.Href != string.Empty) + list.Add($"{ActionHelper.RemoveRestApiFromURL(artifact.Content.Href)}"); } - return new ArtifactCollection(m_caller, list,m_param); + return list; + } + + public ArtifactCollection Specification(Build buildSpecification) + { + var list = GetFileNameChildren($"/builds/{buildSpecification.Id}/artifacts", new List()); + + return new ArtifactCollection(m_caller, list, m_param); + } + + public async Task SpecificationAsync(Build buildSpecification) + { + var list = await GetFileNameChildrenAsync($"/builds/{buildSpecification.Id}/artifacts", new List()); + + return new ArtifactCollection(m_caller, list, m_param); } } @@ -95,7 +210,7 @@ public class ArtifactCollection private readonly List m_urls; private readonly string m_param; - internal ArtifactCollection(ITeamCityCaller caller, List urls, string param="") + internal ArtifactCollection(ITeamCityCaller caller, List urls, string param = "") { m_caller = caller; m_urls = urls; @@ -124,19 +239,20 @@ public List GetArtifactUrl() /// public List Download(string directory = null, bool flatten = false, bool overwrite = true) { + var rx = new Regex("^\\/builds\\/.+\\/artifacts\\/content\\/"); if (directory == null) directory = Directory.GetCurrentDirectory(); var downloaded = new List(); foreach (var url in m_urls) { // user probably didnt use to artifact url generating functions - Debug.Assert(url.StartsWith("/repository/download/")); + Debug.Assert(rx.Match(url).Success); // figure out local filename var parts = url.Split('/').Skip(5).ToArray(); var destination = flatten - ? parts.Last() - : string.Join(Path.DirectorySeparatorChar.ToString(), parts); + ? parts.Last() + : string.Join(Path.DirectorySeparatorChar.ToString(), parts); destination = Path.Combine(directory, destination); // create directories that doesnt exist @@ -154,11 +270,45 @@ public List Download(string directory = null, bool flatten = false, bool else continue; } var currentUrl = url; - if (!string.IsNullOrEmpty(m_param)) + m_caller.GetDownloadFormat(tempFile => File.Move(tempFile, destination), currentUrl, true); + } + return downloaded; + } + + public async Task> DownloadAsync(string directory = null, bool flatten = false, bool overwrite = true) + { + var rx = new Regex("^\\/builds\\/.+\\/artifacts\\/content\\/"); + if (directory == null) + directory = Directory.GetCurrentDirectory(); + var downloaded = new List(); + foreach (var url in m_urls) + { + // user probably didnt use to artifact url generating functions + Debug.Assert(rx.Match(url).Success); + + // figure out local filename + var parts = url.Split('/').Skip(5).ToArray(); + var destination = flatten + ? parts.Last() + : string.Join(Path.DirectorySeparatorChar.ToString(), parts); + destination = Path.Combine(directory, destination); + + // create directories that doesnt exist + var directoryName = Path.GetDirectoryName(destination); + if (directoryName != null && !Directory.Exists(directoryName)) + Directory.CreateDirectory(directoryName); + + // add artifact to list regardless if it was downloaded or skipped + downloaded.Add(Path.GetFullPath(destination)); + + // if the file already exists delete it or move to next artifact + if (File.Exists(destination)) { - currentUrl = $"{currentUrl}?{m_param}"; + if (overwrite) File.Delete(destination); + else continue; } - m_caller.GetDownloadFormat(tempfile => File.Move(tempfile, destination), currentUrl, false); + var currentUrl = url; + await m_caller.GetDownloadFormatAsync(tempFile => File.Move(tempFile, destination), currentUrl, true); } return downloaded; } @@ -180,8 +330,9 @@ public List Download(string directory = null, bool flatten = false, bool /// A list of full paths to all downloaded artifacts. /// public List DownloadFiltered(string directory = null, List filteredFiles = null, - bool flatten = false, bool overwrite = true) + bool flatten = false, bool overwrite = true) { + var rx = new Regex("^\\/builds\\/.+\\/artifacts\\/content\\/"); if (directory == null) directory = Directory.GetCurrentDirectory(); var downloaded = new List(); @@ -191,22 +342,31 @@ public List DownloadFiltered(string directory = null, List filte { foreach (var filteredFile in filteredFiles) { - var currentFilename = new Wildcard(GetFilename(filteredFile), RegexOptions.IgnoreCase); - var currentExt = new Wildcard(GetExtension(filteredFile), RegexOptions.IgnoreCase); + var filenameWithoutFolder = filteredFile.Split('/').Last(); + var currentFolder = new Wildcard(""); + if (filteredFile.Contains('/')) + { + currentFolder = new Wildcard( "\\" + filteredFile.Replace($"/{filenameWithoutFolder}", ""), RegexOptions.IgnoreCase); + } + var currentFilename = new Wildcard(GetFilename(filenameWithoutFolder), RegexOptions.IgnoreCase); + var currentExt = new Wildcard(GetExtension(filenameWithoutFolder), RegexOptions.IgnoreCase); // user probably didnt use to artifact url generating functions - Debug.Assert(url.StartsWith("/repository/download/")); + Debug.Assert(rx.Match(url).Success); + + string[] segments = url.Split('/'); + int contentIndex = Array.IndexOf(segments, "content") + 1; // figure out local filename - var parts = url.Split('/').Skip(5).ToArray(); + var parts = segments.Skip(contentIndex).ToArray(); var destination = flatten - ? parts.Last() - : string.Join(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture), parts); + ? parts.Last() + : string.Join(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture), parts); destination = Path.Combine(directory, destination); - + var folderWihoutFirstPart = Path.GetDirectoryName(destination).Replace(directory, ""); if (currentFilename.IsMatch(Path.GetFileNameWithoutExtension(destination)) && - currentExt.IsMatch(Path.GetExtension(destination))) + currentExt.IsMatch(Path.GetExtension(destination)) && currentFolder.IsMatch(folderWihoutFirstPart)) { // create directories that doesnt exist var directoryName = Path.GetDirectoryName(destination); @@ -223,17 +383,78 @@ public List DownloadFiltered(string directory = null, List filte } var currentUrl = url; - if (!string.IsNullOrEmpty(m_param)) + m_caller.GetDownloadFormat(tempFile => File.Move(tempFile, destination), currentUrl, true); + break; + } + } + } + } + return downloaded; + } + + public async Task> DownloadFilteredAsync(string directory = null, List filteredFiles = null, + bool flatten = false, bool overwrite = true) + { + var rx = new Regex("^\\/builds\\/.+\\/artifacts\\/content\\/"); + if (directory == null) + directory = Directory.GetCurrentDirectory(); + var downloaded = new List(); + foreach (var url in m_urls) + { + if (filteredFiles != null) + { + foreach (var filteredFile in filteredFiles) + { + var filenameWithoutFolder = filteredFile.Split('/').Last(); + var currentFolder = new Wildcard(directory); + if (filteredFile.Contains('/')) + { + currentFolder = new Wildcard( "\\" + filteredFile.Replace($"/{filenameWithoutFolder}", ""), RegexOptions.IgnoreCase); + } + var currentFilename = new Wildcard(GetFilename(filteredFile), RegexOptions.IgnoreCase); + var currentExt = new Wildcard(GetExtension(filteredFile), RegexOptions.IgnoreCase); + + // user probably didnt use to artifact url generating functions + Debug.Assert(rx.Match(url).Success); + + string[] segments = url.Split('/'); + int contentIndex = Array.IndexOf(segments, "content") + 1; + + // figure out local filename + var parts = segments.Skip(contentIndex).ToArray(); + var destination = flatten + ? parts.Last() + : string.Join(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture), parts); + destination = Path.Combine(directory, destination); + + var folderWihoutFirstPart = Path.GetDirectoryName(destination).Replace(Path.GetDirectoryName(directory), ""); + if (currentFilename.IsMatch(Path.GetFileNameWithoutExtension(destination)) && + currentExt.IsMatch(Path.GetExtension(destination)) && currentFolder.IsMatch(folderWihoutFirstPart)) + { + // create directories that doesnt exist + var directoryName = Path.GetDirectoryName(destination); + if (directoryName != null && !Directory.Exists(directoryName)) + Directory.CreateDirectory(directoryName); + + downloaded.Add(Path.GetFullPath(destination)); + + // if the file already exists delete it or move to next artifact + if (File.Exists(destination)) { - currentUrl = $"{currentUrl}?{m_param}"; + if (overwrite) File.Delete(destination); + else continue; } - m_caller.GetDownloadFormat(tempfile => File.Move(tempfile, destination), currentUrl, false); + var currentUrl = url; + + await m_caller.GetDownloadFormatAsync(tempFile => File.Move(tempFile, destination), currentUrl, + false); break; } } } } + return downloaded; } @@ -255,7 +476,7 @@ internal class Wildcard : Regex /// /// The wildcard pattern to match. public Wildcard(string pattern) - : base(WildcardToRegex(pattern)) + : base(WildcardToRegex(pattern)) { } @@ -266,7 +487,7 @@ public Wildcard(string pattern) /// A combination of one or more /// . public Wildcard(string pattern, RegexOptions options) - : base(WildcardToRegex(pattern), options) + : base(WildcardToRegex(pattern), options) { } @@ -277,9 +498,7 @@ public Wildcard(string pattern, RegexOptions options) /// A regex equivalent of the given wildcard. public static string WildcardToRegex(string pattern) { - return "^" + Escape(pattern). - Replace("\\*", ".*"). - Replace("\\?", ".") + "$"; + return "^" + Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + "$"; } } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/BuildConfigs.cs b/src/TeamCitySharp/ActionTypes/BuildConfigs.cs index 1fe0a5b0..44f7e82a 100644 --- a/src/TeamCitySharp/ActionTypes/BuildConfigs.cs +++ b/src/TeamCitySharp/ActionTypes/BuildConfigs.cs @@ -9,7 +9,7 @@ using TeamCitySharp.Connection; using TeamCitySharp.DomainEntities; using TeamCitySharp.Locators; -using static System.Boolean; +using System.Threading.Tasks; namespace TeamCitySharp.ActionTypes { @@ -25,7 +25,7 @@ internal BuildConfigs(ITeamCityCaller caller) public BuildConfigs GetFields(string fields) { - var newInstance = (BuildConfigs) MemberwiseClone(); + var newInstance = (BuildConfigs)MemberwiseClone(); newInstance.m_fields = fields; return newInstance; } @@ -33,7 +33,30 @@ public BuildConfigs GetFields(string fields) public List All() { var buildType = - m_caller.Get(ActionHelper.CreateFieldUrl("/buildTypes", m_fields)); + m_caller.Get(ActionHelper.CreateFieldUrl("/buildTypes", m_fields)); + + return buildType.BuildType; + } + + public async Task AddBuildTemplateAsync(BuildTypeLocator locator, Template template, bool optimizeSettings = false) + { + return await m_caller.PostAsync(template, HttpContentTypes.ApplicationJson, $"/buildTypes/{locator}/templates", HttpContentTypes.ApplicationJson); + } + + public async Task RemoveTemplateAsync(BuildTypeLocator locator, BuildTypeLocator template) + { + await m_caller.DeleteAsync($"/buildTypes/{locator}/templates/{template}"); + } + + public async Task GetBuildTemplateAsync(BuildTypeLocator locator, BuildTypeLocator template) + { + return await m_caller.GetAsync($"/buildTypes/{locator}/templates/{template}"); + } + + public async Task> AllAsync() + { + var buildType = + await m_caller.GetAsync(ActionHelper.CreateFieldUrl("/buildTypes", m_fields)); return buildType.BuildType; } @@ -41,7 +64,15 @@ public List All() public BuildConfig ByConfigurationName(string buildConfigName) { var build = m_caller.GetFormat(ActionHelper.CreateFieldUrl("/buildTypes/name:{0}", m_fields), - buildConfigName); + buildConfigName); + + return build; + } + + public async Task ByConfigurationNameAsync(string buildConfigName) + { + var build = await m_caller.GetFormatAsync(ActionHelper.CreateFieldUrl("/buildTypes/name:{0}", m_fields), + buildConfigName); return build; } @@ -49,7 +80,15 @@ public BuildConfig ByConfigurationName(string buildConfigName) public BuildConfig ByConfigurationId(string buildConfigId) { var build = m_caller.GetFormat(ActionHelper.CreateFieldUrl("/buildTypes/id:{0}", m_fields), - buildConfigId); + buildConfigId); + + return build; + } + + public async Task ByConfigurationIdAsync(string buildConfigId) + { + var build = await m_caller.GetFormatAsync(ActionHelper.CreateFieldUrl("/buildTypes/id:{0}", m_fields), + buildConfigId); return build; } @@ -57,44 +96,89 @@ public BuildConfig ByConfigurationId(string buildConfigId) public BuildConfig ByProjectNameAndConfigurationName(string projectName, string buildConfigName) { var build = - m_caller.Get( - ActionHelper.CreateFieldUrl( - $"/projects/name:{projectName}/buildTypes/name:{buildConfigName}", m_fields)); + m_caller.Get( + ActionHelper.CreateFieldUrl( + $"/projects/name:{projectName}/buildTypes/name:{buildConfigName}", m_fields)); + return build; + } + + public async Task ByProjectNameAndConfigurationNameAsync(string projectName, string buildConfigName) + { + var build = + await m_caller.GetAsync( + ActionHelper.CreateFieldUrl( + $"/projects/name:{projectName}/buildTypes/name:{buildConfigName}", m_fields)); return build; } public BuildConfig ByProjectNameAndConfigurationId(string projectName, string buildConfigId) { var build = - m_caller.Get( - ActionHelper.CreateFieldUrl( - $"/projects/name:{projectName}/buildTypes/id:{buildConfigId}", m_fields)); + m_caller.Get( + ActionHelper.CreateFieldUrl( + $"/projects/name:{projectName}/buildTypes/id:{buildConfigId}", m_fields)); + return build; + } + + public async Task ByProjectNameAndConfigurationIdAsync(string projectName, string buildConfigId) + { + var build = + await m_caller.GetAsync( + ActionHelper.CreateFieldUrl( + $"/projects/name:{projectName}/buildTypes/id:{buildConfigId}", m_fields)); return build; } public BuildConfig ByProjectIdAndConfigurationName(string projectId, string buildConfigName) { var build = - m_caller.Get( - ActionHelper.CreateFieldUrl( - $"/projects/id:{projectId}/buildTypes/name:{Uri.EscapeDataString(buildConfigName)}", m_fields)); + m_caller.Get( + ActionHelper.CreateFieldUrl( + $"/projects/id:{projectId}/buildTypes/name:{Uri.EscapeDataString(buildConfigName)}", m_fields)); + return build; + } + + public async Task ByProjectIdAndConfigurationNameAsync(string projectId, string buildConfigName) + { + var build = + await m_caller.GetAsync( + ActionHelper.CreateFieldUrl( + $"/projects/id:{projectId}/buildTypes/name:{Uri.EscapeDataString(buildConfigName)}", m_fields)); return build; } public BuildConfig ByProjectIdAndConfigurationId(string projectId, string buildConfigId) { var build = - m_caller.Get( - ActionHelper.CreateFieldUrl( - $"/projects/id:{projectId}/buildTypes/id:{buildConfigId}", m_fields)); + m_caller.Get( + ActionHelper.CreateFieldUrl( + $"/projects/id:{projectId}/buildTypes/id:{buildConfigId}", m_fields)); + return build; + } + + public async Task ByProjectIdAndConfigurationIdAsync(string projectId, string buildConfigId) + { + var build = + await m_caller.GetAsync( + ActionHelper.CreateFieldUrl( + $"/projects/id:{projectId}/buildTypes/id:{buildConfigId}", m_fields)); return build; } public List ByProjectId(string projectId) { var buildWrapper = - m_caller.GetFormat( - ActionHelper.CreateFieldUrl("/projects/id:{0}/buildTypes", m_fields), projectId); + m_caller.GetFormat( + ActionHelper.CreateFieldUrl("/projects/id:{0}/buildTypes", m_fields), projectId); + + return buildWrapper?.BuildType ?? new List(); + } + + public async Task> ByProjectIdAsync(string projectId) + { + var buildWrapper = + await m_caller.GetFormatAsync( + ActionHelper.CreateFieldUrl("/projects/id:{0}/buildTypes", m_fields), projectId); return buildWrapper?.BuildType ?? new List(); } @@ -102,8 +186,17 @@ public List ByProjectId(string projectId) public List ByProjectName(string projectName) { var buildWrapper = - m_caller.GetFormat( - ActionHelper.CreateFieldUrl("/projects/name:{0}/buildTypes", m_fields), projectName); + m_caller.GetFormat( + ActionHelper.CreateFieldUrl("/projects/name:{0}/buildTypes", m_fields), projectName); + + return buildWrapper?.BuildType ?? new List(); + } + + public async Task> ByProjectNameAsync(string projectName) + { + var buildWrapper = + await m_caller.GetFormatAsync( + ActionHelper.CreateFieldUrl("/projects/name:{0}/buildTypes", m_fields), projectName); return buildWrapper?.BuildType ?? new List(); } @@ -111,47 +204,82 @@ public List ByProjectName(string projectName) public BuildConfig CreateConfiguration(BuildConfig buildConfig) { return m_caller.PostFormat(buildConfig, HttpContentTypes.ApplicationJson, - HttpContentTypes.ApplicationJson, "/buildTypes"); + HttpContentTypes.ApplicationJson, "/buildTypes"); + } + + public async Task CreateConfigurationAsync(BuildConfig buildConfig) + { + return await m_caller.PostFormatAsync(buildConfig, HttpContentTypes.ApplicationJson, + HttpContentTypes.ApplicationJson, "/buildTypes"); } public BuildConfig CreateConfiguration(string projectName, string configurationName) { return m_caller.PostFormat(configurationName, HttpContentTypes.TextPlain, - HttpContentTypes.ApplicationJson, "/projects/name:{0}/buildTypes", - projectName); + HttpContentTypes.ApplicationJson, "/projects/name:{0}/buildTypes", + projectName); } public BuildConfig CreateConfigurationByProjectId(string projectId, string configurationName) { return m_caller.PostFormat(configurationName, HttpContentTypes.TextPlain, - HttpContentTypes.ApplicationJson, "/projects/id:{0}/buildTypes", - projectId); + HttpContentTypes.ApplicationJson, "/projects/id:{0}/buildTypes", + projectId); + } + + public async Task CreateConfigurationAsync(string projectName, string configurationName) + { + return await m_caller.PostFormatAsync(configurationName, HttpContentTypes.TextPlain, + HttpContentTypes.ApplicationJson, "/projects/name:{0}/buildTypes", + projectName); } internal HttpResponseMessage CopyBuildConfig(string buildConfigId, string buildConfigName, string destinationProjectId, - string newBuildTypeId = "") + string newBuildTypeId = "") { string xmlData; if (newBuildTypeId != "") { xmlData = - string.Format( - "", - buildConfigName, buildConfigId, newBuildTypeId); + string.Format( + "", + buildConfigName, buildConfigId, newBuildTypeId); } else { xmlData = - $""; + $""; } + var response = m_caller.Post(xmlData, HttpContentTypes.ApplicationXml, - $"/projects/id:{destinationProjectId}/buildTypes", - HttpContentTypes.ApplicationJson); + $"/projects/id:{destinationProjectId}/buildTypes", + HttpContentTypes.ApplicationJson); + return response; + } + + internal async Task CopyBuildConfigAsync(string buildConfigId, string buildConfigName, + string destinationProjectId, string newBuildTypeId = "") + { + string xmlData; + if (newBuildTypeId != "") + { + xmlData = + $""; + } + else + { + xmlData = + $""; + } + + var response = await m_caller.PostAsync(xmlData, HttpContentTypes.ApplicationXml, + $"/projects/id:{destinationProjectId}/buildTypes", + HttpContentTypes.ApplicationJson); return response; } public BuildConfig Copy(string buildConfigId, string buildConfigName, string destinationProjectId, - string newBuildTypeId = "") + string newBuildTypeId = "") { var response = CopyBuildConfig(buildConfigId, buildConfigName, destinationProjectId, newBuildTypeId); if (response.StatusCode == HttpStatusCode.OK) @@ -159,11 +287,26 @@ public BuildConfig Copy(string buildConfigId, string buildConfigName, string des var buildConfig = JsonConvert.DeserializeObject(response.RawText()); return buildConfig; } + + return new BuildConfig(); + } + + public async Task CopyAsync(string buildConfigId, string buildConfigName, string destinationProjectId, + string newBuildTypeId = "") + { + var response = await CopyBuildConfigAsync(buildConfigId, buildConfigName, destinationProjectId, + newBuildTypeId); + if (response.StatusCode == HttpStatusCode.OK) + { + var buildConfig = JsonConvert.DeserializeObject(await response.RawTextAsync()); + return buildConfig; + } + return new BuildConfig(); } public Template CopyTemplate(string templateId, string templateName, string destinationProjectId, - string newTemplateId = "") + string newTemplateId = "") { var response = CopyTemplateQuery(templateId, templateName, destinationProjectId, newTemplateId); if (response.StatusCode == HttpStatusCode.OK) @@ -171,31 +314,72 @@ public Template CopyTemplate(string templateId, string templateName, string dest var template = JsonConvert.DeserializeObject