How do I share a label value between multiple CruiseControl.NET builds?

后端 未结 3 1369
Happy的楠姐
Happy的楠姐 2021-01-03 03:30

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 Cr

相关标签:
3条回答
  • 2021-01-03 03:47

    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.

    0 讨论(0)
  • 2021-01-03 03:50

    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

    0 讨论(0)
  • 2021-01-03 04:12

    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>
      
      


    0 讨论(0)
提交回复
热议问题