Unable to parse ARM Output VSTS task - azure-resource-manager

We use VSTS to deploy an ARM template. (Azure Deployment task version: 2).
In this task, we can configure the output variable. The will output the json output of the ARM template in this variable. In my case, it is called armOutputJson.
In the next task, I have an inline powershell script that tries to convert this value to a powershell object.
$outputObject = ConvertFrom-Json -InputObject #"
$(armOutputJson)
"#
Write-Host "##vso[task.setvariable variable=armOutput]"$outputObject
Write-Host $outputObject
The output seems to written to the host like this:
#{storageAccountName=; functionAppName=}
It looks like the settings are not correctly parsed?
Also when trying to access this variable in my deploy task using $(armOutput).functionAppName.value, I got the following error:
[error]Error: Resource '#{storageAccountName=; functionAppName=}.functionAppName.value' doesn't exist. Resource should exist before deployment.
Anyone knows how I can parse the output json to a vsts variable and use it in another task?

Try to call Format-Custom to format the output $outputObject | Format-Custom -Depth 5
Related issue ConvertFrom-Json not deep?

You did it almost right, the approach is good, just some syntax typos. This should work (at least it works for me):
# parse string to json
$outputObject = $(armOutputJson) | ConvertFrom-Json
# outputObject is now object with more levels,
# printing it just like that does not help as each property contains nested objects
# save temporary variable
$storageAccountName = $outputObject.storageAccountName.value
# export VSTS variable
Write-Host "Setting Variable storageAccountName=$storageAccountName"
Write-Host "##vso[task.setvariable variable=storageAccountName]$storageAccountName"

Related

How to set custom filename for pabot result (html)

I implemented test cases for my application and decided to run it everyday. The problem is the result of the previous test will be overwritten by the latest test result. I need to keep them both so I came up with a solution that include the test date and time in the report name, for example; report-202111181704.html (use time in 24-hour format).
I searched through the internet and did not found any solution yet. Anybody here know the solution? or any alternative solution will be fine.
It depends on where you execute your tests. From command line you can save the date to variable. Then use this variable to change the name of generated outputs. For example
date=$(date '+%Y-%m-%d_%H:%M:%S')
robot --output ${date}output.xml --log ${date}log.html --report ${date}report.html test.robot
I found the solution. Instead of setting .html file name, I create a folder and put the result there.
To do this, add --outputdir in pabot command so it's gonna look like this
pabot --pabotlibport $PABOT_PORT --pabotlib --resourcefile ./DeviceSet.dat --processes $thread --verbose --outputdir ./result/$OUTPUT_DIR $ENV
where
$OUTPUT_DIR=`date + "%Y%m%d-%H%M"`
The output folder gonna be like ./result/20220301-2052

Defining setup, teardown and variable in argumentfile in robotframework

Basically 2 issues:
1. I plan to execute multiple test cases from argument file. The structure would look like that:
SOME_PATH/
-test_cases/
-some_keywords/
-argumentfile.txt
How should i define a suite setup and teardown for all those test cases executed from file (-A file)?
From what i know:
a) I could execute it in file with 1st and last test case, but the order of test cases may change so it is not desired.
b) provide it in init.robot and put it somewhere without test cases only to get the setup and teardown. This is because if I execute:
robot -i SOME_TAG -A argumentfile /path/to/init
and the init is in test_case folder it will execute the test_cases with a specific tag + those in a folder twice.
Is there any better way? Provide it, for example, in argumentfile?
2 How to provide PATH variable in argumentfiles in robotframework?
I know there is possibility to do:
--variable PATH:some/path/to/files
but is it not for test suite env?
How to get that variable to be visible in the file itself: ${PATH}/test_case_1.robot
For your 2nd question, you could create a temporary environment variable that you'd then use. Depending on the OS you're using, the way you'll do this will be different:
Windows:
set TESTS_PATH=some/path/here
robot -t %TESTS_PATH%/test_case_1.robot
Unix:
export TESTS_PATH="some/path/here"
robot -t $TESTS_PATH/test_case_1.robot
PS: you might want to avoid asking multiple, different questions in the same thread

View JSON file in Midnight Commander using jq

