我在CruiseControl.NET中设置了两个项目:CI构建和每晚构建。
它们都执行相同的NAnt脚本,但参数不同。
CruiseControl.NET标签(当前由 DefaultLabeler 生成)作为版本的构建部分嵌入到AssemblyInfo中(例如, MajorVersion.MinorVersion.CCNET_Label.SVN_Revision )。
对于更一致的版本控制,我希望两个项目共享相同的CruiseControl.NET标签值。
我已经调查了作为CruiseControl.NET安装的一部分提供的贴标机,但我找不到能满足我想要的标签。
如何在多个CruiseControl.NET构建之间共享标签值?
如果有更好的方法,我想知道。
答案 0 :(得分:9)
我找不到能够做我需要的现有解决方案,所以我最终编写了一个自定义的CruiseControl.NET贴标机。
以下是它的完成方式:
using ThoughtWorks.CruiseControl.Core; using ThoughtWorks.CruiseControl.Remote; // this is the labeller name that will be used in ccnet.config [ReflectorType("customLabeller")] public class CustomLabeller : ILabeller { [ReflectorProperty("syncronisationFilePath", Required = true)] public string SyncronisationFilePath { get; set; } #region ILabeller Members public string Generate(IIntegrationResult previousResult) { if (ShouldIncrementLabel(previousResult)) return IncrementLabel(); if (previousResult.Status == IntegrationStatus.Unknown) return "0"; return previousResult.Label; } public void Run(IIntegrationResult result) { result.Label = Generate(result); } #endregion private string IncrementLabel() { if(!File.Exists(SyncronisationFilePath)) return "0"; using (FileStream fileStream = File.Open(SyncronisationFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { // read last build number from file var bytes = new byte[fileStream.Length]; fileStream.Read(bytes, 0, bytes.Length); string rawBuildNumber = Encoding.ASCII.GetString(bytes); // parse last build number int previousBuildNumber = int.Parse(rawBuildNumber); int newBuildNumber = previousBuildNumber + 1; // increment build number and write back to file bytes = Encoding.ASCII.GetBytes(newBuildNumber.ToString()); fileStream.Seek(0, SeekOrigin.Begin); fileStream.Write(bytes, 0, bytes.Length); return newBuildNumber.ToString(); } } private static bool ShouldIncrementLabel(IIntegrationResult previousResult) { return (previousResult.Status == IntegrationStatus.Success || previousResult.Status == IntegrationStatus.Unknown) } }
<labeller type="sharedLabeller"> <syncronisationFilePath>C:\Program Files\CruiseControl.NET\server\shared\buildnumber.txt</syncronisationFilePath> <incrementOnFailure>false</incrementOnFailure> </labeller>
答案 1 :(得分:3)
我遇到了同样的问题,但我发现将<stateFileLabeller>
与<assemblyVersionLabeller>
结合使用证明是一个更简单的解决方案。
使用stateFileLabeller的唯一问题是,您无法在项目中为状态文件指定目录,因为CruiseControl.NET无法找到它。我将它保留在默认目录中,效果很好。
答案 2 :(得分:3)
我修改了Arnold这个类,使它更像是defaultlabeller的副本:
using System.IO;
using System.Text;
using Exortech.NetReflector;
using ThoughtWorks.CruiseControl.Core;
using ThoughtWorks.CruiseControl.Remote;
// This namespace could be altered and several classes could be put into the same if you'd want to combine several plugins in one dll
namespace ccnet.SharedLabeller.CruiseControl.plugin
{
[ReflectorType("sharedLabeller")]
public class SharedLabeller : ILabeller
{
/// <summary>
/// The path where the file that holds the shared label should be located
/// </summary>
/// <default>none</default>
[ReflectorProperty("sharedLabelFilePath", Required = true)]
public string SharedLabelFilePath { get; set; }
/// <summary>
/// Any string to be put in front of all labels.
/// </summary>
[ReflectorProperty("prefix", Required = false)]
public string Prefix { get; set; }
/// <summary>
/// If true, the label will be incremented even if the build fails. Otherwise it will only be incremented if the build succeeds.
/// </summary>
[ReflectorProperty("incrementOnFailure", Required = false)]
public bool IncrementOnFailure { get; set; }
/// <summary>
/// If false, the label will never be incremented when this project is builded. This is usefull for deployment builds that
/// should use the last successfull of two or more builds
/// </summary>
[ReflectorProperty("increment", Required = false)]
public bool Increment { get; set; }
/// <summary>
/// Allows you to set the initial build number.
/// This will only be used when on the first build of a project, meaning that when you change this value,
/// you'll have to stop the CCNet service and delete the state file.
/// </summary>
/// <default>0</default>
[ReflectorProperty("initialBuildLabel", Required = false)]
public int InitialBuildLabel { get; set; }
public SharedLabeller()
{
IncrementOnFailure = false;
Increment = true;
InitialBuildLabel = 0;
}
#region ILabeller Members
public string Generate(IIntegrationResult integrationResult)
{
if (ShouldIncrementLabel(integrationResult.LastIntegration))
{
return Prefix + this.GetLabel();
}
else
{
return integrationResult.LastIntegration.Label;
}
}
public void Run(IIntegrationResult integrationResult)
{
integrationResult.Label = Generate(integrationResult);
}
#endregion
/// <summary>
/// Get and increments the label, unless increment is false then it only gets the label
/// </summary>
/// <returns></returns>
private string GetLabel()
{
ThoughtWorks.CruiseControl.Core.Util.Log.Debug("About to read label file. Filename: {0}", SharedLabelFilePath);
using (FileStream fileStream = File.Open(this.SharedLabelFilePath,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None))
{
// Read last build number from file
var bytes = new byte[fileStream.Length];
fileStream.Read(bytes, 0, bytes.Length);
string rawBuildNumber = Encoding.UTF8.GetString(bytes);
// Parse last build number
int previousBuildNumber;
if (!int.TryParse(rawBuildNumber, out previousBuildNumber))
{
previousBuildNumber = InitialBuildLabel - 1;
}
if (!Increment)
{
return previousBuildNumber.ToString();
}
int newBuildNumber = previousBuildNumber + 1;
// Increment build number and write back to file
bytes = Encoding.UTF8.GetBytes(newBuildNumber.ToString());
fileStream.Seek(0, SeekOrigin.Begin);
fileStream.Write(bytes, 0, bytes.Length);
return newBuildNumber.ToString();
}
}
private bool ShouldIncrementLabel(IntegrationSummary integrationSummary)
{
return integrationSummary == null || integrationSummary.Status == IntegrationStatus.Success || IncrementOnFailure;
}
}
}
好处应该是您现在可以指定前缀以及“incrementonfailure”。此外,我添加了一个“increment”属性,可用于部署版本,根本不应增加版本号。如果您想自己修改它,我建议您查看它们的实现: CruiseControl.NET repository folder containing labellers