Jenkinsfile: pass env from another script - java

Consider a folder with two jenkins files, JenkinsfileA and JenkinsfileB.
# JenkinsfileA
node {
environment {
APP_NAME = 'APPLICATION_A'
# Load the other jenkins file
load `JenkinsfileB'
}
#JenkinsfileB
node{
echo "Got parameter $APP_NAME"
stage ('do something'){
echo 'doing something'
}
}
In B, the $APP_NAME param is coming up null. What is the canonical way to pass APP_NAME parameter from A into B? Should I be using load here or something else? Are env vars. preferred or can we make use of parameters somehow?
Update
I think the reason env isn't working for me is because jenkins is triggering second job in a completely separate workspace. I'd like to do something like this:
load 'JenkinsfileB', parameters: [[$class: 'StringParameterValue', name: 'MYPARAM', value: "some-value" ]]
But keep getting error
java.lang.IllegalArgumentException: Expected named arguments but got [{parameters=[{$class=StringParameterValue, name=MYPARAM, value=some-value}]}, JenkinsfileB]
And when I try to use build job syntax instead of load the build can't even find JenkinsfileB, so I am stumped.
Unreleated: is node still the correct directive to use to ensure builds run on any agent, or should I be using pipeline{ agent: any}? Got node from this article

Related

In picocli how do you make options on the command line to override the same option in an #-file

I'm currently using picocli 4.7.0-SNAPSHOT to great effect in a Java 11 application that has a complex set of options, so I am making use of the #-file functionality.
What I am trying to get to work is an option specified directly on the command line to override the same option if it exists in the #-file. So options specified on the command line take precedence over the #-file. Is that possible.
When I try to run my test application, heavily based on the picocli example, with both a command line option and an #-file, I get the following error from picocli along with the expected usage:
myapp --sourceDatabaseType=MySQL #.\myapp.options
option '--sourceDatabaseType' (<sourceDatabaseType>) should be specified only once
and then the expected usage information.
Let me paraphrase the question to see if I understand it correctly:
If the end user specifies an option directly on the command line, the command line value should be used, while if that option is not specified on the command line, the value in a file should be used.
Essentially, you are using an #-file with the intention to define default values for one or more options.
However, that is not what #-files were designed for: picocli cannot distinguish between arguments that came from the command line and arguments that came from the #-file.
I would suggest using picocli's default provider mechanism instead.
One idea is to use the built-in PropertiesDefaultProvider:
import picocli.CommandLine.PropertiesDefaultProvider;
#Command(name = "myapp", defaultValueProvider = PropertiesDefaultProvider.class)
class MyApp { }
PropertiesDefaultProvider also uses a file, and the values in that file are only used for options that were not specified on the command line.
The tricky bit is the location of this file. PropertiesDefaultProvider looks for the file in the following locations:
the path specified by system property picocli.defaults.${COMMAND-NAME}.path
a file named .${COMMAND-NAME}.properties in the end user's user home directory
(Replace ${COMMAND-NAME} by the name of the command, so for a command named myapp, the system property is picocli.defaults.myapp.path)
To give end users the ability to specify the location of the file, we need to set the system property before picocli completes parsing the command line arguments.
We can do that with an #Option-annotated setter method. For example:
class MyApp {
#Option(names = "-D")
void setSystemProperty(Map<String, String> properties) {
System.getProperties().putAll(properties);
}
}
This would allow end users to invoke the command with something like this:
myapp --sourceDatabaseType=MySQL -Dpicocli.defaults.myapp.path=.\myapp.options
If this is too verbose, you could go one step further and create a special -# option, to allow users to invoke the command with something like this:
myapp --sourceDatabaseType=MySQL -#.\myapp.options
The implementation for this would be an annotated setter method, similar to the above:
class MyApp {
#Spec CommandSpec spec; // injected by picocli
#Option(names = "-#")
void setDefaultProviderPath(File path) {
// you could do some validation here:
if (!path.canRead()) {
String msg = String.format("ERROR: file not found: %s", path);
throw new ParameterException(spec.commandLine(), msg);
}
// only set the system property if the file exists
System.setProperty("picocli.defaults.myapp.path", path.toString());
}
}

How to configure lightbend/typesafeConfig via command line parameter when using picocli

In our project we are using Lightbend Config / TypesafeConfig.
I can run my program with java -jar. The configuration of my program can also be done by using command line parameters.
Example:
java -jar simpleclient.jar -Dservice.url="http://localhost:8123"
Now I introduced https://picocli.info/ to have a better command line handling for my application.
The problem I'm facing now ist, that picocli doesn't allow the usage of -D... parameters in the standard configuration.
How can this be changed?
When you say “picocli doesn’t allow the use of -D... options”, I assume you mean you want to allow end users to set system properties with the -Dkey=value syntax. When such parameters are passed to the application, the application needs to use these values to set system properties, as shown below.
First, users can set system properties by passing -Dkey=value parameters to the java process instead of to the main class in the jar. In the below invocation, the system properties are set directly and are not passed as parameters to the application:
java -Dservice.url="http://localhost:8123" -jar simpleclient.jar
Secondly, you can define a -D option in your application that sets system properties:
#Command
class SimpleClient {
#Option(names = "-D")
void setProperty(Map<String, String> props) {
props.forEach((k, v) -> System.setProperty(k, v == null ? "" : v));
}
}

Is there any way to automatically setting windows path in a string in groovy?

My project root directory is:
D:/Project/Node_Project
I am using a gradle plugin to install nodejs temporarily in my project root directory so that some nodejs command can run in the project while the thoject builds. The plugin is as below:
plugins {
id "com.github.node-gradle.node" version "2.2.4"
}
node {
download = true
version = "10.10.0"
distBaseUrl = 'https://nodejs.org/dist'
workDir = file("${project.buildDir}/nodejs")
}
So, nodejs is getting installed inside the project in the location:
D:/Project/Node_Project/build/nodejs/node-v10.10.0-win-x64
Now, I am using a .execute(String[] "path to set at environment variable", String path of file to be executed which is in the project root directory) method to run a windows command with node dependency. Code below:
cmd = "node connect.js"
def process = cmd.execute(["PATH=${project.projectDir}/build/nodejs/node-v10.10.0-win-x64"],null)
In the above .execute method, is there a way to auto-populate the "build/nodejs/node-v10.10.0-win-x64" part of the string instead of hardcoding it into the method?
Something like:
def process = cmd.execute(["PATH=${project.projectDir}/.*"],null)
Syntax of .execute method:
https://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/String.html#execute(java.lang.String[],%20java.io.File)
All the codes are inside "build.gradle" file. Please help!
I asked why you don't just write a task of type NodeTask, but I understand that you like to run a it in the background, which you can't do with that.
You could list the content of a directory and use that as part of the command. But you could also just grab it from the extension provided by the plugin.
This is not documented and it might break in future releases of the plugin, but you can do something like this (Groovy DSL):
task connectJS {
dependsOn nodeSetup
doFirst {
def connectProcess = "$node.variant.nodeExec $projectDir/src/js/connect.js".execute()
// Blocking readers (if async, pipe to a log file instead)
connectProcess.in.eachLine { logger.info(it) }
connectProcess.err.eachLine { logger.err(it) }
}
}

How to provide the -Dlogback.configurationFile=./logback.xml option in nodejs spawn method

I have angular2-node.js application. I am executing a jar file through the node server.
Jar execution is happening fine but it's using the logback.xml present in the jar file.
Node js code:
app.get('/report/:parameter1/:parameter2', function(req, res) {
var fileName = path.join(__dirname, '..', 'javaFile', 'xyz.jar');
spawn('/usr/bin/java', ['-jar ', fileName, parameter1 , parameter2, '&'],{
stdio : ['ignore', out, err],
detached : true }).unref();
data = '{response: Success}';
res.status(200).json(data);
res.end();
});
I want to refer the different logback.xml file for jar execution while running the jar from UI. So, i tried the below code:
spawn('/usr/bin/java', ['-jar -Dlogback.configurationFile=./logback.xml', fileName, cacheName , cacheType, '&'],{
stdio : ['ignore', out, err],
detached : true }).unref();
But, it also didn't work and throw the below error:
Unrecognized option: -jar -Dlogback.configurationFile=./logback.xml
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
I am new to node js. I searched the web but couldn't get an answer.
Is there any way to provide the logback.xml file dynamically in node.js code something like we do in shell script like below:
nohup java -jar -Dlogback.configurationFile=./logback.xml xyz.jar
Can anyone provide any solution for this.
The args arguments is <string[]>, so you should split the multiple args into multiple elements of the array, like you've done for the other arguments. You can check the signature of the method here.
Try,
spawn('/usr/bin/java', ['-jar', '-Dlogback.configurationFile=./logback.xml'], ....

Detect Play 2.2.x mode prior to start of Application using Java

I want to point my play application to a particular application config file based on the environment it is running in. There are three and they correspond to the standard Play states:
application.dev.conf
application.test.conf
application.prod.conf
A co-worker shared a method for doing this which requires setting an OS environment variable.
I'd like to eliminate the need to set an OS variable.
My preference is the use whatever Play uses at startup to know what mode it is in.
For example, if you execute play run from the command line, part of the output is "[info] play - Application started (Dev)"
I want to use this information in my Global.java where I override onLoadConfig like so:
public Configuration onLoadConfig(Configuration baseConfiguration, File f, ClassLoader loader) {
String playEnv=<some static method to get mode>;
Config additionalConfig = ConfigFactory.parseFile(new File(f,"conf/application."+playEnv+".conf"));
Config baseConfig = baseConfiguration.getWrappedConfiguration().underlying();
return new Configuration(baseConfig.withFallback(additionalConfig));
}
Everything that I find is how to do this after the application has been started i.e. using isDev(), isTest(), isProd().
Is there static method that provides the mode while I am overriding onLoadConfig in Global.java?
I think play run is dev, play start is prod.
EDIT: If you're looking to see what the current mode is, it's passed in through play.api.Play.current:
Play.current.mode match {
case Play.Mode.Dev => "dev"
case Play.Mode.Prod => "prod"
}
The issue appeared to be addressed in the latest Play (3.0.0). There is another onLoadConfig method added to Global witch has a mode: {Dev,Prod,Test} parameter.
public Configuration onLoadConfig(Configuration config, File path, ClassLoader classloader, Mode mode) {
return onLoadConfig(config, path, classloader); // default implementation
}
Play allows to specifying alternative configuration file with command line so no need for setting OS variables.
You can of course create some bash script / bat file to avoid writing it every time

Categories