Skip to content

Commit 12a457c

Browse files
committed
GenerateMetadataTask introduction.
Created MetadataGenerationUtils utility class for operations shared by ContributionTask and NonInteractiveContributionTask.
1 parent bd387e7 commit 12a457c

File tree

4 files changed

+238
-138
lines changed

4 files changed

+238
-138
lines changed

tests/tck-build-logic/src/main/groovy/org.graalvm.internal.tck-harness.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import org.graalvm.internal.tck.DockerTask
1515
import org.graalvm.internal.tck.ConfigFilesChecker
1616
import org.graalvm.internal.tck.ScaffoldTask
1717
import org.graalvm.internal.tck.GrypeTask
18+
import org.graalvm.internal.tck.GenerateMetadataTask
1819
import org.graalvm.internal.tck.TestedVersionUpdaterTask
1920
import org.graalvm.internal.tck.harness.tasks.TestInvocationTask
2021
import org.graalvm.internal.tck.harness.tasks.CheckstyleInvocationTask
@@ -217,6 +218,11 @@ tasks.register("contribute", ContributionTask.class) { task ->
217218
task.setGroup(METADATA_GROUP)
218219
}
219220

221+
tasks.register("generateMetadata", GenerateMetadataTask.class) { task ->
222+
task.setDescription("Generates metadata and prepares pull request for contibuting on metadata repository based on provided tests.")
223+
task.setGroup(METADATA_GROUP)
224+
}
225+
220226
tasks.register("checkConfigFiles", ConfigFilesChecker.class) { task ->
221227
task.setDescription("Checks content of config files for a new library.")
222228
task.setGroup(METADATA_GROUP)

tests/tck-build-logic/src/main/java/org/graalvm/internal/tck/ContributionTask.java

Lines changed: 40 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import com.fasterxml.jackson.annotation.JsonInclude;
44
import com.fasterxml.jackson.core.type.TypeReference;
5-
import com.fasterxml.jackson.core.util.DefaultIndenter;
6-
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
75
import com.fasterxml.jackson.databind.ObjectMapper;
86
import com.fasterxml.jackson.databind.SerializationFeature;
97
import org.graalvm.internal.tck.exceptions.ContributingException;
@@ -12,23 +10,20 @@
1210
import org.graalvm.internal.tck.utils.ConfigurationStringBuilder;
1311
import org.graalvm.internal.tck.utils.FilesUtils;
1412
import org.graalvm.internal.tck.utils.InteractiveTaskUtils;
13+
import org.graalvm.internal.tck.utils.MetadataGenerationUtils;
1514
import org.gradle.api.DefaultTask;
1615
import org.gradle.api.file.FileSystemOperations;
1716
import org.gradle.api.file.ProjectLayout;
1817
import org.gradle.api.tasks.TaskAction;
1918
import org.gradle.process.ExecOperations;
2019

2120
import javax.inject.Inject;
22-
import java.io.ByteArrayOutputStream;
2321
import java.io.File;
2422
import java.io.IOException;
25-
import java.io.InputStream;
26-
import java.nio.charset.StandardCharsets;
2723
import java.nio.file.Files;
2824
import java.nio.file.Path;
2925
import java.nio.file.StandardOpenOption;
3026
import java.util.ArrayList;
31-
import java.util.Arrays;
3227
import java.util.Comparator;
3328
import java.util.HashMap;
3429
import java.util.HashSet;
@@ -40,8 +35,7 @@
4035
public 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

Comments
 (0)