How to create dynamic folder selection parameter in Jankins pipeline - jenkins

I am trying to use Jenkins as a tool as an automation build.
So, I need to create a pipline with parameter that helps me to select an appropriate directory where I start a build batch file.
By the moment, I have found how to select a directory as a parameter by usage of Extensible Choice plugin.
But it allows me to select a folder at one level, but I need to go deeper and get an oportunity to select via multilevel directory levels.
For example, select directory at level1 and than at level2 and finaly at level3.
Could you please give me any advise how to do that?

Use groovy script in pipeline job to dynamically assign the directory

Thanks. I have tried to find any similar example of code or plugin but haven't been succeed with this.
So, I have decided to do that based on a standard groovy syntax. Here is the code:
node {stage "Directories list output"
def dirname = getdirlist()
echo dirname}
import java.io.File;
import java.io.IOException;
import javax.swing.JFileChooser;
#NonCPS
def getdirlist() {def initialPath = System.getProperty("user.dir");
JFileChooser fc = new JFileChooser(initialPath);
fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
int result = fc.showOpenDialog( null );
switch ( result ){case JFileChooser.APPROVE_OPTION:
File file = fc.getSelectedFile();
def path = fc.getCurrentDirectory().getAbsolutePath();
def outputpath="path="+path+"\nfile name="+file.toString();
break;
case JFileChooser.CANCEL_OPTION:
case JFileChooser.ERROR_OPTION:
break;}
return outputpath}
I can't make it work. I have some suspitions that Jenkins pipeline doesn't allow to open a standard Java file dialog. What can be another aproach to my task?

Related

Jenkins Shared Library - Importing classes from the /src folder in /vars

I am trying to writing a Jenkins Shared Library for my CI process. I'd like to reference a class that is in the \src folder inside a global function defined in the \vars folder, since it would allow me to put most of the logic in classes instead of in the global functions. I am following the repository structure documented on the official Jenkins documentation:
Jenkins Shared Library structure
Here's a simplified example of what I have:
/src/com/example/SrcClass.groovy
package com.example
class SrcClass {
def aFunction() {
return "Hello from src folder!"
}
}
/vars/classFromVars.groovy
import com.example.SrcClass
def call(args) {
def sc = new SrcClass()
return sc.aFunction()
}
Jenkinsfile
#Library('<lib-name>') _
pipeline {
...
post {
always {
classFromVars()
}
}
}
My goal was for the global classes in the /vars folder to act as a sort of public facade and to use it in my Jenkinsfile as a custom step without having to instantiate a class in a script block (making it compatible with declarative pipelines). It all seems pretty straightforward to me, but I am getting this error when running the classFromVars file:
<root>\vars\classFromVars.groovy: 1: unable to resolve class com.example.SrcClass
# line 1, column 1.
import com.example.SrcClass
^
1 error
I tried running the classFromVars class directly with the groovy CLI locally and on the Jenkins server and I have the same error on both environments. I also tried specifying the classpath when running the /vars script, getting the same error, with the following command:
<root>>groovy -cp <root>\src\com\example vars\classFromVars.groovy
Is what I'm trying to achieve possible? Or should I simply put all of my logic in the /vars class and avoid using the /src folder?
I have found several repositories on GitHub that seem to indicate this is possible, for example this one: https://github.com/fabric8io/fabric8-pipeline-library, which uses the classes in the /src folder in many of the classes in the /vars folder.
As #Szymon Stepniak pointed out, the -cp parameter in my groovy command was incorrect. It now works locally and on the Jenkins server. I have yet to explain why it wasn't working on the Jenkins server though.
I found that when I wanted to import a class from the shared library I have, to a script step in the /vars I needed to do it like this:
//thanks to '_', the classes are imported automatically.
// MUST have the '#' at the beginning, other wise it will not work.
// when not using "#BRANCH" it will use default branch from git repo.
#Library('my-shared-library#BRANCH') _
// only by calling them you can tell if they exist or not.
def exampleObject = new example.GlobalVars()
// then call methods or attributes from the class.
exampleObject.runExample()

Defining FOLDER level variables in Jenkins using a shared \vars library

So I'm trying to make define folder level variables by putting them in a groovy file in the \vars directory.
Alas, the documentation is so bad, that it's impossible to figure out how to do that...
Assuming we have to globals G1 and G2, is this how we define them in the groovy file?
#!Groovy
static string G1 = "G1"
static string G2 = "G2"
Assuming the Groovy file is called XYZ.Groovy, how do I define it in the folder so its available for the folder's script?
Assuming I get over that, and that that LIBXYZ is the name the folder associates with the stuff in the /vars directory, is it correct to assume that when I call
#Library("LIBXYZ") _
it will make XYZ available?
In that case, is XYZ.G1 the way to access the globals?
thanks, a.
I have a working example here as I was recently curious about this. I agree that the documentation is wretched.
The following is similar to the info in README.md.
Prep: note that folder here refers to Jenkins Folders from the CloudBees Folder plugin. It is a way to organize jobs.
Code Layout
The first part to note is src/net/codetojoy/shared/Bar.groovy :
package net.codetojoy.shared
class Bar {
static def G1 = "G1"
static def G2 = "G2"
def id
def emitLog() {
println "TRACER hello from Bar. id: ${id}"
}
}
The second part is vars/folderFoo.groovy:
def emitLog(message) {
println "TRACER folderFoo. message: ${message}"
def bar = new net.codetojoy.shared.Bar(id: 5150)
bar.emitLog()
println "TRACER test : " + net.codetojoy.shared.Bar.G1
}
Edit: To use a static/"global" variable in the vars folder, consider the following vars/Keys.groovy:
class Keys {
static def MY_GLOBAL_VAR3 = "beethoven"
}
The folderFoo.groovy script can use Keys.MY_GLOBAL_VAR3.
And then usage (in my example: Basic.Folder.Jenkinsfile):
#Library('folderFoo') _
stage "use shared library"
node {
script {
folderFoo.emitLog 'pipeline test!'
}
}
Jenkins Setup: Folder
Go to New Item and create a new Folder
configure the folder with a new Pipeline library:
Name is folderFoo
Default version is master
Retrieval Method is Modern SCM
Source Code Management in my example is this repo
Jenkins Setup: Pipeline Job
create a new Pipeline job in the folder created above
though a bit confusing (and self-referential), I create a pipeline job that uses this same this repo
specify the Jenkinsfile Basic.Folder.Jenkinsfile
the job should run and use the library

