Skip to content

Commit

Permalink
Merge pull request #42183 from Ramith-D-Rodrigo/c2c-changes
Browse files Browse the repository at this point in the history
Implement `bal test --cloud` for executing tests in docker containers
  • Loading branch information
azinneera committed May 10, 2024
2 parents e3bc06b + 852d2be commit 89f1a39
Show file tree
Hide file tree
Showing 41 changed files with 2,102 additions and 627 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ private static String populateConfigDetails(List<Path> paths, Map<String, String
public static ConfigDetails getTestConfigPaths(Module module, String pkgName, String sourceRoot) {
String moduleName = module.getName();
Path testConfigPath = Paths.get(sourceRoot);
if (!Files.exists(testConfigPath)) {
testConfigPath = getSourceRootInContainer();
}
if (!moduleName.equals(pkgName)) {
testConfigPath = testConfigPath.resolve(MODULES_ROOT)
.resolve(moduleName.substring(moduleName.indexOf(DOT) + 1));
Expand All @@ -170,4 +173,8 @@ public static ConfigDetails getTestConfigPaths(Module module, String pkgName, St
}
}

private static Path getSourceRootInContainer() {
// Since we are inside a docker container, it's current working directory is the source root.
return Paths.get(RuntimeUtils.USER_DIR);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@

import io.ballerina.cli.BLauncherCmd;
import io.ballerina.cli.TaskExecutor;
import io.ballerina.cli.task.CleanTargetBinTestsDirTask;
import io.ballerina.cli.task.CleanTargetCacheDirTask;
import io.ballerina.cli.task.CompileTask;
import io.ballerina.cli.task.CreateTestExecutableTask;
import io.ballerina.cli.task.DumpBuildTimeTask;
import io.ballerina.cli.task.ResolveMavenDependenciesTask;
import io.ballerina.cli.task.RunBuildToolsTask;
Expand Down Expand Up @@ -205,6 +207,9 @@ public TestCommand() {
"generated by the dependencies")
private Boolean showDependencyDiagnostics;

@CommandLine.Option(names = "--cloud", description = "Enable cloud artifact generation")
private String cloud;


private static final String testCmd = "bal test [--OPTIONS]\n" +
" [<ballerina-file> | <package-path>] [(-Ckey=value)...]";
Expand Down Expand Up @@ -338,13 +343,27 @@ public void execute() {
"flag is not set");
}

if (!project.buildOptions().cloud().isEmpty() && project.buildOptions().codeCoverage()) {
this.outStream.println("WARNING: Code coverage generation is not supported with Ballerina cloud test");
}

if (!project.buildOptions().cloud().isEmpty() && this.rerunTests) {
this.outStream.println("WARNING: Rerun failed tests is not supported with Ballerina cloud test");
}

if (!project.buildOptions().cloud().isEmpty() && project.buildOptions().testReport()) {
this.outStream.println("WARNING: Test report generation is not supported with Ballerina cloud test");
}


// Run pre-build tasks to have the project reloaded.
// In code coverage generation, the module map is duplicated.
// Therefore, the project needs to be reloaded beforehand to provide the latest project instance
// which has the newly generated code for code coverage calculation.
// Hence, below tasks are executed before extracting the module map from the project.
TaskExecutor preBuildTaskExecutor = new TaskExecutor.TaskBuilder()
.addTask(new CleanTargetCacheDirTask(), isSingleFile) // clean the target cache dir(projects only)
.addTask(new CleanTargetBinTestsDirTask(), (isSingleFile || project.buildOptions().cloud().isEmpty()))
.addTask(new RunBuildToolsTask(outStream), isSingleFile) // run build tools
.build();
preBuildTaskExecutor.executeTasks(project);
Expand All @@ -365,12 +384,17 @@ public void execute() {
.addTask(new CompileTask(outStream, errStream, false, false,
isPackageModified, buildOptions.enableCache()))
// .addTask(new CopyResourcesTask(), listGroups) // merged with CreateJarTask
.addTask(new RunTestsTask(outStream, errStream, rerunTests, groupList, disableGroupList, testList,
includes, coverageFormat, moduleMap, listGroups, excludes, cliArgs, isParallelExecution),
project.buildOptions().nativeImage())
.addTask(new CreateTestExecutableTask(outStream, groupList, disableGroupList, testList, listGroups,
cliArgs, isParallelExecution),
project.buildOptions().cloud().isEmpty())
.addTask(new RunTestsTask(outStream, errStream, rerunTests, groupList, disableGroupList,
testList, includes, coverageFormat, moduleMap, listGroups, excludes, cliArgs,
isParallelExecution),
(project.buildOptions().nativeImage() ||
!project.buildOptions().cloud().isEmpty()))
.addTask(new RunNativeImageTestTask(outStream, rerunTests, groupList, disableGroupList,
testList, includes, coverageFormat, moduleMap, listGroups, isParallelExecution),
!project.buildOptions().nativeImage())
testList, includes, coverageFormat, moduleMap, listGroups, isParallelExecution),
(!project.buildOptions().nativeImage() || !project.buildOptions().cloud().isEmpty()))
.addTask(new DumpBuildTimeTask(outStream), !project.buildOptions().dumpBuildTime())
.build();

Expand All @@ -391,6 +415,7 @@ private BuildOptions constructBuildOptions() {
.setObservabilityIncluded(observabilityIncluded)
.setDumpBuildTime(dumpBuildTime)
.setSticky(sticky)
.setCloud(cloud)
.setDumpGraph(dumpGraph)
.setDumpRawGraphs(dumpRawGraphs)
.setNativeImage(nativeImage)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com).
//
// WSO2 LLC. 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.projects.Project;
import io.ballerina.projects.ProjectException;
import io.ballerina.projects.internal.model.Target;

import java.io.IOException;

import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException;

/**
* Cleans up the target bin's tests directory.
*
* @since 2201.9.0
*/
public class CleanTargetBinTestsDirTask implements Task {
@Override
public void execute(Project project) {
try {
Target target = new Target(project.targetDir());
target.cleanBinTests();
} catch (IOException | ProjectException e) {
throw createLauncherException("unable to clean the target bin's tests directory: " + e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package io.ballerina.cli.task;

import io.ballerina.cli.utils.BuildTime;
import io.ballerina.cli.utils.BuildUtils;
import io.ballerina.cli.utils.FileUtils;
import io.ballerina.cli.utils.GraalVMCompatibilityUtils;
import io.ballerina.projects.EmitResult;
Expand All @@ -29,15 +30,13 @@
import io.ballerina.projects.ProjectException;
import io.ballerina.projects.ProjectKind;
import io.ballerina.projects.internal.model.Target;
import org.ballerinalang.compiler.plugins.CompilerPlugin;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ServiceLoader;

import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException;
import static io.ballerina.cli.utils.FileUtils.getFileNameWithoutExtension;
Expand Down Expand Up @@ -70,27 +69,10 @@ public void execute(Project project) {
}

this.currentDir = Paths.get(System.getProperty(USER_DIR));
Target target;
Target target = getTarget(project);

try {
if (project.kind().equals(ProjectKind.BUILD_PROJECT)) {
target = new Target(project.targetDir());
} else {
target = new Target(Files.createTempDirectory("ballerina-cache" + System.nanoTime()));
target.setOutputPath(getExecutablePath(project));
}
} catch (IOException e) {
throw createLauncherException("unable to resolve target path:" + e.getMessage());
} catch (ProjectException e) {
throw createLauncherException("unable to create executable:" + e.getMessage());
}
Path executablePath = getExecutablePath(project, target);

Path executablePath;
try {
executablePath = target.getExecutablePath(project.currentPackage()).toAbsolutePath().normalize();
} catch (IOException e) {
throw createLauncherException(e.getMessage());
}
try {
PackageCompilation pkgCompilation = project.currentPackage().getCompilation();
JBallerinaBackend jBallerinaBackend = JBallerinaBackend.from(pkgCompilation, JvmTarget.JAVA_17);
Expand Down Expand Up @@ -149,13 +131,30 @@ public void execute(Project project) {

// notify plugin
// todo following call has to be refactored after introducing new plugin architecture
notifyPlugins(project, target);
BuildUtils.notifyPlugins(project, target);
}

private void notifyPlugins(Project project, Target target) {
ServiceLoader<CompilerPlugin> processorServiceLoader = ServiceLoader.load(CompilerPlugin.class);
for (CompilerPlugin plugin : processorServiceLoader) {
plugin.codeGenerated(project, target);
private Target getTarget(Project project) {
Target target;
try {
if (project.kind().equals(ProjectKind.BUILD_PROJECT)) {
target = new Target(project.targetDir());
} else {
target = new Target(Files.createTempDirectory("ballerina-cache" + System.nanoTime()));
target.setOutputPath(getExecutablePath(project));
}
} catch (IOException e) {
throw createLauncherException("unable to resolve target path:" + e.getMessage());
} catch (ProjectException e) {
throw createLauncherException("unable to create executable:" + e.getMessage());
}
return target;
}
private Path getExecutablePath(Project project, Target target) {
try {
return target.getExecutablePath(project.currentPackage()).toAbsolutePath().normalize();
} catch (IOException e) {
throw createLauncherException(e.getMessage());
}
}

Expand Down

0 comments on commit 89f1a39

Please sign in to comment.