FAKE: How to define MSBuild properties? - f#

I want to switch from MSBuild to FAKE. In my MSBuild script I create a Webdeploy package by invoking MSBuild with the properties DeployOnBuild=True and DeployTarget=Package. This will trigger webdeploy to generate a deployment package while the build is running:
<MSBuild Projects="#(ItemToBuild)"
Targets="Build"
Properties="Configuration=$(Configuration);
Platform=$(Platform);
DeployOnBuild=True;
DeployTarget=Package;
OutFolder=$(OutFolder)" />
How can I do the same thing with FAKE? I've come this far:
Target "Build" (fun _ ->
!! solutionFile
|> MSBuildRelease binDir "Build"
|> Log "Build-Output: "
)
How can I specify the required properties?

If you look at the source code, you'll see that MSBuildRelease is just a shortcut for MSBuild proper with certain predefined properties. If you need to define other properties, besides "Configuration", you can just fall back to MSBuild:
Target "Build" (fun _ ->
!! solutionFile
|> MSBuild binDir "Build"
[
"Configuration", "Release"
"Platform", "AnyCPU"
"DeployOnBuild", "True"
"DeployTarget", "Package"
"OutFolder", "/what/ever"
]
|> Log "Build-Output: "
)

Related

How to list folders containing a file on jenkins pipeline?

I'm trying to list folders containing a certain file on jenkins and use later this array.
I read about findFiles but I can't find a way to use it in this situation.
The finality is that I need to cd to those folders in a loop and perform some actions.
I have only one jenkins where everything is running
Use case:
I have a workspace in which I have packages. I need to run some commands in some folders, I can't do it from the root of y workspace. They may be in subfolders or subsubfolders. The way I can identify a package is when it contains a package.xml (on ROS). Also I don't have any command to list their paths
If nothing else is working then you can try running a normal linux command like:
folders = sh(
script: "locate myfile",
returnStdout: true
)
Then split this to form an array and use the value like :
folders.split("\n")[1]
def packageDirs = findFiles(glob: '**/package.xml')
.findAll { f -> !f.directory }
.collect{ f -> f.path.replace('/', '\\') - ~/\\[^\\]+$/ }
packageDir.each { d ->
dir(d) {
// Process each package here
}
}

How to invoke external build scripts?

How do I execute another FAKE build script from within a FAKE build script?
I want to create a build script which clones a git repo and then executes a build script within the cloned project. After that it should tag the branch and publish the build artifact to a Nexus Repository Manager.
Also I want to hand over some parameter to the external build script, e.g. a version tag.
Here is some pseudo code:
Target "ReleaseBuild" (fun _ ->
CleanDir "src"
cloneSingleBranch "" "http://<URL to git-repo>" "master" "src"
????? "src/build.fsx" versionNumer
... tagging etc. ...
)
The usual way to modularize your build is not by calling FAKE within FAKE, but by having FSI load modules using the #load directive.
For example:
// build.fsx
#r "path/to/FakeLib.dll"
#load "./OtherModule.fsx"
open Fake
Target "ReleaseBuild" <| fun _ ->
CleanDir "src"
cloneSingleBranch "" "http://<URL to git-repo>" "master" "src"
OtherModule.DoWhatever versionNumer
...
// OtherModule.fsx
let DoWhatever version =
...
.
EDIT (in response to comment)
If the other script file doesn't exist when the first one starts, then you could execute it using FSIHelper.executeFSI:
Target "ReleaseBuild" <| fun _ ->
CleanDir "src"
cloneSingleBranch "" "http://<URL to git-repo>" "master" "src"
let result, messages = FSIHelper.executeFSI "src" "build.fsx" []
...
(or executeFSIWithArgs if you need to pass arguments)
If even this doesn't work for you for some reason, I would just resort to executing it as a regular shell command, using Shell.Exec:
Target "ReleaseBuild" <| fun _ ->
CleanDir "src"
cloneSingleBranch "" "http://<URL to git-repo>" "master" "src"
let errCode = Shell.Exec ("path/to/fake.exe", args = "src/build.fsx")
...
But if you want this to be cross-platform, it gets a bit complicated: *.exe won't execute natively on UNIX, you need to run mono and give the .exe file as argument. To work around that, you'd need to wrap fake.exe in a shell script (two scripts - one for Windows, one for UNIX), and then pass the name of that script as argument into the FAKE script.

