Confusion regarding TFS and creating packages with custom versioning - tfs

I'm trying to set up a TFS build that will create/pack a package, however, I am unclear on the versioning. We currently manually create packages with the versioning YEAR.MONTH.DAY.INCREMENT and I am trying to replicate that automatically in the build.
I can't seem to upload a picture at the moment but I'm not sure what to put in the Major, Minor, and Patch fields in order to set the date of the build. I also want to put some sort of "alpha" suffix along with a timestamp on the end (i.e., the INCREMENT).
How can I achieve this? Thanks.

If you don't want to use the data and time (which you can specify the Major, Minor, and Patch value with it) to automatic package versioning.
Then you can try to use the environment variable to version it with suffix in a CI build.
Set the build number format like this :
$(date:yyyy.MM.dd)$(rev:.r) to get the INCREMENTAL number.
Define a version variable and set value with the suffix "alpha"
using logging command in PowerShell:
$version = $env:BUILD_BUILDNUMBER +"-alpha"
Write-Host "##vso[task.setvariable variable=version]$version"
Add a PowerShell task to run the script.
Use the version variable to version your package in subsequent tasks.
You can reference below articles about the NuGet packages versioning:
Versioning NuGet packages in a continuous delivery world: part 1
Versioning NuGet packages in a continuous delivery world: part 2
Package versioning

Related

Jenkins and gradle - build projects with latest versions of dependencies for CI, specific versions for production

I am working with Jenkins, Gradle and our Ivy repository.
Our build scripts specify the exact version of dependencies to be used for the build. This is good practice for production.
For CI it would be interesting if the project build used the latest versions of our own libraries, that way we could not only see if library changes "broke the build" for the library but also if they broke the projects that use them. That seems to be the point of "integration"!
I understand that gradle will take "1.+" instead of "1.2.3" so I could hack the build.gradle for the project on the CI server to achieve this. But perhaps there is a neater way to do it (build script recognises it is in CI mode and uses latest and not specific versions, perhaps by running a sed script on build.gradle to change it).
Am I missing something in Jenkins or gradle? Are there any gradle plugins that achieve this, or alternative approaches that you have used to achieve this?
something alike this might work with Jenkins:
if(System.getenv("BUILD_EXPERIMENTAL") == null) {
// known to be stable versions
apply from: "dependencies.gradle"
} else {
// bleeding edge versions
apply from: "experimental.gradle"
}
this just would need the same project being set up twice, once with and once without environmental variable BUILD_EXPERIMENTAL, which is used to control which dependencies block is being applied.
in case you want it generally being applied, when the project is being built with Jenkins, just replace BUILD_EXPERIMENTAL with BUILD_NUMBER (which by default is being set up in that environment).
If you want to have the latest you can simply use latest, or if it's easier something like [1.0,) that would match all versions greater or equal to 1.0 (assuming that 1.0 is your "smallest version ever") Look here for other matching patterns, which you could also combing with statuses.
Another way would be to have a local filesystem ivy repo only on the jenkins slave, which would have all the latest versions of your libraries, the point is that this repo is not accessible from developers workstations/laptops/VMs. And then you just simply use that in gradle settings in some way (for example have an environment variable defined only on the jenkins slave). This means that you don't need to change build.gradle
I would recommend leveraging Gradle dependency locking for achieving this.
In the build, you would use dynamic versions for your dependencies, locked to a good known state.
Developers and production build would then get these locked versions resolved.
On CI you could have a (set of) dedicated job(s) that runs and updates the lock state for one or more modules at a time. Based on that feedback, you could even commit this dependency upgrade or at least open a pull request for it.
This is my own answer inspired by #Martin Zeitler's answer.
We have a generic build script that get applied to all project build.gradle setting up common options, settings and tasks. We want to add in this logic, but make it optional and not break existing build scripts.
The logic will be activated and controlled by a property project.ext.buildJenkinsWithLatest which is true or false.
When the logic is active dependencies from the project files dependencies-production.gradle or dependencies-jenkins.gradle will be used. The Jenkins dependencies will only be used if the property is true and the CI environment is detected through the presence of the BUILD_NUMBER environment variable.
The generic build script contains this:
if (project.ext.has('buildJenkinsWithLatest')) {
println "Using conditional dependency management..."
//BUILD_NUMBER is not null if this is a Jenkins build
if(project.ext.buildJenkinsWithLatest == true && System.getenv("BUILD_NUMBER") != null) {
println "--- Using alternative dependencies..."
apply from: "dependencies-jenkins.gradle"
}
else {
println "--- Using production dependencies..."
apply from: "dependencies-production.gradle"
}
}
else {
println "Conditional dependency management is not active"
}
Now any project's build.gradle that already applies this script will print this when run:
Conditional dependency management is not active
To use the feature we will need to do the following for our project:
Create a dependencies-jenkins.gradle that contains a dependencies {} clause for the libraries we want to select a version dynamically.
Create a dependencies-production.gradle that contains a dependencies {} clause for those libraries, but with a specific version given.
Remove the libraries from any dependencies {} that remains in the project build.gradle.
Set the property project.ext.buildJenkinsWithLatest to true or false.
Apply the generic build script (after setting the property!).
For example in dependencies-jenkins.gradle use the latest 2.x.x version:
dependencies {
compile 'example:my-library:2+'
}
As to how to specify the versions in a dynamic way see #CantSleepNow's answer.
And in dependencies-production.gradle use a specific version:
dependencies {
compile 'example:my-library:2.3.4'
}
Then within build.gradle set the property and apply the generic build script:
...
project.ext.buildJenkinsWithLatest = true;
apply from: '../bxgradle/bx-std.gradle'
...
Now when the build is run on Jenkins the alternative dependencies will be used. Should one wish to build it on Jenkins with the production dependencies then set project.ext.buildJenkinsWithLatest to false.