Can I import a groovy script from a relative directory into a Jenkinsfile?

I've got a project structured like this:
/
/ Jenkinsfile
/ build_tools /
/ pipeline.groovy # Functions which define the pipeline
/ reporting.groovy # Other misc build reporting stuff
/ dostuff.sh # A shell script used by the pipeline
/ domorestuff.sh # Another pipeline supporting shell-script
Is it possible to import the groovy files in /build_tools so that I can use functions inside those 2 files in my Jenkinsfile?
Ideally, I'd like to have a Jenkins file that looks something like this (pseudocode):
from build_tools.pipeline import build_pipeline
build_pipeline(project_name="my project", reporting_id=12345)
The bit I'm stuck on is how you write a working equivalent of that pretend import statement on line #1 of my pseudocode.
PS. Why I'm doing this: The build_tools folder is actually a git submodule shared by many projects. I'm trying to give each project access to a common set of build tooling to stop each project maintainer from reinventing this wheel.
The best-supported way to load shared groovy code is through shared libraries.
If you have a shared library like this:
simplest-jenkins-shared-library master % cat src/org/foo/Bar.groovy
package org.foo;
def awesomePrintingFunction() {
println "hello world"
}
Shove it into source control, configure it in your jenkins job or even globally (this is one of the only things you do through the Jenkins UI when using pipeline), like in this screenshot:
and then use it, for example, like this:
pipeline {
agent { label 'docker' }
stages {
stage('build') {
steps {
script {
#Library('simplest-jenkins-shared-library')
def bar = new org.foo.Bar()
bar.awesomePrintingFunction()
}
}
}
}
}
Output from the console log for this build would of course include:
hello world
There are lots of other ways to write shared libraries (like using classes) and to use them (like defining vars so you can use them in Jenkinsfiles in super-slick ways). You can even load non-groovy files as resources. Check out the shared library docs for these extended use-cases.

Grails import class from java or groovy folder

I put several .groovy scripts in the src/groovy/search/ folder and got astrayed on how to use them in my controller.
My controller is grails-app/controller/EnvironmentController.groovy and I want to know how to import the classes like
import src.groovy.search.*
Also it's appreciated if anybody could point me to a complete explanation how the import works in Grails (namely how the groovy and java folders are included in the project and how to import them, including importing the java folder inside the groovy one).
Thanks!
Edit: My grails is on 2.4.4
Imports in Grails works in same fashion as in Java. You put your groovy files under src/groovy and java files under src/java. While importing simply import with the package name and no need to include src or groovy in import.
For how to execute groovy scripts in controller or anywhere, you can't just import them. I am assuming you are talking about groovy script and not groovy class. To execute a groovy script, you have two choices.
Suppose you Sample.groovy script file contains below code
public void sayHello(String name) {
println "Say Hello to $name..."
}
public static void sayStaticHello(String name) {
println "Say Static Hello to $name..."
}
So in order to execute it in your controller you can do either:
def script = new GroovyShell().parse(new File('<Path to SampleScript.groovy>'))
script.sayHello("Sandeep Poonia")
script.sayStaticHello("Sandeep Poonia")
or
//for non-static methods
this.class.classLoader.loadClass("SampleScript").newInstance().invokeMethod("sayHello", "Sandeep Poonia")
//for static method
this.class.classLoader.loadClass("SampleScript").invokeMethod("sayStaticHello", "Sandeep Poonia")
Use and IDE: (Grails 2 or less GGTS/STS) (Grails 3 Intelij community edition)
Organise import feature short cuts:
on GGTS/STS(Eclipse)
Ctrl + shift + o all together
on Intelij
Ctrl + Alt + o all together
In your case, if you are using vi or some text editor then all you need is :
import search.*
i.e. remove src.groovy.

Sharing const variables across FAKE fsx scripts

Is there any way to share a variable by including a fsx script within another fsx script.
e.g script buildConsts.fsx contains
let buildDir = "./build/"
I want to reference this in other build scripts e.g.
#load #".\buildConsts.fsx"
let testDlls = !! (buildDir + "*Test*.dll")
When I attempt to run the script the 'buildDir' variable the script fails to compile.
This is a fairly common approach that is used with tools such as MSBuild and PSAKE to modularise scripts. Is this the correct approach with FAKE ?
What you're doing should work - what exactly is the error message that you're getting?
I suspect that the problem is that F# automatically puts the contents of a file in a module and you need to open the module before you can access the constants. The module is named based on the file name, so in your case buildConsts.fsx will generate a module named BuildConsts. You should be able to use it as follows:
#load #".\buildConsts.fsx"
open BuildConsts
let testDlls = !! (buildDir + "*Test*.dll")
You can also add an explicit module declaration to buildconsts.fsx, which is probably a better idea as it is less fragile (won't change when you rename the file):
moule BuildConstants
let buildDir = "./build/"

Resources