So there is that awesome tool for working with JSON data called jq.
And there is that awesome linux file manager called mc.
One day (today) I came around an idea to integrate these two, so I could easily preview JSON files in a pretty/formatted way using F3 keyboard shortcut when in Midnight Commander.
I opened MC extension file using Command → Edit extension file menu actions and then added following to such opened configuration file:
# json
regex/\.json$
View=%view{ascii} jq < %f
I thought it is straightforward, but unexpectedly it does not work: trying to view the JSON (F3) results in error popup with contents of jq's help page (the same as when you type jq by itself), so starting with: "jq - commandline JSON processr [version 1.5]..."
Can anybody tell me why this configuration is incorrect?
Two minutes after I submitted my question I've been revealed.
I thought that maybe jq does not produce standard output... It led me to this question: How to use jq in a shell pipeline? and so I have modified the extension file to look like:
# json
regex/\.json$
View=%view{ascii} jq '.' < %f
And now it works as expected, piping result of jq to the internal mc viewer.
Thank you, me ;)
You don't have to use redirection < here, you could use just a plain filename %f:
# json
regex/\.json$
View=%view{ascii} jq '.' %f
and as you mentioned you have to use a simple filter: .
For anyone wondering, why this no longer works. In version 4.8.29, MC switched from mc.ext to the new mc.ext.ini ini file, which has slightly different syntax. The new entry should look like this
[JSON]
Regex=\.json$
View=%view{ascii} jq '.' < %f
The [JSON] line is necessary.

Robot Framework : Configuration Profiles

I have a configuration file that I am reading into my robot test cases. This configuration file contains the following variables:
${DATABASE_IP} 127.0.0.1
${ORACLE_SYSTEM_ID} xe
${ORACLE_DATABASE_URL} jdbc:oracle:thin:#${DATABASE_IP}:1521:${ORACLE_SYSTEM_ID}
${ORACLE_DATABASE_USER} cooluser
${ORACLE_DATABASE_PASSWORD} coolpassword
${ORACLE_DATABASE_DRIVER} oracle.jdbc.driver.OracleDriver
One thing I'd like to be able to do is change some of these properties, depending on where the script is executed from. Example: jenkins
A simple way to look at this, is say as follows:
I have a test file called database_test.robot.
If I invoke this file on my local machine, I'd like to pass in an argument to ensure ${DATABASE_IP} equates to 127.0.0.1 . When Jenkins does it, I want that value to point somewhere else.
Something like this already exists with maven, where you can specify a profile at runtime. Ex: mvn verify -Plocal-config ; mvn verify -Pjenkins-config
I have looked through the robot framework documentation, but cannot seem to implement something similar. The only way to swap out properties that I see is to remove the old and replace in the new. Note : I have hundreds of properties that will differ, and several other environments aside form Jenkins and local that would take different values.
Robot gives you at least three ways to solve this: argument files, variable files, and resource files. In each of the cases, you can specify which environment settings to use with a command line argument.
Argument files
Argument files are, as the name implies, files from which robot can read arguments. They are a convenient way to specify a group of command line arguments.
For example, you could create a "environments" folder that contains argument files for each of your environments (production.args, staging.args, local.args) and within the file you would set the values for all of the variables.
For example, you could create a file named local.args with the following contents:
--variable DATABASE_IP:127.0.0.1
--variable ORACLE_SYSTEM_ID:xe
--variable ORACLE_DATABASE_URL:jdbc:oracle:thin:#127.0.0.1:1521:xe
--variable ORACLE_DATABASE_USER:cooluser
--variable ORACLE_DATABASE_PASSWORD:coolpassword
--variable ORACLE_DATABASE_DRIVER:oracle.jdbc.driver.OracleDriver
Then, to run with this configuration you would use the -A or --argumentfile option:
robot --argumentfile environments/local.args ...
The advantage to using argument files is that you can override single values on the command line for times when you need to change just one value:
robot --argumentfile environments/local.args --variable ORACLE_DATABASE_USER:anotheruser
Also, with argument files you can also specify any other command line arguments. For example, if you always want to ignore tests on your CI server that are known to be broken, you could include something like --exclude known-broken (where known-broken is a tag you've applied to one or more tests)
One downside to argument files is that you can't define variables based on the value of previous variables (ie: you can't do --variable FOOBAR=${FOO}bar). I've not found that to be much of a problem.
Variable files
Variable files work in a similar way, but let you define the variables with python. The advantage to variable files is that you can do anything that python lets you do. For example, you could automatically determine the IP of the local database, or selectively turn features on or off based on runtime conditions.
The simplest way to define a variable file is to simply create python variables, which robot will find by importing your file.
For example, the variable file for your variables might look like this:
DATABASE_IP = "127.0.0.1"
ORACLE_SYSTEM_ID = "xe"
ORACLE_DATABASE_URL = " jdbc:oracle:thin:#%s:1521:%s % (DATABASE_IP, ORACLE_SYSTEM_ID)
ORACLE_DATABASE_USER} = "cooluser"
ORACLE_DATABASE_PASSWORD} = "coolpassword"
ORACLE_DATABASE_DRIVER} = "oracle.jdbc.driver.OracleDriver"
Resource Files
Much like the other two solutions, you can have separate resource files for each environment. Since robot allows you to use variables in resource file paths within a suite, you can use a variable to define which resource file to use.
For example, you could import a resource file like this:
# some_tests.robot
*** Settings ***
Resource config/${environment}.robot
You would then create a config file for each environment like you normally would (eg: config/local.robot, config/staging.robot, etc). Then, when you run robot you can tell it which resource file to use:
$ robot --variable environment:local ...
I tried the third option with Resource files but given above command line argument statement:
$ robot --variable environment=local
Didn't work for me. After looking at the robot help file, came to know that variable values should be passed through : and not with =.
So I tried with:
$ robot --variable environment:local
And it worked for me.
The correct way to specify the Resource path for a subdirectory is:
Resource ../config/${environment}.robot
if config is a subdirectory.

