How to access build folder number in TFS 2017 - tfs

I typically tell TFS what folder to use via $(build.sourcesdirectory) which translates into C:\Builds\1\s .
However, I need to repack the deployment zip, so I had to add Content\C_C\Builds\myproj\1\s to my CI.
This isn't very good as the 1 can change due to dev ops work.
Is there a variable or technique I can use to replace the 1 with a variable?
I tried $(Agent.Id) with no luck...

You can use PowerShell to retrieve the number from variable $(build.sourcesdirectory) and pass the value to a new variable.
Dynamically get the number Sample:
$string = "$env:BUILD_SOURCESDIRECTORY"
#$string = "E:\andyli-v\01Agent\_work\6\s" (The length is 29, the number '6' in the string is the 27th character, So get the substring as (26,1) means get one character behind the 26th character)
$parameter = $string.Substring(26, 1)
Write-Host "BUILD_SOURCESDIRECTORY is :" $string
Write-Host "The String length is : "$string.Length
Write-Host "The number is : "$parameter
You can use $parameter directly to get the number if do actions within the same script.
Set a variable :
If you want a variable, you can set it via PS :
Write-Output ("##vso[task.setvariable variable=GetNumber;]$parameter")
You can reference there articles to set the variable:
https://roadtoalm.com/2016/08/11/set-output-variable-in-a-powershell-vsts-build-task/
http://blog.majcica.com/2016/02/19/passing-values-between-tfs-2015-build-steps/

Related

Increment variable value in TFS build +1

I have a Microsoft Visual Studio Team Foundation Server (Version 15.117.26714.0) with predefined variable $(ProjectBuildNumber).
Is there any way to increment, during build process, value of variable with minor build number by +1?
$(ProjectBuildNumber) = 663
So, that on next build it will be:
$(ProjectBuildNumber) = 664
You can't reference variables in the build number of the Build Definition. But what you can do is override the build number in the build itself. You can either use a magic log command or use my VSTS Variables Task to set the Build.BuildNumber in the build itself. The Variables Task does expand variable references. You could probably just set the value to the current value to get it expanded.
To issue the log command yourself use a batch script, PowerShell or bash to output the following specific string to the console:
##vso[build.updatebuildnumber]build number
Update build number for current build. Example:
##vso[build.updatebuildnumber]my-new-build-number
Minimum agent version: 1.88
source: https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
An alternative option is to use the $(Rev) option:
Build.BuildNumber = 1.1.$(Rev:.r)
That will automatically increase the variable each time the build runs.
To update a variable in a Build Definition use yet another extension:
These things combined should be able to get what you want.
In the variable section,
set the value of ProjectBuildNumber to $[counter('', 663)].
This will queue build starting with 663 as ProjectBuildNumber and increments by 1 for the subsequent queue of builds.
Unfortunately counter function (Expressions) is not available in TFS 2018. In this old version the best solution for me is to use a PowerShell script as the first Task of the build. You can than have your parameter
$(ProjectBuildNumber)
as an input argument, and place this inline script:
$ProjectBuildNumber=$args[0]
$ProjectBuildNumber++
Write-Host "##vso[task.setvariable variable=ProjectBuildNumber;]$ProjectBuildNumber"
After this Task you can use your incremented ProjectBuildNumber variable in all subsequent Tasks.

VSTS Release multi-line variable

