5

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

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

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

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

我调查了可作为 CruiseControl.NET 安装的一部分使用的标签器,但我找不到可以满足我需求的标签器。

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

我找到了一个方法。请看下面我的回答。

4

3 回答 3

9

我找不到可以满足我需求的现有解决方案,因此我最终编写了一个自定义 CruiseControl.NET 贴标机。

这是如何完成的:

  1. 创建一个新项目。这将被 CC.NET 用作插件库

  2. 输出 DLL 的名称需要匹配 *ccnet.\*.CruiseControl.plugin*。转到项目属性并将“程序集名称”更改为 *ccnet.<在此处插入名称>.CruiseControl.plugin*

  3. 在您的项目中,添加对 CC.NET 服务器安装目录中的三个程序集的引用(默认为:C:\Program Files\CruiseControl.NET\server):
    • NetReflector.dll
    • ThoughtWorks.CruiseControl.Core.dll
    • ThoughtWorks.CruiseControl.Remote.dll

  4. 创建一个新的公共类,例如:
    使用 ThoughtWorks.CruiseControl.Core;
    使用 ThoughtWorks.CruiseControl.Remote;
    
    // 这是将在 ccnet.config 中使用的贴标机名称
    [ReflectorType("customLabeller")]
    公共类 CustomLabeller : ILabeller
    {
     [ReflectorProperty("syncronisationFilePath", 必需 = true)]
     公共字符串 SyncronisationFilePath { 获取;放; }
    
     #region ILabeller 成员
    
     公共字符串生成(IIntegrationResult previousResult)
     {
      if (ShouldIncrementLabel(previousResult))
       返回增量标签();
    
      如果(previousResult.Status == IntegrationStatus.Unknown)
       返回“0”;
    
      返回上一个结果。标签;
     }
    
     公共无效运行(IIntegrationResult 结果)
     {
      result.Label = 生成(结果);
     }
    
     #endregion
    
     私有字符串 IncrementLabel()
     {
      如果(!File.Exists(同步文件路径))
       返回“0”;
    
      使用 (FileStream fileStream = File.Open(SyncronisationFilePath,
           FileMode.OpenOrCreate,
           FileAccess.ReadWrite,
           文件共享。无))
       {
        // 从文件中读取最后的内部版本号
        var bytes = new byte[fileStream.Length];
        fileStream.Read(bytes, 0, bytes.Length);
    
        string rawBuildNumber = Encoding.ASCII.GetString(bytes);
    
        // 解析最后的构建号
        int previousBuildNumber = int.Parse(rawBuildNumber);
        int newBuildNumber = previousBuildNumber + 1;
    
        // 增加内部版本号并写回文件
        bytes = Encoding.ASCII.GetBytes(newBuildNumber.ToString());
    
        fileStream.Seek(0, SeekOrigin.Begin);
        fileStream.Write(bytes, 0, bytes.Length);
    
        返回 newBuildNumber.ToString();
       }
     }
    
     私有静态 bool ShouldIncrementLabel(IIntegrationResult previousResult)
     {
      返回(previousResult.Status == IntegrationStatus.Success ||
        previousResult.Status == IntegrationStatus.Unknown)
     }
    }
    


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

  6. 重启 CC.NET Windows 服务

  7. 创建一个文本文件来存储当前的内部版本号

  8. 将新标签器添加到 ccnet.config 文件中的项目定义中:
        <labeller type="sharedLabeller">
            <syncronisationFilePath>C:\Program Files\CruiseControl.NET\server\shared\buildnumber.txt</syncronisationFilePath>
    <incrementOnFailure>假</incrementOnFailure>
        </labeller>
    
    


于 2009-11-10T14:25:41.653 回答
3

我遇到了同样的问题,但我发现使用<stateFileLabeller>与 the 结合使用被<assemblyVersionLabeller>证明是一个更简单的解决方案。

使用 stateFileLabeller 的唯一问题是您不能为项目中的状态文件指定目录,因为 CruiseControl.NET 不会找到它。我把它放在默认目录中,效果很好。

于 2010-03-23T17:14:42.473 回答
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”。此外,我还添加了一个“增量”属性,可用于部署构建,它根本不应该增加构建号。如果你想自己修改它,我建议你看看他们的实现: CruiseControl.NET repository folder contains labellers

于 2013-05-16T11:09:57.970 回答