Setting envvars in Jenkins plugin - java

I'm trying to develop new Jenkins plugin. I've started from hello-world archetype provided by Jenkins. My plugin works fine!
Bun now i want to put some environment variables from my plugin. I've used whis code to do it
public void perform(Run<?, ?> run, FilePath workspace, Launcher launcher, TaskListener listener) {
...
EnvVars envVars = run.getEnvironment(listener);
envVars.put("SOME_VARIABLE", "SOME_VALUE");
...
}
But it don't work. I'm trying to use this variable on next build step and got nothing. I've googled it and there isn't quite clear discriptions. Source codes of existing plugins (EnvInject, etc) also doesn't help.
What am i doing wrong? Can anybody provide me some samples?

From my plugin...
private void putEnvVar(String key, String value) throws IOException {
Jenkins jenkins = Jenkins.getInstance();
DescribableList<NodeProperty<?>, NodePropertyDescriptor> globalNodeProperties = jenkins.getGlobalNodeProperties();
List<EnvironmentVariablesNodeProperty> envVarsNodePropertyList = globalNodeProperties.getAll(hudson.slaves.EnvironmentVariablesNodeProperty.class);
EnvironmentVariablesNodeProperty newEnvVarsNodeProperty = null;
EnvVars envVars = null;
if (envVarsNodePropertyList == null || envVarsNodePropertyList.isEmpty()) {
newEnvVarsNodeProperty = new hudson.slaves.EnvironmentVariablesNodeProperty();
globalNodeProperties.add(newEnvVarsNodeProperty);
envVars = newEnvVarsNodeProperty.getEnvVars();
} else {
envVars = envVarsNodePropertyList.get(0).getEnvVars();
}
envVars.put(key, value);
}

Related

Eclipse debugger JUnit runs pulls wrong class

