feat: Get tasks from custom tapi model (#1148)

This commit is contained in:
Shi Chen 2022-01-17 15:13:28 +08:00 коммит произвёл GitHub
Родитель 846d52e349
Коммит 339166ecb3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 222 добавлений и 74 удалений

2
.github/workflows/main.yml поставляемый
Просмотреть файл

@ -36,7 +36,7 @@ jobs:
- name: Build & Analyse Gradle Server
uses: gradle/gradle-build-action@v2
with:
arguments: gradle-server:build -x :test -x extension:test -x npm-package:test
arguments: build -x test
env:
JAVA_HOME: ""
- name: Upload lib

Просмотреть файл

@ -7,6 +7,10 @@ import java.util.List;
import org.gradle.tooling.model.Model;
public interface GradleProjectModel extends Model {
boolean getIsRoot();
String getProjectPath();
List<GradleProjectModel> getSubProjects();
List<GradleTask> getTasks();
GradleDependencyNode getDependencyNode();
List<String> getPlugins();
List<GradleClosure> getClosures();

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
package com.microsoft.gradle.api;
public interface GradleTask {
String getName();
String getGroup();
String getPath();
String getProject();
String getBuildFile();
String getRootProject();
String getDescription();
}

Просмотреть файл

@ -6,23 +6,49 @@ package com.microsoft.gradle;
import com.microsoft.gradle.api.GradleClosure;
import com.microsoft.gradle.api.GradleDependencyNode;
import com.microsoft.gradle.api.GradleProjectModel;
import com.microsoft.gradle.api.GradleTask;
import java.io.Serializable;
import java.util.List;
public class DefaultGradleProjectModel implements Serializable, GradleProjectModel {
private boolean isRoot;
private String projectPath;
private List<GradleProjectModel> subProjects;
private List<GradleTask> tasks;
private GradleDependencyNode node;
private List<String> plugins;
private List<GradleClosure> closures;
private List<String> scriptClasspaths;
public DefaultGradleProjectModel(GradleDependencyNode node, List<String> plugins, List<GradleClosure> closures,
public DefaultGradleProjectModel(boolean isRoot, String projectPath, List<GradleProjectModel> subProjects,
List<GradleTask> tasks, GradleDependencyNode node, List<String> plugins, List<GradleClosure> closures,
List<String> scriptClasspaths) {
this.isRoot = isRoot;
this.projectPath = projectPath;
this.subProjects = subProjects;
this.tasks = tasks;
this.node = node;
this.plugins = plugins;
this.closures = closures;
this.scriptClasspaths = scriptClasspaths;
}
public boolean getIsRoot() {
return this.isRoot;
}
public String getProjectPath() {
return this.projectPath;
}
public List<GradleProjectModel> getSubProjects() {
return this.subProjects;
}
public List<GradleTask> getTasks() {
return this.tasks;
}
public GradleDependencyNode getDependencyNode() {
return this.node;
}

Просмотреть файл

@ -0,0 +1,56 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
package com.microsoft.gradle;
import com.microsoft.gradle.api.GradleTask;
import java.io.Serializable;
public class DefaultGradleTask implements Serializable, GradleTask {
private String name;
private String group;
private String path;
private String project;
private String buildFile;
private String rootProject;
private String description;
public DefaultGradleTask(String name, String group, String path, String project, String buildFile,
String rootProject, String description) {
this.name = name;
this.group = group;
this.path = path;
this.project = project;
this.buildFile = buildFile;
this.rootProject = rootProject;
this.description = description;
}
public String getName() {
return name;
}
public String getGroup() {
return group;
}
public String getPath() {
return path;
}
public String getProject() {
return project;
}
public String getBuildFile() {
return buildFile;
}
public String getRootProject() {
return rootProject;
}
public String getDescription() {
return description;
}
}

Просмотреть файл

@ -9,6 +9,7 @@ import com.microsoft.gradle.api.GradleDependencyType;
import com.microsoft.gradle.api.GradleField;
import com.microsoft.gradle.api.GradleMethod;
import com.microsoft.gradle.api.GradleProjectModel;
import com.microsoft.gradle.api.GradleTask;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
@ -32,15 +33,42 @@ import org.gradle.api.plugins.Convention;
import org.gradle.api.plugins.ExtensionsSchema;
import org.gradle.api.plugins.ExtensionsSchema.ExtensionSchema;
import org.gradle.api.reflect.TypeOf;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.internal.classpath.ClassPath;
import org.gradle.tooling.provider.model.ToolingModelBuilder;
public class GradleProjectModelBuilder implements ToolingModelBuilder {
private Set<GradleTask> cachedTasks = new HashSet<>();
public boolean canBuild(String modelName) {
return modelName.equals(GradleProjectModel.class.getName());
}
public Object buildAll(String modelName, Project project) {
cachedTasks.clear();
GradleProjectModel rootModel = buildModel(project, project);
// add task selectors for root project
Set<String> taskNames = new HashSet<>();
for (GradleTask existingTask : rootModel.getTasks()) {
taskNames.add(existingTask.getName());
}
for (GradleTask task : cachedTasks) {
if (!taskNames.contains(task.getName())) {
taskNames.add(task.getName());
GradleTask newTask = new DefaultGradleTask(task.getName(), task.getGroup(), task.getPath(),
project.getName(), project.getBuildscript().getSourceFile().getAbsolutePath(),
task.getRootProject(), task.getDescription());
rootModel.getTasks().add(newTask);
}
}
return rootModel;
}
private GradleProjectModel buildModel(Project rootProject, Project project) {
if (rootProject == null || project == null) {
return null;
}
ScriptHandler buildScript = project.getBuildscript();
ClassPath classpath = ((DefaultScriptHandler) buildScript).getScriptClassPath();
List<String> scriptClasspaths = new ArrayList<>();
@ -50,7 +78,17 @@ public class GradleProjectModelBuilder implements ToolingModelBuilder {
GradleDependencyNode node = generateDefaultGradleDependencyNode(project);
List<String> plugins = getPlugins(project);
List<GradleClosure> closures = getPluginClosures(project);
return new DefaultGradleProjectModel(node, plugins, closures, scriptClasspaths);
List<GradleProjectModel> subModels = new ArrayList<>();
Set<Project> subProjects = project.getSubprojects();
for (Project subProject : subProjects) {
GradleProjectModel subModel = buildModel(rootProject, subProject);
if (subModel != null) {
subModels.add(subModel);
}
}
List<GradleTask> tasks = getGradleTasks(rootProject, project);
return new DefaultGradleProjectModel(project.getParent() == null, project.getProjectDir().getAbsolutePath(),
subModels, tasks, node, plugins, closures, scriptClasspaths);
}
private GradleDependencyNode generateDefaultGradleDependencyNode(Project project) {
@ -142,6 +180,25 @@ public class GradleProjectModelBuilder implements ToolingModelBuilder {
return closures;
}
private List<GradleTask> getGradleTasks(Project rootProject, Project project) {
List<GradleTask> tasks = new ArrayList<>();
TaskContainer taskContainer = project.getTasks();
taskContainer.forEach(task -> {
String name = task.getName();
String group = task.getGroup() == null ? null : task.getGroup();
String path = task.getPath();
String projectName = task.getProject().getName();
String buildFile = task.getProject().getBuildscript().getSourceFile().getAbsolutePath();
String rootProjectName = rootProject.getName();
String description = task.getDescription() == null ? null : task.getDescription();
GradleTask newTask = new DefaultGradleTask(name, group, path, projectName, buildFile, rootProjectName,
description);
tasks.add(newTask);
cachedTasks.add(newTask);
});
return tasks;
}
private boolean isDeprecated(AccessibleObject object) {
for (Annotation annotation : object.getDeclaredAnnotations()) {
if (annotation.toString().contains("Deprecated")) {

Просмотреть файл

@ -17,16 +17,24 @@ import com.github.badsyntax.gradle.JavaEnvironment;
import com.github.badsyntax.gradle.Output;
import com.github.badsyntax.gradle.Progress;
import com.github.badsyntax.gradle.exceptions.GradleConnectionException;
import com.github.badsyntax.gradle.utils.PluginUtils;
import com.github.badsyntax.gradle.utils.Utils;
import com.google.common.base.Strings;
import com.google.protobuf.ByteString;
import com.microsoft.gradle.api.GradleModelAction;
import com.microsoft.gradle.api.GradleProjectModel;
import io.github.g00fy2.versioncompare.Version;
import io.grpc.stub.StreamObserver;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.gradle.internal.service.ServiceCreationException;
import org.gradle.tooling.BuildActionExecuter;
import org.gradle.tooling.BuildCancelledException;
import org.gradle.tooling.CancellationToken;
import org.gradle.tooling.GradleConnector;
@ -88,8 +96,28 @@ public class GetBuildHandler {
try (ProjectConnection connection = gradleConnector.connect()) {
this.environment = buildEnvironment(connection);
replyWithBuildEnvironment(this.environment);
org.gradle.tooling.model.GradleProject gradleProject = getGradleProject(connection);
replyWithProject(getProjectData(gradleProject, gradleProject, new HashSet<>()));
BuildActionExecuter<GradleProjectModel> action = connection.action(new GradleModelAction());
if (action == null) {
responseObserver.onCompleted();
return;
}
File initScript = PluginUtils.createInitScript();
List<String> arguments = Arrays.asList("--init-script", initScript.getAbsolutePath());
String jvmArguments = req.getGradleConfig().getJvmArguments();
if (!Strings.isNullOrEmpty(jvmArguments)) {
arguments.addAll(Arrays.stream(jvmArguments.split(" ")).filter(e -> e != null && !e.isEmpty())
.collect(Collectors.toList()));
}
action.withArguments(arguments);
CancellationToken cancellationToken = GradleBuildCancellation.buildToken(req.getCancellationKey());
Set<OperationType> progressEvents = new HashSet<>();
progressEvents.add(OperationType.PROJECT_CONFIGURATION);
action.withCancellationToken(cancellationToken).addProgressListener(progressListener, progressEvents)
.setStandardOutput(standardOutputListener).setStandardError(standardErrorListener)
.setColorOutput(req.getShowOutputColors());
GradleProjectModel gradleModel = action.run();
GradleProject project = getProjectData(gradleModel);
replyWithProject(project);
} catch (BuildCancelledException e) {
replyWithCancelled(e);
} catch (ServiceCreationException | IOException | IllegalStateException
@ -112,6 +140,8 @@ public class GetBuildHandler {
}
logger.error(e.getMessage());
replyWithError(e);
} catch (Exception e) {
replyWithError(e);
} finally {
GradleBuildCancellation.clearToken(req.getCancellationKey());
}
@ -138,7 +168,8 @@ public class GetBuildHandler {
CancellationToken cancellationToken = GradleBuildCancellation.buildToken(req.getCancellationKey());
buildEnvironment.withCancellationToken(cancellationToken).addProgressListener(progressListener, progressEvents)
.setStandardOutput(standardOutputListener).setStandardError(standardErrorListener);
.setStandardOutput(standardOutputListener).setStandardError(standardErrorListener)
.setColorOutput(req.getShowOutputColors());
String jvmArguments = req.getGradleConfig().getJvmArguments();
if (!Strings.isNullOrEmpty(jvmArguments)) {
buildEnvironment.setJvmArguments(Arrays.stream(jvmArguments.split(" "))
@ -162,75 +193,35 @@ public class GetBuildHandler {
}
}
private org.gradle.tooling.model.GradleProject getGradleProject(ProjectConnection connection) throws IOException {
ModelBuilder<org.gradle.tooling.model.GradleProject> projectBuilder = connection
.model(org.gradle.tooling.model.GradleProject.class);
Set<OperationType> progressEvents = new HashSet<>();
progressEvents.add(OperationType.PROJECT_CONFIGURATION);
CancellationToken cancellationToken = GradleBuildCancellation.buildToken(req.getCancellationKey());
projectBuilder.withCancellationToken(cancellationToken).addProgressListener(progressListener, progressEvents)
.setStandardOutput(standardOutputListener).setStandardError(standardErrorListener)
.setColorOutput(req.getShowOutputColors());
String jvmArguments = req.getGradleConfig().getJvmArguments();
if (!Strings.isNullOrEmpty(jvmArguments)) {
projectBuilder.setJvmArguments(Arrays.stream(jvmArguments.split(" ")).filter(e -> e != null && !e.isEmpty())
.toArray(String[]::new));
}
try {
return projectBuilder.get();
} finally {
GradleBuildCancellation.clearToken(req.getCancellationKey());
private GradleProject getProjectData(GradleProjectModel gradleModel) {
GradleProject.Builder project = GradleProject.newBuilder();
project.setIsRoot(gradleModel.getIsRoot());
project.addAllTasks(getGradleTasks(gradleModel));
List<GradleProject> subProjects = new ArrayList<>();
for (GradleProjectModel subProjectModel : gradleModel.getSubProjects()) {
subProjects.add(getProjectData(subProjectModel));
}
project.addAllProjects(subProjects);
return project.build();
}
private GradleProject getProjectData(org.gradle.tooling.model.GradleProject gradleProject,
org.gradle.tooling.model.GradleProject rootGradleProject, Set<GradleTask> taskSelectors) {
boolean isRoot = gradleProject.getParent() == null;
GradleProject.Builder project = GradleProject.newBuilder().setIsRoot(isRoot);
gradleProject.getChildren().stream().forEach(childGradleProject -> project
.addProjects(getProjectData(childGradleProject, rootGradleProject, taskSelectors)));
gradleProject.getTasks().stream().forEach(task -> {
GradleTask.Builder gradleTask = GradleTask.newBuilder().setProject(task.getProject().getName())
.setName(task.getName()).setPath(task.getPath())
.setBuildFile(task.getProject().getBuildScript().getSourceFile().getAbsolutePath())
.setRootProject(rootGradleProject.getName());
if (task.getDescription() != null) {
gradleTask.setDescription(task.getDescription());
private List<GradleTask> getGradleTasks(GradleProjectModel model) {
List<GradleTask> tasks = new ArrayList<>();
model.getTasks().forEach(task -> {
GradleTask.Builder builder = GradleTask.newBuilder();
builder.setName(task.getName()).setPath(task.getPath()).setProject(task.getProject())
.setBuildFile(task.getBuildFile()).setRootProject(task.getRootProject());
String group = task.getGroup();
if (group != null) {
builder.setGroup(group);
}
if (task.getGroup() != null) {
gradleTask.setGroup(task.getGroup());
String description = task.getDescription();
if (description != null) {
builder.setDescription(description);
}
project.addTasks(gradleTask.build());
taskSelectors.add(gradleTask.build());
tasks.add(builder.build());
});
if (isRoot) {
Set<String> taskNames = new HashSet<>();
for (GradleTask existingTask : project.getTasksList()) {
taskNames.add(existingTask.getName());
}
for (GradleTask task : taskSelectors) {
if (!taskNames.contains(task.getName())) {
taskNames.add(task.getName());
GradleTask.Builder taskSelector = GradleTask.newBuilder().setProject(gradleProject.getName())
.setName(task.getName()).setPath(task.getName())
.setBuildFile(gradleProject.getBuildScript().getSourceFile().getAbsolutePath())
.setRootProject(task.getRootProject());
if (task.getDescription() != null) {
taskSelector.setDescription(task.getDescription());
}
if (task.getGroup() != null) {
taskSelector.setGroup(task.getGroup());
}
project.addTasks(taskSelector.build());
}
}
}
return project.build();
return tasks;
}
private void replyWithProject(GradleProject gradleProject) {

Просмотреть файл

@ -220,7 +220,7 @@ public class GradleServerTest {
stub.getBuild(req, mockResponseObserver);
verify(mockResponseObserver, never()).onError(any());
verify(mockGradleProjectBuilder).setJvmArguments(jvmArgs.split(" "));
verify(mockBuildEnvironmentBuilder).setJvmArguments(jvmArgs.split(" "));
}
@Test
@ -232,13 +232,13 @@ public class GradleServerTest {
stub.getBuild(req1, mockResponseObserver);
verify(mockResponseObserver, never()).onError(any());
verify(mockGradleProjectBuilder).setColorOutput(false);
verify(mockBuildEnvironmentBuilder).setColorOutput(false);
GetBuildRequest req2 = GetBuildRequest.newBuilder().setProjectDir(mockProjectDir.getAbsolutePath().toString())
.setGradleConfig(GradleConfig.newBuilder().setWrapperEnabled(true)).setShowOutputColors(true).build();
stub.getBuild(req2, mockResponseObserver);
verify(mockResponseObserver, never()).onError(any());
verify(mockGradleProjectBuilder).setColorOutput(true);
verify(mockBuildEnvironmentBuilder).setColorOutput(true);
}
@Test
@ -253,11 +253,11 @@ public class GradleServerTest {
stub.getBuild(req, mockResponseObserver);
verify(mockResponseObserver, never()).onError(any());
verify(mockGradleProjectBuilder).addProgressListener(any(org.gradle.tooling.events.ProgressListener.class),
verify(mockBuildEnvironmentBuilder).addProgressListener(any(org.gradle.tooling.events.ProgressListener.class),
onAddProgressListener.capture());
assertEquals(1, onAddProgressListener.getValue().size());
assertTrue(onAddProgressListener.getValue().contains(OperationType.PROJECT_CONFIGURATION));
assertTrue(onAddProgressListener.getValue().contains(OperationType.GENERIC));
}
@Test