Use file features on Job DSL - gradle

I´m using Job DSL and I would like to download a file, read it, and set some env variables.
def static setSecrets(Job delegate, Map overrides = [:]) {
def liveUsername
def livePassword
def file
new URL('https://path/file').withInputStream { i ->
file.withOutputStream {
it << i
}
}
file.withReader { liveUsername = it.readLines().get(0) }
file.withReader { livePassword = it.readLines().get(1) }
def options = [
IDENTITY_USER: liveUsername,
IDENTITY_PASSWORD: livePassword]
setEnv(delegate, options, overrides)
}
This is the exception that I´m receiving
java.lang.NullPointerException: Cannot invoke method withOutputStream() on null object
Seems like the features of file cannot being used. But being in groovy file I was expecting can use the Job DSL templates and also, all the groovy features.

File is null so is throwing NPE when you call a method on it
def file
...
file.withOutputStream { // BANG!

Related

Jenkins Groovy Pipeline Get (Windows)User Folder Per Node

I have a distributed Jenkins build and the user under which the jenkins process runs on the slaves is not necessarily static, so I need a mechanism to get the user per node.
I am trying something like
#!/usr/bin/env groovy
class TestSettings {
public static String NuGetPackagesPath = "${env.USERPROFILE}\\.nuget\\packages"
}
node("master"){
println env.USERPROFILE // works as expected
println TestSettings.NuGetPackagesPath // throws exception
}
node("build"){
println env.USERPROFILE // works as expected
println TestSettings.NuGetPackagesPath // throws exception
}
env doesn't work in the static property, because the property is already initialized before you enter the node closure. So env just isn't available yet.
I see two ways around this:
Turn the property into a function and pass the env variable as parameter.
Make it a non-static function and pass env to the class constructor.
I would propably go with the latter as it will be easier to use when you have many test settings.
class TestSettings {
public static String getNuGetPackagesPath( def env ) { "${env.USERPROFILE}\\.nuget\\packages" }
}
class TestSettings2 {
def env = null
TestSettings2( def env ) {
this.env = env
}
public String getNuGetPackagesPath() { "${env.USERPROFILE}\\.nuget\\packages" }
}
node("master"){
println env.USERPROFILE
println TestSettings.getNuGetPackagesPath( env )
def testSettings = new TestSettings2( env )
// Note that we can use the method like a property!
println testSettings.nuGetPackagesPath
}

Use different file path for testing in Spring Boot

I have a class in my project housing a method to retrieve files (as a list). In order to write unit tests, and to be able to put everything into a versioning tool, I want put a small example directory into my project. However, when I do that, my method needs to be able to distinguish whether or not it should read from the real (project-external) path or the testing environment.
This is my method:
fun getDirectoryContentObject(baseUserDir: String): UserLicenses {
val dirExists = Files.exists(Paths.get(licenseLocation + baseUserDir))
if(!dirExists) {
return UserLicenses(baseUserDir, listOf())
}
val userLicenses = UserLicenses(baseUserDir, listOf())
Files.walk(Paths.get(licenseLocation + baseUserDir)).forEach { outerIt ->
val dirOrFileName = outerIt.fileName.toString()
if (dirOrFileName != baseUserDir && !dirOrFileName.endsWith(licenseFileExtension)) {
val fileList: MutableList<String> = mutableListOf()
Files.walk(Paths.get(outerIt.toString())).forEach { innerIt ->
val subDirOrFileName = innerIt.fileName.toString()
if (subDirOrFileName.endsWith(licenseFileExtension)) {
fileList += subDirOrFileName
}
}
userLicenses.licenseVersions += LicenseVersions(dirOrFileName, fileList)
}
}
return userLicenses
}
The licenseLocation value is set by #Value from application.yml and point to the files outside the project.
How can I tell the method to get the files from the inside the project if it is being executed by a unit test?
You can use spring resource api to get file instance.
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/ResourceUtils.html
External Example:
filepath: file:/some-os-path/some-file-somewhere.abc
ResourceUtils.getFile(filepath);
Test Example:
filepath: classpath:file-from-resources-folder.abc
ResourceUtils.getFile(filepath);

How to write extension method for Gradle dependencies {} block

I'm trying to write extension methods for DependencyHandler.
One of main goals to have autocompletion of these methods.
So I wrote extension function in buildSrc project like this (Shortcuts.kt):
fun DependencyHandler.autoValue() {
add("compileOnly", Libs.Auto.autoValueAnnotations)
add("annotationProcessor", Libs.Auto.autoValueCompiler)
}
And registered it as extension module as described here:
# File: src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
moduleName = buildSrc
moduleVersion = 1.0
extensionClasses = com.example.test.ShortcutsKt
I want to use these methods in build.gradle files like:
dependencies {
...
autoValue()
}
It appears in autocompletion list inside dependencies{} block, but at configuration time I got error:
org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method autoValue() for arguments [] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
at org.gradle.internal.metaobject.AbstractDynamicObject.methodMissingException(AbstractDynamicObject.java:179)
at org.gradle.internal.metaobject.ConfigureDelegate.invokeMethod(ConfigureDelegate.java:87)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeOnDelegationObjects(ClosureMetaClass.java:430)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:369)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:69)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:158)
at build_dh4v5lw1dkt4b2nii5ope5rmy$_run_closure1.doCall(/.../app/build.gradle:29)
Gradle DefaultDependencyHandler implements custom method resolution strategy (to handle scopes notation like testCompile(smth)), so additional methods can be added via dependencies.ext property:
dependencies.ext.autoValue = {
dependencies.add("compileOnly", Libs.Auto.autoValueAnnotations)
dependencies.add("annotationProcessor", Libs.Auto.autoValueCompiler)
}
But in this case you don't get autocompletion.
To enable autocompletion you can mix this two approaches and proxy extension methods from buildSrc via dependencies.ext:
import com.example.test.ShortcutsKt
import java.lang.reflect.Method
import java.lang.reflect.Modifier
// DependencyHandler implementation resolves all undeclared methods by self,
// so we need to add these extension methods to dependencies.ext
def methodNames = ShortcutsKt.declaredMethods
.findAll { isDependencyHandlerExtension(it) }
.collect { it.name }
.unique()
methodNames.each { String methodName ->
dependencies.ext[methodName] = { Object... args ->
ShortcutsKt."$methodName"(dependencies, *args)
}
}
private static boolean isDependencyHandlerExtension(Method method) {
return Modifier.isPublic(method.getModifiers()) &&
Modifier.isStatic(method.getModifiers()) &&
method.parameterCount > 0 &&
method.parameterTypes[0] == DependencyHandler.class
}