When I step through my JUnit, I hit a line that runs, and the intended source code is shown in Eclipse. However, the JVM (launched by Eclipse JUnit launcher), does not use the right version. Instead, it's using some other (older) version. Because I'm not sure what's causing this, I'm providing more details than necessary.
I had built this at one point using the Gradle on the command line, and had 2 versions of the same class file. One at /bin/com.woodsman... the other /bin/main/com.woodsman...
I'm using
Java 11
Eclipse: Version: 2021-09 (4.21.0)
Eclipse: Build id: 20210910-1417
Gradle
JUnit 5
Junit Launcher:
Run Single test:
Test Class: com.woodsman.MyClassTest
Test Method: mySingleTest
Test Runner: JUnit 5
Program Argument: None
VM Arguments: -ea
Checked: Use the -XX:+ShowCodeDetails...
Project execution environment 'JavaSE-11'
Dependencies:
Modulepath entries: (empty)
Classpath Entries
JUnit 5 (Advanced Library)
my-project (My Eclipse project)
Project and External Dependencies
JRE System Library [JavaSE-11]
Source:
Default
org.junits (too many to list)
my-project
java ~/my-project/src/test
java ~/my-project/src/main
resource ~/my-project/src/test
resource ~/my-project/src/main
my-project
.git-crypt ~/my-project
.gradle ~/my-project
... many others ...
bin ~/my-project
build ~/my-project
#WebMvcTest(ApiController.class)
class ApiControllerTest extends MVCBaseTest {
#Test
public void generateFeedbackShouldUseBody() throws Exception {
FeedbackResponse feedbackResponse = new FeedbackResponse();
when(toolInvokerService.generateFeedback(any(), any(), any(Boolean.class))).thenReturn(feedbackResponse);
setDinahClient(toolInvokerService);
ObjectNode requestBody = objectMapper.createObjectNode();
requestBody.put("content", "Cellular phones and laptops are used in communication everyone is using it every day.");
final MockHttpServletRequestBuilder request = post("/feedback")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody.toString());
ResultActions mockResult = mockMvc.perform(request);
String responseBody = mockResult.andReturn().getResponse().getContentAsString();
System.out.println("###="+responseBody);
}
}
#Service
public class ToolInvokerService {
private static final Logger log = LoggerFactory.getLogger(ToolInvokerService.class);
private final ContentBuilderService contentBuilderService;
private final ToolNormalizerService toolNormalizerService;
private final FeedbackMapperService feedbackMapperService;
private final LangDetectClient langDetectClient;
private final GrammartoolClient grammarToolClient;
private final AtdClient atdClient;
private final DinahClient dinahClient;
private final CybertronClient cybertronClient;
private final StatsLogger statsLogger;
public ToolInvokerService(
ContentBuilderService contentBuilderService,
ToolNormalizerService toolNormalizerService,
FeedbackMapperService feedbackMapperService,
LangDetectClient langDetectClient,
GrammartoolClient grammarToolClient,
AtdClient atdClient,
DinahClient dinahClient,
CybertronClient cybertronClient,
StatsLogger statsLogger) {
this.contentBuilderService = contentBuilderService;
this.toolNormalizerService = toolNormalizerService;
this.feedbackMapperService = feedbackMapperService;
this.langDetectClient = langDetectClient;
this.grammarToolClient = grammarToolClient;
this.atdClient = atdClient;
this.dinahClient = dinahClient;
this.cybertronClient = cybertronClient;
this.statsLogger = statsLogger;
}
public FeedbackResponse generateFeedback(UserContext userContext, String content, boolean trustLineBreaks) throws
InterruptedException,
ExecutionException,
URISyntaxException,
IOException,
UnsupportedLanguageException {
long startTime = System.currentTimeMillis();
FileOutputStream fop = new FileOutputStream("ben-test.log",true);
fop.write("gfb-bp1\n".getBytes());
if (StringUtils.isEmpty(content)) {
return getEmptyFeedbackResponse(0L);
}
// to reduce call time on long content verify english for up to 5000 characters
langDetectClient.verifyEnglish(CleanTextUtil.truncateText(content, 5000));
fop.write("gfb-bp2\n".getBytes());
fop.write("gfb-bp2.5\n".getBytes());
fop.write(("## dinahClient.hashCode()="+dinahClient.hashCode()).getBytes());
fop.write(("## dinahClient.toString()="+dinahClient.toString()).getBytes());
ContentMetadataResponse contentMetadata = dinahClient.getContentMetadata(content, trustLineBreaks);
log.info("###"+contentMetadata);
if (CollectionUtils.isEmpty(contentMetadata.getContentMetadata().getSentences())) {
log.warn("no sentence content found: returning empty feedback response");
return getEmptyFeedbackResponse(contentMetadata.getTimedResponseDurationMs());
}
List<ToolResponse> toolResponses = getNormalizedToolResponses(userContext.getLocale(), content, contentMetadata.getContentMetadata());
List<Observation> normalizedObservations = new ArrayList<>();
Map<Tool, Long> toolDurations = new HashMap<>();
Map<Tool, Integer> observationCounts = new HashMap<>();
Map<Tool, List<?>> toolErrors = new HashMap<>();
for (ToolResponse toolResponse : toolResponses) {
normalizedObservations.addAll(toolResponse.getNormalizedToolObservations());
toolDurations.put(toolResponse.getTool(), toolResponse.getTimedResponseDurationMs());
observationCounts.put(toolResponse.getTool(), toolResponse.getToolObservations().size());
toolErrors.put(toolResponse.getTool(), toolResponse.getToolErrors());
}
List<Observation> finalObservations = feedbackMapperService.constructFinalObservations(userContext.getLocale(),
normalizedObservations,
content,
contentMetadata.getContentMetadata());
Stats stats = new Stats(
System.currentTimeMillis() - startTime,
contentMetadata.getTimedResponseDurationMs(),
toolDurations,
observationCounts,
contentMetadata.getContentMetadata().getIgnoreSpans());
FeedbackResponse feedbackResponse = new FeedbackResponse(toolErrors, stats, finalObservations);
statsLogger.logResponse(userContext, feedbackResponse, content, normalizedObservations);
return feedbackResponse;
}
}

