Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New tool build integration #41710

Merged
merged 34 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
69eb836
Merge branch 'master' of https://github.com/ballerina-platform/baller…
ShammiL Nov 29, 2023
552c50b
Merge branch 'master' of https://github.com/ballerina-platform/baller…
ShammiL Dec 20, 2023
69ea9fe
Tool integration basic implementation
Dilhasha Sep 20, 2023
0f1338f
Add getter, remove tool_id and add diagnostic errors
ShammiL Oct 19, 2023
517203d
Handle bad sad error when no optional tool properties are given
ShammiL Oct 19, 2023
9c6c5e0
Fix error with empty tool toml array
ShammiL Oct 20, 2023
f4dd879
Remove generated directory with bal clean and add tests.
ShammiL Oct 26, 2023
d04cd3f
Detect and exit for toml errors in pre build task.
ShammiL Oct 30, 2023
7ce395f
Improve diagnostic message
ShammiL Oct 30, 2023
f876068
Fix checkStyleMain errors
ShammiL Oct 30, 2023
c79c097
Handle tool table property validations
ShammiL Oct 31, 2023
c89371d
Add ballerina toml tests for build tools
ShammiL Oct 31, 2023
d57b447
Address comments
ShammiL Nov 1, 2023
7f2b66e
Fix spotbug in manifestUtils
ShammiL Nov 2, 2023
2722f20
Add test only sample build tool
ShammiL Nov 2, 2023
5a048d0
Add build tool tests for bal build
ShammiL Nov 2, 2023
8107dbc
Add gradle dependencies to sample build tool
ShammiL Nov 3, 2023
3ada0f8
Fix build command with tool test failure
ShammiL Nov 3, 2023
a003a0b
Fix validation for empty options table
ShammiL Nov 16, 2023
25e3418
Tool integration basic implementation
Dilhasha Sep 20, 2023
3593f07
Add getter, remove tool_id and add diagnostic errors
ShammiL Oct 19, 2023
37a50b6
Handle bad sad error when no optional tool properties are given
ShammiL Oct 19, 2023
93e6dcc
Fix checkStyleMain errors
ShammiL Oct 30, 2023
b0bcbc4
Improve code quality
ShammiL Nov 20, 2023
4454988
Fix checkStyle errors
ShammiL Nov 20, 2023
4f3c480
Validate unique tool id and target module
ShammiL Dec 1, 2023
fd07f3c
Add new build command tests
ShammiL Dec 1, 2023
ac57b91
Address minor changes
ShammiL Dec 13, 2023
3ed1293
Add changes to clean command
ShammiL Dec 13, 2023
21f1313
Improve build tool
ShammiL Dec 13, 2023
2d80481
Fix clean command tests
ShammiL Dec 19, 2023
59a535b
Add new changes from review
ShammiL Dec 20, 2023
6ec870d
Change build tool interface
ShammiL Dec 22, 2023
86947a5
Fix printing warnings
ShammiL Dec 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/ballerina-cli/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ dependencies {
testRuntimeOnly project(':project-api-test-artifact:log-creator-in-built-code-modifier')
testRuntimeOnly project(':project-api-test-artifact:log-creator-in-built-code-generator')
testRuntimeOnly project(':project-api-test-artifact:log-creator-in-built-code-analyzer')
testRuntimeOnly project(':project-api-test-artifact:sample-openapi-build-tool')

compilerPluginJar project(':project-api-test-artifact:log-creator-pkg-provided-code-modifier')
compilerPluginJar project(':project-api-test-artifact:log-creator-pkg-provided-code-generator')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.ballerina.cli.task.CreateExecutableTask;
import io.ballerina.cli.task.DumpBuildTimeTask;
import io.ballerina.cli.task.ResolveMavenDependenciesTask;
import io.ballerina.cli.task.RunBallerinaPreBuildToolsTask;
import io.ballerina.cli.utils.BuildTime;
import io.ballerina.cli.utils.FileUtils;
import io.ballerina.projects.BuildOptions;
Expand Down Expand Up @@ -277,6 +278,7 @@ public void execute() {
TaskExecutor taskExecutor = new TaskExecutor.TaskBuilder()
// clean the target directory(projects only)
.addTask(new CleanTargetDirTask(isPackageModified, buildOptions.enableCache()), isSingleFileBuild)
.addTask(new RunBallerinaPreBuildToolsTask(outStream))
// resolve maven dependencies in Ballerina.toml
.addTask(new ResolveMavenDependenciesTask(outStream))
// compile the modules
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
private final PrintStream outStream;
private final Path projectPath;
private boolean exitWhenFinish;

@CommandLine.Option(names = {"--help", "-h"}, hidden = true)
private boolean helpFlag;

Expand All @@ -62,9 +62,9 @@
this.exitWhenFinish = true;
}

public CleanCommand(Path projectPath, boolean exitWhenFinish, Path targetDir) {
public CleanCommand(Path projectPath, PrintStream printStream, boolean exitWhenFinish, Path targetDir) {
this.projectPath = projectPath;
this.outStream = System.out;
this.outStream = printStream;
this.exitWhenFinish = exitWhenFinish;
this.targetDir = targetDir;
}
Expand Down Expand Up @@ -93,18 +93,31 @@
CommandUtil.printError(this.outStream,
"provided target directory '" + this.targetDir + "' does not exist.",
null, false);
CommandUtil.exitError(this.exitWhenFinish);
return;
}
if (!Files.isDirectory(this.targetDir)) {
} else if (!Files.isDirectory(this.targetDir)) {
CommandUtil.printError(this.outStream,
"provided target path '" + this.targetDir + "' is not a directory.",
null, false);
} else {
ProjectUtils.deleteDirectory(this.targetDir);
this.outStream.println("Successfully deleted '" + this.targetDir + "'.");
}

//delete the generated directory
Path generatedDir;
try {
Project project = BuildProject.load(this.projectPath);
generatedDir = project.sourceRoot().resolve(ProjectConstants.GENERATED_MODULES_ROOT);
} catch (ProjectException e) {
CommandUtil.printError(this.outStream, e.getMessage(), null, false);

Check warning on line 111 in cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CleanCommand.java

View check run for this annotation

Codecov / codecov/patch

cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CleanCommand.java#L110-L111

Added lines #L110 - L111 were not covered by tests
CommandUtil.exitError(this.exitWhenFinish);
return;
}
ProjectUtils.deleteDirectory(this.targetDir);
this.outStream.println("Successfully deleted '" + this.targetDir + "'.");
if (Files.notExists(generatedDir)) {
this.outStream.println("Existing generated directory was not found");
} else {
ProjectUtils.deleteDirectory(generatedDir);
this.outStream.println("Successfully deleted '" + generatedDir + "'.");
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2023, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package io.ballerina.cli.task;

import io.ballerina.cli.tool.CodeGeneratorTool;
import io.ballerina.cli.utils.FileUtils;
import io.ballerina.projects.Project;
import io.ballerina.projects.ProjectException;
import io.ballerina.projects.ToolContext;
import io.ballerina.toml.api.Toml;
import io.ballerina.tools.diagnostics.Diagnostic;
import io.ballerina.tools.diagnostics.DiagnosticSeverity;

import java.io.IOException;
import java.io.PrintStream;
import java.util.Collection;
import java.util.List;
import java.util.ServiceLoader;

import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException;
import static io.ballerina.projects.PackageManifest.Tool;

/**
* Task for running tools integrated with the build.
*
* @since 2201.9.0
*/
ShammiL marked this conversation as resolved.
Show resolved Hide resolved
public class RunBallerinaPreBuildToolsTask implements Task {

private final PrintStream outStream;

public RunBallerinaPreBuildToolsTask(PrintStream out) {
this.outStream = out;
}

@Override
public void execute(Project project) {
Collection<Diagnostic> toolDiagnostics = project.currentPackage().manifest().diagnostics().diagnostics();
boolean hasTomlErrors = project.currentPackage().manifest().diagnostics().hasErrors();
if (hasTomlErrors) {
toolDiagnostics.forEach(outStream::println);
throw createLauncherException("compilation contains errors");
}
List<Tool> tools = project.currentPackage().manifest().tools();
ServiceLoader<CodeGeneratorTool> buildRunners = ServiceLoader.load(CodeGeneratorTool.class);
for (Tool tool : tools) {
try {
String commandName = tool.getType();
CodeGeneratorTool targetTool = getTargetTool(commandName, buildRunners);
if (targetTool == null) {
// TODO: Install tool if not found
outStream.println("Command not found: " + commandName);
return;

Check warning on line 69 in cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java

View check run for this annotation

Codecov / codecov/patch

cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java#L68-L69

Added lines #L68 - L69 were not covered by tests
}
try {
validateOptionsToml(tool.getOptionsToml(), commandName);
} catch (IOException e) {
outStream.println("WARNING: Skipping the validation of tool options due to: " +
e.getMessage());

Check warning on line 75 in cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java

View check run for this annotation

Codecov / codecov/patch

cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java#L73-L75

Added lines #L73 - L75 were not covered by tests
}
ToolContext toolContext = ToolContext.from(tool, project.currentPackage());
targetTool.execute(toolContext);
toolContext.diagnostics().forEach(outStream::println);
for (Diagnostic d : toolContext.diagnostics()) {
if (d.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)) {
throw new ProjectException("compilation contains errors");
}
}

Check warning on line 84 in cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java

View check run for this annotation

Codecov / codecov/patch

cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java#L84

Added line #L84 was not covered by tests
} catch (ProjectException e) {
throw createLauncherException(e.getMessage());
}
}
}

private CodeGeneratorTool getTargetTool(String commandName, ServiceLoader<CodeGeneratorTool> buildRunners) {
for (CodeGeneratorTool buildRunner : buildRunners) {
if (buildRunner.toolName().equals(commandName)) {
return buildRunner;
}
}
return null;

Check warning on line 97 in cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java

View check run for this annotation

Codecov / codecov/patch

cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java#L96-L97

Added lines #L96 - L97 were not covered by tests
}

private void validateOptionsToml(Toml optionsToml, String toolName) throws IOException {
if (optionsToml == null) {
throw new IOException("No tool options found");

Check warning on line 102 in cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java

View check run for this annotation

Codecov / codecov/patch

cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java#L102

Added line #L102 was not covered by tests
}
FileUtils.validateToml(optionsToml, toolName);
optionsToml.diagnostics().forEach(outStream::println);
for (Diagnostic d : optionsToml.diagnostics()) {
if (d.diagnosticInfo().severity().equals(DiagnosticSeverity.ERROR)) {
throw new ProjectException("compilation contains errors");
}
}

Check warning on line 110 in cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java

View check run for this annotation

Codecov / codecov/patch

cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBallerinaPreBuildToolsTask.java#L110

Added line #L110 was not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.ballerina.cli.tool;

import io.ballerina.projects.ToolContext;

/**
* {@code CodeGeneratorTool} represents a Ballerina build tool.
*
* @since 2201.9.0
*/
public interface CodeGeneratorTool {
/**
* Execute the command.
*
* @param toolContext the {@link ToolContext} of the build tool
*/
void execute(ToolContext toolContext);

/**
* Retrieve the tool name.
*
* @return the name of the tool.
*/
String toolName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@

package io.ballerina.cli.utils;

import io.ballerina.toml.api.Toml;
import io.ballerina.toml.validator.TomlValidator;
import io.ballerina.toml.validator.schema.Schema;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Optional;

Expand Down Expand Up @@ -88,4 +98,35 @@
return Math.max(lastUnixPos, lastWindowsPos);
}
}

public static String readSchema(String toolName) throws IOException {
ShammiL marked this conversation as resolved.
Show resolved Hide resolved
String schemaFilePath = toolName + "-options-schema.json";
InputStream inputStream = io.ballerina.projects.util.FileUtils.class.getClassLoader()
.getResourceAsStream(schemaFilePath);

if (inputStream == null) {
throw new FileNotFoundException("Schema file for tool options inputStream not found: " + schemaFilePath);

Check warning on line 108 in cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/FileUtils.java

View check run for this annotation

Codecov / codecov/patch

cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/FileUtils.java#L108

Added line #L108 was not covered by tests
ShammiL marked this conversation as resolved.
Show resolved Hide resolved
}
StringBuilder sb = new StringBuilder();
try (
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
ShammiL marked this conversation as resolved.
Show resolved Hide resolved
BufferedReader br = new BufferedReader(inputStreamReader);
) {
String content;
while ((content = br.readLine()) != null) {
if (sb.length() > 0) {
sb.append('\n');
}
sb.append(content);
}
}

return sb.toString();
}

public static void validateToml(Toml optionsToml, String toolName) throws IOException {
Schema schema = Schema.from(FileUtils.readSchema(toolName));
TomlValidator tomlValidator = new TomlValidator(schema);
tomlValidator.validate(optionsToml);
}
}
1 change: 1 addition & 0 deletions cli/ballerina-cli/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
exports io.ballerina.cli.launcher;
exports io.ballerina.cli.utils;
exports io.ballerina.cli.cmd;
exports io.ballerina.cli.tool;

requires io.ballerina.runtime;
requires io.ballerina.lang;
Expand Down
Loading
Loading