Skip to content

Commit 6379716

Browse files
committed
LibraryConfiguration.java: further refactor defaultedVersionSCM() to separate extractDefaultedVersionGitSCM() hack in a scalable manner [JENKINS-69731]
1 parent 2d098a5 commit 6379716

File tree

1 file changed

+151
-119
lines changed

1 file changed

+151
-119
lines changed

src/main/java/org/jenkinsci/plugins/workflow/libs/LibraryConfiguration.java

Lines changed: 151 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,157 @@ public LibraryCachingConfiguration getCachingConfiguration() {
224224
* and have those SCMs tell us what we want here. But that's a job
225225
* for another day.
226226
*/
227-
private String defaultedVersionSCM(@NonNull Run<?, ?> run, @NonNull TaskListener listener, PrintStream logger) {
227+
private boolean isDefaultedVersionSCMSupported(SCM scm) {
228+
// Return "true" if we can extractDefaultedVersionSCM() from this SCM
229+
return ("hudson.plugins.git.GitSCM".equals(scm.getClass().getName()));
230+
}
231+
232+
233+
private String extractDefaultedVersionGitSCM(@NonNull SCM scm, @NonNull Run<?, ?> run, @NonNull TaskListener listener, PrintStream logger) {
234+
if (!("hudson.plugins.git.GitSCM".equals(scm.getClass().getName())))
235+
return null;
236+
228237
String runVersion = null;
229-
Item runParent = run.getParent();
230238

239+
// Avoid importing GitSCM and so requiring that
240+
// it is always installed even if not used by
241+
// particular Jenkins deployment (using e.g.
242+
// SVN, Gerritt, etc.). Our aim is to query this:
243+
// runVersion = scm0.getBranches().first().getExpandedName(run.getEnvironment(listener));
244+
// https://mkyong.com/java/how-to-use-reflection-to-call-java-method-at-runtime/
245+
Class noparams[] = {};
246+
Class[] paramEnvVars = new Class[1];
247+
paramEnvVars[0] = EnvVars.class;
248+
249+
// https://javadoc.jenkins.io/plugin/git/hudson/plugins/git/GitSCM.html#getBranches() =>
250+
// https://javadoc.jenkins.io/plugin/git/hudson/plugins/git/BranchSpec.html#toString()
251+
Method methodGetBranches = null;
252+
try {
253+
methodGetBranches = scm.getClass().getDeclaredMethod("getBranches", noparams);
254+
} catch (Exception x) {
255+
// NoSuchMethodException | SecurityException | NullPointerException
256+
methodGetBranches = null;
257+
}
258+
if (methodGetBranches != null) {
259+
Object branchList = null;
260+
try {
261+
branchList = methodGetBranches.invoke(scm);
262+
} catch (Exception x) {
263+
// InvocationTargetException | IllegalAccessException
264+
branchList = null;
265+
}
266+
if (branchList != null && branchList instanceof List) {
267+
Object branch0 = ((List<Object>) branchList).get(0);
268+
if (branch0 != null && "hudson.plugins.git.BranchSpec".equals(branch0.getClass().getName())) {
269+
Method methodGetExpandedName = null;
270+
try {
271+
methodGetExpandedName = branch0.getClass().getDeclaredMethod("getExpandedName", paramEnvVars);
272+
} catch (Exception x) {
273+
methodGetExpandedName = null;
274+
}
275+
if (methodGetExpandedName != null) {
276+
// Handle possible shell-templated branch specs:
277+
Object expandedBranchName = null;
278+
try {
279+
expandedBranchName = methodGetExpandedName.invoke(branch0, run.getEnvironment(listener));
280+
} catch (Exception x) {
281+
// IllegalAccessException | IOException
282+
expandedBranchName = null;
283+
}
284+
if (expandedBranchName != null) {
285+
runVersion = expandedBranchName.toString();
286+
}
287+
} else {
288+
if (logger != null) {
289+
logger.println("defaultedVersion(): " +
290+
"did not find method BranchSpec.getExpandedName()");
291+
}
292+
}
293+
if (runVersion == null || "".equals(runVersion)) {
294+
runVersion = branch0.toString();
295+
}
296+
} else {
297+
// unknown branchspec class, make no blind guesses
298+
if (logger != null) {
299+
logger.println("defaultedVersion(): " +
300+
"list of branches did not return a " +
301+
"BranchSpec class instance, but " +
302+
(branch0 == null ? "null" :
303+
branch0.getClass().getName()));
304+
}
305+
}
306+
} else {
307+
if (logger != null) {
308+
logger.println("defaultedVersion(): " +
309+
"getBranches() did not return a " +
310+
"list of branches: " +
311+
(branchList == null ? "null" :
312+
branchList.getClass().getName()));
313+
}
314+
}
315+
} else {
316+
// not really the GitSCM we know?
317+
if (logger != null) {
318+
logger.println("defaultedVersion(): " +
319+
"did not find method GitSCM.getBranches()");
320+
}
321+
}
322+
323+
// Still alive? Chop off leading '*/'
324+
// (if any) from single-branch MBP and
325+
// plain "Pipeline" job definitions.
326+
if (runVersion != null) {
327+
runVersion = runVersion.replaceFirst("^\\*/", "");
328+
if (logger != null) {
329+
logger.println("defaultedVersion(): " +
330+
"Discovered runVersion '" + runVersion +
331+
"' in GitSCM source of the pipeline");
332+
}
333+
}
334+
335+
return runVersion;
336+
}
337+
338+
private String extractDefaultedVersionSCM(@NonNull SCM scm, @NonNull Run<?, ?> run, @NonNull TaskListener listener, PrintStream logger) {
339+
String runVersion = null;
340+
341+
if (logger != null) {
342+
logger.println("defaultedVersion(): " +
343+
"inspecting first listed SCM: " +
344+
scm.toString());
345+
}
346+
347+
// TODO: If this hack gets traction, try available methods
348+
// until a non-null result.
349+
// Ideally SCM API itself would have all classes return this
350+
// value (or null if branch concept is not supported there):
351+
runVersion = extractDefaultedVersionGitSCM(scm, run, listener, logger);
352+
353+
if (runVersion == null) {
354+
// got SVN, Gerritt or some other SCM -
355+
// add handling when needed and known how
356+
// or rely on BRANCH_NAME (if set) below...
357+
if (logger != null) {
358+
logger.println("defaultedVersion(): " +
359+
"the first listed SCM was not of currently " +
360+
"supported class with recognized branch support: " +
361+
scm.getClass().getName());
362+
}
363+
}
364+
365+
return runVersion;
366+
}
367+
368+
private String defaultedVersionSCM(@NonNull Run<?, ?> run, @NonNull TaskListener listener, PrintStream logger) {
231369
// Ask for SCM source of the pipeline (if any),
232370
// as the most authoritative source of the branch
233-
// name we want:
371+
// name we want. If we get an SCM class we can
372+
// query deeper (supports branch concept), then
373+
// extract the branch name of the script source.
234374
SCM scm0 = null;
375+
String runVersion = null;
376+
Item runParent = run.getParent();
377+
235378
if (runParent != null && runParent instanceof WorkflowJob) {
236379
// This covers both "Multibranch Pipeline"
237380
// and "Pipeline script from SCM" jobs;
@@ -263,11 +406,11 @@ private String defaultedVersionSCM(@NonNull Run<?, ?> run, @NonNull TaskListener
263406
csfd.getClass().getName() +
264407
"' is not associated with an SCM");
265408
}
266-
} else if (!("hudson.plugins.git.GitSCM".equals(scm0.getClass().getName()))) {
409+
} else if (!isDefaultedVersionSCMSupported(scm0)) {
267410
if (logger != null) {
268411
logger.println("defaultedVersion(): CpsScmFlowDefinition '" +
269412
csfd.getClass().getName() +
270-
"' is associated with an SCM we can not query: " +
413+
"' is associated with an SCM class we can not query for branches: " +
271414
scm0.toString());
272415
}
273416
scm0 = null;
@@ -294,7 +437,7 @@ private String defaultedVersionSCM(@NonNull Run<?, ?> run, @NonNull TaskListener
294437
scmN.getClass().getName() +
295438
"': " + scmN.toString());
296439
}
297-
if ("hudson.plugins.git.GitSCM".equals(scmN.getClass().getName())) {
440+
if (isDefaultedVersionSCMSupported(scmN)) {
298441
// The best we can do here is accept
299442
// the first seen SCM (with branch
300443
// support which we know how to query).
@@ -364,119 +507,8 @@ private String defaultedVersionSCM(@NonNull Run<?, ?> run, @NonNull TaskListener
364507

365508
// Got some hit? Drill deeper!
366509
if (scm0 != null) {
367-
// Avoid importing GitSCM and so requiring that
368-
// it is always installed even if not used by
369-
// particular Jenkins deployment (using e.g.
370-
// SVN, Gerritt, etc.). Our aim is to query this:
371-
// runVersion = scm0.getBranches().first().getExpandedName(run.getEnvironment(listener));
372-
// https://mkyong.com/java/how-to-use-reflection-to-call-java-method-at-runtime/
373-
if (logger != null) {
374-
logger.println("defaultedVersion(): " +
375-
"inspecting first listed SCM: " +
376-
scm0.toString());
377-
}
378-
379-
Class noparams[] = {};
380-
Class[] paramEnvVars = new Class[1];
381-
paramEnvVars[0] = EnvVars.class;
382-
if ("hudson.plugins.git.GitSCM".equals(scm0.getClass().getName())) {
383-
// https://javadoc.jenkins.io/plugin/git/hudson/plugins/git/GitSCM.html#getBranches() =>
384-
// https://javadoc.jenkins.io/plugin/git/hudson/plugins/git/BranchSpec.html#toString()
385-
Method methodGetBranches = null;
386-
try {
387-
methodGetBranches = scm0.getClass().getDeclaredMethod("getBranches", noparams);
388-
} catch (Exception x) {
389-
// NoSuchMethodException | SecurityException | NullPointerException
390-
methodGetBranches = null;
391-
}
392-
if (methodGetBranches != null) {
393-
Object branchList = null;
394-
try {
395-
branchList = methodGetBranches.invoke(scm0);
396-
} catch (Exception x) {
397-
// InvocationTargetException | IllegalAccessException
398-
branchList = null;
399-
}
400-
if (branchList != null && branchList instanceof List) {
401-
Object branch0 = ((List<Object>) branchList).get(0);
402-
if (branch0 != null && "hudson.plugins.git.BranchSpec".equals(branch0.getClass().getName())) {
403-
Method methodGetExpandedName = null;
404-
try {
405-
methodGetExpandedName = branch0.getClass().getDeclaredMethod("getExpandedName", paramEnvVars);
406-
} catch (Exception x) {
407-
methodGetExpandedName = null;
408-
}
409-
if (methodGetExpandedName != null) {
410-
// Handle possible shell-templated branch specs:
411-
Object expandedBranchName = null;
412-
try {
413-
expandedBranchName = methodGetExpandedName.invoke(branch0, run.getEnvironment(listener));
414-
} catch (Exception x) {
415-
// IllegalAccessException | IOException
416-
expandedBranchName = null;
417-
}
418-
if (expandedBranchName != null) {
419-
runVersion = expandedBranchName.toString();
420-
}
421-
} else {
422-
if (logger != null) {
423-
logger.println("defaultedVersion(): " +
424-
"did not find method BranchSpec.getExpandedName()");
425-
}
426-
}
427-
if (runVersion == null || "".equals(runVersion)) {
428-
runVersion = branch0.toString();
429-
}
430-
} else {
431-
// unknown branchspec class, make no blind guesses
432-
if (logger != null) {
433-
logger.println("defaultedVersion(): " +
434-
"list of branches did not return a " +
435-
"BranchSpec class instance, but " +
436-
(branch0 == null ? "null" :
437-
branch0.getClass().getName()));
438-
}
439-
}
440-
} else {
441-
if (logger != null) {
442-
logger.println("defaultedVersion(): " +
443-
"getBranches() did not return a " +
444-
"list of branches: " +
445-
(branchList == null ? "null" :
446-
branchList.getClass().getName()));
447-
}
448-
}
449-
} else {
450-
// not really the GitSCM we know?
451-
if (logger != null) {
452-
logger.println("defaultedVersion(): " +
453-
"did not find method GitSCM.getBranches()");
454-
}
455-
}
456-
457-
// Still alive? Chop off leading '*/'
458-
// (if any) from single-branch MBP and
459-
// plain "Pipeline" job definitions.
460-
if (runVersion != null) {
461-
runVersion = runVersion.replaceFirst("^\\*/", "");
462-
if (logger != null) {
463-
logger.println("defaultedVersion(): " +
464-
"Discovered runVersion '" + runVersion +
465-
"' in SCM source of the pipeline");
466-
}
467-
}
468-
} else {
469-
// else SVN, Gerritt or some other SCM -
470-
// add handling when needed and known how
471-
// or rely on BRANCH_NAME (if set) below...
472-
if (logger != null) {
473-
logger.println("defaultedVersion(): " +
474-
"the first listed SCM was not of currently " +
475-
"supported class with recognized branch support: " +
476-
scm0.getClass().getName());
477-
}
478-
}
479-
} // if (scm0 != null)
510+
runVersion = extractDefaultedVersionSCM(scm0, run, listener, logger);
511+
}
480512

481513
return runVersion;
482514
}

0 commit comments

Comments
 (0)