Artifactory + Custom Gradle Plugin Programmatically (2022)

I'm trying to create a custom gradle plugin (100% java) which will automatically configure Artifactory, avoiding the need of the following DSL:
artifactory {
contextUrl = "${artifactory_contextUrl}" //The base Artifactory URL if not overridden by the publisher/resolver
publish {
repository {
contextUrl = "${artifactory_contextUrl}"
repoKey = 'android-dev'
username = "${artifactory_user}"
password = "${artifactory_password}"
maven = true
}
}
resolve {
repository {
contextUrl = "${artifactory_contextUrl}"
repoKey = 'android-dev-distributions'
username = "${artifactory_user}"
password = "${artifactory_password}"
maven = true
}
}
}
I'm trying to re-create #agrosner own solution (from https://stackoverflow.com/a/25669431/1880280) but I'm missing "ArtifactoryAction". I can't find it anywhere.
The nonworking version posted by #agrosner is the following code:
// Set up plugins so we never need to add them to a build.gradle
project.getPlugins().apply(MAVEN);
project.getPlugins().apply(ARTIFACTORY);
project.setGroup(GROUP);
// Add Artifactory repo to the repositories
project.getRepositories().maven(new ArtifactoryAction(contextUrl + ARTIFACTORY_REPO_ENDPOINT, user, pass));
// We will define the plugin convention here so all of our libraries do not need to
// declare the artifactory closure manually
ArtifactoryPluginConvention pluginConvention =
ArtifactoryPluginUtil.getArtifactoryConvention(project);
pluginConvention.setContextUrl(contextUrl);
PublisherConfig publisherConfig = new PublisherConfig(pluginConvention);
publisherConfig.setContextUrl(contextUrl);
pluginConvention.setPublisherConfig(publisherConfig);
// Use reflection to access private field
PublisherConfig.Repository repository = null;
Field[] fields = PublisherConfig.class.getDeclaredFields();
for(Field field : fields) {
if(field.getName().equalsIgnoreCase("repository")) {
try {
field.setAccessible(true);
repository = (PublisherConfig.Repository) field.get(publisherConfig);
} catch (Exception e) {
e.printStackTrace();
}
}
}
if(repository != null) {
repository.setPassword(pass);
repository.setUsername(user);
repository.setRepoKey(PUBLISHER_REPO_KEY);
repository.setMavenCompatible(true);
}
GradleArtifactoryClientConfigUpdater.update(pluginConvention.getClientConfig(), project.getRootProject());
Can anyone help with an updated 100% java version of this?
Additionally, how would be for the following DSL?
artifactory {
publish {
repository {
repoKey = 'default-gradle-dev-local' // The Artifactory repository key to publish to
username = "${artifactory_user}" // The publisher user name
password = "${artifactory_password}" // The publisher password
maven = true
}
defaults {
publications('mavenJava')
publishArtifacts = true
publishPom = true
}
}}
Thanks in advance
César
ps. The DSL version that was published at #agrosner question thread is not useful for me. I need a Java version.
For your first question related to ArtifactoryAction: this is neither Gradle API nor Artifactory plugin related api, but most probably a custom class that the response author has implemented himself, as a shortcut to declare his custom Artifactory maven repo.
See this API, used to declare maven repositories :
MavenArtifactRepository maven​(Action<? super MavenArtifactRepository> action)
So you can use:
project.getRepositories().maven( mavenArtifactRepository -> {
mavenArtifactRepository.setUrl(contextUrl + MAVEN_PUBLIC_REPO);
mavenArtifactRepository.getCredentials().setUsername("user");
mavenArtifactRepository.getCredentials().setPassword("password");
});
or wrap the action code into a custom implementation of Action<? super MavenArtifactRepository> :
project.getRepositories().maven( new ArtifactoryAction(contextUrl + MAVEN_PUBLIC_REPO, "user", "password") );
[...]
// custom action class, defined somewhere else
class ArtifactoryAction implements Action<MavenArtifactRepository> {
private final String url, userName, password;
ArtifactoryAction(String url, String userName, String password) {
this.url = url; this.userName = userName; this.password = password;
}
#Override
public void execute(MavenArtifactRepository target) {
target.setUrl(url);
target.getCredentials().setUsername(userName);
target.getCredentials().setPassword(password);
}
}
For the other question with java translation of the artifactory { } DSL : see full example below with some inline comments. ( not tested but translated from my kotlin implementation which works fine)
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
import org.jfrog.gradle.plugin.artifactory.ArtifactoryPlugin;
import org.jfrog.gradle.plugin.artifactory.ArtifactoryPluginUtil;
import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention;
import org.jfrog.gradle.plugin.artifactory.dsl.PublisherConfig;
public class CustomArtifactoryPlugin implements Plugin<Project> {
private static String MAVEN_PUBLIC_REPO = "/maven-public";
private String contextUrl = "MY_CUSTOM_REPO_BASE_URL";
#Override
public void apply(Project project) {
// Base gradle publishing plugin
// - maven plugin for pulishing java artefacts
// - ivy plugin if for publishing other type of artefacts: rpms, archives, ..
project.getPluginManager().apply(MavenPublishPlugin.class);
// project.getPluginManager().apply(IvyPublishPlugin.class);
// Apply the Artifactory plugin
project.getPluginManager().apply(ArtifactoryPlugin.class);
// Add Artifactory repo to the repositories
project.getRepositories().maven(new ArtifactoryAction(contextUrl + MAVEN_PUBLIC_REPO, "user", "password"));
// Configure artifactory plugin - using 'withPlugin' ensures that plugin has already been applied
project.getPluginManager().withPlugin("com.jfrog.artifactory", appliedPlugin -> {
// artifactory {
ArtifactoryPluginConvention pluginConvention = ArtifactoryPluginUtil.getArtifactoryConvention(project);
// contextUrl = "${contextUrl}"
pluginConvention.setContextUrl(contextUrl);
// publish {
PublisherConfig publisherConfig = new PublisherConfig(pluginConvention);
pluginConvention.setPublisherConfig(publisherConfig);
// repository {
pluginConvention.getPublisherConfig().repository(repository -> {
// repoKey = 'default-gradle-dev-local' ...
repository.setRepoKey("default-gradle-dev-local"); // The Artifactory repository key to publish to
repository.setUsername("${artifactory_user}"); // The publisher user name
repository.setPassword("${artifactory_password}"); // The publisher password
repository.setMavenCompatible(true);
});
// defaults {
pluginConvention.getPublisherConfig().defaults(artifactoryTask -> {
// publications('mavenJava')
artifactoryTask.publications("mavenJava");
artifactoryTask.setPublishArtifacts("true");
artifactoryTask.setPublishPom("true");
});
});
}
}
EDIT for the publication configuration, you can do as follows:
// create maven publication
project.getExtensions().configure(PublishingExtension.class, publishingExtension -> {
publishingExtension.publications(publications -> {
publications.create("mavenPublication", MavenPublication.class, mavenPublication -> {
mavenPublication.setVersion("1.0.0");
mavenPublication.setGroupId("groupId");
mavenPublication.from(project.getComponents().findByName("java"));
});
});
});