I have task in VSTS release management that deletes files. I want to have the Contents come from a variable. I have created a variable but I can't figure out how to create a multi-line variable. So for example a variable that deletes the three types of files:
Variable Name= ExcludeFiles
Variable Value= "Lib" "bin\*.pdb" "bin\*.dll.config"
It's possible to use a variable with multiple logical lines as input to a multi-line task parameter, but it may not work for every task. This approach is tested on VSTS using the VS Test 2.x task, which I'll use as an example below. I expect it will work for most of the Microsoft-provided tasks.
Background
Tasks define a set of parameters via a JSON file. Each parameter has an internal name in addition to the display name shown in the UI. It's possible to see the internal parameter name using the "Link settings" button on a task (or by finding the task's source code).
In the "Link settings" dialog, the VS Test 2.x task has a "Setting to link" called "Test assemblies", which is a multi-line string. Looking at "Process parameter to link to this setting", we see the value "Parameters.testAssemblyVer2". testAssemblyVer2 is the name of the internal parameter.
When a task executes, it needs to obtain values for its parameters. Most tasks do this by searching the current environment variables for anything starting with "INPUT_". In the case of testAssemblyVer2, the task will look for an environment variable named INPUT_TESTASSEMBLYVER2.
Just before the task executes, we can turn a delimited variable value into an encoded multi-line value, and write it into the environment variable where it's picked up by the task.
Solution
First, define a variable, "Custom.TestAssemblies" with a semicolon-delimited value **\$(BuildConfiguration)\*.tests.dll;!**\obj\**. The semicolon will become the line split.
Next, add a PowerShell task to the build process just before the VS Test task. Configure it as an Inline script with one Argument "$(Custom.TestAssemblies)". Here, the double quotes are critical.
The inline script looks like this:
Param([String]$toMultiLine)
$newlineDelimited = $toMultiLine -replace ';', "%0D%0A"
Write-Host "##vso[task.setvariable variable=INPUT_TESTASSEMBLYVER2]$newlineDelimited"
That's it! The delimiters in the variable value are converted to URL-encoded CR/LF's, and the agent is instructed to update INPUT_TESTASSEMBLYVER2 with that value. The task picks up the value and parses it for '\n', which matches the embedded %0D%0A's.
Summary
Pick a delimiter like ; and use it to divide the parts of your variable value
Obtain the task's internal parameter name using "Link settings"
Insert a PowerShell task just before the target task and insert the code above, substituting the correct variable and task parameter names
If you set the variable system.debug to true, you'll generally see the various INPUT_ parameters and some of the parsing in the trace output. It depends on the implementation of the specific task.
This solution should work equally well for Build and Release sequences.
Multi-line variable is not supported, I submit a user voice here: Multiple lines variable in Build and Release.
Based on the source code of Delete Files task, it splits contents value by ‘\n’, but based on my test, add ‘\n’ to variable isn’t working (e.g. t1.txt \n t2.txt or t1.txt\nt2.txt).
You can custom build/release task per to the source code of Delete Files task or to do it with your logical and execute it through PowerShell/Command Line task.
Bash solution:
emailbody=$(echo "$output" | sed ':a;N;$!ba;s/\n/%0D%0A/g')
The PowerShell solution from Thomas F. Abraham solved my problem. This modification makes it a bit simpler, no input parameter needed:
$newline = "%0D%0A `t"
Write-Host "##vso[task.setvariable variable=LineBreak]$newline"
I also added a tab character so my next line would be indented. Then just refer to the variable $(LineBreak) where ever you want it.
Solution from Thomas also helped point us in right direction.
No issue loading multiline certificates/keys using "bash" task in azure pipeline with,
export CERTIFICATE=$(echo "$(CERTIFICATE_BASE64)" | base64 -d -w 0)
echo "##vso[task.setvariable variable=CERTIFICATE;]$(echo $CERTIFICATE)"
However trying same using "powershell" task in azure pipeline didn't work with,
$CERTIFICATE = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String("$(CERTIFICATE_BASE64)"))
$CERTIFICATE.Replace("`n","`r`n")
Write-Output "##vso[task.setvariable variable=CERTIFICATE;]$CERTIFICATE"
Swapping in the following did work,
$CERTIFICATE.Replace("`n","%0D%0A")
Solution from "Thomas F. Abraham" helped to write a yml template for the VsTest task:
#Note that it is tricky to specify the multiline-string for the VSTest task
#see 'https://github.com/MicrosoftDocs/azure-devops-docs/issues/1580'
#see 'https://stackoverflow.com/questions/44464976/vsts-release-multi-line-variable' for the solution used in this template
#we set the environment variable 'INPUT_TESTASSEMBLYVER2' instead of setting the input 'testAssemblyVer2' for the task !!!
parameters:
- name: testAssemblies
type: string
default: '**\*test*.dll,!**\*TestAdapter.dll,!**\obj\**'
- name: searchFolder
type: string
default: $(Build.Repository.Name)
- name: codeCoverageEnabled
type: boolean
default: false
steps:
- script: |
echo Paramater testAssemblies: ${{ parameters.testAssemblies }}
echo Paramater searchFolder: ${{ parameters.searchFolder }}
echo Paramater codeCoverageEnabled: ${{ parameters.codeCoverageEnabled }}
displayName: 'Parameters for VSTest'
- powershell: |
$newline = "%0D%0A"
$newlineDelimitedTestAssemblies = '${{ parameters.testAssemblies }}' -replace ',', $newline
Write-Host "##vso[task.setvariable variable=INPUT_TESTASSEMBLYVER2]$newlineDelimitedTestAssemblies"
displayName: 'Set INPUT_TESTASSEMBLYVER2 for VSTest task'
- task: VSTest#2
inputs:
testSelector: 'testAssemblies'
searchFolder: '${{ parameters.searchFolder }}'
vstestLocationMethod: 'location'
vstestLocation: 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\Extensions\TestPlatform'
codeCoverageEnabled: ${{ parameters.codeCoverageEnabled }}
displayName: 'Run VSTest VS2022'

Is possible to change the value of a variable during execution of a release in TFS 2017

