Skip to content

Commit 84bbfa1

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

File tree

4 files changed

+242
-139
lines changed

4 files changed

+242
-139
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: 43 additions & 139 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,10 +35,10 @@
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

41+
4742
@Inject
4843
protected abstract ProjectLayout getLayout();
4944

@@ -55,32 +50,24 @@ public abstract class ContributionTask extends DefaultTask {
5550

5651
private final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT).setSerializationInclusion(JsonInclude.Include.NON_NULL);
5752

58-
private Path gradlew;
53+
private Path gradlewPath;
5954
private Path testsDirectory;
60-
private Path metadataDirectory;
61-
62-
private Coordinates coordinates;
6355

64-
private record ContributingQuestion(String question, String help) {}
65-
private final Map<String, ContributingQuestion> questions = new HashMap<>();
56+
String coordinates;
6657

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");
58+
private record ContributingQuestion(String question, String help) {
7159
}
7260

73-
private Path getPathFromProject(String fileName) {
74-
return Path.of(getProjectFile(fileName).getAbsolutePath());
75-
}
61+
private final Map<String, ContributingQuestion> questions = new HashMap<>();
7662

7763
private File getProjectFile(String fileName) {
7864
return getLayout().getProjectDirectory().file(fileName).getAsFile();
7965
}
8066