Vault loading too late

My Plugin is loading before Vault, even tho I added a depend/load-after into the plugin.yml
I tried depend, softdepend and loadbefore. I even tried downgrading the on the server used version of Vault.
I tried even loadbefore without depend and the other way around.
My plugins.yml
name: TrainsaPlugin
version: ${project.version}
main: de.gamingcraft.trainsa.TrainsaPlugin
(...)
loadbefore:
- Vault
depend:
- Vault
commands: (...)
My Main Class:
public final class TrainsaPlugin extends JavaPlugin {
(...)
public static Economy econ = null;
public static Permission perms = null;
public static Chat chat = null;
#Override
public void onEnable() {
(...)
if (!setupEconomy() ) {
System.out.println("Disabled due to no Vault dependency found!");
getServer().getPluginManager().disablePlugin(this);
return;
}
setupPermissions();
setupChat();
}
private boolean setupEconomy() {
if (getServer().getPluginManager().getPlugin("Vault") == null) {
return false;
}
RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
if (rsp == null) {
return false;
}
econ = rsp.getProvider();
return econ != null;
}
private boolean setupChat() {
RegisteredServiceProvider<Chat> rsp = getServer().getServicesManager().getRegistration(Chat.class);
chat = rsp.getProvider();
return chat != null;
}
private boolean setupPermissions() {
RegisteredServiceProvider<Permission> rsp = getServer().getServicesManager().getRegistration(Permission.class);
perms = rsp.getProvider();
return perms != null;
}
#Override
public void onDisable() {
}
(...)
}
The Log
[22:35:43 INFO]: [TrainsaPlugin] Disabling TrainsaPlugin v1.0
(...)
[22:35:43 INFO]: Server permissions file permissions.yml is empty, ignoring it
[22:35:43 INFO]: Done (1,912s)! For help, type "help" or "?"
[22:35:43 INFO]: [Vault] Checking for Updates ...
I know, that my main-class disables my plugin when Vault is not found and i want that because it's essential at the moment.
TL;DR: My problem is, that Vault loads too late.
To your plugin.yml add depend: [Vault]
For more info see this
You added vault to loadbefore, which makes your plugin load before vault. If you want vault to load before your plugin, use depend: [Vault,someOtherPlugin,someOtherPlugin,etc].
I fixed it by adding
<scope>provided</scope>
to every dependency, that was a plugin in the pom.xml

