Jenkins; Inject Environment Variable in Jelly field? - java

This has been bugging me for a little while, there is a list with environment variables and I want to use them in the configuration of one of my builds on my own custom plugin, as such:
So in this case I would like the ${WORKSPACE} to resolve to a path that has been configured by the environment.
Anyone know how to do this? I can't seem to find it as a Jelly tag.

The type of variable expansion you are asking for can only be performed by the build step itself. If this is your own plug-in then you can apply the change I suggest here, otherwise you can always ask the plug-in author to do so. Short of either you'll have to rely on the work-around Slav provided.
If you do have access to the source for the plug-in here's how to expand variables during execution of the build step. I assume the build step class is SanityTestResultsToJUnitXMLBuilder. Inside this class's perform method you need to expand the source and destination directory fields. I added place holders for other pieces of code you'd normally find in a build step for brevity.
public class SanityTestResultsToJUnitXMLBuilder extends Builder {
private final String sourceDirectory;
private final String destinationDirectory;
/* Constructor and getters typically appear here. */
#Override
public void perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
EnvVars environment = build.getEnvironment(listener);
String expandedSourceDirectory = environment.expand(sourceDirectory);
String expandedDestinationDirectory = environment.expand(destinationDirectory);
/* The rest of the perform() logic goes here */
}
/* Other methods typically appear here. */
/* The Descriptor typically appears here. */
}

Not sure what exactly you are asking for, but you can get the $WORKSPACE environment variable by:
def workspace = manager.build.getEnvVars()["WORKSPACE"]

Related

Android annotation processing - generate different code for different build flavor

I'm building a library that requires some annotation processing to generate code. I now run into an issue that the release build doesn't need to have as much code as the debug build does (since this is a library for modifying configuration variants - primarily used for testing purposes). The following code illustrates the situations. Let's say I want to create a class ConfigManager from some annotated classes and properties. In debug builds, I need this much:
public class ConfigManager {
public Class getConfigClass() {
return abc.class;
}
public void method1() {
doSomething1();
}
public void method2() {
doSomething2();
}
public void method3() {
doSomething3();
}
}
While in release builds, I only need this much:
public class ConfigManager {
public Class getConfigClass() {
return abc.class;
}
}
I have a feeling it may be possible by writing a Gradle plugin to check for build flavor at compile time and invoke a different processor/or somehow pass a parameter to a processor to generate different code. However this topic is pretty new to me so I'm not sure how to achieve this. A couple hours of googling also didnt help. So I'm wondering if anyone could give me a direction or example? Thanks
Pass an option (release=true/false) to your processor.
From javac https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html
-Akey[=value]
Specifies options to pass to annotation processors. These options are not interpreted by javac directly, but are made available for use by individual processors. The key value should be one or more identifiers separated by a dot (.).
In combination with Processor.html#getSupportedOptions https://docs.oracle.com/javase/8/docs/api/javax/annotation/processing/Processor.html#getSupportedOptions
Returns the options recognized by this processor. An implementation of the processing tool must provide a way to pass processor-specific options distinctly from options passed to the tool itself, see getOptions.
Implementation outline:
public Set<String> getSupportedOptions() {
Set<String> set = new HashSet<>();
set.add("release");
return set;
}
// -Arelease=true
boolean isRelease(ProcessingEnvironment env) {
return Boolean.parseBoolean(env.getOptions().get("release"));
}
See Pass options to JPAAnnotationProcessor from Gradle for how to pass options in a gradle build.

Configuring DropWizard Programmatically