TeamCity Current Date variable in MMdd format

In TeamCity is there an easy way to get a variable for the current date in the format MMdd (eg 0811 for 8-Aug)?
My google-fu did not turn up an existing plugins. I looked into writing a plugin, but not having a jdk installed, that looks time consuming.
This is quite easy to do with a PowerShell build step (no plugin required) using the following source code:
echo "##teamcity[setParameter name='env.BUILD_START_TIME' value='$([DateTime]::Now)']"
or (for UTC):
echo "##teamcity[setParameter name='env.BUILD_START_TIME' value='$([DateTime]::UtcNow)']"
This uses TeamCity's Service Message feature that allows you to interact with the build engine at runtime e.g. set build parameters.
You can then reference this build parameter from other places in TeamCity using the syntax %env.BUILD_START_TIME%
The advantage of this approach is you don't need to use a plugin. The disadvantage is you need to introduce a build step.
For Unix based build agents I propose next custom script as one of build commands:
export current_build_date_format="+%%Y.%%m.%%d"
export current_build_date="$(date $current_build_date_format)"
echo "##teamcity[setParameter name='env.current_build_date' value='$current_build_date']"
You have to make double % sign to avoid interpretation for date executable command line argument FORMAT string (see %Y.%m.%d) as already existing TeamCity variable.
The Groovy Plugin for TeamCity provides build start date/time properties:
Provides build properties:
system.build.start.date / env.BUILD_START_DATE
system.build.start.time / env.BUILD_START_TIME
This blog post has installation / configuration instructions for the Groovy plugin, as well an example of customizing the date/time format.
You can also try Date Build Number plug-in. It povides additional var in build number format rather than build property.
Similar to the Date Build Number plugin mentioned in this answer, there exists a derived plugin called Formatted Date Parameter. It provides a customizable parameter build.formatted.timestamp that can be used out of the box in fields or other parameters. No need for a separate build step.
An old question, but for those looking for a solution now there is a system parameter available.
system.buildStartTime
You need to declare it in config (it's not available until runtime) in order to run. I set mine to value [Filled Automatically]
As you can guess, this time is set to the build start time, so that may not be ideal for some needs. But it's easy and reliable.
To add a dated folder to my build in TeamCity I added the following to my custom script. What had me stuck was the double % sign in the date string. D'oh
TARGET_DIR=/Users/admin/build/daily
TARGET=$(date "+%%Y-%%m-%%d")
if [ ! -d ${TARGET_DIR} ]; then
mkdir -vp ${TARGET_DIR}/
fi
mv -v build.dmg ${TARGET_DIR}/build_${TARGET}.dmg
If you only want to have one-line bash command in a build step, just use as below.
echo "##teamcity[setParameter name='build.timestamp' value='$(date +%%m%%d)']"
(double % symbol is for TeamCity own escape rule to use % character)
It will set a MMdd parameter value right after the execution during runtime so very useful to put at any build step. Then, you can retrieve a parameter value afterward.
Note that you should create build.timestamp parameter firstly to TeamCity project.
A step further, I made a simple bash script to have bash date format timestamp. This script will set timestamp to whatever bash supported datetime format and parameter name to TeamCity.
name="" # TeamCity parameter name
format="%Y-%m-%dT%H:%M:%S%z" # ISO8601 format by default
result="" # a TeamCity parameter value to be set
for ARGUMENT in "$#"
do
KEY=$(echo "$ARGUMENT" | cut -f1 -d=)
VALUE=$(echo "$ARGUMENT" | cut -f2 -d=)
case "$KEY" in
name) name=${VALUE} ;;
format) format=${VALUE} ;;
*)
esac
done
result=$(date "+$format")
echo "##teamcity[setParameter name='$name' value='$result']"
Below usage will set ISO8601 format timestamp to build.timestamp parameter.
./teamcity_datetime.sh name=build.timestamp
If you want to set only MMdd, the execution could be as below.
./teamcity_datetime.sh name=build.timestamp format="%%m%%d"

Resources