How to use GitVersion Environment variables - f#

I have a project which I used to build via AppVeyor. The build sequence was the following:
Install and run GitVersion
Build project
Create package using evaluated version number.
The last step was done by the PowerShell command:
nuget pack path/tofile.nuspec -Version (get-item env:GitVersion_InformationalVersion).Value
As you can see the version is taken from environment variable defined by GitVersion.
Now I want to migrate the build to a FAKE build script.
I have these dependencies defined in my script.
"Clean"
=?> ("GitVersion", Choco.IsAvailable)
==> "RestorePackages"
==> "BuildApp"
==> "CreatePackage"
==> "Default"
Git version step is straightforward.
Target "GitVersion" (fun _ ->
"gitversion.portable" |> Choco.Install id
Shell.Exec("gitversion","/l console /output buildserver" ) |> ignore
)
I can see in my logs that variables are set by GitVersion.
Adding Environment Variable. name='GitVersion_SemVer'
value='1.1.1-xxx'
The next step is to create the package.
Target "CreatePackage" (fun _ ->
TraceEnvironmentVariables()
let version =
match buildServer with
| AppVeyor -> environVar "GitVersion_SemVer"
| _ -> baseVersion + "-local"
NuGet (fun p ->
{p with
OutputPath = packagingDir
WorkingDir = "."
Version = version
Publish = false })
nuspecFileName
)
I'm printing all the variables defined, after that I'm trying to get the version by reading variable and assigning it to version.
Unfortunately version stays empty when I run the build. After I added TraceEnvironmentVariables() method call I can see that none of the variables defined by GitVersion is presented in the output.
As John Palmer and dustinmoris said the process started by Shell.Execute sets all variables as process-level ones.
Is there a way to use Shell.Execute so that the process can set global scope environment variables?
UPD
As a workaround, I've added extra step in AppVeyor.yml config file:
init:
- git config --global core.autocrlf input
install:
- choco install gitversion.portable -y
before_build:
- ps: gitversion /l console /output buildserver /b (get-item env:APPVEYOR_REPO_BRANCH).Value
build_script:
- cmd: build.bat BuildApp
In this case, variables are set in a global scope and I can get them and use in my build script.
Obviously, PowerShell starts GitVersion in a different way. I guess, I should mimic it somehow in my build script.
So my question remains the same, how to use GitVersion as a target in my script and get the version number back.

Have you had a look at Fake GitVersionHelper? http://fsharp.github.io/FAKE/apidocs/fake-gitversionhelper.html
#r "packages/FAKE/tools/FakeLib.dll"
open Fake
open Fake.GitVersionHelper
let version = GitVersion (id)
printfn "FullSemVer %s" version.FullSemVer
printfn "NuGetVersionV2 %s" version.NuGetVersionV2

Your problem is that you create a process-level environment variable. After you exist the shell process the next step which runs in a different process doesn't know about any env vars which you set there.
You will have to set a permanent environment variable like user-level or machine-level one.
Have a look at the Environment.SetEnvironmentVariable method in .NET.
Example:
Environment.SetEnvironmentVariable("key", "value", EnvironmentVariableTarget.Machine);
However, I don't think this is a good solution though. I don't know GitVersion and frankly don't understand why you need this thing. Can your build script not determine the semantic version itself? Clearly setting the sem version is a manual step, because no automation tool would know how to correctly increment the version based on your code changes. So you should pick one place in your project (1 file, like readme notes, or anything else where it makes sense) to set your semantic version and have all other tools read it from there to set assembly versions during the build, package nuget packages, create tags in git, etc..

Related

Jenkins pipeline to change appssettings.json file and build according to the environment

I had a requirment to build a console application, but i need to change some values in appssettings.json file according to the environment and then build it. I am new to jenkins and want to know how to acheive this.
for dev change values in json file and build it -> for test again change the json values and build it -> till prod
This can be done in multiple ways for example (the common idea between these is to check the incoming branch):
You might find better ways to do it but you can use this as a start.
Using bash, jq, sponge through sh step:
Create a json file as a template like the following (consider keeping this file in a version control to clone every build)
# settings.json
{
environment: 'ENVIRONMENT_NAME',
appVersion: 'APP_VERSION'
}
Check the branch name value through if condition and update the template according to the branch value
jq '.environment = "branch_name"' settings.json|sponge settings.json
Use the customized settings.json in your application's code
Using Config File Provider Plugin which can be used inside the Jenkins pipeline as the following (also update it based on the branch name)
configFileProvider([configFile(fileId: 'FILE_ID', targetLocation: 'FILE_LOCATION')]) {}
Check if the application framework can make use of environment variables.