I have essentially the same question as here but am hoping to get a less vague, more informative answer.
I'm looking for a way to configure DropWizard programmatically, or at the very least, to be able to tweak configs at runtime. Specifically I have a use case where I'd like to configure metrics in the YAML file to be published with a frequency of, say, 2 minutes. This would be the "normal" default. However, under certain circumstances, I may want to speed that up to, say, every 10 seconds, and then throttle it back to the normal/default.
How can I do this, and not just for the metrics.frequency property, but for any config that might be present inside the YAML config file?
Dropwizard reads the YAML config file and configures all the components only once on startup. Neither the YAML file nor the Configuration object is used ever again. That means there is no direct way to configure on run-time.
It also doesn't provide special interfaces/delegates where you can manipulate the components. However, you can access the objects of the components (usually; if not you can always send a pull request) and configure them manually as you see fit. You may need to read the source code a bit but it's usually easy to navigate.
In the case of metrics.frequency you can see that MetricsFactory class creates ScheduledReporterManager objects per metric type using the frequency setting and doesn't look like you can change them on runtime. But you can probably work around it somehow or even better, modify the code and send a Pull Request to dropwizard community.
Although this feature isn't supported out of the box by dropwizard, you're able to accomplish this fairly easy with the tools they give you. Note that the below solution definitely works on config values you've provided, but it may not work for built in configuration values.
Also note that this doesn't persist the updated config values to the config.yml. However, this would be easy enough to implement yourself simply by writing to the config file from the application. If anyone would like to write this implementation feel free to open a PR on the example project I've linked below.
Code
Start off with a minimal config:
config.yml
myConfigValue: "hello"
And it's corresponding configuration file:
ExampleConfiguration.java
public class ExampleConfiguration extends Configuration {
private String myConfigValue;
public String getMyConfigValue() {
return myConfigValue;
}
public void setMyConfigValue(String value) {
myConfigValue = value;
}
}
Then create a task which updates the config:
UpdateConfigTask.java
public class UpdateConfigTask extends Task {
ExampleConfiguration config;
public UpdateConfigTask(ExampleConfiguration config) {
super("updateconfig");
this.config = config;
}
#Override
public void execute(Map<String, List<String>> parameters, PrintWriter output) {
config.setMyConfigValue("goodbye");
}
}
Also for demonstration purposes, create a resource which allows you to get the config value:
ConfigResource.java
#Path("/config")
public class ConfigResource {
private final ExampleConfiguration config;
public ConfigResource(ExampleConfiguration config) {
this.config = config;
}
#GET
public Response handleGet() {
return Response.ok().entity(config.getMyConfigValue()).build();
}
}
Finally wire everything up in your application:
ExampleApplication.java (exerpt)
environment.jersey().register(new ConfigResource(configuration));
environment.admin().addTask(new UpdateConfigTask(configuration));
Usage
Start up the application then run:
$ curl 'http://localhost:8080/config'
hello
$ curl -X POST 'http://localhost:8081/tasks/updateconfig'
$ curl 'http://localhost:8080/config'
goodbye
How it works
This works simply by passing the same reference to the constructor of ConfigResource.java and UpdateConfigTask.java. If you aren't familiar with the concept see here:
Is Java "pass-by-reference" or "pass-by-value"?
The linked classes above are to a project I've created which demonstrates this as a complete solution. Here's a link to the project:
scottg489/dropwizard-runtime-config-example
Footnote: I haven't verified this works with the built in configuration. However, the dropwizard Configuration class which you need to extend for your own configuration does have various "setters" for internal configuration, but it may not be safe to update those outside of run().
Disclaimer: The project I've linked here was created by me.
I solved this with bytecode manipulation via Javassist
In my case, I wanted to change the "influx" reporter
and modifyInfluxDbReporterFactory should be ran BEFORE dropwizard starts
private static void modifyInfluxDbReporterFactory() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("com.izettle.metrics.dw.InfluxDbReporterFactory"); // do NOT use InfluxDbReporterFactory.class.getName() as this will force the class into the classloader
CtMethod m = cc.getDeclaredMethod("setTags");
m.insertAfter(
"if (tags.get(\"cloud\") != null) tags.put(\"cloud_host\", tags.get(\"cloud\") + \"_\" + host);tags.put(\"app\", \"sam\");");
cc.toClass();
}

How to set up a configured embedder for use of meta filters (-skip) with Serenity, JBehave and Selenium