Using M2Doc programmatically : Error in the generated .docx document

I'm trying to use M2Doc programmatically, I managed to generate my .docx file without getting errors in the validation part but I'm getting the following Error in the generated document:
{m:self.Name} Couldn't find the 'aqlFeatureAccess(org.eclipse.emf.common.util.URI.Hierarchical,java.lang.String)' service
The "self.Name" part is what I wrote in my template.
I think I'm lacking some kind of reference to a service but I don't know how to fix it.
The self variable is a reference to a model based on a meta-model I created. But I'm not sure I imported it correctly in my code.
I based my code on the code I found on the M2Doc website + some code I found on their GitHub, especially concerning how to add a service in the queryEnvironment.
I searched in the source code of acceleo and M2Doc to see which services they add but it seems that they already import all the services I'm using.
As I said, the validation part is going well and doesn't generate a validation file.
public static void parseDocument(String templateName) throws Exception{
final URI templateURI = URI.createFileURI("Template/"+templateName+"."+M2DocUtils.DOCX_EXTENSION_FILE);
final IQueryEnvironment queryEnvironment =
org.eclipse.acceleo.query.runtime.Query.newEnvironmentWithDefaultServices(null);
final Map<String, String> options = new HashMap<>(); // can be empty
M2DocUtils.prepareEnvironmentServices(queryEnvironment, templateURI, options); // delegate to IServicesConfigurator
prepareEnvironmentServicesCustom(queryEnvironment, options);
final IClassProvider classProvider = new ClassProvider(ClassLoader.getSystemClassLoader()); // use M2DocPlugin.getClassProvider() when running inside Eclipse
try (DocumentTemplate template = M2DocUtils.parse(templateURI, queryEnvironment, classProvider)) {
ValidationMessageLevel validationLevel = validateDocument(template, queryEnvironment, templateName);
if(validationLevel == ValidationMessageLevel.OK){
generateDocument(template, queryEnvironment, templateName, "Model/ComplexKaosModel.kaos");
}
}
}
public static void prepareEnvironmentServicesCustom(IQueryEnvironment queryEnvironment, Map<String, String> options){
Set<IService> services = ServiceUtils.getServices(queryEnvironment, FilterService.class);
ServiceUtils.registerServices(queryEnvironment, services);
M2DocUtils.getConfigurators().forEach((configurator) -> {
ServiceUtils.registerServices(queryEnvironment, configurator.getServices(queryEnvironment, options));
});
}
public static void generateDocument(DocumentTemplate template, IQueryEnvironment queryEnvironment,
String templateName, String modelPath)throws Exception{
final Map<String, Object> variable = new HashMap<>();
variable.put("self", URI.createFileURI(modelPath));
final Monitor monitor = new BasicMonitor.Printing(System.out);
final URI outputURI = URI.createFileURI("Generated/"+templateName+".generated."+M2DocUtils.DOCX_EXTENSION_FILE);
M2DocUtils.generate(template, queryEnvironment, variable, outputURI, monitor);
}
The variable "self" contains an URI:
variable.put("self", URI.createFileURI(modelPath));
You have to load your model and set the value of self to an element from your model using something like:
final ResourceSet rs = new ResourceSetImpl();
final Resource r = rs.getResource(uri, true);
final EObject value = r.getContents()...;
variable.put("self", value);
You can get more details on resource loading in the EMF documentation.