How to set a variable in build and get it in release?

We have a version number which is retrieved from a file during the build and needs to be passed to the deployment script. What is the best way to do this in TFS 2017?
Right now, we are thinking of embedding this version number in the artifact file name and parsing it during deployment, which feels a bit clumsy.
BTW, is there a way to get the artifact file name easily? Looks like TFS already knows this as shown in the log below:
No path specified for search pattern: *.zip defaulting to: F:\TFS2017_Release_Agent\_work\r1\a
2017-12-08T16:38:36.8519067Z Searching for: *.zip under directory: F:\TFS2017_Release_Agent\_work\r1\a
2017-12-08T16:38:36.8519067Z Found: 1 files to extract:
2017-12-08T16:38:36.8519067Z F:\TFS2017_Release_Agent\_work\r1\a\ZFJ0_ServiceSearchPlusBuildDefn\BETALink.Service.SearchPlus\ZFJ0_BETALink10.4 DevOps_BETALink.Service.SearchPlus_1.0.0_886.zip
2017-12-08T16:38:36.8519067Z Creating destination folder: F:\TFS2017_Release_Agent\_work\r1\a\48
2017-12-08T16:38:36.8519067Z Extracting file: F:\TFS2017_Release_Agent\_work\r1\a\ZFJ0_ServiceSearchPlusBuildDefn\BETALink.Service.SearchPlus\ZFJ0_BETALink10.4 DevOps_BETALink.Service.SearchPlus_1.0.0_886.zip
2017-12-08T16:38:36.8519067Z [command]F:\TFS2017_Release_Agent\_work\_tasks\ExtractFiles_5e1e3830-fbfb-11e5-aab1-090c92bc4988\1.112.1\7zip\7z.exe x -oF:\TFS2017_Release_Agent\_work\r1\a\48 F:\TFS2017_Release_Agent\_work\r1\a\ZFJ0_ServiceSearchPlusBuildDefn\BETALink.Service.SearchPlus\ZFJ0_BETALink10.4 DevOps_BETALink.Service.SearchPlus_1.0.0_886.zip
2017-12-08T16:38:36.8987827Z
First, custom build variable couldn't be used directly in your release definition with TFS 2017.
There had also been a related user voice:
Project level build/release variables
https://visualstudio.uservoice.com/forums/330519-visual-studio-team-services/suggestions/14515326-project-level-build-release-variables#
As a workaround, you could use some 3-rd party extension such as Variable (de|re)Hydration Tasks that help you make use of your build variables in your Release workflows.
Variable Dehydration Task - During your build you can save the variables to a json file stored with your other build assets
Variable Rehydration Task - During your Release you can load the saved variables and gain access to them.
It does this by prefixes, so you can save/restore all default build variables that are prefixed with 'BUILD-', but if you prefix your own variables with i.e. 'ABC_' you can also save them from your build and restore them in your release.
Another way is do it through powershell scripts, how to please refer: TFS 2015 Release management access build variables
About build artifact name, there is not a related predefined system variable, it's just entered as an argument in Publish Build Artifacts task.

How do I get TFS 2015 to parse 3 digit versioning for NuGet packaging