While creating new scenarios I only want to test the scenario I am currently working with. For this purpose I want to use the Meta: #skip tag before my scenarios. As I found out I have to use the embedder to configure the used meta tags, so I tried:
configuredEmbedder().useMetaFilters(Arrays.asList("-skip"));
but actually this still has no effect on my test scenarios. I used it in the constructor of my SerenityStories test suite definition. Here is the complete code of this class:
public class AcceptanceTestSuite extends SerenityStories {
#Managed
WebDriver driver;
public AcceptanceTestSuite() {
System.setProperty("webdriver.chrome.driver", "D:/files/chromedriver/chromedriver.exe");
System.setProperty("chrome.switches", "--lang=en");
System.setProperty("restart.browser.each.scenario", "true");
configuredEmbedder().useMetaFilters(Arrays.asList("-skip"));
runSerenity().withDriver("chrome");
}
#Override
public Configuration configuration() {
Configuration configuration = super.configuration();
Keywords keywords = new LocalizedKeywords(DEFAULTSTORYLANGUAGE);
Properties properties = configuration.storyReporterBuilder().viewResources();
properties.setProperty("encoding", "UTF-8");
configuration.useKeywords(keywords)
.useStoryParser(new RegexStoryParser(keywords, new ExamplesTableFactory(new LoadFromClasspath(this.getClass()))))
.useStoryLoader(new UTF8StoryLoader()).useStepCollector(new MarkUnmatchedStepsAsPending(keywords))
.useDefaultStoryReporter(new ConsoleOutput(keywords)).storyReporterBuilder().withKeywords(keywords).withViewResources(properties);
return configuration;
}
}
Is this the wrong place or have I missed something? Still all scenarios are executed.
EDIT:
I changed following classes and now I think that it "works"
public AcceptanceTestSuite() {
System.setProperty("webdriver.chrome.driver", "D:/files/chromedriver/chromedriver.exe");
System.setProperty("chrome.switches", "--lang=de");
System.setProperty("restart.browser.each.scenario", "true");
this.useEmbedder(configuredEmbedder());
runSerenity().withDriver("chrome");
}
#Override
public Embedder configuredEmbedder() {
final Embedder embedder = new Embedder();
embedder.embedderControls()
.useThreads(1)
.doGenerateViewAfterStories(true)
.doIgnoreFailureInStories(false)
.doIgnoreFailureInView(false)
.doVerboseFailures(true);
final Configuration configuration = configuration();
embedder.useConfiguration(configuration);
embedder.useStepsFactory(stepsFactory());
embedder.useMetaFilters(Arrays.asList("-skip"));
return embedder;
}
But now I get the message [pool-1-thread-1] INFO net.serenitybdd.core.Serenity - TEST IGNORED but the scenario is still executed. Only in the result page I get the info that this scenario is ignored (but still executed). Is there a way to SKIP the scenario so it won't run?
I could not make it run with using configuredEmbedder() but by adding -Dmetafilter="+working -finished" as goals in my mvn run configurations and using the tags #working for scenarios I'm working with and which I want to run and #finsihed for scenarios I don't want to execute. Still I have to change the run configuration if I want to change the meta tags so it is not very comfortable but still I get what I was looking for.
As long as you document it well (some doc in https://github.com/serenity-bdd/the-serenity-book would be brilliant), I think as a JBehave/Serenity user you are well enough placed to decide which option makes the most sense.
Investigation
I debugged the serenity-jbehave classes, trying to understand why setting
configuredEmbedder().useMetaFilters(Collections.singletonList("-skip"))
is not working in all the possible places I put it within my class extending the SerenityStories, I found the strategic code place where metaFilters in ExtendedEmbedder#embedder are overwritten with what we define in our class into settings from serenity-jbehave.
This method is SerenityReportingRunner#createPerformableTree:
private PerformableTree createPerformableTree(List<CandidateSteps> candidateSteps, List<String> storyPaths) {
ExtendedEmbedder configuredEmbedder = this.getConfiguredEmbedder();
configuredEmbedder.useMetaFilters(getMetaFilters());
BatchFailures failures = new BatchFailures(configuredEmbedder.embedderControls().verboseFailures());
PerformableTree performableTree = configuredEmbedder.performableTree();
RunContext context = performableTree.newRunContext(getConfiguration(), candidateSteps,
configuredEmbedder.embedderMonitor(), configuredEmbedder.metaFilter(), failures);
performableTree.addStories(context, configuredEmbedder.storyManager().storiesOfPaths(storyPaths));
return performableTree;
}
This line changes the set metaFilters:
configuredEmbedder.useMetaFilters(getMetaFilters());
It overrides the current metaFilters value.
Going further the call chain, we get to the logic that defines from where it gets metaFilters, i.e. where we can actually set it.
SerenityReportingRunner#createPerformableTree
↓
SerenityReportingRunner#getMetaFilters
↓
SerenityReportingRunner#getMetafilterSetting
This is the method we need!
private String getMetafilterSetting() {
Optional<String> environmentMetafilters = getEnvironmentMetafilters();
Optional<String> annotatedMetafilters = getAnnotatedMetafilters(testClass);
Optional<String> thucAnnotatedMetafilters = getThucAnnotatedMetafilters(testClass);
return environmentMetafilters.orElse(annotatedMetafilters.orElse(thucAnnotatedMetafilters.orElse("")));
}
As we see here, the metaFilters can be defined in three places, and they override each other. In the priority lowering order, they are:
Value of metafilter (exactly all lowercase!) VM property.
Value of on net.serenitybdd.jbehave.annotations.Metafilter annotation on our SerenityStories class.
Value of on net.thucydides.jbehave.annotations.Metafilter annotation on our SerenityStories class. This annotation is deprecated, but left in place for backwards-compatibility.
Solution that is working with the current serenity-jbehave version
I've tried/debugged all these three options, they work and override each other as described above.
1. Use environment metafilter property
Added this to my JVM run arguments:
-Dmetafilter=skip
2. Use the modern #Metafilter annotation
import net.serenitybdd.jbehave.SerenityStories;
import net.serenitybdd.jbehave.annotations.Metafilter;
#Metafilter("-skip")
public class Acceptance extends SerenityStories {
3. Use the deprecated #Metafilter annotation
import net.serenitybdd.jbehave.SerenityStories;
import net.thucydides.jbehave.annotations.Metafilter;
#Metafilter("-skip") // warned as deprecated
public class Acceptance extends SerenityStories {
Solution for my current project is to use the current #Metafilter("-skip") annotation on my test class, to not depend on/have to change VM properties of the particular Jenkins/local dev execution.
Possible pull request to make
https://github.com/serenity-bdd/serenity-core/issues/95 — here Serenity guys have suggested me to do a PR with this fix, since they are not concentrated on Serenity + JBehave now.
I understand where to make the changes (in the code chain described above), but I don't know what overriding logic should be:
— MetaFilters from configuredEmbedder override any of ENV/annotation MetaFilters.
OR
— Any ENV/annotation MetaFilters override Metafilters from configuredEmbedder
OR
— MetaFilters from configuredEmbedder are merged with ENV/annotation MetaFilters. This option required merging priority.
Any suggestions?
In any type of fix, I would prefer add the explicit logs about how the overriding is now working into SerenityReportingRunner#getMetafilterSetting, since the current behaviour is really non-obvious and took lots of time to investigate.

How to change code settings in eclipse

Sorry if the question title is confusing. Let me explain further.
I am building a Java project with Eclipse. In my Java product I have conditionals that determine what code is included in the product and relies on static final constants for dead stripping.
class BuildFlags
{
public static final boolean SOME_FLAG = true; // Need to set this programmatically
}
class SomeOtherClass
{
public void someMethod()
{
if (BuildFlags.SOME_FLAG)
{
// flag specific code
}
}
}
My question is how can I change BuildFlags.SOME_FLAG (above) so that I can run a special build without changing the source? Is there some way I can pass flags to the jvm (from eclipse) which I can then access to set this flag programatically?
You do this by setting a system property value (see the docs on java) and then getting it from System.getProperty(). System properties can be set in Eclipse by editing the run configuration.
Note that properties are set as strings -- you will have to convert it to a boolean.
java -DsomeFlag=true <class>
and
String flag = System.getProperty("someFlag");

In Eclipse, how do I change the default modifiers in the class/type template?

Eclipse's default template for new types (Window > Preferences > Code Style > Code Templates > New Java Files) looks like this:
${filecomment}
${package_declaration}
${typecomment}
${type_declaration}
Creating a new class, it'll look something like this:
package pkg;
import blah.blah;
public class FileName {
// Class is accessible to everyone, and can be inherited
}
Now, I'm fervent in my belief that access should be as restricted as possible, and inheritance should be forbidden unless explicitly permitted, so I'd like to change the ${type_declaration} to declare all classes as final rather than public:
package pkg;
import blah.blah;
final class FileName {
// Class is only accessible in package, and can't be inherited
}
That seems easier said than done. The only thing I've found googling is a 2004 question on Eclipse's mailing list which was unanswered.
So, the question in short: How can I change the default class/type modifiers in Eclipse?
I'm using Eclipse Galileo (3.5) if that matters.
Looks like it is not possible. The ${type_declaration} is internal stuff.
What you can do is to click everytime the final checkbox in the "New Java Class"-Dialog. But that's not something you want to.
Just check the appropriate access modifier when creating the new class with the New Class Wizard.
New Java Class Wizard
Okay, i think there isn't any cool answer, so what about that "hack"?
${filecomment}
${package_declaration}
${typecomment}
import invalid;/* ${type_declaration} */
final class ${type_name} { }
If you now hit Control + Shift + O to organize imports, the old type declaration disappears. You could also add organize imports to save action to automate.
I know it's bad, but it does what you want.
Maybe this will help you?
eclipse\plugins\org.eclipse.jdt.ui_*.jar\templates\
Eclipse custom variable for java code templates
Here is my workaround:
Edit the template:
${filecomment}
${package_declaration}
${typecomment}
final class ${type_name} {
/* ${type_declaration} //delete */
/**
* #see {#link Object#toString()}
* #return String representation of this instance.
*/
public String toString() {
return "some impl";
}
}
Comment out the ${type_declaration} because it is required. You have comment to delete, but requirement is achieved. Sorry if this is a 2 year old thread, but to me it is still relevant.

Categories

Resources