Jenkins plugin development - environment variables - java

Is there any possibility to get a map of environment variables that are used in Jenkins?
I am trying to develop my own plugin and need to access the variable BUILD_USER_ID, which is provided by the build user vars plugin.
There is a class called EnvVars, which inherits from TreeMap, but it is obviously empty, if you create an object of this.
EnvVars env = new EnvVars();
Where are these variables stored , so that I can get them and use them in my plugin?

I expect you mean build variables injected by Build User Vars Plugin into build.
If you are interested in reading static jobs configuration (from system groovy script for instance), use job.getBuildWrappersList().get(org.jenkinsci.plugins.builduser.BuildUser.class) to get user configured instance of BuildUser. In case of Build User Vars Plugin there is not much configuration to read, though.
If you would like to access actual variable values injected into the build process (from a BuildStep for instance), call build.getEnvironment(TaskListener) to get populated EnvVars instance with all variables. Note that these variables are not available outside of build context.

Related

GAE appengine-web.xml per environment without no compile

I have an Java application on Google App Engine.
I would like to change the configurations of appengine-web.xml without compile the package again, bacause I have to pass the same final package (war) for each environment. (DEV, HOM, PRD).
My problem is, I would like to change the instance-classe in some environments because on HOM I can use a less power instance than PRD.
There is a way to set this values in with variables or another way to do it?
I could do it with maven and replace the file, but I want to keep the same final package for each environment.

What's the proper way to have various URL endpoints for dev and release in a Java application?