FAKE: Target prints all available targets in build script

Question: Is there a command in FAKE available which prints all the defined targets in the build script?
I want to setup my FAKE build in such a way that it prints a list of all available targets in the build script when I do not specify a target.
For example:
> build.cmd
Available targets:
- Clean
Depends on: []
- DeleteBinObj
Depends on: []
- RestorePackages
Depends on: ["Clean"]
- Build
Depends on: ["RestorePackages"]
- CopyBinaries
Depends on: ["RunTests"]
- RunTests
Depends on: ["Build"]
- Default
Depends on: ["CopyBinaries"]
In the FAKE build script I would define something like:
Target "Default" (fun _ ->
listTargets
)
RunTargetOrDefault "Default"
The only thing that is missing it the command listTargets.
In your build.cmd replace
packages\FAKE\tools\FAKE.exe build.fsx %*
with
if [%1] == [] (
packages\FAKE\tools\FAKE.exe build.fsx --listTargets
) else (
packages\FAKE\tools\FAKE.exe build.fsx %*
)

How to pass Teamcity build parameters into an Ant script that is launched by Fake script?

I have an Ant build.xml which contains the following code:
<mkdir dir="c:/MyDir/${build.number}/html"/>
This works fine when I run this task as a separate TeamCity build step (as an Ant task).
I have moved the execution of this script into a Fake F# script. Now, when I execute the Fake script from Teamcity, the value of the parameter is not being set (it literally creates a folder with the name "${build.number}").
I launch my ant script in Fake like this:
let cmd = sprintf #"%s\plugins\ant\bin\ant.bat" (Configuration.agentHomeDir.ToString())
let args = ""
let dir = ""
Shell.Exec(cmd, args, dir)
How would I refer to Teamcity's build number from inside my ant script correctly?
Well, I ended up passing the buildnumber via a command line argument.
in fake script:
let buildNumber = environVar "BUILD_NUMBER"
let cmd = sprintf #"%s\plugins\ant\bin\ant.bat" (Configuration.agentHomeDir.ToString())
let args = sprintf "-DbuildNumber=%s" buildNumber.ToString()
let dir = ""
Shell.Exec(cmd, args, dir)
in ant's build.xml:
<property name="buildNumber" value="buildNumber" />
...
<mkdir dir="c:\mydir\${buildNumber}" />
Would welcome a more graceful solution.

ANT Gradle - Axis WSDL 2 Java : No such property: axis for class: org.gradle.api.internal

