I'm setting up an Azure Pipelines build that needs to package a C# .NET class library into a NuGet package.
In this documentation, it lists a couple different ways to automatically generate SemVer strings. In particular, I want to implement this one:
$(Major).$(Minor).$(rev:.r), where Major and Minor are two variables
defined in the build pipeline. This format will automatically
increment the build number and the package version with a new patch
number. It will keep the major and minor versions constant, until you
change them manually in the build pipeline.
But that's all they say about it, no example is provided. A link to learn more takes you to this documentation, where it says this:
For byBuildNumber, the version will be set to the build number, ensure
that your build number is a proper SemVer e.g. 1.0.$(Rev:r). If you
select byBuildNumber, the task will extract a dotted version, 1.2.3.4
and use only that, dropping any label. To use the build number as is,
you should use byEnvVar as described above, and set the environment
variable to BUILD_BUILDNUMBER.
Again, no example is provided. It looks like I want to use versioningScheme: byBuildNumber, but I'm not quite sure how to set the build number, I think it pulls it from the BUILD_BUILDNUMBER environment variable, but I can't find a way to set environment variables, only script variables. Furthermore, am I suppose to just set that to 1.0.$(Rev:r), or to $(Major).$(Minor).$(rev:.r)? I'm afraid that would just interpret it literally.
Googling for the literal string "versioningScheme: byBuildNumber" returns a single result... Does anyone have a working azure-pipelines.yml with this versioning scheme?
Working YAML example for Packaging/Versioning using byBuildNumber
NOTE the second parameter of the counter - it is a seed value, really useful when migrating builds from other build systems like TeamCity; It allows you to set the next build version explicitly upon migration. After the migration and initial build in Azure DevOps, the seed value can be set back to zero or whatever start value (like 100) you may prefer every time majorMinorVersion is changed:
reference: counter expression
name: $(majorMinorVersion).$(semanticVersion) # $(rev:r) # NOTE: rev resets when the default retention period expires
pool:
vmImage: 'vs2017-win2016'
# pipeline variables
variables:
majorMinorVersion: 1.0
# semanticVersion counter is automatically incremented by one in each execution of pipeline
# second parameter is seed value to reset to every time the referenced majorMinorVersion is changed
semanticVersion: $[counter(variables['majorMinorVersion'], 0)]
projectName: 'MyProjectName'
buildConfiguration: 'Release'
# Only run against master
trigger:
- master
# Build
- task: DotNetCoreCLI#2
displayName: Build
inputs:
projects: '**/*.csproj'
arguments: '--configuration $(BuildConfiguration)'
# Package
- task: DotNetCoreCLI#2
displayName: 'NuGet pack'
inputs:
command: 'pack'
configuration: $(BuildConfiguration)
packagesToPack: '**/$(ProjectName)*.csproj'
packDirectory: '$(build.artifactStagingDirectory)'
versioningScheme: byBuildNumber # https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/build/dotnet-core-cli?view=azure-devops#yaml-snippet
# Publish
- task: DotNetCoreCLI#2
displayName: 'Publish'
inputs:
command: 'push'
nuGetFeedType: 'internal'
packagesToPush: '$(build.artifactStagingDirectory)/$(ProjectName)*.nupkg'
publishVstsFeed: 'MyPackageFeedName'
byBuildNumber uses the build number you define in your YAML with the name field.
Ex: name: $(Build.DefinitionName)-$(date:yyyyMMdd)$(rev:.r)
So if you set your build format to name: 1.0.$(rev:.r), it should work as you expect.
I had the similar issue and now let me make it clear.
Firstly, what is the definition of Build Number?
By the official document of Azure Pipeline YAML scheme, it is
name: string # build numbering format
resources:
containers: [ containerResource ]
repositories: [ repositoryResource ]
variables: { string: string } | [ variable | templateReference ]
trigger: trigger
pr: pr
stages: [ stage | templateReference ]
Look at the first line:
name: string # build numbering format
Yes, that's it!
So you could define it like
name: 1.0.$(Rev:r)
if you prefer to Semantic Versioning. Then
Secondly, what's the meaning of versioningScheme: 'byBuildNumber' in task NuGetCommand#2?
It's really straightforward: just use the format defined by name!
Last but not least
The official document on Package Versioning and Pack NuGet packages don't make it clear that what a build number really is and how to define it. It's really misleading. And I'm so sad as an MS employee as I'd to resort to external resource to make all that clear.
Azure Pipeline Nuget Package Versioning Scheme, How to Get “1.0.$(Rev:r)”
This should be a issue in the documentation. I reproduced this issue when I set $(Major).$(Minor).$(rev:.r) in the Build number format in the Options of build pipeline:
However, I suddenly noticed that the build number is not correct with that format after many build tests:
There are two points . between 0 and 2 (Open above image in a new tab). Obviously this is very strange. So, I changed the Build number format to:
$(Major).$(Minor)$(rev:.r)
Or
$(Major).$(Minor).$(rev:r)
Now, everything is working fine.
As test, I just set the Build number format to $(rev:.r), and the build number is .x. So, we could confirm that the value of $(rev:.r) including the . by default.
Note: Since where Major and Minor are two variables defined in the build pipeline, so we need defined them in the variables manually.
Hope this helps.
Issues
My issues:
when trying the answer by #Emil, my first package started at 2.0 (I did no further testing to investigate)
when trying the answer by #Leo Liu-MSFT, I was unable to find the matching "Options" tab.
I therefore used this solution by #LanceMcCarthy.
Fix
Set the variables:
variables:
major: '1'
minor: '0'
revision: $[counter(variables['minor'], 1)] # This will get reset every time minor gets bumped.
nugetVersion: '$(major).$(minor).$(revision)'
then use nugetVersion as an environment variable when packing:
- task: NuGetCommand#2
inputs:
command: 'pack'
packagesToPack: '**/*.csproj'
packDestination: '$(Build.ArtifactStagingDirectory)'
versionEnvVar: 'nugetVersion'
versioningScheme: 'byEnvVar'
I think the issue many of use have is that there is no option menu. I upvoted SHarpC's post as this worked for me.
I have a workaround to add a suffix (i.e. '-beta'), since it's for some reason ignored by the Nuget pack command when using the Classic editor and setting auto versioning by build number:
Set a new environment variable, set the value as the predefined $(Build.BuildNumber) variable:
Set the build number:
Set NuGet pack command to auto-name by environment variable and specify newly added variable name:
If you're interested in the whole build/release pipeline design and YAML, have a look at my article here
The core of the problem is solved in the approved answer and refined in #Emils answer, so this is just another approach to the azure-pipelines.yml that works for us with DevOps artifacts.
name: $(majorMinorVersion).$(semanticVersion)
trigger:
- main
variables:
majorMinorVersion: 1.0
semanticVersion: $[counter(variables['majorMinorVersion'], 0)]
pool:
vmImage: windows-latest
steps:
- task: DotNetCoreCLI#2
displayName: 'Create Packages'
inputs:
command: pack
configuration: 'Release'
packagesToPack: '**/<VS projectname>.csproj'
versioningScheme: byBuildNumber
- task: NuGetAuthenticate#0
displayName: 'NuGet Authenticate'
- task: NuGetCommand#2
displayName: 'NuGet Push to feed'
inputs:
command: push
publishVstsFeed: '<DevOps projectname>/<feed name>'
BTW: Don't forget this little hinch
Im simply trying to pass value between build steps in TeamCity. Im currently using PowerShell.
My Powershell code looks like
$guid = [guid]::NewGuid().ToString()
echo "##teamcity[setParameter name='env.test' value='$guid']"
echo %env.test%
When I save this step and then run configuration all I get is following error
Warning: No enabled compatible agents for this build configuration.
Please register a build agent or tweak build configuration requirements.
Print screen of an error
When I remove usage of %env.test% (= last line) variable everything works fine, but the problem is of course that I cannot use this variable anywhere.
Any help is appreciated
You can check the list of undefined parameters if you press on lightbulb left to the Run button or if you go to the build configuration > Parameters page. You'll see there that env.test parameter "value is required". You need to define it (empty value can be used).
I'm using the TeamCity AutoIncrementer Plugin: https://confluence.jetbrains.com/display/TW/Autoincrementer
I'm attempting to modify the config file at: [TeamCity Data Directory]/config/autoincrementer.properties
Within the config file it says:
# Autoincrementer plugin (pre 6.5 EAP).
#
# This file contains values for auto-incremented properties.
# Each auto-incremented property must start with 'autoinc_Test.' prefix.
# Value of the property must be a positive integer.
# To use auto-incremented property in a build you can add a reference to the property
# in build configuration settings, e.g: %autoinc_Test.build.number%. When plugin discovers such reference
# initial value for the referenced property will be written in this file.
# You can change properties values in this file manually at any time.
# Note that if you want to set a property to some value you need to put ! character
# before the value (after the equals sign).
My values look like:
autoinc.foo=1683367\:25
autoinc.bar=-1\:10
I believe the first number is the changelist from Perforce.
I want to change the last number for foo from 25 to 200 (this is the build number).
I've tried putting the exclamation character at autoinc.foo=!1683367:200 and at autoinc.foo=1683367:!200. In both cases TeamCity will overwrite this file and change it back to 26 on the next build.
1) How do I change the build number? Does this require a TeamCity restart?
2) How is this working at all if each autoinc requires 'autoinc_Test.' prefix?
I am using TeamCity 8.0.6.
The version we are using works by adding a ! after the = sign as per the comments in the file (e.g. autoinc.globalbuildnum=!1).
I noticed that the comments in the version we are using are different to those you have posted. We are using the plugin that is compatible with TeamCity 8.x+ which is currently at the link you posted. It was updated on 7th April 2015
I need to give a server name to a maven build. During the maven build this server name will be used to make a call that server do some tests on that server.
Our servers have jenkins slaves on them and is grouped using labels
Example
Slaves/Node | Label
Server1 | BackEndServers
Server2 | BackEndServers
Server3 | FrontEndServers
Server4 | FrontEndServers
With Elastic Axis plugin i can say run my Jenkins job on this Node Label (for example on BackEndServers) and the same project will be executed on both of the servers (Server1 & Server2).
In my case I cannot do this as maven is not installed on the BackEndServers where my code is running. But the maven build needs to know about the server names though.
So is there a way how I can get the server names from a label and then run the same job multiple times passsing each servername to the maven build?
Example
Giving that I have the label 'BackEndServers'
obtain a list of node names 'Server1,Server2'
and run my job for each node name and pass a parameter to it
aka
Having Job (with parameter Server1)
Having Job (with parameter Server2)
Use Jenkins environment variables like NODE_NAME in the Maven command of the build job as value for a system property. For example:
mvn clean install -Djenkins.node.name=${NODE_NAME}
In your Maven project (pom.xml) configure the plugin, which requires the node name, with the help of following property: ${jenkins.node.name}
Here are some links - how to trigger Jenkins builds remotely:
How to trigger Jenkins builds remotely and to pass paramter
Triggering builds remotely in Jenkins
Launching a build with parameters
I don't, if it is possible in the way you want it. But the provided information should help you to find a solution.
Try Jenkins.getInstance().getComputer(env.NODE_NAME).getNode() See more on official Doc
In the end I created a 2 jobs.
To interogate the Jenkens nodes for me and build up a string of servers to use
Then use Dynamic Axis lable with the list I have in Job 1 to execute my maven build
In Job 1 - I used The EnjEnv plugin and it has a 'Evaludated Groovy Script' section that basically you can do anything... but it should return a property map. I don't know how to return a value from a Groovy script so this worked kewl for me as I can reference property (or Environment variables) from almost anyware
import hudson.model.*
String labelIWantServersOf = TheLabelUsedOnTheElasticAxisPlugin; // This is the label assosiated with nodes for which i want the server names of
String serverList = '';
for (aSlave in hudson.model.Hudson.instance.slaves) {
out.println('Evaluating Server(' + aSlave.name + ') with label = ' + aSlave.getLabelString());
if (aSlave.getLabelString().indexOf(labelIWantServersOf ) > -1) {
serverList += aSlave.name + ' ';
out.println('Valid server found: ' + aSlave.name);
}
}
out.println('Final server list where SOAP projects will run on = ' + serverList + ' which will be used in the environment envInject map');
Map<String, String> myMap = new HashMap<>(2);
myMap.put("serverNamesToExecuteSoapProjectOn", serverList );
return myMap;
Then I had some issue to pass the Environment var onto my next job. So I simply wrote the values that I wanted to a property file using a windows batc script in the Build process
echo serverNamesToExecuteSoapProjectOn=%serverNamesToExecuteSoapProjectOn%> baseEnvMap.properties
Then as a post build action I had a "Trigger parameterized build on other projects' calling my 2nd job and I passed the baseEnvMap.properties to it.
Then on my Job 2 which is a Multiconfig job I added a Dynamic Axis using the environment var that was passed via the property file to job 2.
This will duplicate Job 2 and execute it each time with the value that the groovy script build up which I can reference in my mvn arguments.
To list out all nodes of label name LABELNAME:
http://ServerIP:8080/label/LABELNAME/api/json?pretty=true
I was trying to resolve this issue, and searching forums etc. and trying for myself, without success.
We have a jenkins job and there we use the Release Plugin (with a standard configuration)
In the job then we have the "Perform Maven Release" in the left side to generate a version (tag, change poms, etc.) This work perfect.
We want to send an email to the team when the release has been done.
I tried the enviroment variable that the release plugin sets (IS_M2RELEASEBUILD by default) and combine with the email-ext plugin plugin where I can attach a groovy script (advanced=>trigger=>script trigger)
And I tried a lot of scripts to active the email, and none works, my last chance was:
def env = System.getenv()
env['IS_M2RELEASEBUILD'] == 'true'
but when I perform the release we have not the email sent (so this script evaluate the conditional to false or whatever)
Anyone has this setup in his Jenkins?
Thanks a lot!
You need to use "Editable Email Notification" as "Post-build Action" and paste
def env = build.getEnvironment();
String isRelease = env['IS_M2RELEASEBUILD'];
logger.println "IS_M2RELEASEBUILD="+isRelease;
if ( isRelease == null || isRelease.equals('false')) {
logger.println "cancel=true;";
cancel=true;
}
as Pre-send Script, fill in your E-Mail(s) in "Project Recipient List" and add an "Success"-Trigger.
(precondition is you have not changed the default "Release envrionment variable" in "Maven release build")
https://wiki.jenkins-ci.org/display/JENKINS/Email-ext+plugin
This plugin allows you to configure every aspect of email notifications. You can customize when an email is sent, who should receive it, and what the email says.
This is not an answer, just a suggestion (I can't add comments). Have you tried echoing that environment variable in a post-build and pre-build step?
Have you tried having another build run when the release build completes successfully and have that job send the email, perhaps by running a shell script.