Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically create the RealJenkinsRuleInit plugin #782

Merged
merged 6 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 17 additions & 23 deletions src/main/java/org/jvnet/hudson/test/PluginUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,27 @@ static File createRealJenkinsRulePlugin(File destinationDirectory, String baseli

// we need to create a jar for the classes which we can then put into the plugin.
Path tmpClassesJar = Files.createTempFile("rjr", "jar");
try (FileOutputStream fos = new FileOutputStream(tmpClassesJar.toFile());
JarOutputStream classesJarOS = new JarOutputStream(fos, mf)) {

// the actual class
try (InputStream classIS = RealJenkinsRuleInit.class.getResourceAsStream(RealJenkinsRuleInit.class.getSimpleName() + ".class")) {
String path = RealJenkinsRuleInit.class.getPackageName().replace('.', '/');
createJarEntry(classesJarOS, path + '/' + RealJenkinsRuleInit.class.getSimpleName() + ".class", classIS);
try {
try (FileOutputStream fos = new FileOutputStream(tmpClassesJar.toFile());
JarOutputStream classesJarOS = new JarOutputStream(fos, mf)) {
// the actual class
try (InputStream classIS = RealJenkinsRuleInit.class.getResourceAsStream(RealJenkinsRuleInit.class.getSimpleName() + ".class")) {
String path = RealJenkinsRuleInit.class.getPackageName().replace('.', '/');
createJarEntry(classesJarOS, path + '/' + RealJenkinsRuleInit.class.getSimpleName() + ".class", classIS);
}
}
createJarEntry(classesJarOS, "META-INF/services/hudson.Plugin", RealJenkinsRuleInit.class.getName().getBytes(StandardCharsets.UTF_8));
}

// the actual JPI
File jpi = new File(destinationDirectory, pluginName+".jpi");
try (FileOutputStream fos = new FileOutputStream(jpi); JarOutputStream jos = new JarOutputStream(fos, mf)) {
try (FileInputStream fis = new FileInputStream(tmpClassesJar.toFile())) {
createJarEntry(jos, "WEB-INF/lib/"+pluginName+".jar", fis);
// the actual JPI
File jpi = new File(destinationDirectory, pluginName+".jpi");
try (FileOutputStream fos = new FileOutputStream(jpi); JarOutputStream jos = new JarOutputStream(fos, mf)) {
try (FileInputStream fis = new FileInputStream(tmpClassesJar.toFile())) {
createJarEntry(jos, "WEB-INF/lib/" + pluginName + ".jar", fis);
}
}
return jpi;
} finally {
Files.delete(tmpClassesJar);
}
Files.delete(tmpClassesJar);
return jpi;
}

private static void createJarEntry(JarOutputStream jos, String entryName, InputStream data) throws IOException {
Expand All @@ -71,11 +72,4 @@ private static void createJarEntry(JarOutputStream jos, String entryName, InputS
jos.closeEntry();
}

private static void createJarEntry(JarOutputStream jos, String entryName, byte[] data) throws IOException {
JarEntry je = new JarEntry(entryName);
jos.putNextEntry(je);
jos.write(data);
jos.closeEntry();
}

}
13 changes: 12 additions & 1 deletion src/main/java/org/jvnet/hudson/test/RealJenkinsRuleInit.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,27 @@
import hudson.Plugin;
import java.net.URL;
import java.net.URLClassLoader;

import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

import jenkins.model.Jenkins;

/**
* Plugin for use by {@link RealJenkinsRule}.
jtnord marked this conversation as resolved.
Show resolved Hide resolved
* <p>
* <stong>NOTE</strong>: this and only this class is added into a dynamically generated plugin, see {@link PluginUtils#createRealJenkinsRulePlugin(java.io.File, String)}.
jtnord marked this conversation as resolved.
Show resolved Hide resolved
* In order for this to occur correctly there need to be no inner classes or other code dependencies here (except what can be loaded by reflection).
*/
@Restricted(NoExternalUse.class)
jglick marked this conversation as resolved.
Show resolved Hide resolved
public class RealJenkinsRuleInit extends Plugin {

@SuppressWarnings("deprecation") // @Initializer just gets run too late, even with before = InitMilestone.PLUGINS_PREPARED
public RealJenkinsRuleInit() {}

@Override
public void start() throws Exception {
new URLClassLoader(new URL[] {new URL(System.getProperty("RealJenkinsRule.location"))}, ClassLoader.getSystemClassLoader().getParent()).
new URLClassLoader("RealJenkinsRule",new URL[] {new URL(System.getProperty("RealJenkinsRule.location"))}, ClassLoader.getSystemClassLoader().getParent()).
loadClass("org.jvnet.hudson.test.RealJenkinsRule$Init2").
getMethod("run", Object.class).
invoke(null, Jenkins.get());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ private static void hangs(JenkinsRule r) throws Throwable {

@Test
public void noDetachedPlugins() throws Throwable {
// XXX this test will falsely pass if the RealJenkinsRuleInit plugin targets a version of Jenkins that has no detacthed plugins.
// we should be the only plugin in Jenkins.
rr.then(RealJenkinsRuleTest::_noDetachedPlugins);
}

Expand Down