I'm building a Java desktop application, using JavaFX, Gradle, javafx-gradle-plugin. This application connects to a server that I also build. When I compile a release version, running gradle jfxNative, I want it to talk to the production server; but otherwise, I want it to talk to localhost.
What's the proper Java/Gradle way of handling this? Some sort of compilation profile?
You can use Gradle's source sets for this:
Sample build.gradle:
apply plugin: 'java'
sourceSets {
prod {
java {
srcDirs = ['src/main/java', 'src/prod/java']
}
}
dev {
java {
srcDirs = ['src/main/java', 'src/dev/java']
}
}
}
task devJar(type: Jar) {
from sourceSets.dev.output
manifest {
attributes("Main-Class": "MyPackage.MyClass")
}
}
task prodJar(type: Jar) {
from sourceSets.prod.output
manifest {
attributes("Main-Class": "MyPackage.MyClass")
}
}
Now you can create two configuration classes for your dev and prod versions:
src/dev/java/MyPackage/Configuration.java
src/prod/java/MyPackage/Configuration.java
All the common code will be in the main source set:
src/main/java/MyPackage/MyClass.java
MyClass can get some values from the configuration class (e.g. Configuration.getBaseUrl())
Running gradle devJar/ gradle prodJar builds one of the variants.
Note: you may need to extend jfxNative/jfxJar instead of Jar in your case.
The simplest solution: Have a configuration file containing such information.
You either compile it into the application as a java resource or place it next to the jar file so it can be easily looked up via the filesystem.
With gradle all you need to do is define two build tasks with different input properties and insert the values into your properties file with groovy templating.
application.properties in src/main/resources:
server.address=${serverAddress}
add to your build.gradle
task setProductionServerAddress {
processResources.expand([serverAddress: "https://app.example.com/v1"])
}
jfxJar.dependsOn(setProductionServerAddress)
jfxNative.dependsOn(setProductionServerAddress)
And then on the application:
Properties properties = new Properties();
properties.load(getClass().getResourceAsStream("/application.properties"));
if (properties.getProperty("server.address").equals("${serverAddress}")) {
setUrl("http://localhost:8080/v1");
} else {
setUrl(properties.getProperty("server.address"));
}
Have it check environment variables for names of configuration files. Nothing to do with gradle or build. The same program should run properly wherever it is deployed.
See, e.g., Properties for dev and production
The easiest approach is to define a system property which specifies where the file system location for your data is. The production appserver would define one value (using java -D in the startup script), and your dev app server would define another value. Your application source would consult the system property value (using System.getProperty()) to discover the appropriate location
Also, this makes sense.
Put the information you need in JNDI - that's what it is designed for.
Consider letting your application refuse to do anything if the information is not there.
Another reference: What is the best way to manage configuration data
EDIT: Well, what you're asking is logically not possible then, it seems to me. "It should connect to production, unless a specific someone wants to connect to development, but that feature should only be available to unknown persons" The start menu is only a shortcut for running the application, so you can install a "dev" shortcut with command line settings that are read as environment vars.
I would go with the one of the "12 factor app" concept which can be read here
One of its main concept is to use system environment variable which should determine whether you are working on a prod or dev or qa env etc.
each project/environment/machine should contain its relevant env property, which after then can be retrieved through the gradle process similar to maven profile plugin.
An example for how to detect:
`if (project.hasProperty('env') && project.getProperty('env') == 'prod') {
apply from: 'gradle/production.gradle'
} else {
apply from: 'gradle/development.gradle'
}`
more on this approach using gradle can be found: gradle profile
In my opinion and like others have suggested, this has little to do with the build and more to do with Run Time.
Therefore you could resort to checking for some kind of run time flag - a convenient and often used approach is to use System Properties.
On your Dev box, you could set an Environment variable - lets say FX _DESKTOP_APP_ENV = DEV or some such.
From your code you can look this up and decide the URL you want to use.
String env = System.getenv("FX _DESKTOP_APP_ENV");
String url = env == null ? "Production" : env;
On windows systems you can set up your system environment variables like so -- enter link description here
On *nix systems enter link description here
Hope this helps
You need to pick a configuration scheme (if JavaFX doesn't pick one for you).
I like https://github.com/typesafehub/config .
The config library will have instructions on how to make your "production" config differ from your "development" config.
See also JavaFX:Editable Configuration Files After Packaging
What's the proper Java/Gradle way of handling this? Some sort of compilation profile?
No, I would strongly recommend against compiling different code for production v.s. test. It will invalidate your testing. This should be handled in configuration, not in code. The conventional Java way of doing this is with configuration files (which can be compiled into the JAR as resources).
How to do this with Typesafe Config
I've had a bit of a look, and I am surprised not to find a good quality tutorial I can link you to here, sorry (I found a few rubbish ones). Perhaps this question will become a reference for others.
I would do something like this:
Create a "dev" and "prod" config files, along the lines of https://stackoverflow.com/a/33261928/8261
Arrange for your app to use the "dev" config file when running in your IDE and "prod" config file when running from a compiled JAR, as per Can you tell on runtime if you're running java from within a jar?
My guess as to why there aren't many tutorials for this is that all application or web Frameworks handle this for you.

How to override properties file using plugin in Jenkins?

In my Selenium-TestNG-Maven automation framework, I am have properties file for storing 'application-url'. The Jenkins job is configured for this. I have to run this test suite on QA/Stage/Production server based on need. But not sure how can I dynamically provide or override the 'application-url' property used in the code. (Environment Injector plugin? How?)
As per code, Selenium WebDriver instance in created, then java code reads the properties file and same URL is used by Selenium instance to open a webpage.
I dynamically provide URLs by using the choice parameter for my Jenkins job.
First select this project is parameter as pictured below:
Then select the Add Parameter > Choice Parameter as pictured below:
Then save.
Now when you are building you will be able to select the url to use for that particular build, like this:
And when you need to reference the url, you can pass it through to maven by using the $URL in the Maven Goals.
ADDED: Here is an example of how I am using the choice parameter in the Maven goals
I am passing the ${browserName} parameter that is defined using the Choice Parameter through maven which will be referenced using the system property "browser". So when I want to get the value in my code, I just use
System.getProperty("browser");
And I am able to access that passed parameter.
You can configure your jenkins to pull the latest code from any of the repository (Github, SVN) and in the Execute Shell build step, you can write a shell script to achieve the same.

Jenkins build matrix with unique parameter per configuration

I installed the Matrix Groovy Execution Strategy Plugin and I face an issue where for each of these builds I have to provide a unique parameter like bundle id or hockeyapp id. The plugin doesn't let me inject those parameters from inside the groovy script because it compares the combinations with the result values f.e.
Combinations:
{axis1:"a", axis2:"z"}
Result
{axis1:"a", axis2:"z", bundleId:"com.foo.bar"}
I don't like the idea of adding all the bundleIDs and hockeyappIDs as the dimensions because it produces a really huge matrix and any change in the parameters would produce great amount of changes needed in the script.
How can I add a unique parameter for each of the build configuration from the matrix?
What you probably want is the EnvInject plugin. Amongst other things this allows you to set environment variables in groovy script.
The current axes (axises) are available to this script as environment variables already
So add the plugin and this will give you a
Inject environment variables to the build process under Build Environment
Under Evaluated Groovy script use a variant of this script
if(AXIS_A == "a")
return [COMPUTE_VAR: "123456"]
else
return [COMPUTE_VAR: "abcdefg"]
Assuming your axis is called AXIS_A
The method wants a map returned so it is possible to add multiple environment variables
From the help in Jenkins
Evaluate a Groovy script and inject a map result.
The groovy script must return a map Java object.
You can access parameters and other environment variables through variables in the Groovy script.

Jenkins execute shell on job's executor during CONFIGURATION time (and access workspace)

I would like to create a simple Jenkins plugin.
Basically it is a custom build step (Builder extension) with a dropdown list. The trick is that I want to fill this dropdown list from the result of a shell script/command executed during configuration time.
Here is my method stub.
public ListBoxModel doFill...Items(#AncestorInPath AbstractProject project) {
// determine workspace
// project.getSomeWorkspace() or project.getSomeWorkspace().getRemote()
...
// invoke some shell commands
String[] results = ...
ListBoxModel items = new ListBoxModel();
for (String item : results) {
items.add(item);
}
return items;
}
My questions are the following:
If there are slaves too, does Jenkins maintain 2 workspaces (so the freshest source code will exist both locations?
My understanding is that (after the first build) there are always two workspaces: on the master there are meta informations (and source code too?), on the slave there are the source code and the build intermediates, information, artifacts. (unless we extract artifacts or use the copy-to-slave-plugin)
Where will be the workspace what I get with the project.getSomeWorkspace() or project.getSomeWorkspace().getRemote()? (master/slave?)
How can I invoke a shell command on the machine that WILL execute the build? Or at least is there a way to choose the master / one of the slaves particularly? (Suppose that I already configured a label on which group of machines I want to run the job.)
I don't have access to AbstractBuild, BuildListener and Launcher (since they don't exist yet...)
How can I find out which properties can I get with #AncestorInPath.
I understand that this is a shorthand, an injection from the StaplerRequest invoked by Jenkins? How can I see the request?
It is important where the execution of the shell command takes place, even if there are two identical workspaces on master and slave. In my case there may be a Windows master (in the future) and an OSX slave. I do need the OSX to run my commands. (Currently there is only a master on OSX.)
EDIT:
Here is an example, part of what I am trying to do. I created a simple Xcode project in Swift (JenkinsSwift). In terminal from the project's directory I can issue the following command:
xcodebuild -project JenkinsSwift.xcodeproj -list
And get the following response:
Targets:
JenkinsSwift
JenkinsSwiftTests
Build Configurations:
Debug
Release
If no build configuration is specified and -scheme is not passed then "Release" is used.
Schemes:
JenkinsSwift
During configuration time I want to navigate to the project workspace on an OS X machine I want to issue the previous command. This way I could parse this response and allow the users to choose a Target / Configuration / Scheme during configuration. (Of course this can be done manually from with bash scripts, but I wanted to make it easier.)
This works differently, there is no workspace for a job by default. One is allocated as soon as build is run on the build machine (be it master or a slave). There can be any number of workspaces for a given job based on where and how many times the job run. Though, there is no guarantee there will be some on master. Do not confuse terms workspace (living on build machine) and build result directory on master.
Project#getSomeWorkspace(), gives you a workspace used by some past build. Note, this is done on purely best effort bases as there might be none.
There is no way to know where the build will run at the configuration time unless you tie the job to one particular machine. See hudson.model.Node#createLauncher(TaskListener) on how to run processes in Jenkins grid.
#AncestorInPath allows you to inject some of the domain object that ware traversed by stapler during URL binding. You should not try to inject anything that might not be part of the url. There is no way known to me for you to inject the request, stapler uses the one that initiated the action method invocation.
The bottom line is that what you try sounds highly unusual. Perhaps there is an easier way to solve your original problem.

Categories

Resources