How to zero pad the build counter in TeamCity - teamcity

I'm trying to follow some guidance from this article which describes NuGet and SemVer best practices.
Point #3 states that I should "Use leading zeros in the numerical suffix to auto-increment prereleases" but I am struggling working out how I can zero pad the build.counter parameter in TeamCity so that I get 0025 instead of 25.
Does anyone have a mechanism to handle this?

You could write a powershell script like:
function Update-BuildNumber([string]$buildNumber)
{
$VersionComponents = $buildNumber.Split(".")
$buildNumber = ""
foreach($VersionComponent in $VersionComponents)
{
$index = [array]::IndexOf($VersionComponents, $VersionComponent)
if (($index + 1) -eq $VersionComponents.Count)
{
$buildNumber += "00" + $VersionComponent
}
else
{
$buildNumber += $VersionComponent + "."
}
}
Write-Output "##teamcity[buildNumber '$buildNumber']"
}
And call it from a Teamcity build step and pass the parameter %build.number% something like:
Update-BuildNumber -buildNumber %build.number%

If I were you, I would make use of GitVersion. It includes an option to use a LegacySemVerPadded version of the generated version number. There are various other alternatives of the generated version number as well.
There is a TeamCity Meta Runner for it here.
GitVersion does the work of calculating the new Semantic Version Number for you, based on the current state of your repository.
Failing that, yeah, do the work elsewhere, in PowerShell, and then use TeamCity Service Messages to change the build number in TeamCity. You can find a PowerShell Module here.
That provides some helper functions for doing just that.

Related

Bamboo: Access script variable in subsequent maven task

I have seen many posts where people asking to access Bamboo variables in script but this is not about that.
I am defining a variable in Shell Script task, as below, and then I would like to access that variable in the subsequent maven task.
#!/bin/sh
currentBuildNumber=${bamboo.buildNumber}
toSubtract=1
newVersion=$(( currentBuildNumber - toSubtract ))
echo "Value of newVersion: ${newVersion}"
This one goes perfectly fine. However I have a subsequent maven 3 task where I try to access this variable by typing ${newVersion} I get below error
error 07-Jun-2019 14:12:20 Exception in thread "main" java.lang.StackOverflowError
simple 07-Jun-2019 14:12:21 Failing task since return code of [mvn --batch-mode -Djava.io.tmpdir=/tmp versions:set -DnewVersion=1.0.${newVersion}] was 1 while expected 0
Basically, I would like to automate the version number of the built jar files just by using ${bamboo.buildNumber} and subtracting some number so that I won't have to enter the new version number every time I run a build.
Appreciate your help... thanks,
EDIT: I posted the same question on Atlassian forum too... I will update this post when I get an answer there... https://community.atlassian.com/t5/Bamboo-questions/Bamboo-Access-script-variable-in-subsequent-maven-task/qaq-p/1104334
Generally, the best solution I have found is to output the result to a file and use the Inject Variables task to read the variable into the build.
For example, in some builds I need a SUFFIX variable, so in a bash script I end up doing
SUFFIX=suffix=-beta-my-feature
echo $SUFFIX >> .suffix.cfg
Then I can use the Inject Variables Task to read that file
Inject Variables Task
Make sure it is a Result variable and you should be able to get to it using ${bamboo.NAMESPACE.name} for the suffix one, it would be ${bamboo.VERSION.suffix}