8167
private void loadQuestions() throws IOException {
8268
File questionsJson = getProjectFile("tests/tck-build-logic/src/main/resources/contributing/questions.json");
83-
List<Question> contributingQuestions = objectMapper.readValue(questionsJson, new TypeReference<>() {});
69+
List<Question> contributingQuestions = objectMapper.readValue(questionsJson, new TypeReference<>() {
70+
});
8471
for (var question : contributingQuestions) {
8572
questions.put(question.questionKey(), new ContributingQuestion(question.question(), question.help()));
8673
}
@@ -96,7 +83,7 @@ void run() throws IOException {
9683
coordinates = getCoordinates();
9784
InteractiveTaskUtils.closeSection();
9885

99-
Path coordinatesMetadataRoot = getPathFromProject(CoordinateUtils.replace("metadata/$group$/$artifact$", coordinates));
86+
Path coordinatesMetadataRoot = MetadataGenerationUtils.getPathFromProject(getLayout(), CoordinateUtils.replace("metadata/$group$/$artifact$", CoordinateUtils.fromString(coordinates)));
10087
boolean isExistingLibrary = Files.exists(coordinatesMetadataRoot);
10188

10289
Path testsLocation = getTestsLocation();
@@ -111,29 +98,31 @@ void run() throws IOException {
11198
List<String> packages = getAllowedPackages();
11299
InteractiveTaskUtils.closeSection();
113100

114-
List<Coordinates> additionalTestImplementationDependencies = getAdditionalDependencies();
101+
List<String> additionalTestImplementationDependencies = getAdditionalDependencies();
115102
InteractiveTaskUtils.closeSection();
116103

117104
// initialize project
118-
initializeWorkingDirectories();
105+
gradlewPath = MetadataGenerationUtils.getPathFromProject(getLayout(), GRADLEW);
106+
testsDirectory = MetadataGenerationUtils.computeTestsDirectory(getLayout(), coordinates);
107+
119108
createStubs(isExistingLibrary);
120109
updateAllowedPackages(packages, isExistingLibrary);
121110

122111
// generate necessary boilerplate code
123112
addTests(testsLocation);
124113
addResources(resourcesLocation);
125114
addDockerImages(dockerImages);
126-
addUserCodeFilterFile(packages);
115+
MetadataGenerationUtils.addUserCodeFilterFile(getLayout(), testsDirectory, packages);
127116
addAdditionalDependencies(additionalTestImplementationDependencies);
128-
addAgentConfigBlock();
117+
MetadataGenerationUtils.addAgentConfigBlock(testsDirectory);
129118

130119
// run agent in conditional mode
131-
collectMetadata();
120+
MetadataGenerationUtils.collectMetadata(getExecOperations(), testsDirectory, getLayout(), coordinates, gradlewPath);
132121

133122
// create a PR
134123
boolean shouldCreatePR = shouldCreatePullRequest();
135124
if (shouldCreatePR) {
136-
String branch = BRANCH_NAME_PREFIX + coordinates.toString().replace(':', '-');
125+
String branch = BRANCH_NAME_PREFIX + coordinates.replace(':', '-');
137126
createPullRequest(branch);
138127

139128
InteractiveTaskUtils.printUserInfo("After your pull requests gets generated, please update the pull request description to mention all places where your pull request" +
@@ -143,15 +132,9 @@ void run() throws IOException {
143132
InteractiveTaskUtils.printSuccessfulStatement("Contribution successfully completed! Thank you!");
144133
}
145134

146-
private Coordinates getCoordinates() {
135+
private String getCoordinates() {
147136
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-
});
137+
return InteractiveTaskUtils.askQuestion(question.question(), question.help(), (answer) -> answer);
155138
}
156139

157140
private Path getTestsLocation() {
@@ -200,7 +183,7 @@ private void checkPackages(Path testsPath) throws ContributingException {
200183
}
201184
}
202185

203-
private Path getResourcesLocation(){
186+
private Path getResourcesLocation() {
204187
ContributingQuestion question = questions.get("resourcesLocation");
205188
return InteractiveTaskUtils.askQuestion(question.question(), question.help(), (answer) -> {
206189
if (answer.equalsIgnoreCase("-")) {
@@ -241,21 +224,15 @@ private List<String> getAllowedPackages() {
241224
return InteractiveTaskUtils.askRecurringQuestions(question.question(), question.help(), 1, answer -> answer);
242225
}
243226

244-
private List<Coordinates> getAdditionalDependencies() {
227+
private List<String> getAdditionalDependencies() {
245228
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-
});
229+
return InteractiveTaskUtils.askRecurringQuestions(question.question(), question.help(), 0, answer -> answer);
253230
}
254231

255232
private void createStubs(boolean shouldUpdate) {
256-
InteractiveTaskUtils.printUserInfo("Generating stubs for: " + coordinates );
233+
InteractiveTaskUtils.printUserInfo("Generating stubs for: " + coordinates);
257234
String opt = shouldUpdate ? "--update" : "";
258-
invokeCommand(gradlew + " scaffold --coordinates " + coordinates + " --skipTests " + opt, "Cannot generate stubs for: " + coordinates);
235+
MetadataGenerationUtils.invokeCommand(getExecOperations(), gradlewPath + " scaffold --coordinates " + coordinates + " --skipTests " + opt, "Cannot generate stubs for: " + coordinates);
259236
}
260237

261238
private void updateAllowedPackages(List<String> allowedPackages, boolean libraryAlreadyExists) throws IOException {
@@ -264,8 +241,9 @@ private void updateAllowedPackages(List<String> allowedPackages, boolean library
264241

265242
List<MetadataIndexEntry> entries = objectMapper.readValue(metadataIndex, new TypeReference<>() {});
266243
int replaceEntryIndex = -1;
244+
Coordinates dependencyCoordinates = CoordinateUtils.fromString(coordinates);
267245
for (int i = 0; i < entries.size(); i++) {
268-
if (entries.get(i).module().equals(coordinates.group() + ":" + coordinates.artifact())) {
246+
if (entries.get(i).module().equals(dependencyCoordinates.group() + ":" + dependencyCoordinates.artifact())) {
269247
replaceEntryIndex = i;
270248
break;
271249
}
@@ -289,7 +267,7 @@ private void updateAllowedPackages(List<String> allowedPackages, boolean library
289267
objectMapper.writeValue(metadataIndex, entries);
290268
}
291269

292-
private void addTests(Path originalTestsLocation){
270+
private void addTests(Path originalTestsLocation) {
293271
Path destination = testsDirectory.resolve("src").resolve("test").resolve("java");
294272
Path allTests = originalTestsLocation.resolve(".");
295273

@@ -301,7 +279,7 @@ private void addTests(Path originalTestsLocation){
301279
});
302280
}
303281

304-
private void addResources(Path originalResourcesDirectory){
282+
private void addResources(Path originalResourcesDirectory) {
305283
if (originalResourcesDirectory == null) {
306284
return;
307285
}
@@ -311,8 +289,8 @@ private void addResources(Path originalResourcesDirectory){
311289

312290
InteractiveTaskUtils.printUserInfo("Copying resources from: " + originalResourcesDirectory + " to " + destination);
313291
getFileSystemOperations().copy(copySpec -> {
314-
copySpec.from(originalResourcesDirectory);
315-
copySpec.into(destination);
292+
copySpec.from(originalResourcesDirectory);
293+
copySpec.into(destination);
316294
});
317295
}
318296

@@ -326,39 +304,24 @@ private void addDockerImages(List<String> images) throws IOException {
326304
ensureFileBelongsToProject(destination);
327305

328306
if (!Files.exists(destination)) {
329-
Files.createFile(destination);
307+
Files.createDirectories(destination.getParent());
330308
}
331309

332310
for (String image : images) {
333-
writeToFile(destination, image.concat(System.lineSeparator()), StandardOpenOption.APPEND);
311+
MetadataGenerationUtils.writeToFile(destination, image.concat(System.lineSeparator()), StandardOpenOption.APPEND);
334312
}
335313
}
336314

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 {
315+
private void addAdditionalDependencies(List<String> dependencies) throws IOException {
353316
if (dependencies.isEmpty()) {
354317
return;
355318
}
356319

357-
Path buildFilePath = testsDirectory.resolve(BUILD_FILE);
358-
InteractiveTaskUtils.printUserInfo("Adding following dependencies to " + BUILD_FILE + " file: " + dependencies);
320+
Path buildFilePath = testsDirectory.resolve(MetadataGenerationUtils.BUILD_FILE);
321+
InteractiveTaskUtils.printUserInfo("Adding following dependencies to " + MetadataGenerationUtils.BUILD_FILE + " file: " + dependencies);
359322

360323
if (!Files.isRegularFile(buildFilePath)) {
361-
throw new RuntimeException("Cannot add additional dependencies to " + buildFilePath + ". Please check if a " + BUILD_FILE + " exists on that location.");
324+
throw new RuntimeException("Cannot add additional dependencies to " + buildFilePath + ". Please check if a " + MetadataGenerationUtils.BUILD_FILE + " exists on that location.");
362325
}
363326

364327
ConfigurationStringBuilder sb = new ConfigurationStringBuilder();
@@ -368,39 +331,13 @@ private void addAdditionalDependencies(List<Coordinates> dependencies) throws IO
368331
if (line.trim().equalsIgnoreCase("dependencies {")) {
369332
sb.indent();
370333
for (var dependency : dependencies) {
371-
sb.append("testImplementation").space().quote(dependency.toString()).newLine();
334+
sb.append("testImplementation").space().quote(dependency).newLine();
372335
}
373336
sb.unindent();
374337
}
375338
}
376339

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);
340+
MetadataGenerationUtils.writeToFile(buildFilePath, sb.toString(), StandardOpenOption.WRITE);
404341
}
405342

406343
private boolean shouldCreatePullRequest() {
@@ -410,53 +347,20 @@ private boolean shouldCreatePullRequest() {
410347

411348
private void createPullRequest(String branch) {
412349
InteractiveTaskUtils.printUserInfo("Creating new branch: " + branch);
413-
invokeCommand("git switch -C " + branch, "Cannot create a new branch");
350+
MetadataGenerationUtils.invokeCommand(getExecOperations(), "git switch -C " + branch, "Cannot create a new branch");
414351

415352
InteractiveTaskUtils.printUserInfo("Staging changes");
416-
invokeCommand("git add .", "Cannot add changes");
353+
MetadataGenerationUtils.invokeCommand(getExecOperations(), "git add .", "Cannot add changes");
417354

418355
InteractiveTaskUtils.printUserInfo("Committing changes");
419-
invokeCommand("git", List.of("commit", "-m", "Add metadata for " + coordinates), "Cannot commit changes", null);
356+
MetadataGenerationUtils.invokeCommand(getExecOperations(), "git", List.of("commit", "-m", "Add metadata for " + coordinates), "Cannot commit changes", null);
420357

421358
InteractiveTaskUtils.printUserInfo("Pushing changes");
422-
invokeCommand("git push origin " + branch, "Cannot push to origin");
359+
MetadataGenerationUtils.invokeCommand(getExecOperations(), "git push origin " + branch, "Cannot push to origin");
423360

424361
InteractiveTaskUtils.printUserInfo("Complete pull request creation on the above link");
425362
}
426363

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-
460364
private void ensureFileBelongsToProject(Path file) {
461365
if (!file.isAbsolute() || !file.startsWith(getLayout().getProjectDirectory().getAsFile().getAbsolutePath())) {
462366
throw new RuntimeException("The following file doesn't belong to the metadata repository: " + file);

0 commit comments

Comments
 (0)