From e2c8f0b1e6ebd822b218a9577f067f0150227048 Mon Sep 17 00:00:00 2001 From: Marc-Andre Vezeau Date: Thu, 12 Dec 2013 13:17:13 -0500 Subject: [PATCH 01/99] Added support for ParentProject and Projects inside a Project Added support for ParentProject and Projects inside a Project --- src/TeamCitySharp/DomainEntities/Project.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/TeamCitySharp/DomainEntities/Project.cs b/src/TeamCitySharp/DomainEntities/Project.cs index 02a833c7..afb154d5 100644 --- a/src/TeamCitySharp/DomainEntities/Project.cs +++ b/src/TeamCitySharp/DomainEntities/Project.cs @@ -14,7 +14,9 @@ public override string ToString() public string Name { get; set; } public string WebUrl { get; set; } + public Project ParentProject { get; set; } public BuildTypeWrapper BuildTypes { get; set; } public Parameters Parameters { get; set; } + public ProjectWrapper Projects { get; set; } } } \ No newline at end of file From de51ecee1c1c3fcb9fc5d4010333983ee337eeaf Mon Sep 17 00:00:00 2001 From: Marc-Andre Vezeau Date: Mon, 16 Dec 2013 16:26:44 -0500 Subject: [PATCH 02/99] Added support to Create, move, copy a project, Support to get the artifacts filtered and detection of many new object * Change each call of TeamCityCaller to use the interface ITeamCityCaller * Added new method to download artifact filtered in BuildArtifacts (DownloadFiltered) * Added new method to modify a build trigger in BuildConfigs(ModifTrigger) * Added new method to modify a build snapshot dependencies in BuildConfigs(ModifSnapshotDependencies) * Added new method to modify a build artifact dependencies in BuildConfigs(ModifArtifactDependencies) * Added new method to create a project to inherit a project (Project) * Added new method to move a project to inherit a project (Project) * Added new method to modify a parameters inside a project (Project) * Added new method to modify a setting inside a project (Project) * Added new method to detect if the current user is Administrator (User) * Added new method to generate a ProjectId (Since 8.0) valid for teamcity (Project) * Added new type of Content GetBoolean (TeamCityCaller) * New Object detected in ArtifactDependency - SourceBuildType * New objects detected in Build - BuildType - Properties - Running_info * New Objects detected in BuildConfig - Number - Personnel - History - Pinned -Running - Template * New object detected in Project - Template * New objects detected in SnapshotDependency - Type - SourceBuildType * New class object Running_info - SourceBuildType - Template - Templates * Fix some issues --- README.md | 15 ++- src/TeamCitySharp/ActionTypes/Agents.cs | 4 +- .../ActionTypes/BuildArtifacts.cs | 72 ++++++++++- src/TeamCitySharp/ActionTypes/BuildConfigs.cs | 121 +++++++++++++++++- src/TeamCitySharp/ActionTypes/Builds.cs | 21 ++- src/TeamCitySharp/ActionTypes/Changes.cs | 4 +- .../ActionTypes/IBuildConfigs.cs | 11 +- src/TeamCitySharp/ActionTypes/IBuilds.cs | 2 + src/TeamCitySharp/ActionTypes/IProjects.cs | 6 + src/TeamCitySharp/ActionTypes/IUsers.cs | 1 + src/TeamCitySharp/ActionTypes/Projects.cs | 77 ++++++++++- .../ActionTypes/ServerInformation.cs | 25 ++-- src/TeamCitySharp/ActionTypes/Users.cs | 9 +- src/TeamCitySharp/ActionTypes/VcsRoots.cs | 4 +- .../Connection/ITeamCityCaller.cs | 9 +- .../Connection/TeamCityCaller.cs | 24 ++++ .../Connection/TeamCityDateFilter.cs | 2 +- .../DomainEntities/ArtifactDependency.cs | 8 ++ src/TeamCitySharp/DomainEntities/Build.cs | 48 +++---- .../DomainEntities/BuildConfig.cs | 46 ++++--- src/TeamCitySharp/DomainEntities/File.cs | 2 +- src/TeamCitySharp/DomainEntities/Plugin.cs | 4 +- src/TeamCitySharp/DomainEntities/Project.cs | 1 + .../DomainEntities/Running_info.cs | 12 ++ .../DomainEntities/SnapshotDependency.cs | 10 +- .../DomainEntities/SourceBuildType.cs | 14 ++ src/TeamCitySharp/DomainEntities/Template.cs | 21 +++ src/TeamCitySharp/DomainEntities/Templates.cs | 9 ++ src/TeamCitySharp/DomainEntities/VcsRoot.cs | 4 +- src/TeamCitySharp/TeamCityClient.cs | 2 +- src/TeamCitySharp/TeamCitySharp.csproj | 5 + 31 files changed, 494 insertions(+), 99 deletions(-) create mode 100644 src/TeamCitySharp/DomainEntities/Running_info.cs create mode 100644 src/TeamCitySharp/DomainEntities/SourceBuildType.cs create mode 100644 src/TeamCitySharp/DomainEntities/Template.cs create mode 100644 src/TeamCitySharp/DomainEntities/Templates.cs diff --git a/README.md b/README.md index 4db5e6a8..3bd275eb 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ Each area has its own list of methods available List ErrorBuildsByBuildConfigId(string buildConfigId); Build LastErrorBuildByBuildConfigId(string buildConfigId); List ByBuildConfigId(string buildConfigId); + List ByBuildConfigId(string buildConfigId, List param); + List ByBuildLocator(BuildLocator locator, List param); List ByConfigIdAndTag(string buildConfigId, string tag); List ByUserName(string userName); List ByBuildLocator(BuildLocator locator); @@ -84,9 +86,15 @@ Each area has its own list of methods available Project ById(string projectLocatorId); Project Details(Project project); 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 GenerateID(string projectName); void Delete(string projectName); 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); ###BuildConfigs List All(); @@ -98,6 +106,9 @@ 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 ModifArtifactDependencies(string format, string oldDendencyConfigurationId, string id); + bool ModifSnapshotDependencies(string format, string oldDendencyConfigurationId, string id) BuildConfig CreateConfiguration(string projectName, string configurationName); void SetConfigurationSetting(BuildTypeLocator locator, string settingName, string settingValue); @@ -137,6 +148,7 @@ Each area has its own list of methods available List AllUserRolesByUserGroup(string userGroupName); bool Create(string username, string name, string email, string password); bool AddPassword(string username, string password); + bool IsAdministrator(string username); ###Agents List All(); @@ -169,4 +181,5 @@ Thanks to the following contributors: * Alexander Fast (@mizipzor) * Serge Baltic * Philipp Dolder -* Mark deVilliers \ No newline at end of file +* Mark deVilliers +* Marc-Andre Vezeau (@exfo) diff --git a/src/TeamCitySharp/ActionTypes/Agents.cs b/src/TeamCitySharp/ActionTypes/Agents.cs index 56944acc..5e1e4e87 100644 --- a/src/TeamCitySharp/ActionTypes/Agents.cs +++ b/src/TeamCitySharp/ActionTypes/Agents.cs @@ -6,9 +6,9 @@ namespace TeamCitySharp.ActionTypes { internal class Agents : IAgents { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; - internal Agents(TeamCityCaller caller) + internal Agents(ITeamCityCaller caller) { _caller = caller; } diff --git a/src/TeamCitySharp/ActionTypes/BuildArtifacts.cs b/src/TeamCitySharp/ActionTypes/BuildArtifacts.cs index bb711879..d8cc129a 100644 --- a/src/TeamCitySharp/ActionTypes/BuildArtifacts.cs +++ b/src/TeamCitySharp/ActionTypes/BuildArtifacts.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; using System.Xml; @@ -11,9 +12,9 @@ namespace TeamCitySharp.ActionTypes { internal class BuildArtifacts : IBuildArtifacts { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; - public BuildArtifacts(TeamCityCaller caller) + public BuildArtifacts(ITeamCityCaller caller) { _caller = caller; } @@ -31,10 +32,10 @@ public ArtifactWrapper ByBuildConfigId(string buildConfigId) public class ArtifactWrapper { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; private readonly string _buildConfigId; - internal ArtifactWrapper(TeamCityCaller caller, string buildConfigId) + internal ArtifactWrapper(ITeamCityCaller caller, string buildConfigId) { _caller = caller; _buildConfigId = buildConfigId; @@ -93,10 +94,10 @@ public ArtifactCollection Specification(string buildSpecification) public class ArtifactCollection { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; private readonly List _urls; - internal ArtifactCollection(TeamCityCaller caller, List urls) + internal ArtifactCollection(ITeamCityCaller caller, List urls) { _caller = caller; _urls = urls; @@ -156,5 +157,64 @@ public List Download(string directory = null, bool flatten = false, bool } return downloaded; } + + /// + /// Takes a list of artifact urls and downloads them, see ArtifactsBy* methods. + /// + /// + /// Destination directory for downloaded artifacts, default is current working directory. + /// + /// + /// If all files will be downloaded to destination directory, no subfolders will be created. + /// + /// + /// If files that already exist where a downloaded file is to be placed will be deleted prior to download. + /// + /// + /// + /// A list of full paths to all downloaded artifacts. + /// + public List DownloadFiltered(string directory = null, List filteredExtensionFiles = null, bool flatten = false, bool overwrite = true) + { + if (directory == null) + { + directory = Directory.GetCurrentDirectory(); + } + var downloaded = new List(); + foreach (var url in _urls) + { + // user probably didnt use to artifact url generating functions + Debug.Assert(url.StartsWith("/repository/download/")); + + // figure out local filename + var parts = url.Split('/').Skip(5).ToArray(); + var destination = flatten + ? parts.Last() + : string.Join(Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture), 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); + } + bool download = filteredExtensionFiles == null || filteredExtensionFiles.Contains(Path.GetExtension(destination)); + // add artifact to list regardless if it was downloaded or skipped + if (download) + { + downloaded.Add(Path.GetFullPath(destination)); + + // if the file already exists delete it or move to next artifact + if (File.Exists(destination)) + { + if (overwrite) File.Delete(destination); + else continue; + } + _caller.GetDownloadFormat(tempfile => File.Move(tempfile, destination), url); + } + } + return downloaded; + } } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/BuildConfigs.cs b/src/TeamCitySharp/ActionTypes/BuildConfigs.cs index 0a73e58d..e3065303 100644 --- a/src/TeamCitySharp/ActionTypes/BuildConfigs.cs +++ b/src/TeamCitySharp/ActionTypes/BuildConfigs.cs @@ -1,9 +1,14 @@ using System; using System.Collections.Generic; using System.IO; -using System.Net.Mime; +using System.Linq; +using System.Net; +using System.Text.RegularExpressions; using System.Xml; using EasyHttp.Http; +using JsonFx.Json; +using JsonFx.Serialization; +using JsonFx.Serialization.Resolvers; using TeamCitySharp.Connection; using TeamCitySharp.DomainEntities; using TeamCitySharp.Locators; @@ -12,9 +17,9 @@ namespace TeamCitySharp.ActionTypes { internal class BuildConfigs : IBuildConfigs { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; - internal BuildConfigs(TeamCityCaller caller) + internal BuildConfigs(ITeamCityCaller caller) { _caller = caller; } @@ -127,8 +132,8 @@ public void PutAllBuildTypeParameters(BuildTypeLocator locator, IDictionary downloadHandler) { - _caller.GetDownloadFormat(downloadHandler, "/app/rest/buildTypes/{0}", locator); + var url = string.Format("/app/rest/buildTypes/{0}", locator); + _caller.GetDownloadFormat(downloadHandler, url); } public void PostRawAgentRequirement(BuildTypeLocator locator, string rawXml) @@ -200,5 +206,108 @@ public BuildConfig BuildType(BuildTypeLocator locator) return build; } + public bool ModifTrigger(string buildTypeId, string triggerID, string newBt) + { + //Get data from the old trigger + var urlExtractAllTriggersOld = String.Format("/app/rest/buildTypes/id:{0}/triggers", buildTypeId); + var triggers = _caller.GetFormat(urlExtractAllTriggersOld); + foreach (var trigger in triggers.Trigger.OrderByDescending(m => m.Id)) + { + if (trigger.Type != "buildDependencyTrigger") continue; + + foreach (var property in trigger.Properties.Property) + { + if (property.Name != "dependsOn") continue; + + if (triggerID != property.Value) continue; + + property.Value = newBt; + var writer = new JsonWriter(new DataWriterSettings(new ConventionResolverStrategy(ConventionResolverStrategy.WordCasing.Lowercase, "-"))); + var ttt = writer.Write(trigger); + var urlNewTrigger = String.Format("/app/rest/buildTypes/id:{0}/triggers", buildTypeId); + var response = _caller.Post(ttt, HttpContentTypes.ApplicationJson, urlNewTrigger, HttpContentTypes.ApplicationJson); + if (response.StatusCode != HttpStatusCode.OK) continue; + + var urlDeleteOld = String.Format("/app/rest/buildTypes/id:{0}/triggers/{1}", buildTypeId, trigger.Id); + _caller.Delete(urlDeleteOld); + if (response.StatusCode == HttpStatusCode.OK) + { + return true; + } + } + } + return false; + } + + public bool ModifSnapshotDependencies(string buildTypeId, string dependencyId, string newBt) + { + + var urlExtractOld = String.Format("/app/rest/buildTypes/id:{0}/snapshot-dependencies/{1}", + buildTypeId, dependencyId); + var snapshot = _caller.GetFormat(urlExtractOld); + snapshot.Id = newBt; + snapshot.SourceBuildType.Id = newBt; + + var urlNewTrigger = String.Format("/app/rest/buildTypes/id:{0}/snapshot-dependencies", + buildTypeId); + var writer = + new JsonWriter( + new DataWriterSettings( + new ConventionResolverStrategy(ConventionResolverStrategy.WordCasing.Lowercase, "-"))); + + var ttt = (writer.Write(snapshot)); + ttt = Regex.Replace(ttt, "source-build-type", "source-buildType"); + + + var response = _caller.Post(ttt, HttpContentTypes.ApplicationJson, urlNewTrigger, HttpContentTypes.ApplicationJson); + if (response.StatusCode == HttpStatusCode.OK) + { + var urlDeleteOld = String.Format("/app/rest/buildTypes/id:{0}/snapshot-dependencies/{1}", + buildTypeId, dependencyId); + _caller.Delete(urlDeleteOld); + if (response.StatusCode == HttpStatusCode.OK) + { + return true; + } + } + + return false; + } + + public bool ModifArtifactDependencies(string buildTypeId, string dependencyId, string newBt) + { + + var urlAllExtractOld = String.Format("/app/rest/buildTypes/id:{0}/artifact-dependencies", + buildTypeId); + var artifacts = _caller.GetFormat(urlAllExtractOld); + foreach (var artifact in artifacts.ArtifactDependency.OrderByDescending(m => m.Id)) + { + if (dependencyId != artifact.SourceBuildType.Id) continue; + artifact.SourceBuildType.Id = newBt; + var writer = + new JsonWriter( + new DataWriterSettings( + new ConventionResolverStrategy( + ConventionResolverStrategy.WordCasing.Lowercase, "-"))); + var ttt = writer.Write(artifact); + ttt = Regex.Replace(ttt, "source-build-type", "source-buildType"); + + var urlNewTrigger = String.Format( + "/app/rest/buildTypes/id:{0}/artifact-dependencies", buildTypeId); + + var response = _caller.Post(ttt, HttpContentTypes.ApplicationJson, urlNewTrigger, + HttpContentTypes.ApplicationJson); + if (response.StatusCode == HttpStatusCode.OK) + { + var urlDeleteOld = + String.Format("/app/rest/buildTypes/id:{0}/artifact-dependencies/{1}", + buildTypeId, artifact.Id); + _caller.Delete(urlDeleteOld); + return response.StatusCode == HttpStatusCode.OK; + } + } + + return false; + } } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/Builds.cs b/src/TeamCitySharp/ActionTypes/Builds.cs index 4c52f340..ee4c9c84 100644 --- a/src/TeamCitySharp/ActionTypes/Builds.cs +++ b/src/TeamCitySharp/ActionTypes/Builds.cs @@ -9,9 +9,9 @@ namespace TeamCitySharp.ActionTypes { internal class Builds : IBuilds { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; - internal Builds(TeamCityCaller caller) + internal Builds(ITeamCityCaller caller) { _caller = caller; } @@ -19,11 +19,18 @@ internal Builds(TeamCityCaller caller) public List ByBuildLocator(BuildLocator locator) { var buildWrapper = _caller.GetFormat("/app/rest/builds?locator={0}", locator); - if (int.Parse(buildWrapper.Count) > 0) + return int.Parse(buildWrapper.Count) > 0 ? buildWrapper.Build : new List(); + } + public List ByBuildLocator(BuildLocator locator, List param) + { + var strParam = ""; + foreach (var tmpParam in param) { - return buildWrapper.Build; + strParam += ","; + strParam += tmpParam; } - return new List(); + var buildWrapper = _caller.Get(string.Format("/app/rest/builds?locator={0}{1}", locator, strParam)); + return int.Parse(buildWrapper.Count) > 0 ? buildWrapper.Build : new List(); } public Build LastBuildByAgent(string agentName) @@ -93,6 +100,10 @@ public Build LastErrorBuildByBuildConfigId(string buildConfigId) maxResults: 1 )); return builds != null ? builds.FirstOrDefault() : new Build(); + } + public List ByBuildConfigId(string buildConfigId, List param) + { + return ByBuildLocator(BuildLocator.WithDimensions(BuildTypeLocator.WithId(buildConfigId)), param); } public List ByBuildConfigId(string buildConfigId) diff --git a/src/TeamCitySharp/ActionTypes/Changes.cs b/src/TeamCitySharp/ActionTypes/Changes.cs index 5218b4aa..956e6dea 100644 --- a/src/TeamCitySharp/ActionTypes/Changes.cs +++ b/src/TeamCitySharp/ActionTypes/Changes.cs @@ -7,9 +7,9 @@ namespace TeamCitySharp.ActionTypes { internal class Changes : IChanges { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; - internal Changes(TeamCityCaller caller) + internal Changes(ITeamCityCaller caller) { _caller = caller; } diff --git a/src/TeamCitySharp/ActionTypes/IBuildConfigs.cs b/src/TeamCitySharp/ActionTypes/IBuildConfigs.cs index 51fffe60..f8c12d02 100644 --- a/src/TeamCitySharp/ActionTypes/IBuildConfigs.cs +++ b/src/TeamCitySharp/ActionTypes/IBuildConfigs.cs @@ -17,6 +17,9 @@ public interface IBuildConfigs BuildConfig ByProjectIdAndConfigurationId(string projectId, string buildConfigId); List ByProjectId(string projectId); List ByProjectName(string projectName); + bool ModifTrigger(string format, string oldTriggerConfigurationId, string id); + bool ModifArtifactDependencies(string format, string oldDendencyConfigurationId, string id); + bool ModifSnapshotDependencies(string format, string oldDendencyConfigurationId, string id); BuildConfig CreateConfiguration(string projectName, string configurationName); void SetConfigurationSetting(BuildTypeLocator locator, string settingName, string settingValue); @@ -63,7 +66,13 @@ public interface IBuildConfigs /// /// Locates a build type by its locator. - /// Essentially, it works either like or , whichever is defined in the locator. + /// Essentially, it works either like + /// BuildConfigByConfigurationId + /// + /// or + /// BuildConfigByConfigurationName + /// + /// , whichever is defined in the locator. /// /// Locator for the build type. /// The build type with all its properties. diff --git a/src/TeamCitySharp/ActionTypes/IBuilds.cs b/src/TeamCitySharp/ActionTypes/IBuilds.cs index 6afba988..be2dbcb3 100644 --- a/src/TeamCitySharp/ActionTypes/IBuilds.cs +++ b/src/TeamCitySharp/ActionTypes/IBuilds.cs @@ -15,6 +15,8 @@ public interface IBuilds List ErrorBuildsByBuildConfigId(string buildConfigId); Build LastErrorBuildByBuildConfigId(string buildConfigId); List ByBuildConfigId(string buildConfigId); + List ByBuildConfigId(string buildConfigId, List param); + List ByBuildLocator(BuildLocator locator, List param); List ByConfigIdAndTag(string buildConfigId, string tag); List ByUserName(string userName); List ByBuildLocator(BuildLocator locator); diff --git a/src/TeamCitySharp/ActionTypes/IProjects.cs b/src/TeamCitySharp/ActionTypes/IProjects.cs index febce5c2..d1efc668 100644 --- a/src/TeamCitySharp/ActionTypes/IProjects.cs +++ b/src/TeamCitySharp/ActionTypes/IProjects.cs @@ -10,8 +10,14 @@ public interface IProjects Project ById(string projectLocatorId); Project Details(Project project); 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 GenerateID(string projectName); void Delete(string projectName); 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); } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/IUsers.cs b/src/TeamCitySharp/ActionTypes/IUsers.cs index 7d60ec9d..b2df0774 100644 --- a/src/TeamCitySharp/ActionTypes/IUsers.cs +++ b/src/TeamCitySharp/ActionTypes/IUsers.cs @@ -14,5 +14,6 @@ public interface IUsers List AllUserRolesByUserGroup(string userGroupName); bool Create(string username, string name, string email, string password); bool AddPassword(string username, string password); + bool IsAdministrator(string username); } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/Projects.cs b/src/TeamCitySharp/ActionTypes/Projects.cs index 16f87758..b3637fca 100644 --- a/src/TeamCitySharp/ActionTypes/Projects.cs +++ b/src/TeamCitySharp/ActionTypes/Projects.cs @@ -1,5 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text.RegularExpressions; using EasyHttp.Http; +using JsonFx.Json; +using JsonFx.Serialization; +using JsonFx.Serialization.Resolvers; using TeamCitySharp.Connection; using TeamCitySharp.DomainEntities; @@ -7,9 +13,9 @@ namespace TeamCitySharp.ActionTypes { internal class Projects : IProjects { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; - internal Projects(TeamCityCaller caller) + internal Projects(ITeamCityCaller caller) { _caller = caller; } @@ -45,6 +51,52 @@ public Project Create(string projectName) return _caller.Post(projectName, HttpContentTypes.ApplicationXml, "/app/rest/projects/", string.Empty); } + public Project Create(string projectName, string sourceId, string projectId = "") + { + var id = projectId == "" ? GenerateID(projectName) : projectId; + var xmlData = String.Format( "", projectName, id , sourceId); + var response = _caller.Post(xmlData, HttpContentTypes.ApplicationXml, "/app/rest/projects", HttpContentTypes.ApplicationJson); + if (response.StatusCode == HttpStatusCode.OK) + { + var reader = + new JsonReader( new DataReaderSettings(new ConventionResolverStrategy(ConventionResolverStrategy.WordCasing.Lowercase, "-"))); + var project = reader.Read(response.RawText); + return project; + } + return new Project(); + } + + public Project Move(string projectId, string destinationId) + { + var xmlData = String.Format("", destinationId); + var url = String.Format("/app/rest/projects/id:{0}/parentProject", projectId); + var response = _caller.Put(xmlData, HttpContentTypes.ApplicationXml, url, HttpContentTypes.ApplicationJson); + if (response.StatusCode == HttpStatusCode.OK) + { + var reader = new JsonReader( new DataReaderSettings(new ConventionResolverStrategy(ConventionResolverStrategy.WordCasing.Lowercase, "-"))); + var project = reader.Read(response.RawText); + return project; + } + return new Project(); + } + + internal HttpResponse CopyProject(string projectid, string projectName, string newProjectId) + { + var xmlData = String.Format("", projectName, newProjectId, projectid); + var response = _caller.Post(xmlData, HttpContentTypes.ApplicationXml, "/app/rest/projects", HttpContentTypes.ApplicationJson); + return response; + } + public Project Copy(string projectid, string projectName, string newProjectId) + { + var response = CopyProject(projectid, projectName, newProjectId); + if (response.StatusCode == HttpStatusCode.OK) + { + var reader = new JsonReader(new DataReaderSettings(new ConventionResolverStrategy(ConventionResolverStrategy.WordCasing.Lowercase, "-"))); + var project = reader.Read(response.RawText); + return project; + } + return new Project(); + } public void Delete(string projectName) { _caller.DeleteFormat("/app/rest/projects/name:{0}", projectName); @@ -59,5 +111,24 @@ public void SetProjectParameter(string projectName, string settingName, string s { _caller.PutFormat(settingValue, "/app/rest/projects/name:{0}/parameters/{1}", projectName, settingName); } + public string GenerateID(string projectName) + { + projectName = Regex.Replace(projectName, @"[^\p{L}\p{N}]+", ""); + return projectName; + } + public bool ModifParameters(string buildTypeId, string param, string value) + { + var url = String.Format("/app/rest/projects/id:{0}/parameters/{1}", buildTypeId, param); + + var response = _caller.Put(value, HttpContentTypes.TextPlain, url, string.Empty); + return response.StatusCode == HttpStatusCode.OK; + } + + public bool ModifSettings(string projectId, string setting, string value) + { + var url = String.Format("/app/rest/projects/{0}/{1}", projectId, setting); + var response = _caller.Put(value, HttpContentTypes.TextPlain, url, string.Empty); + return response.StatusCode == HttpStatusCode.OK; + } } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/ServerInformation.cs b/src/TeamCitySharp/ActionTypes/ServerInformation.cs index 88925a89..72b8d3ca 100644 --- a/src/TeamCitySharp/ActionTypes/ServerInformation.cs +++ b/src/TeamCitySharp/ActionTypes/ServerInformation.cs @@ -1,13 +1,12 @@ -namespace TeamCitySharp.ActionTypes -{ - using System.Collections.Generic; - using System.Text; - using TeamCitySharp.Connection; - using TeamCitySharp.DomainEntities; +using System.Collections.Generic; +using System.Text; +using TeamCitySharp.Connection; +using TeamCitySharp.DomainEntities; +namespace TeamCitySharp.ActionTypes +{ internal class ServerInformation : IServerInformation { - private const string ServerUrlPrefix = "/app/rest/server"; private readonly ITeamCityCaller _caller; internal ServerInformation(ITeamCityCaller caller) @@ -17,30 +16,28 @@ internal ServerInformation(ITeamCityCaller caller) public Server ServerInfo() { - var server = _caller.Get(ServerUrlPrefix); + var server = _caller.Get("/app/rest/server"); return server; } public List AllPlugins() { - var pluginWrapper = _caller.Get(ServerUrlPrefix + "/plugins"); + var pluginWrapper = _caller.Get("/app/rest/server/plugins"); return pluginWrapper.Plugin; } public string TriggerServerInstanceBackup(BackupOptions backupOptions) { - var backupOptionsUrlPart = this.BuildBackupOptionsUrl(backupOptions); - var url = string.Concat(ServerUrlPrefix, "/backup?", backupOptionsUrlPart); + var backupOptionsUrlPart = BuildBackupOptionsUrl(backupOptions); + var url = string.Concat("/app/rest/server/backup?", backupOptionsUrlPart); return _caller.StartBackup(url); } public string GetBackupStatus() { - var url = string.Concat(ServerUrlPrefix, "/backup"); - - return _caller.GetRaw(url); + return _caller.GetRaw("/app/rest/server/backup"); } private string BuildBackupOptionsUrl(BackupOptions backupOptions) diff --git a/src/TeamCitySharp/ActionTypes/Users.cs b/src/TeamCitySharp/ActionTypes/Users.cs index 6b494ac8..1f1a4ae2 100644 --- a/src/TeamCitySharp/ActionTypes/Users.cs +++ b/src/TeamCitySharp/ActionTypes/Users.cs @@ -8,9 +8,9 @@ namespace TeamCitySharp.ActionTypes { internal class Users : IUsers { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; - internal Users(TeamCityCaller caller) + internal Users(ITeamCityCaller caller) { _caller = caller; } @@ -99,6 +99,11 @@ public bool AddPassword(string username, string password) return result; } + public bool IsAdministrator(string username) + { + var isAdministrator = _caller.GetBoolean(string.Format("/app/rest/users/username:{0}/roles/SYSTEM_ADMIN/g", username)); + return isAdministrator; + } } } \ No newline at end of file diff --git a/src/TeamCitySharp/ActionTypes/VcsRoots.cs b/src/TeamCitySharp/ActionTypes/VcsRoots.cs index 9e1e95a9..d7619e7d 100644 --- a/src/TeamCitySharp/ActionTypes/VcsRoots.cs +++ b/src/TeamCitySharp/ActionTypes/VcsRoots.cs @@ -9,9 +9,9 @@ namespace TeamCitySharp.ActionTypes { internal class VcsRoots: IVcsRoots { - private readonly TeamCityCaller _caller; + private readonly ITeamCityCaller _caller; - internal VcsRoots(TeamCityCaller caller) + internal VcsRoots(ITeamCityCaller caller) { _caller = caller; } diff --git a/src/TeamCitySharp/Connection/ITeamCityCaller.cs b/src/TeamCitySharp/Connection/ITeamCityCaller.cs index aee4df5c..c8b5c3b8 100644 --- a/src/TeamCitySharp/Connection/ITeamCityCaller.cs +++ b/src/TeamCitySharp/Connection/ITeamCityCaller.cs @@ -1,8 +1,8 @@ -namespace TeamCitySharp.Connection -{ - using System; - using EasyHttp.Http; +using System; +using EasyHttp.Http; +namespace TeamCitySharp.Connection +{ internal interface ITeamCityCaller { void Connect(string userName, string password, bool actAsGuest); @@ -38,5 +38,6 @@ internal interface ITeamCityCaller void Delete(string urlPart); string GetRaw(string urlPart); + bool GetBoolean(string urlPart, params object[] parts); } } \ No newline at end of file diff --git a/src/TeamCitySharp/Connection/TeamCityCaller.cs b/src/TeamCitySharp/Connection/TeamCityCaller.cs index 35879822..3c48cc72 100644 --- a/src/TeamCitySharp/Connection/TeamCityCaller.cs +++ b/src/TeamCitySharp/Connection/TeamCityCaller.cs @@ -288,5 +288,29 @@ private string GetContentType(string data) return HttpContentTypes.ApplicationXml; return HttpContentTypes.TextPlain; } + + public bool GetBoolean(string urlPart, params object[] parts) + { + var urlfull = string.Format(urlPart, parts); + + try + { + if (CheckForUserNameAndPassword()) + throw new ArgumentException("If you are not acting as a guest you must supply userName and password"); + + if (string.IsNullOrEmpty(urlfull)) + throw new ArgumentException("Url must be specfied"); + + var url = CreateUrl(urlfull); + + var response = CreateHttpClient(_configuration.UserName, _configuration.Password, HttpContentTypes.ApplicationJson).Get(url); + return !IsHttpError(response); + } + catch (Exception) + { + return false; + } + + } } } \ No newline at end of file diff --git a/src/TeamCitySharp/Connection/TeamCityDateFilter.cs b/src/TeamCitySharp/Connection/TeamCityDateFilter.cs index e83ff5dc..e54262c9 100644 --- a/src/TeamCitySharp/Connection/TeamCityDateFilter.cs +++ b/src/TeamCitySharp/Connection/TeamCityDateFilter.cs @@ -33,7 +33,7 @@ public override bool TryRead(DataReaderSettings settings, IStream> tokens) { - tokens = new Token[] + tokens = new[] { ModelGrammar.TokenPrimitive(FormatDate(value)) }; diff --git a/src/TeamCitySharp/DomainEntities/ArtifactDependency.cs b/src/TeamCitySharp/DomainEntities/ArtifactDependency.cs index 487b9565..f9d57701 100644 --- a/src/TeamCitySharp/DomainEntities/ArtifactDependency.cs +++ b/src/TeamCitySharp/DomainEntities/ArtifactDependency.cs @@ -1,5 +1,8 @@ +using System.Runtime.Serialization; + namespace TeamCitySharp.DomainEntities { + [DataContract] public class ArtifactDependency { public override string ToString() @@ -7,8 +10,13 @@ public override string ToString() return "artifact_dependency"; } + [DataMember(Name = "id")] public string Id { get; set; } + [DataMember(Name = "type")] public string Type { get; set; } + [DataMember(Name = "properties")] public Properties Properties { get; set; } + [DataMember(Name = "source-buildType")] + public SourceBuildType SourceBuildType { get; set; } } } \ No newline at end of file diff --git a/src/TeamCitySharp/DomainEntities/Build.cs b/src/TeamCitySharp/DomainEntities/Build.cs index 7d16fc34..a688c39e 100644 --- a/src/TeamCitySharp/DomainEntities/Build.cs +++ b/src/TeamCitySharp/DomainEntities/Build.cs @@ -1,27 +1,29 @@ using System; -namespace TeamCitySharp.DomainEntities -{ - public class Build - { - public string Id { get; set; } - public string Number { get; set; } - public string Status { get; set; } - public string BuildTypeId { get; set; } - public string Href { get; set; } - public string WebUrl { get; set; } - public string StatusText { get; set; } +namespace TeamCitySharp.DomainEntities +{ + public class Build + { + public string Id { get; set; } + public string Number { get; set; } + public string Status { get; set; } + public string BuildTypeId { get; set; } + public string Href { get; set; } + public string WebUrl { get; set; } + public string StatusText { get; set; } public DateTime StartDate { get; set; } - public DateTime FinishDate { get; set; } - - public BuildConfig BuildConfig { get; set; } - public Agent Agent { get; set;} - public ChangeWrapper Changes { get; set; } - - public override string ToString() - { - return Number; - } - - } + public DateTime FinishDate { get; set; } + public BuildConfig BuildType { get; set; } + public BuildConfig BuildConfig { get; set; } + public Agent Agent { get; set;} + public ChangeWrapper Changes { get; set; } + public Properties Properties { get; set; } + public Running_info Running_info { get; set; } + + public override string ToString() + { + return Number; + } + + } } \ No newline at end of file diff --git a/src/TeamCitySharp/DomainEntities/BuildConfig.cs b/src/TeamCitySharp/DomainEntities/BuildConfig.cs index 93034b20..aebdb4ec 100644 --- a/src/TeamCitySharp/DomainEntities/BuildConfig.cs +++ b/src/TeamCitySharp/DomainEntities/BuildConfig.cs @@ -1,29 +1,35 @@ -namespace TeamCitySharp.DomainEntities -{ - public class BuildConfig - { - public override string ToString() - { - return Name; - } - - public string Id { get; set; } - public string Name { get; set; } - public string Href { get; set; } - public string ProjectId { get; set; } - public string ProjectName { get; set; } - public string Description { get; set; } - public string WebUrl { get; set; } - - public Project Project { get; set; } +namespace TeamCitySharp.DomainEntities +{ + public class BuildConfig + { + public override string ToString() + { + return Name; + } + + public string Id { get; set; } + public string Name { get; set; } + public string Number { get; set; } + public string Status { get; set; } + public string Href { get; set; } + public string ProjectId { get; set; } + public string ProjectName { get; set; } + public string Description { get; set; } + public string WebUrl { get; set; } + public bool? Personal { get; set; } + public bool? History { get; set; } + public bool? Pinned { get; set; } + public bool? Running { get; set; } + public Project Project { get; set; } + public Template Template { get; set; } public Parameters Parameters { get; set; } public ArtifactDependencies ArtifactDependencies { get; set; } public SnapshotDependencies SnapshotDependencies { get; set; } public VcsRootEntries VcsRootEntries { get; set; } public BuildSteps Steps { get; set; } public AgentRequirements AgentRequirements { get; set; } - public BuildTriggers Triggers { get; set; } - public Properties Settings { get; set; } + public BuildTriggers Triggers { get; set; } + public Properties Settings { get; set; } } } \ No newline at end of file diff --git a/src/TeamCitySharp/DomainEntities/File.cs b/src/TeamCitySharp/DomainEntities/File.cs index 11a3b972..ba1d7c73 100644 --- a/src/TeamCitySharp/DomainEntities/File.cs +++ b/src/TeamCitySharp/DomainEntities/File.cs @@ -2,6 +2,6 @@ { public class File { - public string relativefile { get; set; } + public string Relativefile { get; set; } } } \ No newline at end of file diff --git a/src/TeamCitySharp/DomainEntities/Plugin.cs b/src/TeamCitySharp/DomainEntities/Plugin.cs index 1603faa4..0c545ac5 100644 --- a/src/TeamCitySharp/DomainEntities/Plugin.cs +++ b/src/TeamCitySharp/DomainEntities/Plugin.cs @@ -3,12 +3,12 @@ public class Plugin { public string Name { get; set; } - public string displayName { get; set; } + public string DisplayName { get; set; } public string Version { get; set; } public override string ToString() { - return displayName; + return DisplayName; } } } \ No newline at end of file diff --git a/src/TeamCitySharp/DomainEntities/Project.cs b/src/TeamCitySharp/DomainEntities/Project.cs index afb154d5..34b47654 100644 --- a/src/TeamCitySharp/DomainEntities/Project.cs +++ b/src/TeamCitySharp/DomainEntities/Project.cs @@ -17,6 +17,7 @@ public override string ToString() public Project ParentProject { get; set; } public BuildTypeWrapper BuildTypes { get; set; } public Parameters Parameters { get; set; } + public Templates Templates { get; set; } public ProjectWrapper Projects { get; set; } } } \ No newline at end of file diff --git a/src/TeamCitySharp/DomainEntities/Running_info.cs b/src/TeamCitySharp/DomainEntities/Running_info.cs new file mode 100644 index 00000000..671faf75 --- /dev/null +++ b/src/TeamCitySharp/DomainEntities/Running_info.cs @@ -0,0 +1,12 @@ +namespace TeamCitySharp.DomainEntities +{ + public class Running_info + { + public int? PercentageComplete { get; set; } + public int? ElapsedSeconds { get; set; } + public int? EstimatedTotalSeconds { get; set; } + public string CurrentStageText { get; set; } + public string Outdated { get; set; } + public string ProbablyHanging { get; set; } + } +} diff --git a/src/TeamCitySharp/DomainEntities/SnapshotDependency.cs b/src/TeamCitySharp/DomainEntities/SnapshotDependency.cs index 6f0cfe50..6ab596eb 100644 --- a/src/TeamCitySharp/DomainEntities/SnapshotDependency.cs +++ b/src/TeamCitySharp/DomainEntities/SnapshotDependency.cs @@ -1,13 +1,21 @@ +using System.Runtime.Serialization; + namespace TeamCitySharp.DomainEntities { + [DataContract] public class SnapshotDependency { public override string ToString() { return "snapshot_dependency"; } - + [DataMember(Name = "id")] public string Id { get; set; } + [DataMember(Name = "type")] + public string Type { get; set; } + [DataMember(Name = "properties")] public Properties Properties { get; set; } + [DataMember(Name = "source-buildType")] + public SourceBuildType SourceBuildType { get; set; } } } \ No newline at end of file diff --git a/src/TeamCitySharp/DomainEntities/SourceBuildType.cs b/src/TeamCitySharp/DomainEntities/SourceBuildType.cs new file mode 100644 index 00000000..1c8aafc8 --- /dev/null +++ b/src/TeamCitySharp/DomainEntities/SourceBuildType.cs @@ -0,0 +1,14 @@ +using System.Runtime.Serialization; + +namespace TeamCitySharp.DomainEntities +{ + public class SourceBuildType + { + public override string ToString() + { + return Id; + } + [DataMember(Name = "id")] + public string Id { get; set; } + } +} diff --git a/src/TeamCitySharp/DomainEntities/Template.cs b/src/TeamCitySharp/DomainEntities/Template.cs new file mode 100644 index 00000000..19319960 --- /dev/null +++ b/src/TeamCitySharp/DomainEntities/Template.cs @@ -0,0 +1,21 @@ +namespace TeamCitySharp.DomainEntities +{ + public class Template + { + public string Id { get; set; } + public string Name { get; set; } + public string Href { get; set; } + public string ProjectId { get; set; } + public string ProjectName { get; set; } + + public Template() + { + Id = ""; + Name = ""; + Href = ""; + ProjectId = ""; + ProjectName = ""; + + } + } +} diff --git a/src/TeamCitySharp/DomainEntities/Templates.cs b/src/TeamCitySharp/DomainEntities/Templates.cs new file mode 100644 index 00000000..2b86d435 --- /dev/null +++ b/src/TeamCitySharp/DomainEntities/Templates.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace TeamCitySharp.DomainEntities +{ + public class Templates + { + public List