11package io .jenkins .tools .pluginmodernizer .core .extractor ;
22
33import io .jenkins .tools .pluginmodernizer .core .model .JDK ;
4+ import io .jenkins .tools .pluginmodernizer .core .model .Platform ;
5+ import io .jenkins .tools .pluginmodernizer .core .model .PlatformConfig ;
6+ import java .util .Collections ;
47import java .util .HashMap ;
8+ import java .util .LinkedList ;
59import java .util .List ;
610import java .util .Map ;
711import java .util .stream .Stream ;
1317import org .slf4j .LoggerFactory ;
1418
1519/**
16- * Visitor for a Jenkinsfile
20+ * Visitor for a Jenkinsfile to accumulate @see PluginMetadata.
1721 */
1822public class JenkinsfileVisitor extends GroovyIsoVisitor <PluginMetadata > {
1923
@@ -22,6 +26,9 @@ public class JenkinsfileVisitor extends GroovyIsoVisitor<PluginMetadata> {
2226 */
2327 public static final Logger LOG = LoggerFactory .getLogger (JenkinsfileVisitor .class );
2428
29+ /**
30+ * Keep track of variables if there are defined on top level and not directly on the method invocation.
31+ */
2532 private final Map <String , Object > variableMap = new HashMap <>();
2633
2734 @ Override
@@ -36,67 +43,198 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
3643 return variableDeclarations ;
3744 }
3845
46+ @ Override
47+ public J visitMapEntry (G .MapEntry mapEntry , PluginMetadata pluginMetadata ) {
48+ super .visitMapEntry (mapEntry , pluginMetadata );
49+ J .MethodInvocation method = getCursor ().firstEnclosing (J .MethodInvocation .class );
50+ if (method == null ) {
51+ return mapEntry ;
52+ }
53+ if (method .getSimpleName ().equals ("buildPlugin" )) {
54+ if ("useContainerAgent" .equals (mapEntry .getKey ().toString ())) {
55+ if (mapEntry .getValue () instanceof J .Literal literal ) {
56+ pluginMetadata .setUseContainerAgent (Boolean .valueOf (literal .getValueSource ()));
57+ } else if (mapEntry .getValue () instanceof J .Identifier ) {
58+ Expression resolvedArg = resolveVariable (mapEntry .getValue ());
59+ if (resolvedArg instanceof J .Literal literal ) {
60+ pluginMetadata .setUseContainerAgent (Boolean .valueOf (literal .getValueSource ()));
61+ }
62+ }
63+ }
64+ if ("forkCount" .equals (mapEntry .getKey ().toString ())) {
65+ if (mapEntry .getValue () instanceof J .Literal literal ) {
66+ pluginMetadata .setForkCount (literal .getValue ().toString ());
67+ } else if (mapEntry .getValue () instanceof J .Identifier ) {
68+ Expression resolvedArg = resolveVariable (mapEntry .getValue ());
69+ if (resolvedArg instanceof J .Literal literal ) {
70+ pluginMetadata .setForkCount (literal .getValue ().toString ());
71+ }
72+ }
73+ }
74+ }
75+ return mapEntry ;
76+ }
77+
3978 @ Override
4079 public J .MethodInvocation visitMethodInvocation (J .MethodInvocation method , PluginMetadata pluginMetadata ) {
4180 LOG .debug ("Visiting method invocation {}" , method );
4281 method = super .visitMethodInvocation (method , pluginMetadata );
4382 if ("buildPlugin" .equals (method .getSimpleName ())) {
4483 List <Expression > args = method .getArguments ();
4584
46- List <Integer > jdkVersions =
47- args .stream ().flatMap (this ::extractJdkVersions ).distinct ().toList ();
85+ // Empty args means Java 8 in Windows and Linux
86+ if (args .size () == 1 && args .get (0 ) instanceof J .Empty ) {
87+ pluginMetadata .addPlatform (new PlatformConfig (Platform .LINUX , JDK .JAVA_8 , null , true ));
88+ pluginMetadata .addPlatform (new PlatformConfig (Platform .WINDOWS , JDK .JAVA_8 , null , true ));
89+ return method ;
90+ }
4891
49- LOG .info ("JDK versions found: {}" , jdkVersions );
92+ List <PlatformConfig > platforms = new LinkedList <>();
93+ for (Expression expression : args ) {
94+ platforms .addAll (extractPlatforms (expression ));
95+ }
96+ // Filter platforms (Remove implicit if there is at least one explicit)
97+ if (platforms .stream ().anyMatch (pc -> !pc .implicit ())) {
98+ platforms .removeIf (PlatformConfig ::implicit );
99+ }
100+ // If all platform are unknown ensure each platform on the list is present with LINUX and WINDOWS
101+ if (platforms .stream ().allMatch (pc -> pc .name () == Platform .UNKNOWN )) {
102+ List <PlatformConfig > newPlatforms = new LinkedList <>();
103+ for (PlatformConfig pc : platforms ) {
104+ newPlatforms .add (new PlatformConfig (Platform .LINUX , pc .jdk (), null , false ));
105+ newPlatforms .add (new PlatformConfig (Platform .WINDOWS , pc .jdk (), null , false ));
106+ }
107+ platforms = newPlatforms ;
108+ }
109+ // If there is a platform without JDK ensure all all JDK are using the same platform
110+ if (platforms .stream ().anyMatch (pc -> pc .jdk () == null )) {
111+ List <PlatformConfig > newPlatforms = new LinkedList <>();
112+ for (PlatformConfig pc : platforms ) {
113+ if (!pc .name ().equals (Platform .UNKNOWN )) {
114+ if (platforms .stream ().allMatch (p -> p .jdk () == null )) {
115+ newPlatforms .add (new PlatformConfig (pc .name (), JDK .JAVA_8 , null , false ));
116+ continue ;
117+ }
118+ for (PlatformConfig pc2 : platforms ) {
119+ if (pc2 .jdk () != null ) {
120+ newPlatforms .add (new PlatformConfig (pc .name (), pc2 .jdk (), null , false ));
121+ }
122+ }
123+ }
124+ }
125+ platforms = newPlatforms ;
126+ }
50127
51- jdkVersions .forEach (jdkVersion -> pluginMetadata .addJdk (JDK .get (jdkVersion )));
128+ LOG .info ("Platform: {}" , platforms );
129+ pluginMetadata .setPlatforms (platforms );
52130 }
53131
54132 return method ;
55133 }
56134
57- private Stream < Integer > extractJdkVersions (Expression arg ) {
135+ private List < PlatformConfig > extractPlatforms (Expression arg ) {
58136 if (arg instanceof G .MapEntry ) {
59- return Stream .of (arg )
137+
138+ // Get 'configurations' stream
139+ Stream <G .MapEntry > configurations = Stream .of (arg )
60140 .map (G .MapEntry .class ::cast )
61- .filter (entry -> "configurations" .equals (((J .Literal ) entry .getKey ()).getValue ()))
141+ .filter (entry -> "configurations" .equals (((J .Literal ) entry .getKey ()).getValue ()));
142+
143+ // List of platform config from 'configurations' parameter
144+ List <PlatformConfig > platformFromConfigs = configurations
62145 .map (entry -> resolveConfigurations (entry .getValue ()))
63146 .filter (value -> value instanceof G .ListLiteral )
64147 .flatMap (value -> ((G .ListLiteral ) value ).getElements ().stream ())
65148 .filter (expression -> expression instanceof G .MapLiteral )
66- .flatMap (expression -> ((G .MapLiteral ) expression ).getElements ().stream ())
67- .filter (mapExpr -> mapExpr instanceof G .MapEntry )
149+ .map (expression -> (G .MapLiteral ) expression )
150+ .map (JenkinsfileVisitor ::toPlatformEntry )
151+ .toList ();
152+
153+ // Cannot be combinated
154+ if (!platformFromConfigs .isEmpty ()) {
155+ return platformFromConfigs ;
156+ }
157+
158+ // List of JDK versions from 'jdkVersions' parameter
159+ List <Integer > jdkVersions = Stream .of (arg )
68160 .map (G .MapEntry .class ::cast )
69- .filter (mapEntry -> "jdk" .equals (((J .Literal ) mapEntry .getKey ()).getValue ()))
70- .map (mapEntry -> Integer .parseInt (
71- ((J .Literal ) mapEntry .getValue ()).getValue ().toString ()));
72- } else {
161+ .filter (entry -> "jdkVersions" .equals (((J .Literal ) entry .getKey ()).getValue ()))
162+ .map (entry -> resolveConfigurations (entry .getValue ()))
163+ .filter (value -> value instanceof G .ListLiteral )
164+ .map (value -> (G .ListLiteral ) value )
165+ .flatMap (value -> value .getElements ().stream ())
166+ .map (expression ->
167+ Integer .parseInt (((J .Literal ) expression ).getValue ().toString ()))
168+ .toList ();
169+
170+ // List of platforms from 'platforms' parameter
171+ List <String > platforms = Stream .of (arg )
172+ .map (G .MapEntry .class ::cast )
173+ .filter (entry -> "platforms" .equals (((J .Literal ) entry .getKey ()).getValue ()))
174+ .map (entry -> resolveConfigurations (entry .getValue ()))
175+ .filter (value -> value instanceof G .ListLiteral )
176+ .map (value -> (G .ListLiteral ) value )
177+ .flatMap (value -> value .getElements ().stream ())
178+ .map (expression -> expression instanceof J .Literal ? expression .toString () : null )
179+ .toList ();
180+
181+ // Combine all JDK versions with all platforms
182+ List <PlatformConfig > platformFromJdkVersions = new LinkedList <>();
183+ for (Integer jdk : jdkVersions ) {
184+ platformFromJdkVersions .add (new PlatformConfig (Platform .UNKNOWN , JDK .get (jdk ), null , true ));
185+ }
186+ for (String platform : platforms ) {
187+ platformFromJdkVersions .add (new PlatformConfig (Platform .fromPlatform (platform ), null , null , true ));
188+ }
189+
190+ return platformFromJdkVersions ;
191+
192+ } else if (arg instanceof J .Identifier ) {
73193 Expression resolvedArg = resolveVariable (arg );
74194 return Stream .of (resolvedArg )
75195 .filter (resolved -> resolved instanceof G .MapLiteral )
76196 .flatMap (resolved -> ((G .MapLiteral ) resolved ).getElements ().stream ())
77- .filter (entry -> entry instanceof G .MapEntry )
78- .map (G .MapEntry .class ::cast )
79197 .filter (entry -> "configurations" .equals (((J .Literal ) entry .getKey ()).getValue ()))
80198 .map (entry -> resolveConfigurations (entry .getValue ()))
81199 .filter (value -> value instanceof G .ListLiteral )
82200 .flatMap (value -> ((G .ListLiteral ) value ).getElements ().stream ())
83201 .filter (expression -> expression instanceof G .MapLiteral )
84- .flatMap (expression -> ((G .MapLiteral ) expression ).getElements ().stream ())
85- .filter (mapExpr -> mapExpr instanceof G .MapEntry )
86- .map (G .MapEntry .class ::cast )
87- .filter (mapEntry -> "jdk" .equals (((J .Literal ) mapEntry .getKey ()).getValue ()))
88- .map (mapEntry -> Integer .parseInt (
89- ((J .Literal ) mapEntry .getValue ()).getValue ().toString ()));
202+ .map (expression -> (G .MapLiteral ) expression )
203+ .map (JenkinsfileVisitor ::toPlatformEntry )
204+ .toList ();
90205 }
206+ return Collections .emptyList ();
91207 }
92208
93- private Expression resolveVariable (Expression expression ) {
94- if (expression instanceof J .Identifier ) {
95- String variableName = ((J .Identifier ) expression ).getSimpleName ();
96- if (variableMap .containsKey (variableName )) {
97- return (Expression ) variableMap .get (variableName );
209+ /**
210+ * Return if the map entry is a platform entry.
211+ * @param mapLiteral The map entry
212+ * @return The platform config
213+ */
214+ private static PlatformConfig toPlatformEntry (G .MapLiteral mapLiteral ) {
215+ Stream <G .MapEntry > entries = mapLiteral .getElements ().stream ();
216+ List <G .MapEntry > list = entries .toList ();
217+ Integer jdk = null ;
218+ String platform = null ;
219+ for (G .MapEntry entry : list ) {
220+ if (entry .getKey () instanceof J .Literal key ) {
221+ if ("jdk" .equals (key .getValue ())) {
222+ jdk = Integer .parseInt (entry .getValue ().toString ());
223+ }
224+ if ("platform" .equals (key .getValue ())) {
225+ platform = entry .getValue ().toString ();
226+ }
98227 }
99228 }
229+
230+ return new PlatformConfig (Platform .fromPlatform (platform ), JDK .get (jdk ), null , false );
231+ }
232+
233+ private Expression resolveVariable (Expression expression ) {
234+ String variableName = ((J .Identifier ) expression ).getSimpleName ();
235+ if (variableMap .containsKey (variableName )) {
236+ return (Expression ) variableMap .get (variableName );
237+ }
100238 return expression ;
101239 }
102240
0 commit comments