Bazel- How to recursively glob deleted_packages to ignore maven outputs?

I have a mutli-module project which I'm migrating from Maven to Bazel. During this migration people will need to be able to work on both build systems.
After an mvn clean install Maven copies some of the BUILD files into the target folder.
When I later try to run bazel build //... it thinks the BUILD files under the various target folders are valid packages and fails due to some mismatch.
I've seen deleted_packages but AFAICT it requires I specify the list of folders to "delete" while I can't do that for 200+ modules.
I'm looking for the ability to say bazel build //... --deleted_packages=**/target.
Is this supported? (my experimentation says it's not but I might be wrong). If it's not supported is there an existing hack for it?
Can you use your shell to find the list of packages to ignore?
deleted=$(find . -name target -type d)
bazel build //... --deleted_packages="$deleted"
#Laurent's answer gave me the lead but Bazel didn't accept relative paths and required I add both classes and test-classes folders under target to delete the package so I decided to answer with the complete solution:
#!/bin/bash
#find all the target folders under the current working dir
target_folders=$(find . -name target -type d)
#find the repo root (currently assuming it's git based)
repo_root=$(git rev-parse --show-toplevel)
repo_root_length=${#repo_root}
#the current bazel package prefix is the PWD minus the repo root and adding a slash
current_bazel_package="/${PWD:repo_root_length}"
deleted_packages=""
for target in $target_folders
do
#cannonicalize the package path
full_package_path="$current_bazel_package${target:1}"
classes_full="${full_package_path}/classes"
test_classes_full="${full_package_path}/test-classes"
deleted_packages="$deleted_packages,$classes_full,$test_classes_full"
done
#remove the leading comma and call bazel-real with the other args
bazel-real "$#" --deleted_packages=${deleted_packages:1}
This script was checked in under tools/bazel which is why it calls bazel-real at the end.
I'm sorry I don't think this is supported. Some brainstorming:
Is it an option to point maven outputs somewhere else?
Is is an option not to use //... but explicit target(s)?
Maybe just remove the bad BUILD files before running bazel?

How to make a Java console output a environment variable in Jenkins?

I am new to Jenkins and even though I found a few similar questions, none of the solutions seemed to work for me the way I need it to. It might look like a basic problem to some but for me it's a very big deal that I'm struggling with.
Basically, I built a project that executes Java Selenium code, which displays session ID in Jenkins' Console Output and that's what I need to add to environment variables to be used in the projects triggered after completion of this one.
I tried some Groovy scripts but I don't think I understand enough how to work with it and so whatever I was given, wasn't what I hoped to get.
Has anyone done something similar to provide some tips on how to achieve that?
Many thanks
There are two options (in theory, one of them doesn't work, see 2. below) depending on whether the printing is under your control or not.
Printing is under your control:
Write the session ID to a properties file, e.g. from-build-log.properties:
sessionId=...
Add post-build action → Trigger parameterized build on other projects →
This plugin triggers builds on other projects, with parameters that are predefined, or supplied by the finished build.
Every parameter will be passed to the target project(s), even if the target is not parameterized, or if no property of that name is defined.
Add parameters → Parameters from properties file
Use properties from file: from-build-log.properties
Printing is not under your control:
Add post-build action → Post build task → :
This feature allows you to associate shell or a batch scripts that perform some tasks on Hudson depending on the build log output. If the log text matches somewhere in the build log file, the script will execute. [...]
Java Regex are allowed, and groups can be used as script parameters. If the text is "Last Build : #(\d+)" and the script is "script.sh", then if the log contains a line "Last Build : #4", the script "script.sh 4" will be called.
Tasks → Script → :
[...] References %1, .. %n are allowed, and will be replaced by the groups matched by the Regex. %0 is the whole match.
Unfortunately this doesn't to work since there is an issue known since 2013: [JENKINS-17268] Post build task plugin: Passing arguments does not work as documented.
Build → Execute Windows batch command → Command:
#echo( & echo CMD: sessionId=123456789
Post build task → Tasks:
Log text: sessionId=(\d+)
Script:
#echo( & echo sessionId='%1'(!) of '%0'
Console Output:
...
[Freestyle-project] $ cmd /c call C:\Windows\TEMP\hudson4684581005071706054.bat
CMD: sessionId=123456789
C:\Program Files (x86)\Jenkins\workspace\Freestyle-project>exit 0
Performing Post build task...
Match found for :sessionId=(\d+) : True
Logical operation result is TRUE
Running script : #echo( & echo sessionId='%1'(!) of '%0'
[Freestyle-project] $ cmd /c call C:\Windows\TEMP\hudson1525182929053902824.bat
sessionId=''(!) of 'C:\Windows\TEMP\hudson1525182929053902824.bat'
C:\Program Files (x86)\Jenkins\workspace\Freestyle-project>exit 0
POST BUILD TASK : SUCCESS
END OF POST BUILD TASK : 0
Finished: SUCCESS
%0 is not the "the whole match" but the script's name, as usual with Windows command line. %1 is empty.
A workaround is:
Add build step → Execute shell → Command:
sed -En 's/.*(sessionId=[0-9]+)/\1/p' \
../../jobs/${JOB_NAME}/builds/${BUILD_NUMBER}/log > from-build-log.properties
Add post-build action → Trigger parameterized build on other projects
Add parameters → Parameters from properties file
Use properties from file: from-build-log.properties

Pass a dynamic parameter in Jenkins build

I want to pass a dynamic parameter in Jenkins in a scheduled job (this build runs every day at 3:00 am)
This works if I executed it in my linux command line:
mvn package -DintegrationTag=$(date +%d-%m-%y)
or
mvn package -DintegrationTag="$(date +%d-%m-%y)"
or
mvn package -DintegrationTag="$(date +"%d-%m-%y")"
with these 3 options this is what is executed, for example (this is what I want to do in Jenkins):
mvn package -DintegrationTag=16-09-2013
but any of these sentences, do not work in my Jenkins goals and options (because the dynamic parameter).
Is there any way to do it?
The solution:
Content of the file which constains the script:
echo "NOW=`date +%d-%m-%y`"> env.properties
Path of the properties file:
env.properties
In project, goals and options:
clean test package -DintegrationTag=$NOW
Inject environment variables to the build process = true
In a Build "execute shell" section add this
NOW=`date +%d-%m-%y`
mvn package -DintegrationTag=$NOW
Another option can be to execute a top level maven target in jenkins.
The first two steps of injecting the required variable value into the build environment remains same as the answer given by #Iker below.
In the third step, give goal as
clean test packageand then in Properties section within the 'Advanced' tab, giveintegrationTag=$<your variable name>
Note that this solution is useful when one creates a free style project in jenkins. For maven 2/3 projects,solution by #Iker is good:)

How to execute package for one submodule only on Jenkins?

I have a sbt project with 4 modules: module-a, module-b, module-c, module-d.
Each module can be packaged as a WAR. I want to set up a deployment on Jenkins that would build only one of the 4 modules and deploy it to a container.
In detail, I want to have 4 Jenkins jobs - job-a, job-b, job-c, job-d, each building only the defined module (a to d).
For now, I am using clean update test package as the command for the Jenkins sbt build, but this results in packaging all 4 modules that is not necessary.
I already tried project -module-a clean update test package but with no luck.
You may also like to execute project-scoped clean and test tasks as follows:
sbt module-a/clean module-a/test
The solution is slightly shorter and clearer as to what project the following commands apply to.
You don't need to execute update task since it's implicitly executed by test as described in inspect tree test.
There's a way to make it cleaner with an alias. Use the following in the build.sbt:
addCommandAlias("jenkinsJob4ModuleA", "; module-a/clean; module-a/test")
With the alias, execute jenkinsJob4ModuleA to have the same effect as the above solution.
Quote the argument to project, i.e. project module-a, and don't use a dash before the name of the submodule.
The entire command line for the Jenkins job would than be as follows:
./sbt "project module-a" clean update test

Resources