how to share code in workflowLibs in Jenkins using workflow plugin - jenkins-workflow

In my workflowLibs directory I have a few files:
src/org/inin/Pipeline.groovy
src/org/inin/Build.groovy
src/org/inin/Test.groovy
The Build.groovy look like this:
package org.inin;
def DoBuild(foo){
echo "I am building: $foo"
}
The Test.groovy look like this:
package org.inin;
def DoTest(foo){
echo "I am testing: $foo"
}
I want my builds to do something like this:
def pipeline = new org.inin.Pipeline()
pipeline.DoBuild() or pipeline.Build.DoBuild()
pipeline.DoTest() or pipeline.Test.DoTest()
But I don't know how to make the Pipeline.groovy reference files in it's own directory.
I tried doing this:
package org.inin;
load "Build.groovy"
//evaluate(new File("./Build.groovy"))
But I always get:
java.lang.NoSuchMethodError: No such DSL method DoBuild found among ...
What's the proper way to do share code among groovy files in the workflowLibs directory structure?

I ended up doing some hackery:
src/org/inin/Pipeline.groovy:
package org.inin;
def getBuild(){
return new Build();
}
def getTest(){
return new Test();
}
src/org/inin/Build.groovy:
package org.inin;
def DoMavenBuild(gitRepo, gitBranch, pomName ){
...
}
src/org/inin/Test.groovy:
package org.inin;
def DoTest(){
...
}
And in the job itself:
def pipeline = new org.inin.Pipeline();
pipeline.build.DoMavenBuild(...);
pipeline.test.DoTest();

Related

Powershell script not working when included in Jenkins Pipeline Script

What I am trying to achieve with Powershell is as follows:
Increment the Build Number in the AssemblyInfo.cs file on the Build Server. My Script looks like below right now after over a 100 iterations of different variations I am still unable to get it to work. The script works well in the Powershell console but when included into the Jenkins Pipeline Script I get various errors that are proving hard to fix...
def getVersion (file) {
def result = powershell(script:"""Get-Content '${file}' |
Select-String '[0-9]+\\.[0-9]+\\.[0-9]+\\.' |
foreach-object{$_.Matches.Value}.${BUILD_NUMBER}""", returnStdout: true)
echo result
return result
}
...
powershell "(Get-Content ${files[0].path}).replace('[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+',
${getVersion(files[0].path)})) } | Set-Content ${files[0].path}"
...
How about a groovy approach (with Jenkins keywords) instead of PowerShell:
def updtaeAssemblyVersion() {
def files = findFiles(glob: '**/AssemblyInfo.cs')
files.each {
def content = readFile file: it.path
def modifedContent = content.repalceAll(/([0-9]+\\.[0-9]+\\.[0-9]+\\.)([0-9]+)/,"\$1${BUILD_NUMBER}")
writeFile file: it.path, text: modifedContent
}
}
It will read all relevant files and replace only the build section of the version for every occurrence that matches the version regex.

How does Pytest figure out that the monkeypatch fixture is for monkeypatching?

Consider this simple example from pytest's docs
# contents of test_module.py with source code and the test
from pathlib import Path
def getssh():
"""Simple function to return expanded homedir ssh path."""
return Path.home() / ".ssh"
def test_getssh(monkeypatch):
# mocked return function to replace Path.home
# always return '/abc'
def mockreturn():
return Path("/abc")
# Application of the monkeypatch to replace Path.home
# with the behavior of mockreturn defined above.
monkeypatch.setattr(Path, "home", mockreturn)
# Calling getssh() will use mockreturn in place of Path.home
# for this test with the monkeypatch.
x = getssh()
assert x == Path("/abc/.ssh")
How does Pytest figure out that the param monkeypatch is the one for monkeypatching?

Gradle task to write hg revision to file

Is there a simple way to write to file the mercurial version (or similar external command) in a gradle task:
I'm not yet groovy/gradle conversant, but my current effort looks like this:
task versionInfo(type:Exec){
commandLine 'hg id -i -b -t'
ext.versionfile = new File('bin/$baseName-buildinfo.properties')
doLast {
versionfile.text = 'build.revision=' + standardOutput.toString()
}
}
There are two issues with this build script:
the command line needs to be split; gradle's trying to execute a binary named hg id -i -b t instead of hg with arguments id, -i, -b and t
The standard output needs to be captured; you can make it a ByteOutputStream to be read later
Try this:
task versionInfo(type:Exec){
commandLine 'hg id -i -b -t'.split()
ext.versionfile = new File('bin/$baseName-buildinfo.properties')
standardOutput = new ByteArrayOutputStream()
doLast {
versionfile.text = 'build.revision=' + standardOutput.toString()
}
}
Here I have a little bit different approach, which uses javahg to get revision. And add task "writeRevisionToFile"
I wrote brief post on my blog Gradle - Get Hg Mercurial revision.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.aragost.javahg:javahg:0.4'
}
}
task writeRevisionToFile << {
new File(projectDir, "file-with-revision.txt").text = scmRevision
}
import com.aragost.javahg.Changeset
import com.aragost.javahg.Repository
import com.aragost.javahg.commands.ParentsCommand
String getHgRevision() {
def repo = Repository.open(projectDir)
def parentsCommand = new ParentsCommand(repo)
List<Changeset> changesets = parentsCommand.execute()
if (changesets == null || changesets.size() != 1) {
def message = "Exactly one was parent expected. " + changesets
throw new Exception(message)
}
return changesets[0].node
}
ext {
scmRevision = getHgRevision()
}