Creating a closure in ext

I am implementing the texturePacker task given in LibGDX's TexturePacker with gradle.
project.ext {
// ...
texturePacker = ["assets", "../android/assets", "texture"]
}
import com.badlogic.gdx.tools.texturepacker.TexturePacker
task texturePacker << {
if (project.ext.has('texturePacker')) {
logger.info "Calling TexturePacker: "+ texturePacker
TexturePacker.process(texturePacker[0], texturePacker[1], texturePacker[2])
}
}
I got it working with the suggested modifications for the classpath and added extension variable. Now I want to modify the textPacker extension variable to be a closure (Is that the right terminology?) with descriptive member names rather than an array. I tried doing this:
project.ext {
// ...
texturePacker {
inputDir = "assets"
outputDir = "../android/assets"
packFileName = "texture"
}
}
This gives the following error:
Error:Could not find method texturePacker() for arguments [build_4dusyb6n0t7j9dfuws8cc2jlu$_run_closure1$_closure7#6305684e] on project ':desktop' of type org.gradle.api.Project.
I am very new to gradle and groovy, so I have no idea what this error means. More importantly, what is the correct way to do what I want?
I suppose, closure is not the thing you need, since it's used not to store variables, but to store some executable code. By the way, if need to store it, you have to add = as follows:
project.ext {
texturePacker = {
inputDir = "assets"
outputDir = "../android/assets"
packFileName = "texture"
}
}
Anyway, if need to store variables within texturePacker variable, you rather have to use a Map type, then a Closure. This could be done like this:
project.ext {
texturePacker = [
inputDir : "assets",
outputDir : "../android/assets",
packFileName : "texture"
]
}
And then you can access this variable just by names, as:
println texturePacker.inputDir
Or, I think you can also go for implementing your own task with those properties. You can use DefaultTask which is a standard implementation of a regular task (and I'm sure it'd be enough for you);
class TexturePacker extends DefaultTask {
String inputDir; // a property - not a field!
String outputDir; // a property - not a field!
...
#TaskAction
void doSth(){
// do sth with properties above - that will be called automatically by gradle as a task-execution
}
}
task packer (type:TexturePacker) {
inputDir '<your-input-dir>'
outputDir '<your-output-dir>'
}
Syntax might not be super correct, but I think you get the idea.

groovy/SoapUi Call a static function from another script

I am trying to write a groovy script which will contain functions that are common to the SoapUI test Suite. Specifically I want to write a script that will contain all the logs that are output from the test suite.
GroovyScript1 will call a function in the GroovyScripts.groovy file. All is present in a SoapUI test suite.
I have not found any helpful advice on how to perform this task.
To specify again, I want to call a function contained in another Groovy Script.
Yes You can do this by following steps,
In your "GroovyScripts.groovy" file add below code,
class GLF
{
def log
def context
def testRunner
def GLF(logIn, contextIn, testRunnerIn)
{
this.log = logIn
this.context = contextIn
this.testRunner = testRunnerIn
}
//Till abobe line you must keep same code except class name
public String returnVal()
{
return 'Himanshu'
}
}
context.setProperty("Rt", new GLF(log, context, testRunner))
============================ END GroovyScripts.groovy ==========
Now in your "GroovyScript1" file you should use below code,
lib = testRunner.testCase.testSuite.project.testSuites["GroovyLibraryFunction"].testCases["TestCase 1"].testSteps["EndpointVerification"]
lib.run(testRunner, context)
def RT = context.Rt
def PT = RT.returnVal()
log.info PT
This way you can achive your target.

Resources