How to pass "args" while using Intellij IDEA [example list 3.11 in Odersky's Scala book (2nd Ed)]

I basically try to run the example 3.11 in Odersky's book (Programming in Scala). I am using Intellij IDE. While runing the code, the "else" branch got executed.
The screen capture is here:
The source is here in case you need it to try:
package ch3
import scala.io.Source
object l3p11 extends App{
def widthOfLength(s: String) = s.length.toString.length
if (args.length > 0){
val lines = Source.fromFile(args(0)).getLines().toList
val longestLine = lines.reduceLeft(
(a, b) => if (a.length > b.length) a else b
)
val maxWidth = widthOfLength(longestLine)
for (line <- lines){
val numSpaces = maxWidth - widthOfLength(line)
val padding = " " * numSpaces
println(padding + line.length + "|" + line)
}
}
else
Console.err.println("Please enter filename")
}
The reason, I think, is becuase I did not pass args correctly (say here I want to pass the source file l3p11.scala as the args). I tried several option, but have not find a way to pass the args correctly for the code to be executed in the "if" branch. There are two directions in my mind to resolve this problem:
1. Find the right way to pass args in Intellij IDE
Run Scala in commond line, a similar command such as
$ scala l3p11.scala l3p11.scala
should be able to pass the args correctly. But my current setting gives "bash: scala: command not found". I currently use scala REPL to run scala code following the set up given in Odersky's Coursera course on Scala. I think I need to change the set up in orde run scala directly, instead of using "sbt->console" to invoke the scala interpreter like what I am doing now.
Any suggestion on either direction (or other directions that I have not thought of) to resolve the problem is welcome.
Update 1:
Direction 2 works after I reinstall scala. (My to be corrected understanding is that the installation of sbt does not provide an executable binary of scala to be included in the environment list for Windows. Therefore, scala command cannot be found before). After installation of scala directly:
$ scala l3p11.scala l3p11.scala
gives the expected results. But I still have not figured out how to get this result with Intellij IDEA.
Update 2:
I revisited the "Program arguments" option after Joe's confirmation. The reason I was not be able to get it work before was that I only add "l3p11.scala". Adding the complete path from working directory "src/main/scala/ch3/l3p11.scala" solved the problem. The result is as following:
To pass command-line arguments when running a program in IntelliJ IDEA, use the "Edit Configurations …" menu item under "Run". Choose the entry for your main program. There's a "Program arguments" text field where you specify the arguments to pass to the program.
I'm not super familiar on how it will run on windows but if you are able to run it directly from the command line then I think you'll need to compile first, that's the scalac command. So:
$ scalac l3p11.scala
then you can run just with the class name, not sure if you would need quotes on the arg:
$ scala l3p11 l3p11.scala

How can I automatically syntax check a powershell script file?

I want to write a unit-test for some code which generates a powershell script and then check that the script has valid syntax.
What's a good way to do this without actually executing the script?
A .NET code solution is ideal, but a command line solution that I could use by launching an external process would be good enough.
I stumbled onto Get-Command -syntax 'script.ps1' and found it concise and useful.
ETA from the comment below: This gives a detailed syntax error report, if any; otherwise it shows the calling syntax (parameter list) of the script.
You could run your code through the Parser and observe if it raises any errors:
# Empty collection for errors
$Errors = #()
# Define input script
$inputScript = 'Do-Something -Param 1,2,3,'
[void][System.Management.Automation.Language.Parser]::ParseInput($inputScript,[ref]$null,[ref]$Errors)
if($Errors.Count -gt 0){
Write-Warning 'Errors found'
}
This could easily be turned into a simple function:
function Test-Syntax
{
[CmdletBinding(DefaultParameterSetName='File')]
param(
[Parameter(Mandatory=$true, ParameterSetName='File', Position = 0)]
[string]$Path,
[Parameter(Mandatory=$true, ParameterSetName='String', Position = 0)]
[string]$Code
)
$Errors = #()
if($PSCmdlet.ParameterSetName -eq 'String'){
[void][System.Management.Automation.Language.Parser]::ParseInput($Code,[ref]$null,[ref]$Errors)
} else {
[void][System.Management.Automation.Language.Parser]::ParseFile($Path,[ref]$null,[ref]$Errors)
}
return [bool]($Errors.Count -lt 1)
}
Then use like:
if(Test-Syntax C:\path\to\script.ps1){
Write-Host 'Script looks good!'
}
PS Script Analyzer is a good place to start at static analysis of your code.
PSScriptAnalyzer provides script analysis and checks for potential
code defects in the scripts by applying a group of built-in or
customized rules on the scripts being analyzed.
It also integrates with Visual Studio Code.
There are a number of strategies for mocking PowerShell as part of unit tests, and also have a look at Pester.
The Scripting Guy's Unit Testing PowerShell Code With Pester
PowerShellMagazine's Get Started With Pester (PowerShell unit testing framework)

Get current system local encoding in Perl on Windows

I need to get the current encoding according to the system local settings. I'm looking for such function working this way:
my $sysEncoding = getSystemEncoding();
#and now $sysEncoding equals e.g. 'windows-1250'
I looked everywhere on the internet. I've found just the module PerlIO::locale. But I thing that the system encoding should be recognized easier without additional modules.
Encode::Locale provides the means to handle this.
use Win32::API;
if (Win32::API->Import('kernel32', 'int GetACP()')) {
$enc = GetACP();
print "Current local encoding is '$enc'\n";
}
Thanks for hint to Ikegami.

How to mark a build unstable in Jenkins when running shell scripts

In a project I'm working on, we are using shell scripts to execute different tasks. Some are sh/bash scripts that run rsync, and some are PHP scripts. One of the PHP scripts is running some integration tests that output to JUnit XML, code coverage reports, and similar.
Jenkins is able to mark the jobs as successful / failed based on exit status. In PHP, the script exits with 1 if it has detected that the tests failed during the run. The other shell scripts run commands and use the exit codes from those to mark a build as failed.
// :: End of PHP script:
// If any tests have failed, fail the build
if ($build_error) exit(1);
In Jenkins Terminology, an unstable build is defined as:
A build is unstable if it was built successfully and one or more publishers report it unstable. For example if the JUnit publisher is configured and a test fails then the build will be marked unstable.
How can I get Jenkins to mark a build as unstable instead of only success / failed when running shell scripts?
Modern Jenkins versions (since 2.26, October 2016) solved this: it's just an advanced option for the Execute shell build step!
You can just choose and set an arbitrary exit value; if it matches, the build will be unstable. Just pick a value which is unlikely to be launched by a real process in your build.
It can be done without printing magic strings and using TextFinder. Here's some info on it.
Basically you need a .jar file from http://yourserver.com/cli available in shell scripts, then you can use the following command to mark a build unstable:
java -jar jenkins-cli.jar set-build-result unstable
To mark build unstable on error, you can use:
failing_cmd cmd_args || java -jar jenkins-cli.jar set-build-result unstable
The problem is that jenkins-cli.jar has to be available from shell script. You can either put it in easy-to-access path, or download in via job's shell script:
wget ${JENKINS_URL}jnlpJars/jenkins-cli.jar
Use the Text-finder plugin.
Instead of exiting with status 1 (which would fail the build), do:
if ($build_error) print("TESTS FAILED!");
Than in the post-build actions enable the Text Finder, set the regular expression to match the message you printed (TESTS FAILED!) and check the "Unstable if found" checkbox under that entry.
You should use Jenkinsfile to wrap your build script and simply mark the current build as UNSTABLE by using currentBuild.result = "UNSTABLE".
stage {
status = /* your build command goes here */
if (status === "MARK-AS-UNSTABLE") {
currentBuild.result = "UNSTABLE"
}
}
you should also be able to use groovy and do what textfinder did
marking a build as un-stable with groovy post-build plugin
if(manager.logContains("Could not login to FTP server")) {
manager.addWarningBadge("FTP Login Failure")
manager.createSummary("warning.gif").appendText("<h1>Failed to login to remote FTP Server!</h1>", false, false, false, "red")
manager.buildUnstable()
}
Also see Groovy Postbuild Plugin
In my job script, I have the following statements (this job only runs on the Jenkins master):
# This is the condition test I use to set the build status as UNSTABLE
if [ ${PERCENTAGE} -gt 80 -a ${PERCENTAGE} -lt 90 ]; then
echo WARNING: disc usage percentage above 80%
# Download the Jenkins CLI JAR:
curl -o jenkins-cli.jar ${JENKINS_URL}/jnlpJars/jenkins-cli.jar
# Set build status to unstable
java -jar jenkins-cli.jar -s ${JENKINS_URL}/ set-build-result unstable
fi
You can see this and a lot more information about setting build statuses on the Jenkins wiki: https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+CLI
Configure PHP build to produce xml junit report
<phpunit bootstrap="tests/bootstrap.php" colors="true" >
<logging>
<log type="junit" target="build/junit.xml"
logIncompleteSkipped="false" title="Test Results"/>
</logging>
....
</phpunit>
Finish build script with status 0
...
exit 0;
Add post-build action Publish JUnit test result report for Test report XMLs. This plugin will change Stable build to Unstable when test are failing.
**/build/junit.xml
Add Jenkins Text Finder plugin with console output scanning and unchecked options. This plugin fail whole build on fatal error.
PHP Fatal error:
Duplicating my answer from here because I spent some time looking for this:
This is now possible in newer versions of Jenkins, you can do something like this:
#!/usr/bin/env groovy
properties([
parameters([string(name: 'foo', defaultValue: 'bar', description: 'Fails job if not bar (unstable if bar)')]),
])
stage('Stage 1') {
node('parent'){
def ret = sh(
returnStatus: true, // This is the key bit!
script: '''if [ "$foo" = bar ]; then exit 2; else exit 1; fi'''
)
// ret can be any number/range, does not have to be 2.
if (ret == 2) {
currentBuild.result = 'UNSTABLE'
} else if (ret != 0) {
currentBuild.result = 'FAILURE'
// If you do not manually error the status will be set to "failed", but the
// pipeline will still run the next stage.
error("Stage 1 failed with exit code ${ret}")
}
}
}
The Pipeline Syntax generator shows you this in the advanced tab:
I find the most flexible way to do this is by reading a file in the groovy post build plugin.
import hudson.FilePath
import java.io.InputStream
def build = Thread.currentThread().executable
String unstable = null
if(build.workspace.isRemote()) {
channel = build.workspace.channel;
fp = new FilePath(channel, build.workspace.toString() + "/build.properties")
InputStream is = fp.read()
unstable = is.text.trim()
} else {
fp = new FilePath(new File(build.workspace.toString() + "/build.properties"))
InputStream is = fp.read()
unstable = is.text.trim()
}
manager.listener.logger.println("Build status file: " + unstable)
if (unstable.equalsIgnoreCase('true')) {
manager.listener.logger.println('setting build to unstable')
manager.buildUnstable()
}
If the file contents are 'true' the build will be set to unstable. This will work on the local master and on any slaves you run the job on, and for any kind of scripts that can write to disk.
I thought I would post another answer for people that might be looking for something similar.
In our build job we have cases where we would want the build to continue, but be marked as unstable. For ours it's relating to version numbers.
So, I wanted to set a condition on the build and set the build to unstable if that condition is met.
I used the Conditional step (single) option as a build step.
Then I used Execute system Groovy script as the build step that would run when that condition is met.
I used Groovy Command and set the script the following
import hudson.model.*
def build = Thread.currentThread().executable
build.#result = hudson.model.Result.UNSTABLE
return
That seems to work quite well.
I stumbled upon the solution here
http://tech.akom.net/archives/112-Marking-Jenkins-build-UNSTABLE-from-environment-inject-groovy-script.html
In addition to all others answers, jenkins also allows the use of the unstable() method (which is in my opinion clearer).
This method can be used with a message parameter which describe why the build is unstable.
In addition of this, you can use the returnStatus of your shell script (bat or sh) to enable this.
For example:
def status = bat(script: "<your command here>", returnStatus: true)
if (status != 0) {
unstable("unstable build because script failed")
}
Of course, you can make something with more granularity depending on your needs and the return status.
Furthermore, for raising error, you can also use warnError() in place of unstable(). It will indicate your build as failed instead of unstable, but the syntax is same.
The TextFinder is good only if the job status hasn't been changed from SUCCESS to FAILED or ABORTED.
For such cases, use a groovy script in the PostBuild step:
errpattern = ~/TEXT-TO-LOOK-FOR-IN-JENKINS-BUILD-OUTPUT.*/;
manager.build.logFile.eachLine{ line ->
errmatcher=errpattern.matcher(line)
if (errmatcher.find()) {
manager.build.#result = hudson.model.Result.NEW-STATUS-TO-SET
}
}
See more details in a post I've wrote about it:
http://www.tikalk.com/devops/JenkinsJobStatusChange/
As a lighter alternative to the existing answers, you can set the build result with a simple HTTP POST to access the Groovy script console REST API:
curl -X POST \
--silent \
--user "$YOUR_CREDENTIALS" \
--data-urlencode "script=Jenkins.instance.getItemByFullName( '$JOB_NAME' ).getBuildByNumber( $BUILD_NUMBER ).setResult( hudson.model.Result.UNSTABLE )" $JENKINS_URL/scriptText
Advantages:
no need to download and run a huge jar file
no kludges for setting and reading some global state (console text, files in workspace)
no plugins required (besides Groovy)
no need to configure an extra build step that is superfluous in the PASSED or FAILURE cases.
For this solution, your environment must meet these conditions:
Jenkins REST API can be accessed from slave
Slave must have access to credentials that allows to access the Jenkins Groovy script REST API.
If you want to use a declarative approach I suggest you to use code like this.
pipeline {
stages {
// create separate stage only for problematic command
stage("build") {
steps {
sh "command"
}
post {
failure {
// set status
unstable 'rsync was unsuccessful'
}
always {
echo "Do something at the end of stage"
}
}
}
}
post {
always {
echo "Do something at the end of pipeline"
}
}
}
In case you want to keep everything in one stage use catchError
pipeline {
stages {
// create separate stage only for problematic command
stage("build") {
steps {
catchError(stageResult: 'UNSTABLE') {
sh "command"
}
sh "other command"
}
}
}
}
One easy way to set a build as unstable, is in your "execute shell" block, run exit 13
You can just call "exit 1", and the build will fail at that point and not continue. I wound up making a passthrough make function to handle it for me, and call safemake instead of make for building:
function safemake {
make "$#"
if [ "$?" -ne 0 ]; then
echo "ERROR: BUILD FAILED"
exit 1
else
echo "BUILD SUCCEEDED"
fi
}

Resources