In TFS 2017, when a release definition is created a set of custom variables can be created too.
In the scope of an Agent, Is possible to change the value of one variable?
I tried with an inline powershell script:
$env:MyVariable = "changed value"
also try with :
[Environment]::SetEnvironmentVariable("MyVariable ", "changed value.", "User")
without success.
You could use the Logging command to change the custom variable's value.
In your PowerShell script file(script1.ps1), write:
$NewVersion = "NewValue"
Write-Host ("##vso[task.setvariable variable=customVariable;]$NewVersion")
Then add a Powershell script to run this file.
And you could add another Powershell script file(script2.ps1) to output the custom value. Run this file after script1 to check if the value has been changed successfully.
Here is a similar question: How to change a tfs build variable in script
Did you try Write-Host?
Write-host $env:OutputVar
Can't check myself now, but you can take a look here for detail.

VSO Build vNext - get TFS revision number

In my build steps I need to provide TFS revision number as a paramter. I know there is a variable $(Build.SourceVersion) but it returns it with a "CS" prefix e.g. "CS1234"
Is there an easy way to remove that "CS" prefix? Any built-in string functions?
Thanks
I'm not aware about any built-in functions to format that string - you'll have to do it in your script somewhere. Note that $(Build.SourceVersion) variable returns empty string if you specify it in the Build Number Format field in your build definition. This thread might give you more details.
There is no build in method. Also changeset number and revision number are not the same thing. You will get COMMIT ID in $(Build.SourceVersion) if you are using GIT repository.
You may use PowerShell to strip that part off. Following line should give you the numeric portion.
[string]$version = ($Env:BUILD_SOURCEVERSION -replace'\D+(\d+)','$1')
Adding to #cilerler's answer, I've used this generic Powershell script as my first VSTS build step:
Param(
[string] $SourceBranchName = $Env:BUILD_SOURCEBRANCHNAME,
[string] $SourceVersion = $Env:BUILD_SOURCEVERSION
)
Write-Host "SourceBranchName = $SourceBranchName"
Write-Host "SourceVersion = $SourceVersion"
if ($SourceBranchName -eq "trunk"){
$MajorMinor = "0.0"
}
else{
$MajorMinor = $SourceBranchName
}
# Remove CS from changeset number
$Revision = ($SourceVersion -replace 'C','')
$BuildNumber = "$MajorMinor.$Revision.0"
Write-Host "Setting Build Number '$BuildNumber'"
Write-Host "##vso[build.updatebuildnumber]$BuildNumber"
Note that it presumes that your branch name is in the format Major.Minor (eg. 1.4) or trunk.
Also, it seems the VSTS documentation is wrong, the Build.SourceVersion variables is of the form C1226.

How to specify a value for a Jenkins environment variable that contains a space

I am trying to specify a value for a Jenkins environment variable (as created on the Manage Jenkins -> Configure System screen, under the heading "Global properties") which contains a space. I want to use this environment variable in an Execute Shell build step. The option that I need to appear in the command line in the build step is:
--platform="Windows 7"
The syntax I am using on the command line is --platform=${VARIABLE_NAME}
No matter how I attempt to format it, Jenkins seems to reformat it so that it is treated as two values. I have tried:
Windows 7
"Windows 7"
'Windows 7'
Windows\ 7
The corresponding results, when output during the Execute Shell build step have been:
--platform=Windows 7
'--platform="Windows' '7"'
'--platform='\''Windows' '7'\'''
--platform=Windows/ 7
I have also tried changing my command line syntax to --platform='${VARIABLE_NAME}' as well as '--platform=${VARIABLE_NAME}', but in each of those cases the ${VARIABLE_NAME} is not resolved at all and just appears as ${VARIABLE_NAME} on the resulting command.
I am hoping there is a way to make this work. Any suggestions are most appreciated.
You should be able to use spaces without any special characters in the global properties section.
For example, I set a variable "THIS_VAL" to have the value "HAS SPACES".
My test build job was the following:
#!/bin/bash
set +v
echo ${THIS_VAL}
echo "${THIS_VAL}"
echo $THIS_VAL
and the output was
[workspace] $ /bin/bash /tmp/hudson8126983335734936805.sh
HAS SPACES
HAS SPACES
HAS SPACES
Finished: SUCCESS
I think what you need to do is use the following:
--platform="${VARIABLE_NAME}"
NOTE: Use double quotes, not single quotes. Using single quotes makes the stuff inside the quotes literal, meaning that any variables will be printed as is, not parsed into the actual value. Therefore '${VARIABLE_NAME}' will be printed as is, not parsed into "Windows 7".
EDIT:
Based on #BobSilverberg comment below, use the following:
--platform="$VARIABLE_NAME"
Note: no curly brackets.

Resources