如何在多个CruiseControl.NET构建之间共享标签值?

时间:2009-11-10 09:20:49

标签: build build-automation cruisecontrol.net versioning ccnet-config

我在CruiseControl.NET中设置了两个项目:CI构建和每晚构建。

它们都执行相同的NAnt脚本,但参数不同。

CruiseControl.NET标签(当前由 DefaultLabeler 生成)作为版本的构建部分嵌入到AssemblyInfo中(例如, MajorVersion.MinorVersion.CCNET_Label.SVN_Revision )。

对于更一致的版本控制,我希望两个项目共享相同的CruiseControl.NET标签值。

我已经调查了作为CruiseControl.NET安装的一部分提供的贴标机,但我找不到能满足我想要的标签。

如何在多个CruiseControl.NET构建之间共享标签值?
如果有更好的方法,我想知道。

我发现了一种方法。请参阅下面的答案。

3 个答案:

答案 0 :(得分:9)

我找不到能够做我需要的现有解决方案,所以我最终编写了一个自定义的CruiseControl.NET贴标机。

以下是它的完成方式:

        
  1. 创建一个新项目。这将被CC.NET作为插件库使用
  2.     
  3. 输出DLL的名称需要匹配* ccnet。\ *。CruiseControl.plugin *。去项目 属性并将“程序集名称”更改为* ccnet。<在此处插入名称> .CruiseControl.plugin *

  4.     
  5. 在您的项目中,添加对CC.NET服务器安装目录中找到的三个程序集的引用(默认为:C:\ Program Files \ CruiseControl.NET \ server):         
                  
    • NetReflector.dll
    •             
    • ThoughtWorks.CruiseControl.Core.dll
    •             
    • ThoughtWorks.CruiseControl.Remote.dll
    •         
            
        
  6.     
  7. 创建一个新的公共类,例如:
    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)
     }
    }
    


  8.     
  9. 编译项​​目并将DLL复制到CC.NET服务器安装目录(默认为:C:\ Program Files \ CruiseControl.NET \ server)

  10.     
  11. 重新启动CC.NET Windows服务

  12.     
  13. 创建一个文本文件以存储当前的内部版本号

  14.     
  15. 将新贴标机添加到ccnet.config文件中的项目定义中:
        <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