Rhino debugger - can't hit a breakpoint?

I have this legacy web application on inspection, that utilizes Rhino to script some database import tasks. Scripted task is executed properly.
However, I can't seem to hit a breakpoint in the JS script file. I'm not even sure if it's possible to debug JS script this way, so if anyone can give some more insight or advice... The core setup is as follows:
Debugger (listener):
// executes when the app is launched...
if (!ContextFactory.hasExplicitGlobal()) {
ContextFactory cxf = new ContextFactory();
ContextFactory.initGlobal(cxf);
String rhino = "transport=socket,suspend=y,address=9999";
System.out.println(">>>>>> RHINO <<<<<<");
RhinoDebugger debugger = new RhinoDebugger(rhino);
debugger.start();
cxf.addListener(debugger);
}
...
Scripting context:
#Component("importDebugMockup")
public class ImportDebugMockup extends Import {
#Autowired private SomeDAO someDAO;
#Autowired private SomeOtherDAO someOtherDAO;
...
private ContextFactory cxf;
private Document doc;
public ImportDebugMockup() {
this.cxf = ContextFactory.getGlobal();
}
...
#Transactional
public Map<String, Object> doImport(final String scriptName, final String filePath)
throws ScriptException, IOException {
final Map<String, Object> results = new HashMap<>();
final String scriptSource = this.readJSFileToString(filePath, Charset.forName("UTF-8"));
Context context = this.cxf.enterContext();
try {
Scriptable scope = new ImporterTopLevel(context);
ScriptableObject.putProperty(scope, "doc", doc);
ScriptableObject.putProperty(scope, "someDAO", this.someDAO);
ScriptableObject.putProperty(scope, "someOtherDAO", this.someOtherDAO);
...
ScriptableObject.putProperty(scope, "results", results);
Object functionArgs[] = { "null" };
String scriptExecName = "script" + scriptName + ".js";
context.evaluateString(scope, scriptSource, scriptExecName, 1, null);
Function fct = (Function) scope.get("doImport", scope); // call doImport()
Object result = fct.call(context, scope, scope, functionArgs);
} finally {
Context.exit();
}
return results;
}
}
The script:
importPackage(java.io);
importPackage(some.package);
// ...
// some utility functions here
// ...
function doImport() {
...
var i = 0; // set breakpoint here - can't hit it
someDAO.doSomething(...); // using propagated java object
...
someOtherDAO.doSomethingElse();
...
}
EDIT
Remote JS Debug configuration (with Mozilla Rhino - Attaching Connector at port 9999) is set up, like in this article, for example. Source is configured to point to directory where the JS script is located, however it does not suspend on breakpoint...

Categories