diff --git a/project/UnitTests/Core/Label/CustomLabellerTest.cs b/project/UnitTests/Core/Label/CustomLabellerTest.cs
new file mode 100644
index 000000000..b63096aa2
--- /dev/null
+++ b/project/UnitTests/Core/Label/CustomLabellerTest.cs
@@ -0,0 +1,92 @@
+using Exortech.NetReflector;
+using NUnit.Framework;
+using ThoughtWorks.CruiseControl.Core.Label;
+
+namespace ThoughtWorks.CruiseControl.UnitTests.Core.Label
+{
+ [TestFixture]
+ public class CustomLabellerTest : IntegrationFixture
+ {
+ private CustomLabeller labeller;
+
+ private string exampleCode = @"
+
+ if (
+ integrationResult != null
+ && integrationResult.LastIntegration != null
+ && !integrationResult.LastIntegration.IsInitial()
+ )
+ {
+ if (integrationResult.LastIntegration.Status == ThoughtWorks.CruiseControl.Remote.IntegrationStatus.Success)
+ {
+ System.Version lastVersion = System.Version.Parse(integrationResult.LastIntegration.Label);
+ System.Version nextVersion = new System.Version(lastVersion.Major, lastVersion.Minor, lastVersion.Build, lastVersion.Revision + 1);
+ ret = nextVersion.ToString();
+ }
+ else
+ {
+ ret = integrationResult.LastIntegration.Label;
+ }
+ }
+ else
+ {
+ ret = new System.Version(1, 1, 1, 1).ToString();
+ }
+
+
+";
+
+ [SetUp]
+ public void SetUp()
+ {
+ labeller = new CustomLabeller();
+ }
+
+ [Test]
+ public void GenerateInitialLabelWoCode()
+ {
+ Assert.AreEqual("0.0.0.0", labeller.Generate(InitialIntegrationResult()));
+ }
+
+ [Test]
+ public void GenerateLabelWoCode()
+ {
+ Assert.AreEqual("0.0.0.0", labeller.Generate(SuccessfulResult("35")));
+ }
+
+ [Test]
+ public void GenerateNextLabel()
+ {
+ labeller.CsCode = @"ret = ""somelabel"";";
+ Assert.AreEqual("somelabel", labeller.Generate(SuccessfulResult("previouslabel")));
+ }
+
+ [Test]
+ public void GenerateInitialLabel()
+ {
+ labeller.CsCode = @"ret = ""somelabel"";";
+ Assert.AreEqual("somelabel", labeller.Generate(SuccessfulResult("previouslabel")));
+ }
+
+ [Test]
+ public void GenerateInitialLabelWithExampleCode()
+ {
+ labeller.CsCode = exampleCode;
+ Assert.AreEqual("1.1.1.1", labeller.Generate(InitialIntegrationResult()));
+ }
+
+ [Test]
+ public void GenerateNextLabelWithExampleCode()
+ {
+ labeller.CsCode = exampleCode;
+ Assert.AreEqual("1.2.3.5", labeller.Generate(SuccessfulResult("1.2.3.4")));
+ }
+
+ [Test]
+ public void GenerateSameLabelWithExampleCode()
+ {
+ labeller.CsCode = exampleCode;
+ Assert.AreEqual("1.2.3.4", labeller.Generate(FailedResult("1.2.3.4")));
+ }
+ }
+}
diff --git a/project/UnitTests/UnitTests.csproj b/project/UnitTests/UnitTests.csproj
index 06a1f2db0..ccdbdfd4b 100644
--- a/project/UnitTests/UnitTests.csproj
+++ b/project/UnitTests/UnitTests.csproj
@@ -376,6 +376,7 @@
+
diff --git a/project/core/core.csproj b/project/core/core.csproj
index 6431d5c55..77cf18bb8 100644
--- a/project/core/core.csproj
+++ b/project/core/core.csproj
@@ -372,6 +372,7 @@
Code
+
Code
diff --git a/project/core/label/CustomLabeller.cs b/project/core/label/CustomLabeller.cs
new file mode 100644
index 000000000..de7f14658
--- /dev/null
+++ b/project/core/label/CustomLabeller.cs
@@ -0,0 +1,135 @@
+using System;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Exortech.NetReflector;
+using ThoughtWorks.CruiseControl.Remote;
+using System.Globalization;
+using Microsoft.CSharp;
+using System.CodeDom.Compiler;
+using System.Reflection;
+
+namespace ThoughtWorks.CruiseControl.Core.Label
+{
+ ///
+ ///
+ /// Allows CCNet create custom code-generated labels
+ ///
+ ///
+ /// You can do this by specifying your own configuration of the default labeller in your project.
+ ///
+ ///
+ ///
Custom Labeller
+ /// 1.0
+ ///
+ ///
+ /// <labeller type="customlabeller">
+ /// <cscode>1</cscode>
+ /// </labeller>
+ ///
+ ///
+ [ReflectorType("customlabeller")]
+ public class CustomLabeller
+ : LabellerBase
+ {
+ ///
+ /// Generates the specified integration result.
+ ///
+ /// The integration result.
+ ///
+ ///
+ public override string Generate(IIntegrationResult integrationResult)
+ {
+ MethodInfo method = this.CreateFunction(this.CsCode);
+ string ret = (string)method.Invoke(null, new object[1] { integrationResult });
+ return ret;
+ }
+
+ [ReflectorProperty("usings", Required = false)]
+ public string Usings { get; set; }
+
+ [ReflectorProperty("referencedassemblies", Required = false)]
+ public string ReferencedAssemblies { get; set; }
+
+ [ReflectorProperty("cscode", Required = true)]
+ public string CsCode { get; set; }
+
+ private string CSCodeWrapper
+ {
+ get
+ {
+ return @"
+
+using System;
+using ThoughtWorks.CruiseControl.Core;
+using ThoughtWorks.CruiseControl.Remote;
+
+namespace CustomLabelerGeneratorUserFunctions
+{
+ public class CustomLabelerGenerator
+ {
+ public static string Generate(ThoughtWorks.CruiseControl.Core.IIntegrationResult integrationResult)
+ {
+ string ret = ""0.0.0.0"";
+
+ return ret;
+ }
+ }
+}
+";
+ }
+ }
+
+ public MethodInfo CreateFunction(string function)
+ {
+ System.Text.StringBuilder usings = new System.Text.StringBuilder();
+ if (!string.IsNullOrWhiteSpace(this.Usings))
+ {
+ foreach (var each in this.Usings.Split(';'))
+ {
+ if (!string.IsNullOrWhiteSpace(each))
+ {
+ usings.AppendFormat("using {0};", each);
+ usings.AppendLine();
+ }
+ }
+ }
+
+ string finalCode = usings.ToString() + CSCodeWrapper.Replace("", function);
+
+ CSharpCodeProvider provider = new CSharpCodeProvider();
+ var parameters = new CompilerParameters();
+ parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
+ parameters.ReferencedAssemblies.Add(typeof(ThoughtWorks.CruiseControl.Remote.IntegrationStatus).Assembly.Location);
+ if (!string.IsNullOrWhiteSpace(this.ReferencedAssemblies))
+ {
+ foreach (var each in this.ReferencedAssemblies.Split(';'))
+ {
+ if (!string.IsNullOrWhiteSpace(each))
+ {
+ parameters.ReferencedAssemblies.Add(each);
+ }
+ }
+ }
+
+ parameters.GenerateInMemory = true;
+ parameters.GenerateExecutable = false;
+ parameters.IncludeDebugInformation = false;
+ CompilerResults results = provider.CompileAssemblyFromSource(parameters, finalCode);
+ if (results.Errors != null && results.Errors.Count > 0)
+ {
+ var path = System.IO.Path.GetTempFileName();
+ System.IO.File.WriteAllText(path, finalCode);
+ foreach (var each in results.Errors)
+ {
+ Console.WriteLine("ERROR in {0}: {1}", path, each);
+ }
+
+ throw new ApplicationException("There are compilation errors. Please see " + path);
+ }
+
+
+ Type binaryFunction = results.CompiledAssembly.GetType("CustomLabelerGeneratorUserFunctions.CustomLabelerGenerator");
+ return binaryFunction.GetMethod("Generate");
+ }
+ }
+}
diff --git a/project/core/sourcecontrol/Git.cs b/project/core/sourcecontrol/Git.cs
index c07f0ead0..b3827e9ea 100644
--- a/project/core/sourcecontrol/Git.cs
+++ b/project/core/sourcecontrol/Git.cs
@@ -231,6 +231,15 @@ public class Git : ProcessSourceControl
[ReflectorProperty("commitUntrackedFiles", Required = false)]
public bool CommitUntrackedFiles { get; set; }
+ ///
+ /// Indicates that files committed during the build process should be pushed to remmote repository after tagging. This requires 'commitBuildModifications'
+ /// and 'pushCommitedOnSuccess' to be set to 'true'.
+ ///
+ /// 1.6
+ /// false
+ [ReflectorProperty("pushCommitedOnSuccess", Required = false)]
+ public bool PushCommitedOnSuccess { get; set; }
+
///
/// Used to set the "user.name" configuration setting in the local repository. Required for the 'tagOnSuccess ' feature.
///
@@ -366,6 +375,11 @@ public override void LabelSourceControl(IIntegrationResult result)
// create a tag and push it.
GitCreateTag(tagName, commitMessage, result);
GitPushTag(tagName, result);
+
+ if (CommitBuildModifications && PushCommitedOnSuccess)
+ {
+ GitPushAll(result);
+ }
}
#region private methods
@@ -754,6 +768,30 @@ private void GitPushTag(string tagName, IIntegrationResult result)
ProcessExecutor.ProcessOutput -= ProcessExecutor_ProcessOutput;
}
+ ///
+ /// Push commited content with "git push origin HEAD:'branch name'".
+ ///
+ /// IIntegrationResult of the current build.
+ private void GitPushAll(IIntegrationResult result)
+ {
+ ProcessArgumentBuilder buffer = new ProcessArgumentBuilder();
+ buffer.AddArgument("push");
+ buffer.AddArgument("origin");
+ buffer.AddArgument("HEAD:"+ Branch);
+
+ // initialize progress information
+ var bpi = GetBuildProgressInformation(result);
+ bpi.SignalStartRunTask(string.Concat("git ", buffer.ToString()));
+
+ // enable Stdout monitoring
+ ProcessExecutor.ProcessOutput += ProcessExecutor_ProcessOutput;
+
+ Execute(NewProcessInfo(buffer.ToString(), result));
+
+ // remove Stdout monitoring
+ ProcessExecutor.ProcessOutput -= ProcessExecutor_ProcessOutput;
+ }
+
///
/// Initialize the git submodules.
///