diff --git a/packages/repositories.config b/packages/repositories.config
index bcd17bb0..3468aa5e 100644
--- a/packages/repositories.config
+++ b/packages/repositories.config
@@ -2,5 +2,6 @@
+
\ No newline at end of file
diff --git a/src/TeamCitySharp/ActionTypes/Agents.cs b/src/TeamCitySharp/ActionTypes/Agents.cs
index 56944acc..6b9837ee 100644
--- a/src/TeamCitySharp/ActionTypes/Agents.cs
+++ b/src/TeamCitySharp/ActionTypes/Agents.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.IO;
using TeamCitySharp.Connection;
using TeamCitySharp.DomainEntities;
@@ -13,11 +14,26 @@ internal Agents(TeamCityCaller caller)
_caller = caller;
}
- public List All()
+ public List All(bool includeDisconnected = true, bool includeUnauthorized = true)
{
- var agentWrapper = _caller.Get("/app/rest/agents");
+ var url = string.Format("/app/rest/agents?includeDisconnected={0}&includeUnauthorized={1}",
+ includeDisconnected.ToString().ToLower(), includeUnauthorized.ToString().ToLower());
+
+ var agentWrapper = _caller.Get(url);
return agentWrapper.Agent;
}
+
+ private string AddqueryString(string url, string queryString)
+ {
+ if (url.Contains("?"))
+ url += "&";
+ else
+ url += "?";
+
+ url += queryString;
+
+ return url;
+ }
}
}
\ No newline at end of file
diff --git a/src/TeamCitySharp/ActionTypes/BuildConfigs.cs b/src/TeamCitySharp/ActionTypes/BuildConfigs.cs
index cdcd4a0f..b01b6271 100644
--- a/src/TeamCitySharp/ActionTypes/BuildConfigs.cs
+++ b/src/TeamCitySharp/ActionTypes/BuildConfigs.cs
@@ -114,6 +114,24 @@ public void PostRawBuildTrigger(BuildTypeLocator locator, string rawXml)
_caller.PostFormat(rawXml, HttpContentTypes.ApplicationXml, "/app/rest/buildTypes/{0}/triggers", locator);
}
+ public void SetArtifactDependency(BuildTypeLocator locator, ArtifactDependency dependency)
+ {
+ _caller.PostFormat(dependency, HttpContentTypes.ApplicationJson,
+ HttpContentTypes.ApplicationJson, "/app/rest/buildTypes/{0}/artifact-dependencies", locator);
+ }
+
+ public void SetSnapshotDependency(BuildTypeLocator locator, SnapshotDependency dependency)
+ {
+ _caller.PostFormat(dependency, HttpContentTypes.ApplicationJson,
+ HttpContentTypes.ApplicationJson, "/app/rest/buildTypes/{0}/snapshot-dependencies", locator);
+ }
+
+ public void SetTrigger(BuildTypeLocator locator, BuildTrigger trigger)
+ {
+ _caller.PostFormat(trigger, HttpContentTypes.ApplicationJson, HttpContentTypes.ApplicationJson,
+ "/app/rest/buildTypes/{0}/triggers", locator);
+ }
+
public void SetConfigurationParameter(BuildTypeLocator locator, string key, string value)
{
_caller.PutFormat(value, HttpContentTypes.TextPlain, "/app/rest/buildTypes/{0}/parameters/{1}", locator, key);
diff --git a/src/TeamCitySharp/ActionTypes/Builds.cs b/src/TeamCitySharp/ActionTypes/Builds.cs
index 4c52f340..ca4bbe9e 100644
--- a/src/TeamCitySharp/ActionTypes/Builds.cs
+++ b/src/TeamCitySharp/ActionTypes/Builds.cs
@@ -95,6 +95,13 @@ public Build LastErrorBuildByBuildConfigId(string buildConfigId)
return builds != null ? builds.FirstOrDefault() : new Build();
}
+ public Build ById(string id)
+ {
+ var build = _caller.GetFormat("/app/rest/builds/id:{0}", id);
+
+ return build ?? new Build();
+ }
+
public List ByBuildConfigId(string buildConfigId)
{
return ByBuildLocator(BuildLocator.WithDimensions(BuildTypeLocator.WithId(buildConfigId)
diff --git a/src/TeamCitySharp/ActionTypes/IAgents.cs b/src/TeamCitySharp/ActionTypes/IAgents.cs
index 36b5ade5..1292b1a3 100644
--- a/src/TeamCitySharp/ActionTypes/IAgents.cs
+++ b/src/TeamCitySharp/ActionTypes/IAgents.cs
@@ -5,6 +5,6 @@ namespace TeamCitySharp.ActionTypes
{
public interface IAgents
{
- List All();
+ List All(bool includeDisconnected = false, bool includeUnauthorized = false);
}
}
\ No newline at end of file
diff --git a/src/TeamCitySharp/ActionTypes/IBuildConfigs.cs b/src/TeamCitySharp/ActionTypes/IBuildConfigs.cs
index 2829ec2d..ef90817d 100644
--- a/src/TeamCitySharp/ActionTypes/IBuildConfigs.cs
+++ b/src/TeamCitySharp/ActionTypes/IBuildConfigs.cs
@@ -22,9 +22,15 @@ public interface IBuildConfigs
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 SetArtifactDependency(BuildTypeLocator locator, ArtifactDependency dependency);
+
void PostRawBuildStep(BuildTypeLocator locator, string rawXml);
+
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);
@@ -62,6 +68,7 @@ public interface IBuildConfigs
/// ]]>
///
void PostRawSnapshotDependency(BuildTypeLocator locator, XmlElement rawXml);
+ void SetSnapshotDependency(BuildTypeLocator locator, SnapshotDependency dependency);
///
/// Locates a build type by its locator.
diff --git a/src/TeamCitySharp/ActionTypes/IBuilds.cs b/src/TeamCitySharp/ActionTypes/IBuilds.cs
index 6afba988..2c57fa2a 100644
--- a/src/TeamCitySharp/ActionTypes/IBuilds.cs
+++ b/src/TeamCitySharp/ActionTypes/IBuilds.cs
@@ -14,6 +14,7 @@ public interface IBuilds
Build LastBuildByBuildConfigId(string buildConfigId);
List ErrorBuildsByBuildConfigId(string buildConfigId);
Build LastErrorBuildByBuildConfigId(string buildConfigId);
+ Build ById(string id);
List ByBuildConfigId(string buildConfigId);
List ByConfigIdAndTag(string buildConfigId, string tag);
List ByUserName(string userName);
diff --git a/src/TeamCitySharp/ActionTypes/Projects.cs b/src/TeamCitySharp/ActionTypes/Projects.cs
index 16f87758..69bc82fb 100644
--- a/src/TeamCitySharp/ActionTypes/Projects.cs
+++ b/src/TeamCitySharp/ActionTypes/Projects.cs
@@ -1,7 +1,9 @@
using System.Collections.Generic;
+using System.Text.RegularExpressions;
using EasyHttp.Http;
using TeamCitySharp.Connection;
using TeamCitySharp.DomainEntities;
+using TeamCitySharp.Locators;
namespace TeamCitySharp.ActionTypes
{
@@ -42,7 +44,20 @@ public Project Details(Project project)
public Project Create(string projectName)
{
- return _caller.Post(projectName, HttpContentTypes.ApplicationXml, "/app/rest/projects/", string.Empty);
+ return Create(projectName, "_Root");
+ }
+
+ public Project Create(string projectName, string rootProjectId)
+ {
+ var project = new NewProjectDescription
+ {
+ Name = projectName,
+ Id = GenerateId(projectName),
+ ParentProject = new ParentProjectWrapper(ProjectLocator.WithId(rootProjectId))
+ };
+
+ return _caller.Post(project, HttpContentTypes.ApplicationJson, "/app/rest/projects/",
+ HttpContentTypes.ApplicationJson);
}
public void Delete(string projectName)
@@ -59,5 +74,11 @@ 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;
+ }
}
}
\ No newline at end of file
diff --git a/src/TeamCitySharp/Connection/ITeamCityCaller.cs b/src/TeamCitySharp/Connection/ITeamCityCaller.cs
index aee4df5c..ec6a95f8 100644
--- a/src/TeamCitySharp/Connection/ITeamCityCaller.cs
+++ b/src/TeamCitySharp/Connection/ITeamCityCaller.cs
@@ -27,7 +27,7 @@ internal interface ITeamCityCaller
void Get(string urlPart);
- T Post(string data, string contenttype, string urlPart, string accept);
+ T Post(object data, string contenttype, string urlPart, string accept);
bool Authenticate(string urlPart);
diff --git a/src/TeamCitySharp/Connection/TeamCityCaller.cs b/src/TeamCitySharp/Connection/TeamCityCaller.cs
index 35879822..dd126fc0 100644
--- a/src/TeamCitySharp/Connection/TeamCityCaller.cs
+++ b/src/TeamCitySharp/Connection/TeamCityCaller.cs
@@ -42,17 +42,17 @@ public void GetFormat(string urlPart, params object[] parts)
public T PostFormat(object data, string contenttype, string accept, string urlPart, params object[] parts)
{
- return Post(data.ToString(), contenttype, string.Format(urlPart, parts), accept);
+ return Post(data, contenttype, string.Format(urlPart, parts), accept);
}
public void PostFormat(object data, string contenttype, string urlPart, params object[] parts)
{
- Post(data.ToString(), contenttype, string.Format(urlPart, parts), string.Empty);
+ Post(data, contenttype, string.Format(urlPart, parts), string.Empty);
}
public void PutFormat(object data, string contenttype, string urlPart, params object[] parts)
{
- Put(data.ToString(), contenttype, string.Format(urlPart, parts), string.Empty);
+ Put(data, contenttype, string.Format(urlPart, parts), string.Empty);
}
public void DeleteFormat(string urlPart, params object[] parts)
@@ -143,7 +143,7 @@ private HttpResponse GetResponse(string urlPart)
return response;
}
- public T Post(string data, string contenttype, string urlPart, string accept)
+ public T Post(object data, string contenttype, string urlPart, string accept)
{
return Post(data, contenttype, urlPart, accept).StaticBody();
}
diff --git a/src/TeamCitySharp/Connection/TeamcityJsonEncoderDecoderConfiguration.cs b/src/TeamCitySharp/Connection/TeamcityJsonEncoderDecoderConfiguration.cs
index 4a40a74f..339d06e7 100644
--- a/src/TeamCitySharp/Connection/TeamcityJsonEncoderDecoderConfiguration.cs
+++ b/src/TeamCitySharp/Connection/TeamcityJsonEncoderDecoderConfiguration.cs
@@ -1,9 +1,13 @@
using System.Collections.Generic;
+using System.IO;
using EasyHttp.Codecs;
using EasyHttp.Codecs.JsonFXExtensions;
using EasyHttp.Configuration;
+using JsonFx.IO;
using JsonFx.Json;
+using JsonFx.Model;
using JsonFx.Serialization;
+using JsonFx.Serialization.Filters;
namespace TeamCitySharp.Connection
{
@@ -11,7 +15,7 @@ public class TeamcityJsonEncoderDecoderConfiguration : IEncoderDecoderConfigurat
{
public IEncoder GetEncoder()
{
- var jsonWriter = new JsonWriter(new DataWriterSettings(DefaultEncoderDecoderConfiguration.CombinedResolverStrategy()
+ var jsonWriter = new CamelCaseJsonWriter(new DataWriterSettings(DefaultEncoderDecoderConfiguration.CombinedResolverStrategy()
, new TeamCityDateFilter()), new[] { "application/.*json", "text/.*json" });
var writers = new List { jsonWriter };
@@ -29,4 +33,39 @@ public IDecoder GetDecoder()
return new DefaultDecoder(dataReaderProvider);
}
}
+
+ public class CamelCaseJsonWriter : JsonWriter
+ {
+ public CamelCaseJsonWriter(DataWriterSettings settings, params string[] contentTypes)
+ : base(settings, contentTypes)
+ {}
+
+ protected override ITextFormatter GetFormatter()
+ {
+ return new CamelCaseJsonFormatter(this.Settings);
+ }
+ }
+
+ public class CamelCaseJsonFormatter : JsonWriter.JsonFormatter
+ {
+ public CamelCaseJsonFormatter(DataWriterSettings settings)
+ : base(settings)
+ {}
+
+ protected override void WritePropertyName(TextWriter writer, string propertyName)
+ {
+ base.WritePropertyName(writer, CamelCase(propertyName));
+ }
+
+ private static string CamelCase(string input)
+ {
+ if (string.IsNullOrEmpty(input))
+ return input;
+
+ var chars = input.ToCharArray();
+ chars[0] = chars[0].ToString().ToLower().ToCharArray()[0];
+
+ return new string(chars);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/TeamCitySharp/DomainEntities/ArtifactDependency.cs b/src/TeamCitySharp/DomainEntities/ArtifactDependency.cs
index 487b9565..4278a7c8 100644
--- a/src/TeamCitySharp/DomainEntities/ArtifactDependency.cs
+++ b/src/TeamCitySharp/DomainEntities/ArtifactDependency.cs
@@ -1,14 +1,40 @@
+using JsonFx.Json;
+
namespace TeamCitySharp.DomainEntities
{
public class ArtifactDependency
{
+ public ArtifactDependency()
+ {
+ Properties = new Properties();
+ Type = "artifact_dependency";
+ }
public override string ToString()
{
- return "artifact_dependency";
+ return Type;
}
public string Id { get; set; }
- public string Type { get; set; }
public Properties Properties { get; set; }
+ [JsonName("source-buildType")]
+ public SourceBuildType SourceBuildType { get; set; }
+ public string Type { get; set; }
+
+ public static ArtifactDependency Default(string dependsOnbuildId)
+ {
+ var dependency = new ArtifactDependency();
+
+ dependency.Properties.Add("cleanDestinationDirectory", "true");
+ dependency.Properties.Add("pathRules", "* => Temp");
+ dependency.Properties.Add("revisionName", "sameChainOrLastFinished");
+ dependency.Properties.Add("revisionValue", "latest.sameChainOrLastFinished");
+
+ dependency.SourceBuildType = new SourceBuildType
+ {
+ Id = dependsOnbuildId
+ };
+
+ return dependency;
+ }
}
}
\ No newline at end of file
diff --git a/src/TeamCitySharp/DomainEntities/BuildTrigger.cs b/src/TeamCitySharp/DomainEntities/BuildTrigger.cs
index f6f9ec78..96a954ac 100644
--- a/src/TeamCitySharp/DomainEntities/BuildTrigger.cs
+++ b/src/TeamCitySharp/DomainEntities/BuildTrigger.cs
@@ -2,6 +2,11 @@ namespace TeamCitySharp.DomainEntities
{
public class BuildTrigger
{
+ public BuildTrigger()
+ {
+ Properties = new Properties();
+ }
+
public override string ToString()
{
return "trigger";
@@ -10,5 +15,18 @@ public override string ToString()
public string Id { get; set; }
public string Type { get; set; }
public Properties Properties { get; set; }
+
+ public static BuildTrigger FinishBuildTrigger(string dependsOnbuildId)
+ {
+ var trigger = new BuildTrigger
+ {
+ Type = "buildDependencyTrigger"
+ };
+
+ trigger.Properties.Add("afterSuccessfulBuildOnly", "true");
+ trigger.Properties.Add("dependsOn", dependsOnbuildId);
+
+ return trigger;
+ }
}
}
\ No newline at end of file
diff --git a/src/TeamCitySharp/DomainEntities/NewProjectDescription.cs b/src/TeamCitySharp/DomainEntities/NewProjectDescription.cs
new file mode 100644
index 00000000..42ccf97d
--- /dev/null
+++ b/src/TeamCitySharp/DomainEntities/NewProjectDescription.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using JsonFx.Json;
+using TeamCitySharp.Locators;
+
+namespace TeamCitySharp.DomainEntities
+{
+ public class NewProjectDescription
+ {
+ public string Name { get; set; }
+ public string Id { get; set; }
+ public ParentProjectWrapper ParentProject { get; set; }
+ }
+}
diff --git a/src/TeamCitySharp/DomainEntities/ParentProjectWrapper.cs b/src/TeamCitySharp/DomainEntities/ParentProjectWrapper.cs
new file mode 100644
index 00000000..2bec04da
--- /dev/null
+++ b/src/TeamCitySharp/DomainEntities/ParentProjectWrapper.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using TeamCitySharp.Locators;
+
+namespace TeamCitySharp.DomainEntities
+{
+ public class ParentProjectWrapper
+ {
+ private readonly ProjectLocator _locator;
+
+ public ParentProjectWrapper(ProjectLocator locator)
+ {
+ _locator = locator;
+ }
+
+ public string Locator { get { return _locator.ToString(); } }
+ }
+}
diff --git a/src/TeamCitySharp/DomainEntities/Properties.cs b/src/TeamCitySharp/DomainEntities/Properties.cs
index bb13d698..dc796224 100644
--- a/src/TeamCitySharp/DomainEntities/Properties.cs
+++ b/src/TeamCitySharp/DomainEntities/Properties.cs
@@ -4,6 +4,16 @@ namespace TeamCitySharp.DomainEntities
{
public class Properties
{
+ public Properties()
+ {
+ Property = new List();
+ }
+
+ public void Add(string name, string value)
+ {
+ Property.Add(new Property(name, value));
+ }
+
public override string ToString()
{
return "properties";
diff --git a/src/TeamCitySharp/DomainEntities/Property.cs b/src/TeamCitySharp/DomainEntities/Property.cs
index 70f3cb25..d2dadab0 100644
--- a/src/TeamCitySharp/DomainEntities/Property.cs
+++ b/src/TeamCitySharp/DomainEntities/Property.cs
@@ -2,6 +2,15 @@ namespace TeamCitySharp.DomainEntities
{
public class Property
{
+ public Property()
+ {}
+
+ public Property(string name, string value)
+ {
+ Name = name;
+ Value = value;
+ }
+
public override string ToString()
{
return Name;
diff --git a/src/TeamCitySharp/DomainEntities/SnapshotDependency.cs b/src/TeamCitySharp/DomainEntities/SnapshotDependency.cs
index 6f0cfe50..abde4502 100644
--- a/src/TeamCitySharp/DomainEntities/SnapshotDependency.cs
+++ b/src/TeamCitySharp/DomainEntities/SnapshotDependency.cs
@@ -1,13 +1,42 @@
+using JsonFx.Json;
+
namespace TeamCitySharp.DomainEntities
{
public class SnapshotDependency
{
+ public SnapshotDependency()
+ {
+ Properties = new Properties();
+ Type = "snapshot_dependency";
+ }
+
public override string ToString()
{
- return "snapshot_dependency";
+ return Type;
}
public string Id { get; set; }
- public Properties Properties { get; set; }
+ public Properties Properties { get; set; }
+ [JsonName("source-buildType")]
+ public SourceBuildType SourceBuildType { get; set; }
+ public string Type { get; set; }
+
+ public static SnapshotDependency Default(string dependsOnbuildId)
+ {
+ var dependency = new SnapshotDependency();
+
+ dependency.Properties.Add("run-build-if-dependency-failed", "RUN_ADD_PROBLEM");
+ dependency.Properties.Add("run-build-if-dependency-failed-to-start", "MAKE_FAILED_TO_START");
+ dependency.Properties.Add("run-build-on-the-same-agent", "false");
+ dependency.Properties.Add("take-started-build-with-same-revisions", "true");
+ dependency.Properties.Add("take-successful-builds-only", "true");
+
+ dependency.SourceBuildType = new SourceBuildType
+ {
+ Id = dependsOnbuildId
+ };
+
+ return dependency;
+ }
}
}
\ 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..e5c1f89f
--- /dev/null
+++ b/src/TeamCitySharp/DomainEntities/SourceBuildType.cs
@@ -0,0 +1,7 @@
+namespace TeamCitySharp.DomainEntities
+{
+ public class SourceBuildType
+ {
+ public string Id { get; set; }
+ }
+}
diff --git a/src/TeamCitySharp/Locators/ProjectLocator.cs b/src/TeamCitySharp/Locators/ProjectLocator.cs
new file mode 100644
index 00000000..5291db9c
--- /dev/null
+++ b/src/TeamCitySharp/Locators/ProjectLocator.cs
@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+
+namespace TeamCitySharp.Locators
+{
+ public class ProjectLocator
+ {
+ public static ProjectLocator WithId(string id)
+ {
+ return new ProjectLocator {Id = id};
+ }
+
+ public static ProjectLocator WithName(string name)
+ {
+ return new ProjectLocator {Name = name};
+ }
+
+ public string Id { get; set; }
+ public string Name { get; set; }
+
+ public override string ToString()
+ {
+ if (!string.IsNullOrEmpty(Id))
+ {
+ return "id:" + Id;
+ }
+
+ if (!string.IsNullOrEmpty(Name))
+ {
+ return "name:" + Name;
+ }
+
+
+ var locatorFields = new List();
+
+ return string.Join(",", locatorFields.ToArray());
+ }
+ }
+}
diff --git a/src/TeamCitySharp/TeamCitySharp.csproj b/src/TeamCitySharp/TeamCitySharp.csproj
index 2e7df5aa..55d3469d 100644
--- a/src/TeamCitySharp/TeamCitySharp.csproj
+++ b/src/TeamCitySharp/TeamCitySharp.csproj
@@ -67,6 +67,10 @@
+
+
+
+
diff --git a/src/Tests/IntegrationTests/SampleBuildsUsage.cs b/src/Tests/IntegrationTests/SampleBuildsUsage.cs
index 152cad5f..daa77e2e 100644
--- a/src/Tests/IntegrationTests/SampleBuildsUsage.cs
+++ b/src/Tests/IntegrationTests/SampleBuildsUsage.cs
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Net;
+using System.Runtime.CompilerServices;
using NUnit.Framework;
using TeamCitySharp.Locators;
@@ -190,5 +191,18 @@ public void it_does_not_populate_the_status_text_field_of_the_build_object()
Assert.That(build.Count == 1);
Assert.IsNull(build[0].StatusText);
}
+
+ [Test]
+ public void ig_returns_correct_build_when_calling_by_id()
+ {
+ const string buildId = "5726";
+ var client = new TeamCityClient("localhost:81");
+ client.Connect("admin", "qwerty");
+
+ var build = client.Builds.ById(buildId);
+
+ Assert.That(build != null);
+ Assert.That(build.Id == buildId);
+ }
}
}