22
33import com .fasterxml .jackson .annotation .JsonInclude ;
44import com .fasterxml .jackson .core .type .TypeReference ;
5- import com .fasterxml .jackson .core .util .DefaultIndenter ;
6- import com .fasterxml .jackson .core .util .DefaultPrettyPrinter ;
75import com .fasterxml .jackson .databind .ObjectMapper ;
86import com .fasterxml .jackson .databind .SerializationFeature ;
97import org .graalvm .internal .tck .exceptions .ContributingException ;
1210import org .graalvm .internal .tck .utils .ConfigurationStringBuilder ;
1311import org .graalvm .internal .tck .utils .FilesUtils ;
1412import org .graalvm .internal .tck .utils .InteractiveTaskUtils ;
13+ import org .graalvm .internal .tck .utils .MetadataGenerationUtils ;
1514import org .gradle .api .DefaultTask ;
1615import org .gradle .api .file .FileSystemOperations ;
1716import org .gradle .api .file .ProjectLayout ;
1817import org .gradle .api .tasks .TaskAction ;
1918import org .gradle .process .ExecOperations ;
2019
2120import javax .inject .Inject ;
22- import java .io .ByteArrayOutputStream ;
2321import java .io .File ;
2422import java .io .IOException ;
25- import java .io .InputStream ;
26- import java .nio .charset .StandardCharsets ;
2723import java .nio .file .Files ;
2824import java .nio .file .Path ;
2925import java .nio .file .StandardOpenOption ;
3026import java .util .ArrayList ;
31- import java .util .Arrays ;
3227import java .util .Comparator ;
3328import java .util .HashMap ;
3429import java .util .HashSet ;
4035public abstract class ContributionTask extends DefaultTask {
4136 private static final String BRANCH_NAME_PREFIX = "add-support-for-" ;
4237 private static final String METADATA_INDEX = "metadata/index.json" ;
43- private static final String BUILD_FILE = "build.gradle" ;
44- private static final String USER_CODE_FILTER_FILE = "user-code-filter.json" ;
38+ private static final String GRADLEW = "gradlew" ;
4539 private static final String REQUIRED_DOCKER_IMAGES_FILE = "required-docker-images.txt" ;
4640
4741 @ Inject
@@ -55,24 +49,15 @@ public abstract class ContributionTask extends DefaultTask {
5549
5650 private final ObjectMapper objectMapper = new ObjectMapper ().enable (SerializationFeature .INDENT_OUTPUT ).setSerializationInclusion (JsonInclude .Include .NON_NULL );
5751
58- private Path gradlew ;
52+ private Path gradlewPath ;
5953 private Path testsDirectory ;
60- private Path metadataDirectory ;
6154
62- private Coordinates coordinates ;
55+ String coordinates ;
6356
64- private record ContributingQuestion (String question , String help ) {}
65- private final Map <String , ContributingQuestion > questions = new HashMap <>();
66-
67- private void initializeWorkingDirectories (){
68- testsDirectory = getPathFromProject (CoordinateUtils .replace ("tests/src/$group$/$artifact$/$version$" , coordinates ));
69- metadataDirectory = getPathFromProject (CoordinateUtils .replace ("metadata/$group$/$artifact$/$version$" , coordinates ));
70- gradlew = getPathFromProject ("gradlew" );
57+ private record ContributingQuestion (String question , String help ) {
7158 }
7259
73- private Path getPathFromProject (String fileName ) {
74- return Path .of (getProjectFile (fileName ).getAbsolutePath ());
75- }
60+ private final Map <String , ContributingQuestion > questions = new HashMap <>();
7661
7762 private File getProjectFile (String fileName ) {
7863 return getLayout ().getProjectDirectory ().file (fileName ).getAsFile ();
@@ -96,7 +81,7 @@ void run() throws IOException {
9681 coordinates = getCoordinates ();
9782 InteractiveTaskUtils .closeSection ();
9883
99- Path coordinatesMetadataRoot = getPathFromProject (CoordinateUtils .replace ("metadata/$group$/$artifact$" , coordinates ));
84+ Path coordinatesMetadataRoot = MetadataGenerationUtils . getPathFromProject (getLayout (), CoordinateUtils .replace ("metadata/$group$/$artifact$" , CoordinateUtils . fromString ( coordinates ) ));
10085 boolean isExistingLibrary = Files .exists (coordinatesMetadataRoot );
10186
10287 Path testsLocation = getTestsLocation ();
@@ -111,29 +96,31 @@ void run() throws IOException {
11196 List <String > packages = getAllowedPackages ();
11297 InteractiveTaskUtils .closeSection ();
11398
114- List <Coordinates > additionalTestImplementationDependencies = getAdditionalDependencies ();
99+ List <String > additionalTestImplementationDependencies = getAdditionalDependencies ();
115100 InteractiveTaskUtils .closeSection ();
116101
117102 // initialize project
118- initializeWorkingDirectories ();
103+ gradlewPath = MetadataGenerationUtils .getPathFromProject (getLayout (), GRADLEW );
104+ testsDirectory = MetadataGenerationUtils .computeTestsDirectory (getLayout (), coordinates );
105+
119106 createStubs (isExistingLibrary );
120107 updateAllowedPackages (packages , isExistingLibrary );
121108
122109 // generate necessary boilerplate code
123110 addTests (testsLocation );
124111 addResources (resourcesLocation );
125112 addDockerImages (dockerImages );
126- addUserCodeFilterFile (packages );
113+ MetadataGenerationUtils . addUserCodeFilterFile (testsDirectory , packages );
127114 addAdditionalDependencies (additionalTestImplementationDependencies );
128- addAgentConfigBlock ();
115+ MetadataGenerationUtils . addAgentConfigBlock (testsDirectory );
129116
130117 // run agent in conditional mode
131- collectMetadata ();
118+ MetadataGenerationUtils . collectMetadata (getExecOperations (), testsDirectory , getLayout (), coordinates , gradlewPath );
132119
133120 // create a PR
134121 boolean shouldCreatePR = shouldCreatePullRequest ();
135122 if (shouldCreatePR ) {
136- String branch = BRANCH_NAME_PREFIX + coordinates .toString (). replace (':' , '-' );
123+ String branch = BRANCH_NAME_PREFIX + coordinates .replace (':' , '-' );
137124 createPullRequest (branch );
138125
139126 InteractiveTaskUtils .printUserInfo ("After your pull requests gets generated, please update the pull request description to mention all places where your pull request" +
@@ -143,15 +130,9 @@ void run() throws IOException {
143130 InteractiveTaskUtils .printSuccessfulStatement ("Contribution successfully completed! Thank you!" );
144131 }
145132
146- private Coordinates getCoordinates () {
133+ private String getCoordinates () {
147134 ContributingQuestion question = questions .get ("coordinates" );
148- return InteractiveTaskUtils .askQuestion (question .question (), question .help (), (answer ) -> {
149- try {
150- return CoordinateUtils .fromString (answer );
151- } catch (IllegalArgumentException ex ) {
152- throw new ContributingException (ex .getMessage ());
153- }
154- });
135+ return InteractiveTaskUtils .askQuestion (question .question (), question .help (), (answer ) -> answer );
155136 }
156137
157138 private Path getTestsLocation () {
@@ -200,7 +181,7 @@ private void checkPackages(Path testsPath) throws ContributingException {
200181 }
201182 }
202183
203- private Path getResourcesLocation (){
184+ private Path getResourcesLocation () {
204185 ContributingQuestion question = questions .get ("resourcesLocation" );
205186 return InteractiveTaskUtils .askQuestion (question .question (), question .help (), (answer ) -> {
206187 if (answer .equalsIgnoreCase ("-" )) {
@@ -241,21 +222,15 @@ private List<String> getAllowedPackages() {
241222 return InteractiveTaskUtils .askRecurringQuestions (question .question (), question .help (), 1 , answer -> answer );
242223 }
243224
244- private List <Coordinates > getAdditionalDependencies () {
225+ private List <String > getAdditionalDependencies () {
245226 ContributingQuestion question = questions .get ("additionalDependencies" );
246- return InteractiveTaskUtils .askRecurringQuestions (question .question (), question .help (), 0 , answer -> {
247- try {
248- return CoordinateUtils .fromString (answer );
249- } catch (IllegalArgumentException ex ) {
250- throw new ContributingException (ex .getMessage ());
251- }
252- });
227+ return InteractiveTaskUtils .askRecurringQuestions (question .question (), question .help (), 0 , answer -> answer );
253228 }
254229
255230 private void createStubs (boolean shouldUpdate ) {
256- InteractiveTaskUtils .printUserInfo ("Generating stubs for: " + coordinates );
231+ InteractiveTaskUtils .printUserInfo ("Generating stubs for: " + coordinates );
257232 String opt = shouldUpdate ? "--update" : "" ;
258- invokeCommand (gradlew + " scaffold --coordinates " + coordinates + " --skipTests " + opt , "Cannot generate stubs for: " + coordinates );
233+ MetadataGenerationUtils . invokeCommand (getExecOperations (), gradlewPath + " scaffold --coordinates " + coordinates + " --skipTests " + opt , "Cannot generate stubs for: " + coordinates );
259234 }
260235
261236 private void updateAllowedPackages (List <String > allowedPackages , boolean libraryAlreadyExists ) throws IOException {
@@ -264,8 +239,9 @@ private void updateAllowedPackages(List<String> allowedPackages, boolean library
264239
265240 List <MetadataIndexEntry > entries = objectMapper .readValue (metadataIndex , new TypeReference <>() {});
266241 int replaceEntryIndex = -1 ;
242+ Coordinates dependencyCoordinates = CoordinateUtils .fromString (coordinates );
267243 for (int i = 0 ; i < entries .size (); i ++) {
268- if (entries .get (i ).module ().equals (coordinates .group () + ":" + coordinates .artifact ())) {
244+ if (entries .get (i ).module ().equals (dependencyCoordinates .group () + ":" + dependencyCoordinates .artifact ())) {
269245 replaceEntryIndex = i ;
270246 break ;
271247 }
@@ -289,7 +265,7 @@ private void updateAllowedPackages(List<String> allowedPackages, boolean library
289265 objectMapper .writeValue (metadataIndex , entries );
290266 }
291267
292- private void addTests (Path originalTestsLocation ){
268+ private void addTests (Path originalTestsLocation ) {
293269 Path destination = testsDirectory .resolve ("src" ).resolve ("test" ).resolve ("java" );
294270 Path allTests = originalTestsLocation .resolve ("." );
295271
@@ -301,7 +277,7 @@ private void addTests(Path originalTestsLocation){
301277 });
302278 }
303279
304- private void addResources (Path originalResourcesDirectory ){
280+ private void addResources (Path originalResourcesDirectory ) {
305281 if (originalResourcesDirectory == null ) {
306282 return ;
307283 }
@@ -311,8 +287,8 @@ private void addResources(Path originalResourcesDirectory){
311287
312288 InteractiveTaskUtils .printUserInfo ("Copying resources from: " + originalResourcesDirectory + " to " + destination );
313289 getFileSystemOperations ().copy (copySpec -> {
314- copySpec .from (originalResourcesDirectory );
315- copySpec .into (destination );
290+ copySpec .from (originalResourcesDirectory );
291+ copySpec .into (destination );
316292 });
317293 }
318294
@@ -326,39 +302,24 @@ private void addDockerImages(List<String> images) throws IOException {
326302 ensureFileBelongsToProject (destination );
327303
328304 if (!Files .exists (destination )) {
329- Files .createFile (destination );
305+ Files .createDirectories (destination . getParent () );
330306 }
331307
332308 for (String image : images ) {
333- writeToFile (destination , image .concat (System .lineSeparator ()), StandardOpenOption .APPEND );
309+ MetadataGenerationUtils . writeToFile (destination , image .concat (System .lineSeparator ()), StandardOpenOption .APPEND );
334310 }
335311 }
336312
337- private void addUserCodeFilterFile (List <String > packages ) throws IOException {
338- InteractiveTaskUtils .printUserInfo ("Generating " + USER_CODE_FILTER_FILE );
339- List <Map <String , String >> filterFileRules = new ArrayList <>();
340-
341- // add exclude classes
342- filterFileRules .add (Map .of ("excludeClasses" , "**" ));
343-
344- // add include classes
345- packages .forEach (p -> filterFileRules .add (Map .of ("includeClasses" , p + ".**" )));
346-
347- DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter ();
348- prettyPrinter .indentArraysWith (DefaultIndenter .SYSTEM_LINEFEED_INSTANCE );
349- objectMapper .writer (prettyPrinter ).writeValue (testsDirectory .resolve (USER_CODE_FILTER_FILE ).toFile (), Map .of ("rules" , filterFileRules ));
350- }
351-
352- private void addAdditionalDependencies (List <Coordinates > dependencies ) throws IOException {
313+ private void addAdditionalDependencies (List <String > dependencies ) throws IOException {
353314 if (dependencies .isEmpty ()) {
354315 return ;
355316 }
356317
357- Path buildFilePath = testsDirectory .resolve (BUILD_FILE );
358- InteractiveTaskUtils .printUserInfo ("Adding following dependencies to " + BUILD_FILE + " file: " + dependencies );
318+ Path buildFilePath = testsDirectory .resolve (MetadataGenerationUtils . BUILD_FILE );
319+ InteractiveTaskUtils .printUserInfo ("Adding following dependencies to " + MetadataGenerationUtils . BUILD_FILE + " file: " + dependencies );
359320
360321 if (!Files .isRegularFile (buildFilePath )) {
361- throw new RuntimeException ("Cannot add additional dependencies to " + buildFilePath + ". Please check if a " + BUILD_FILE + " exists on that location." );
322+ throw new RuntimeException ("Cannot add additional dependencies to " + buildFilePath + ". Please check if a " + MetadataGenerationUtils . BUILD_FILE + " exists on that location." );
362323 }
363324
364325 ConfigurationStringBuilder sb = new ConfigurationStringBuilder ();
@@ -368,39 +329,13 @@ private void addAdditionalDependencies(List<Coordinates> dependencies) throws IO
368329 if (line .trim ().equalsIgnoreCase ("dependencies {" )) {
369330 sb .indent ();
370331 for (var dependency : dependencies ) {
371- sb .append ("testImplementation" ).space ().quote (dependency . toString () ).newLine ();
332+ sb .append ("testImplementation" ).space ().quote (dependency ).newLine ();
372333 }
373334 sb .unindent ();
374335 }
375336 }
376337
377- writeToFile (buildFilePath , sb .toString (), StandardOpenOption .WRITE );
378- }
379-
380- private void addAgentConfigBlock () throws IOException {
381- Path buildFilePath = testsDirectory .resolve (BUILD_FILE );
382- InteractiveTaskUtils .printUserInfo ("Configuring agent block in: " + BUILD_FILE );
383-
384- if (!Files .isRegularFile (buildFilePath )) {
385- throw new RuntimeException ("Cannot add agent block to " + buildFilePath + ". Please check if a " + BUILD_FILE + " exists on that location." );
386- }
387-
388- try (InputStream stream = ContributionTask .class .getResourceAsStream ("/contributing/agent.template" )) {
389- if (stream == null ) {
390- throw new RuntimeException ("Cannot find template for the graalvm configuration block" );
391- }
392-
393- String content = System .lineSeparator () + (new String (stream .readAllBytes (), StandardCharsets .UTF_8 ));
394- writeToFile (buildFilePath , content , StandardOpenOption .APPEND );
395- }
396- }
397-
398- private void collectMetadata () {
399- InteractiveTaskUtils .printUserInfo ("Generating metadata" );
400- invokeCommand (gradlew + " -Pagent test" , "Cannot generate metadata" , testsDirectory );
401-
402- InteractiveTaskUtils .printUserInfo ("Performing metadata copy" );
403- invokeCommand (gradlew + " metadataCopy --task test --dir " + metadataDirectory , "Cannot perform metadata copy" , testsDirectory );
338+ MetadataGenerationUtils .writeToFile (buildFilePath , sb .toString (), StandardOpenOption .WRITE );
404339 }
405340
406341 private boolean shouldCreatePullRequest () {
@@ -410,53 +345,20 @@ private boolean shouldCreatePullRequest() {
410345
411346 private void createPullRequest (String branch ) {
412347 InteractiveTaskUtils .printUserInfo ("Creating new branch: " + branch );
413- invokeCommand ("git switch -C " + branch , "Cannot create a new branch" );
348+ MetadataGenerationUtils . invokeCommand (getExecOperations (), "git switch -C " + branch , "Cannot create a new branch" );
414349
415350 InteractiveTaskUtils .printUserInfo ("Staging changes" );
416- invokeCommand ("git add ." , "Cannot add changes" );
351+ MetadataGenerationUtils . invokeCommand (getExecOperations (), "git add ." , "Cannot add changes" );
417352
418353 InteractiveTaskUtils .printUserInfo ("Committing changes" );
419- invokeCommand ("git" , List .of ("commit" , "-m" , "Add metadata for " + coordinates ), "Cannot commit changes" , null );
354+ MetadataGenerationUtils . invokeCommand (getExecOperations (), "git" , List .of ("commit" , "-m" , "Add metadata for " + coordinates ), "Cannot commit changes" , null );
420355
421356 InteractiveTaskUtils .printUserInfo ("Pushing changes" );
422- invokeCommand ("git push origin " + branch , "Cannot push to origin" );
357+ MetadataGenerationUtils . invokeCommand (getExecOperations (), "git push origin " + branch , "Cannot push to origin" );
423358
424359 InteractiveTaskUtils .printUserInfo ("Complete pull request creation on the above link" );
425360 }
426361
427- private void writeToFile (Path path , String content , StandardOpenOption writeOption ) throws IOException {
428- Files .createDirectories (path .getParent ());
429- Files .writeString (path , content , StandardCharsets .UTF_8 , writeOption );
430- }
431-
432- private void invokeCommand (String command , String errorMessage ) {
433- invokeCommand (command , errorMessage , null );
434- }
435-
436- private void invokeCommand (String command , String errorMessage , Path workingDirectory ) {
437- String [] commandParts = command .split (" " );
438- String executable = commandParts [0 ];
439-
440- List <String > args = List .of (Arrays .copyOfRange (commandParts , 1 , commandParts .length ));
441- invokeCommand (executable , args , errorMessage , workingDirectory );
442- }
443-
444- private void invokeCommand (String executable , List <String > args , String errorMessage , Path workingDirectory ) {
445- ByteArrayOutputStream execOutput = new ByteArrayOutputStream ();
446- var result = getExecOperations ().exec (execSpec -> {
447- if (workingDirectory != null ) {
448- execSpec .setWorkingDir (workingDirectory );
449- }
450- execSpec .setExecutable (executable );
451- execSpec .setArgs (args );
452- execSpec .setStandardOutput (execOutput );
453- });
454-
455- if (result .getExitValue () != 0 ) {
456- throw new RuntimeException (errorMessage + ". See: " + execOutput );
457- }
458- }
459-
460362 private void ensureFileBelongsToProject (Path file ) {
461363 if (!file .isAbsolute () || !file .startsWith (getLayout ().getProjectDirectory ().getAsFile ().getAbsolutePath ())) {
462364 throw new RuntimeException ("The following file doesn't belong to the metadata repository: " + file );
0 commit comments