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

发布于 2024-08-10 20:58:52 字数 432 浏览 9 评论 0原文

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

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

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

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

我研究了作为 CruiseControl.NET 安装的一部分提供的贴标机,但我找不到能够满足我要求的贴标机。

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

我找到了办法。请参阅下面我的回答。

I have two projects set up in CruiseControl.NET: CI build and nightly build.

Both of them execute the same NAnt script, but with different parameters.

The CruiseControl.NET label (currently generated by the DefaultLabeler) is embedded into AssemblyInfo as the build part of the version (for example, MajorVersion.MinorVersion.CCNET_Label.SVN_Revision).

For more consistent versioning I would like both projects to share the same CruiseControl.NET label value.

I have investigated the labelers that are available as part of the CruiseControl.NET installation, but I could not find one that does what I want.

How do I share a label value between multiple CruiseControl.NET builds?
If there is a better way to do this, I would like to know.

I found a way. See my answer below.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

热血少△年 2024-08-17 20:58:52

我找不到满足我需要的现有解决方案,因此我最终编写了一个自定义 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("syncronizationFilePath", 必需 = true)]
     公共字符串 SynchronizationFilePath { 获取;放; }
    
     #region ILabeller 成员
    
     公共字符串生成(IIntegrationResult previousResult)
     {
      if (ShouldIncrementLabel(前一个结果))
       返回增量标签();
    
      if (previousResult.Status == IntegrationStatus.Unknown)
       返回“0”;
    
      返回上一个结果.标签;
     }
    
     公共无效运行(IIntegrationResult结果)
     {
      结果.标签=生成(结果);
     }
    
     #endregion
    
     私有字符串 IncrementLabel()
     {
      if(!File.Exists(同步文件路径))
       返回“0”;
    
      使用 (FileStream fileStream = File.Open(SynchronizationFilePath,
           文件模式.OpenOrCreate,
           文件访问.ReadWrite,
           文件共享。无))
       {
        // 从文件中读取最后一个版本号
        var bytes = new byte[fileStream.Length];
        fileStream.Read(字节, 0, 字节.长度);
    
        字符串 rawBuildNumber = Encoding.ASCII.GetString(bytes);
    
        // 解析最后的构建号
        int previousBuildNumber = int.Parse(rawBuildNumber);
        int newBuildNumber = previousBuildNumber + 1;
    
        // 增加构建号并写回文件
        字节 = Encoding.ASCII.GetBytes(newBuildNumber.ToString());
    
        fileStream.Seek(0, SeekOrigin.Begin);
        fileStream.Write(字节, 0, 字节. 长度);
    
        返回 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 文件中的项目定义中:
     <贴标机类型=“sharedLabeller”>
            C:\Program Files\CruiseControl.NET\server\shared\buildnumber.txt
    
        
    
    
    

I could not find an existing solution that to do what I needed, so I ended up writing a custom CruiseControl.NET labeller.

Here's how it is done:

  1. Create a new project. This will be used as a plugin library by CC.NET
  2. The name of the output DLL needs to match *ccnet.\*.CruiseControl.plugin*. Go to project
    properties and change "Assembly name" to *ccnet.<insert name here>.CruiseControl.plugin*

  3. In your project, add references to the three assemblies found in the CC.NET server installation directory (default is: C:\Program Files\CruiseControl.NET\server):
    • NetReflector.dll
    • ThoughtWorks.CruiseControl.Core.dll
    • ThoughtWorks.CruiseControl.Remote.dll

  4. Create a new public class such as this:
    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)
     }
    }
    
  5. Compile your project and copy the DLL to CC.NET server installation directory (default is: C:\Program Files\CruiseControl.NET\server)
  6. Restart CC.NET Windows service
  7. Create a text file to store the current build number
  8. Add the new labeler to you project definition in ccnet.config file:
        <labeller type="sharedLabeller">
            <syncronisationFilePath>C:\Program Files\CruiseControl.NET\server\shared\buildnumber.txt</syncronisationFilePath>
    <incrementOnFailure>false</incrementOnFailure>
        </labeller>
    
    
囍笑 2024-08-17 20:58:52

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

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

I ran into the same issue, but I found that using the <stateFileLabeller> in conjunction with the <assemblyVersionLabeller> proved to be a much simpler solution.

The only gotcha about using the stateFileLabeller is that you can't specify a directory for your state files in a project, because CruiseControl.NET won't find it. I left it in the default directory, and it works great.

你是暖光i 2024-08-17 20:58:52

我修改了 Arnold 类,使其更像是默认标签器的复制品:

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 存储库文件夹

I've modified the class Arnold made making it more of a replica of the 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;
        }
    }
}

The benefit should be that you now can specify prefix as well as "incrementonfailure". Also I've added a "increment" property that can be used for deployment builds that should not increment the build number at all. If you want to modify it yourself I would advise to have a look at their implementations:
CruiseControl.NET repository folder containing labellers

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文