Scala command line parser using Scallop

I'm fairly new to Scala and need to build a really simple command line parser which provides something like the following which I created using JRuby in a few minutes:-
java -jar demo.jar --help
Command Line Example Application
Example: java -jar demo.jar --dn "CN=Test" --nde-url "http://www.example.com" --password "password"
For usage see below:
-n http://www.example.com
-p, --password set the password
-c, --capi set add to Windows key-store
-h, --help Show this message
-v, --version Print version
Scallop looks like it will do the trick, but I can't seem to find a simple example that works! All of the examples I've found seem to be fragmented and don't work for some reason or other.
UPDATE
I found this example which works, but I'm not sure how to bind it into the actual args within the main method.
import org.rogach.scallop._;
object cmdlinetest {
def main(args: Array[String])
val opts = Scallop(List("-d","--num-limbs","1"))
.version("test 1.2.3 (c) 2012 Mr Placeholder")
.banner("""Usage: test [OPTION]... [pet-name]
|test is an awesome program, which does something funny
|Options:
|""".stripMargin)
.footer("\nFor all other tricks, consult the documentation!")
.opt[Boolean]("donkey", descr = "use donkey mode")
.opt("monkeys", default = Some(2), short = 'm')
.opt[Int]("num-limbs", 'k',
"number of libms", required = true)
.opt[List[Double]]("params")
.opt[String]("debug", hidden = true)
.props[String]('D',"some key-value pairs")
// you can add parameters a bit later
.args(List("-Dalpha=1","-D","betta=2","gamma=3", "Pigeon"))
.trailArg[String]("pet name")
.verify
println(opts.help)
}
}
Well, I'll try to add more examples :)
In this case, it would be much better to use ScallopConf:
import org.rogach.scallop._
object Main extends App {
val opts = new ScallopConf(args) {
banner("""
NDE/SCEP Certificate enrollment prototype
Example: java -jar demo.jar --dn CN=Test --nde-url http://www.example.com --password password
For usage see below:
""")
val ndeUrl = opt[String]("nde-url")
val password = opt[String]("password", descr = "set the password")
val capi = toggle("capi", prefix = "no-", descrYes = "enable adding to Windows key-store", descrNo = "disable adding to Windows key-store")
val version = opt[Boolean]("version", noshort = true, descr = "Print version")
val help = opt[Boolean]("help", noshort = true, descr = "Show this message")
}
println(opts.password())
}
It prints:
$ java -jar demo.jar --help
NDE/SCEP Certificate enrollment prototype
Example: java -jar demo.jar --dn CN=Test --nde-url http://www.example.com --password password
For usage see below:
-c, --capi enable adding to Windows key-store
--no-capi disable adding to Windows key-store
--help Show this message
-n, --nde-url <arg>
-p, --password <arg> set the password
--version Print version
Did you read the documentation? It looks like all you have to do is call get for each option you want:
def get [A] (name: String)(implicit m: Manifest[A]): Option[A]
It looks like you might need to provide the expected return type in the method call. Try something like this:
val donkey = opts.get[Boolean]("donkey")
val numLimbs = opts.get[Int]("num-limbs")
If you're just looking for a quick and dirty way to parse command line arguments, you can use pirate, an extremely barebones way to parse arguments. Here is what it would look like to handle the usage you describe above:
import com.mosesn.pirate.Pirate
object Main {
def main(commandLineArgs: Array[String]) {
val args = Pirate("[ -n string ] [ -p string ] [ -chv ]")("-n whatever -c".split(" "))
val c = args.flags.contains('c')
val v = args.flags.contains('v')
val h = args.flags.contains('h')
val n = args.strings.get("n")
val p = args.strings.get("p")
println(Seq(c, v, h, n, p))
}
}
Of course, for your program, you would pass commandLineArgs instead of "-n whatever -c".
Unfortunately, pirate does not yet support GNU style arguments, nor the version or help text options.

Scalate ResourceNotFoundException in Scalatra

I'm trying the following based on scalatra-sbt.g8:
class FooWeb extends ScalatraServlet with ScalateSupport {
beforeAll { contentType = "text/html" }
get("/") {
templateEngine.layout("/WEB-INF/scalate/templates/hello-scalate.jade")
}
}
but I'm getting the following exception (even though the file exists) - any clues?
Could not load resource: [/WEB-INF/scalate/templates/hello-scalate.jade]; are you sure it's within [null]?
org.fusesource.scalate.util.ResourceNotFoundException: Could not load resource: [/WEB-INF/scalate/templates/hello-scalate.jade]; are you sure it's within [null]?
FWIW, the innermost exception is coming from org.mortbay.jetty.handler.ContextHandler.getResource line 1142: _baseResource==null.
Got an answer from the scalatra mailing list. The problem was that I was starting the Jetty server with:
import org.mortbay.jetty.Server
import org.mortbay.jetty.servlet.{Context,ServletHolder}
val server = new Server(8080)
val root = new Context(server, "/", Context.SESSIONS)
root.addServlet(new ServletHolder(new FooWeb()), "/*")
server.start()
I needed to insert this before start():
root.setResourceBase("src/main/webapp")