I have the following code snap in ANT build.xml which is converting WSDL to Java. It works and uses axis-ant.jar 1.4.0
<!-- Build generated jars -->
<target name="axis-WSDL-2-Java" depends="init">
<taskdef resource="axis-tasks.properties" classpathref="axis.classpath" />
<axis-wsdl2java
output="${build.gen.src}"
testcase="true"
verbose="true"
url="${build.src.wsdl.v1}/${build.ws.wsdlfile}" >
</axis-wsdl2java>
<!-- Compile artifacts -->
<echo message="Compiling WS artifact source for Axis..." />
<javac destdir="${build.gen.classes}" debug="true" >
<src path="${build.gen.src}" />
<classpath>
<pathelement path="${build.lib.3rdParty}" />
<path refid="axis.classpath" />
</classpath>
</javac>
<jar .... some jar code here...
</jar>
</target>
Now, I converted the build script to Gradle and came up with the following Gradle code snap..
//wsdl to java
task axisWSDLTojava() << {
println "-- Inside axisWSDLToJava"
def flGen = new File( "$project.buildDir/thidsGen/src" )
flGen.mkdirs()
flGen = new File( "$project.buildDir/thidsGen/classes" )
flGen.mkdirs()
ant {
taskdef(
resource: 'axis-tasks.properties',
classpath: configurations.axisAnt.asPath )
axis-wsdl2java(
output: "$project.buildDir/thidsGen/src",
testcase: "true",
verbose: "true",
url: "$projectDir/src/ws/v1/wsdl/MDSSFileInfo.wsdl")
}
}
//compile generated src to classes
task compileJavaWsArtifacts (type: JavaCompile, dependsOn: axisWSDLTojava) << {
println "-- Inside compileGenSrc"
source = "$project.buildDir/thidsGen/src"
classpath = configurations.axisAnt.asPath
destinationDir = "$project.buildDir/thidsGen/classes"
}
// Build jar with web service artifacts
task jarWsArtifacts( type: Jar, dependsOn: compileJavaWsArtifacts ) << {
println "-- Inside jarWsArtifacts"
// some code here
// some code here to create the jar etc
}
Gradle logic for calling the respective task is all set i.e. I call the above task as dependsOn in CompileJava Gradle task..
// Compile java server components - must have artifacts first
compileJava {
dependsOn jarWsArtifacts
}
Configuration section in Gradle is defined as:
// Custom configurations
configurations {
axisAnt
}
Dependencies section in Gradle is defined as:
// Define dependencies
dependencies {
// Compilation
//compile 'groupid:artifactid:x.x.x'
//compile 'groupid:artifactid:x.x.x#yyy'
//other bunch of dependencies... come here which are required for compile task in Gradle
//axis-wsdl2java generates java files, which generates class files and jard into a -ws.jar file
compile fileTree( dir: 'build/resultantJar', include: "$ProjectName-ws-*.jar" )
// Unit Tests
testCompile 'xxx:yyy:x.x.x'
testCompile 'xxx:yyy:x.x.x'
//more artifacts for testCompile..
// Integration tests
// Everything from compile and testCompile targets
integrationTestCompile configurations.compile
integrationTestCompile configurations.testCompile
// Output of compiling "main" files
integrationTestCompile sourceSets.main.output
// Additional dependencies from war and others
integrationTestCompile 'xxx:yyy:x.x.x'
integrationTestCompile 'xxx:yyy:x.x.x'
//other enteries for IT test task
// All configuration files in conf folder in source control required for IT tests.
integrationTestRuntime files( 'conf' )
//Axis-ANT
axisAnt 'axis:axis-ant:1.4.0'
axisAnt 'othergroupid:otherartifactid:x.x.x'
axisAnt 'othergroupid:otherartifactid:x.x.x'
// comes here which are required for axis-wsdl2java to work
}
BUT, While running "gradle clean build", I'm getting the following error message:
:axisWSDLTojava FAILED
FAILURE: Build failed with an exception.
* Where:
Build file '/production/jenkinsAKS/workspace/DFDailyFeedSvc/build.gradle' line: 90
* What went wrong:
Execution failed for task ':axisWSDLTojava'.
> No such property: axis for class: org.gradle.api.internal.project.DefaultAntBuilder
Possible solutions: ant
Any idea, why it's not able to see axis-wsdl2java (which I see if defined in axis-tasks.properties file within axis-ant.jar version 1.4.0 as following:)
#properties file for taskdefing the public Axis taskdefs
axis-wsdl2java=org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask
axis-java2wsdl=org.apache.axis.tools.ant.wsdl.Java2WsdlAntTask
axis-admin=org.apache.axis.tools.ant.axis.AdminClientTask
OK, resolved.
Changing the following in the Gradle code did the trick. Don't know why Gradle didn't pick it without double quotes way. REASON: In Java/Groovy (Gradle uses Groovy), you can't have a function with a "-" in it's name (you can have giga_fifa but not giga-fifa). Glad, using "" resolved it.
axis-wsdl2java(
with
"axis-wsdl2java"(
Other thing, wherever I used "$project.buildDir .. I changed that to $buildDir as ANT was complaining about project.buildDir not found or buildDir not found when it was written in $project.buildDir format. Using $buildDir resolved those issues.
Also, compileJavaWsArtifacts was NOT seeing the generated src files!!! even though there were generated successfully after wsdl2java operation in Gradle build. So, did the shenzi using the following code:
//compile generated src to classes
//task compileJavaWsArtifacts (type: JavaCompile, dependsOn: axisWSDLToJava) << {
// source = "$buildDir/thidsGen/src"
// classpath = configurations.axisAnt.asPath
// destinationDir = "$buildDir/thidsGen/classes"
//}
//compile generated src to classes
task compileJavaWsArtifacts (dependsOn: axisWSDLToJava) << {
ant {
javac( destdir: "$buildDir/thidsGen/classes", debug: 'true', includeAntRuntime: 'no', classpath: configurations.axisAnt.asPath ) {
src( path: "$buildDir/thidsGen/src" )
}
}
}

Resources