diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 79508d44fb..f9f031461a 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -49,6 +49,21 @@ jobs: cd maven mvn clean verify -DunitTests=true -pl core-unittests -am -Dmaven.javadoc.skip=true -Plocal-dev-javase cd .. + - name: Prepare Codename One binaries for Maven plugin tests + run: | + set -euo pipefail + rm -rf maven/target/cn1-binaries + git clone --depth=1 --filter=blob:none https://github.com/codenameone/cn1-binaries maven/target/cn1-binaries + - name: Run Maven plugin tests + working-directory: maven + env: + CN1_BINARIES: ${{ github.workspace }}/maven/target/cn1-binaries + run: | + mvn -B -Dmaven.javadoc.skip=true \ + -DunitTests=true \ + -Dcodename1.platform=javase \ + -Dcn1.binaries="${CN1_BINARIES}" \ + -pl codenameone-maven-plugin -am -Plocal-dev-javase test - name: Generate static analysis HTML summaries if: ${{ always() }} env: diff --git a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CompileCSSMojo.java b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CompileCSSMojo.java index a3f4902729..15e4c7fe7f 100644 --- a/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CompileCSSMojo.java +++ b/maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/CompileCSSMojo.java @@ -70,11 +70,61 @@ protected File findCSSDirectory() { if (themeCss.exists()) { return cssSibling; } - + } return null; } + protected File findLocalizationDirectory() { + if (project.getCompileSourceRoots() != null) { + for (String dir : project.getCompileSourceRoots()) { + File dirFile = new File(dir); + File parent = dirFile.getParentFile(); + if (parent == null) { + continue; + } + File localizationSibling = new File(parent, "l10n"); + if (hasLocalizationBundles(localizationSibling)) { + return localizationSibling; + } + } + } + + File cn1ProjectDir = getCN1ProjectDir(); + if (cn1ProjectDir != null) { + File defaultLocalization = new File(cn1ProjectDir, path("src", "main", "l10n")); + if (hasLocalizationBundles(defaultLocalization)) { + return defaultLocalization; + } + File rootLocalization = new File(cn1ProjectDir, "l10n"); + if (hasLocalizationBundles(rootLocalization)) { + return rootLocalization; + } + } + + return null; + } + + private boolean hasLocalizationBundles(File directory) { + if (directory == null || !directory.isDirectory()) { + return false; + } + File[] files = directory.listFiles(); + if (files == null) { + return false; + } + for (File file : files) { + if (file.isDirectory()) { + if (hasLocalizationBundles(file)) { + return true; + } + } else if (file.getName().endsWith(".properties")) { + return true; + } + } + return false; + } + private void executeImpl(String themePrefix) throws MojoExecutionException, MojoFailureException { if (!isCN1ProjectDir()) { return; @@ -201,6 +251,11 @@ private void executeImpl(String themePrefix) throws MojoExecutionException, Mojo java.createArg().setValue("-merge"); java.createArg().setFile(mergeFile); + File localizationDir = findLocalizationDirectory(); + if (localizationDir != null) { + java.createArg().setValue("-l"); + java.createArg().setFile(localizationDir); + } int res = java.executeJava(); if (res != 0) { throw new MojoExecutionException("An error occurred while compiling the CSS files. Inputs: "+inputs+", output: " + new File(project.getBuild().getOutputDirectory() + File.separator + themePrefix + "theme.res") +", merge file: "+mergeFile); diff --git a/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/CompileCSSMojoTest.java b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/CompileCSSMojoTest.java new file mode 100644 index 0000000000..265ce9dded --- /dev/null +++ b/maven/codenameone-maven-plugin/src/test/java/com/codename1/maven/CompileCSSMojoTest.java @@ -0,0 +1,146 @@ +package com.codename1.maven; + +import org.apache.maven.model.Build; +import org.apache.maven.plugin.logging.SystemStreamLog; +import org.apache.maven.project.MavenProject; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Java; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CompileCSSMojoTest { + + @Test + void addsLocalizationDirectoryToDesignerInvocation(@TempDir Path tempDir) throws Exception { + Path projectDir = setupProject(tempDir, true); + TestCompileCSSMojo mojo = createMojo(projectDir); + + mojo.executeImpl(); + + List args = mojo.getRecordingJava().getCommandLineArguments(); + assertTrue(args.contains("-l"), "Expected -l argument when localization directory exists"); + int index = args.indexOf("-l"); + assertTrue(index >= 0 && index + 1 < args.size(), "Expected localization directory argument after -l"); + assertEquals(projectDir.resolve("src/main/l10n").toFile().getAbsolutePath(), args.get(index + 1)); + } + + @Test + void skipsLocalizationArgumentWhenDirectoryMissing(@TempDir Path tempDir) throws Exception { + Path projectDir = setupProject(tempDir, false); + TestCompileCSSMojo mojo = createMojo(projectDir); + + mojo.executeImpl(); + + List args = mojo.getRecordingJava().getCommandLineArguments(); + assertFalse(args.contains("-l"), "Did not expect -l argument without localization directory"); + } + + private TestCompileCSSMojo createMojo(Path projectDir) throws IOException { + MavenProject mavenProject = new MavenProject(); + mavenProject.setFile(projectDir.resolve("pom.xml").toFile()); + mavenProject.addCompileSourceRoot(projectDir.resolve("src/main/java").toString()); + Build build = new Build(); + build.setDirectory(projectDir.resolve("target").toString()); + build.setOutputDirectory(projectDir.resolve("target/classes").toString()); + mavenProject.setBuild(build); + mavenProject.setArtifacts(new HashSet<>()); + + TestCompileCSSMojo mojo = new TestCompileCSSMojo(projectDir.resolve("designer.jar").toFile()); + mojo.project = mavenProject; + mojo.antProject = new Project(); + mojo.antProject.setBaseDir(projectDir.toFile()); + mojo.antProject.init(); + mojo.pluginArtifacts = new ArrayList<>(); + mojo.properties = new Properties(); + mojo.properties.setProperty("codename1.cssTheme", "true"); + mojo.setLog(new SystemStreamLog()); + + return mojo; + } + + private Path setupProject(Path tempDir, boolean includeLocalization) throws IOException { + Path projectDir = tempDir.resolve("project"); + Files.createDirectories(projectDir); + Files.createDirectories(projectDir.resolve("src/main/java")); + Path cssDir = Files.createDirectories(projectDir.resolve("src/main/css")); + Files.write(cssDir.resolve("theme.css"), Arrays.asList("/* test css */")); + Files.write(projectDir.resolve("codenameone_settings.properties"), Arrays.asList("codename1.cssTheme=true")); + Files.createDirectories(projectDir.resolve("target/classes")); + Files.createFile(projectDir.resolve("designer.jar")); + Files.write(projectDir.resolve("pom.xml"), Arrays.asList( + "", + " 4.0.0", + " com.codename1", + " test-project", + " 1.0-SNAPSHOT", + "" + )); + + if (includeLocalization) { + Path localizationDir = Files.createDirectories(projectDir.resolve("src/main/l10n")); + Files.write(localizationDir.resolve("Messages.properties"), Arrays.asList("greeting=Hello")); + } + + return projectDir; + } + + private static class TestCompileCSSMojo extends CompileCSSMojo { + private final File designerJar; + private RecordingJava recordingJava; + + private TestCompileCSSMojo(File designerJar) { + this.designerJar = designerJar; + } + + @Override + public Java createJava() { + recordingJava = new RecordingJava(); + recordingJava.setProject(antProject); + return recordingJava; + } + + @Override + protected void setupCef() { + // Skip CEF setup during tests. + } + + @Override + protected File getDesignerJar() { + return designerJar; + } + + RecordingJava getRecordingJava() { + return recordingJava; + } + } + + private static class RecordingJava extends Java { + private List commandLineArguments = new ArrayList<>(); + + @Override + public int executeJava() { + commandLineArguments = Arrays.asList(getCommandLine().getCommandline()); + return 0; + } + + List getCommandLineArguments() { + return commandLineArguments; + } + } +}