When I set my TFS 2015 build definition, that is creating a NuGet package, I set the Build Number format with:
$(BuildDefinitionName)_$(Major).$(Minor)$(rev:.r)
Where Major and Minor or just variables that I defined. When I use the step "NuGet Packager", I get the error:
Could not find version number data in BUILD_BUILDNUMBER.
When I use 4 digits, I don't get the error. How do I get it to work with semantic versioning?
I found the solution:
1) You need to get access to your Build Agent machine
2) Navigate to where the Build Agent is installed.
For me --> C:\BuildAgent\tasks\NuGetPackager
3) You will see folder versions, so go into the latest one.
4) Modify the PowerShell script, NuGetPackager.ps1
Find --> $VersionRegex = "\d+.\d+.\d+.\d+"
And replace with --> $VersionRegex = "\d+.\d+.\d+.\d+|\d+.\d+.\d+"
5) And then save the script.
What I am doing is modifying the regular expression to say "Search for the pattern #.#.#.# OR #.#.# in the build number string". Whereas before it was only looking for "#.#.#.#".
Now, when you do your build, the TFS Build Agent will be able parse the build version:
Set workingFolder to default: C:\BuildAgent\tasks\NuGetPackager\0.1.58
Executing the powershell script: C:\BuildAgent\tasks\NuGetPackager\0.1.58\NuGetPackager.ps1
Getting version number from build
BUILD_BUILDNUMBER: Planning.Domain.Library-CI_1.0.7
Version: 1.0.7
If you look at https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/NugetPackager/NuGetPackager.ps1 :
if ($b_versionByBuild)
{
Write-Verbose "Autoversion: Getting version number from build"
##Get Version from Build
# Regular expression pattern to find the version in the build number
# and then apply it to the assemblies
$VersionRegex = "\d+\.\d+\.\d+(?:\.\d+)?"
Support for 3 part build numbers came from this commit:
https://github.com/Microsoft/vsts-tasks/commit/233c112bc06b91964a559090b8acfd4452cdec0b
Before this commit the regular expresion was just \d+\.\d+\.\d+\.\d+. So maybe you have an outdated task code in your TFS.
I just checked my on-premise TFS 2015. It cannot parse 3 number version.

How to apply the build number format to shelveset builds in tfs?

I have a TFS build definition with the
Process > Basic > Build Number Format parameter set to
1.1.2-alpha$(Rev:.r)
This works fine whenever I build from the 'Latest Sources' and the build agent applies the correct version number (1.1.2-alpha1 and so on). However, when I try to build from a shelveset with the same build definition, the build fails with the following error:
'31927' is not a valid version string.
So, how can I make sure that the build agent applies the same naming pattern when building from a shelveset?
Error message:
The error is caused by the nuget pack task in your build process. You used the build number to version the nuget package but the build number "31927" does not meet the Nuget Versioning.
When you queue a build with shelveset, the build number always use the format: Build N. It does not read the settings you configured in "Build Number Format". Refer to this link for details: Private Build.
The completed build is named by using the format Build N where N is a
unique integer value. This format differs from that of public builds,
which you specify by using the Build Number Format parameter.
That's means that, to avoid this issue, you need to use some other ways to version your nuget package.

Versioning modules independently in multi project environement and zipping all dependencies

I am new to ant and Ivy. We are using Jenkins for CI with ant for builds, Ivy for dependency manger. We have several modules/projects which generate jars and wars, which can be independently versioned and released (not all modules will be released at the same time), so, need to maintain version number separately for each module. We want to use the version format A.B.C.D (ex: 1.2.1.2). I found I can use a property file to enter a version number and use ant BuildNumber task to increment the number for our nightly builds. So, once all the features are in and tested we move the last successful nightly build as new released version but we want to change the version number without rebuilding it. For example last successful build was 1.2.1.20 and it was tested thoroughly and has all the feature, we have to make this build from 1.2.1.20 to 1.3.0.0 without rebuilding the modules. How can I do that using ant? And also I need to publish them to my shared repository with the version 1.3.0.0. How do I do that?
Also, we want to create a zip file for each module with all dependency files along with the module's jar file for delivery. Is there any ivy or ant tasks that can help to create this?
I think you've asked two questions...
Generally, every build I create is releasable so I'm always incrementing the last digit in my release number scheme. For controlling the version number I prefer to use the ivy buildnumber task, which increments based on what has been previously pushed to your repository (very useful).
Creating a zip package is quite straight forward. Just alter your ivy file to publish more than one artifact.

Resources