diff --git a/build.gradle b/build.gradle index 55f0ee8ff..a831eb5c9 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,10 @@ allprojects { // Apply common project setup but exclude submodule, it has its own build.gradle - if (!path.startsWith(":openremote")) { + if (findProject(":openremote") && !path.startsWith(":openremote")) { apply from: "${project(":openremote").projectDir}/project.gradle" + } else if (!findProject(":openremote")) { + apply from: "${project.rootDir}/custom-project.gradle" } } diff --git a/custom-project.gradle b/custom-project.gradle new file mode 100644 index 000000000..445706106 --- /dev/null +++ b/custom-project.gradle @@ -0,0 +1,320 @@ +// Common configuration applied to all projects +import java.nio.file.* +import java.nio.file.attribute.* +import java.util.Set +import static org.apache.tools.ant.taskdefs.condition.Os.FAMILY_WINDOWS +import static org.apache.tools.ant.taskdefs.condition.Os.isFamily +import static org.jetbrains.gradle.ext.ShortenCommandLine.MANIFEST +import org.jetbrains.gradle.ext.Application +import org.jetbrains.gradle.ext.JUnit + +// Configure versions in gradle.properties (putting a gradle.properties file +// in a subproject only overrides root properties of same name for the actual +// subproject, not for its children!) +version = hasProperty("openremoteVersion") ? openremoteVersion : "0.0.0" + +configurations.all { + resolutionStrategy { + + //failOnVersionConflict() + + // This has been replaced with eclipse angus implementation + exclude group: "com.sun.activation", module: "jakarta.activation" + + eachDependency { DependencyResolveDetails details -> + if (details.requested.group == 'org.eclipse.angus' && details.requested.name == 'angus-activation' && details.requested.version == '1.0.0') { + details.useVersion '2.0.0' + } + } + } +} + +// Ensure git hook creation task is executed +if (project == rootProject) { + + project.afterEvaluate { + + if (rootProject.hasProperty("gradleFileEncrypt")) { + println("File encryption plugin config found, configuring git pre commit hook and decrypt task dependency") + try { + // Write git hook for encryption plugin checks before any commit + def path = Paths.get(rootProject.projectDir.path, ".git/hooks/pre-commit") + def f = path.toFile() + f.text = """#!/bin/sh + +echo "***** Running gradle encryption plugin checkFilesGitIgnored task ******" + +./gradlew checkFilesGitIgnoredNew + +status=\$? + +if [ \$status != 0 ]; then + echo "***** One or more encrypted files are not listed in a .gitignore - please add to prevent unencrypted version of file(s) from being committed *****" +fi + +exit \$status +""" + Set perms = Files.readAttributes(path, PosixFileAttributes.class).permissions() + perms.add(PosixFilePermission.OWNER_WRITE) + perms.add(PosixFilePermission.OWNER_READ) + perms.add(PosixFilePermission.OWNER_EXECUTE) + perms.add(PosixFilePermission.GROUP_WRITE) + perms.add(PosixFilePermission.GROUP_READ) + perms.add(PosixFilePermission.GROUP_EXECUTE) + perms.add(PosixFilePermission.OTHERS_READ) + perms.add(PosixFilePermission.OTHERS_EXECUTE) + Files.setPosixFilePermissions(path, perms) + } catch (Exception ignored) {} + + // Add dependency on decrypt task for deployment installDist only if GFE_PASSWORD defined + def password = System.env.GFE_PASSWORD + if (password != null) { + Task decryptTask = getTasksByName("decryptFiles", false)[0] + + try { + def installDist = tasks.getByPath(":deployment:installDist") + installDist.dependsOn decryptTask + installDist.mustRunAfter(decryptTask) + } catch (Exception ex) { + println("Failed to add decryptFiles task dependency: " + ex) + } + } + } else { + // Remove git hook + try { + Files.delete(Paths.get(rootProject.projectDir.path, ".git/hooks/pre-commit")) + } catch (Exception ignored) { + } + } + } +} + + +// Configure Conditional plugins +if (project == rootProject) { + apply plugin: "org.jetbrains.gradle.plugin.idea-ext" + + // Configure IDEA + if (project.hasProperty("idea") && idea.project) { + // IDEA settings + idea.project.settings { + compiler { + javac { + javacAdditionalOptions "-parameters" + } + } + runConfigurations { + defaults(JUnit) { + shortenCommandLine = MANIFEST + workingDirectory = projectDir.toString() + } + defaults(Application) { + mainClass = 'org.openremote.manager.Main' + shortenCommandLine = MANIFEST + workingDirectory = projectDir.toString() + } + "Demo Setup"(Application) { + moduleName = getProject().idea.module.name + ".openremote.setup.demo" + envs = [ + OR_SETUP_TYPE: "demo" + ] + } + "Demo Setup with Proxy"(Application) { + moduleName = getProject().idea.module.name + ".openremote.setup.demo" + envs = [ + OR_SETUP_TYPE: "demo", + OR_WEBSERVER_LISTEN_HOST: "0.0.0.0", + OR_SSL_PORT: "-1" + ] + } + "Test Setup"(Application) { + moduleName = getProject().idea.module.name + ".openremote.setup.integration" + } + "Test Setup with Proxy"(Application) { + moduleName = getProject().idea.module.name + ".openremote.setup.integration" + envs = [ + OR_WEBSERVER_LISTEN_HOST: "0.0.0.0", + OR_SSL_PORT: "-1" + ] + } + "Empty"(Application) { + moduleName = getProject().idea.module.name + ".openremote.manager.main" + } + "Empty with Proxy"(Application) { + moduleName = getProject().idea.module.name + ".openremote.manager.main" + envs = [ + OR_WEBSERVER_LISTEN_HOST: "0.0.0.0", + OR_SSL_PORT: "-1" + ] + } + } + } + + idea.project.settings.runConfigurations { + "Custom Deployment"(Application) { + moduleName = "${getProject().idea.module.name}.setup.main" + envs = [ + OR_MAP_SETTINGS_PATH: "../deployment/map/mapsettings.json", + OR_MAP_TILES_PATH: "../deployment/map/mapdata.mbtiles", + OR_CUSTOM_APP_DOCROOT: "../deployment/manager/app", + OR_CONSOLE_APP_CONFIG_DOCROOT: "../deployment/manager/consoleappconfig" + ] + } + } + } +} + +// Give test projects more memory (Gradle 5 reduced this to 512MB) +subprojects { + tasks.withType(Test) { + maxHeapSize = "2g" + } +} + +// Default repositories for dependency resolution +repositories { + maven { + url = "https://repo.osgeo.org/repository/release/" + } + mavenCentral() + maven { + url "https://pkgs.dev.azure.com/OpenRemote/OpenRemote/_packaging/OpenRemote/maven/v1" + } + maven { + url "https://s01.oss.sonatype.org/content/repositories/snapshots" + } +} + +// Eclipse needs help +apply plugin: "eclipse" + +// Intellij needs help +apply plugin: 'idea' +// Use the same output directories in IDE as in gradle +idea { + module { + outputDir file('build/classes/main') + testOutputDir file('build/classes/test') + excludeDirs += file(".node") + excludeDirs += file("node_modules") + excludeDirs += file("dist") + excludeDirs += file("lib") + excludeDirs += file("build") + } +} + + + +def resolveDependency(String path) { + "io.openremote:openremote-" + path.substring(1) + ":" + version +} + +def resolveTask(String path) { + tasks.getByPath(path) +} + +def getYarnInstallTask() { + def customPackageJsonFile = Paths.get(rootProject.projectDir.path, "package.json").toFile() + if (!customPackageJsonFile.exists()) { + // No custom project yarn package.json so use standard openremote repo package.json + return resolveTask(":yarnInstall") + } else { + return tasks.getByPath(":yarnInstall") + } +} + +// Gets the list of runtime JAR dependencies; can be used in custom project deployment installDist task to populate +// extensions directory +def getDeploymentJars(Project project = project) { + if (project.configurations.find { it.name == "runtimeClasspath" } == null) { + return [] + } + + return project.configurations.runtimeClasspath.resolvedConfiguration.resolvedArtifacts.findAll { + dep -> dep.name != "openremote-manager" }.collect { + println "CopyLibs Artifact: ${it.file.path}" + return it.file + } +} + +ext { + resolveDependency = this.&resolveDependency + resolveTask = this.&resolveTask + getYarnInstallTask = this.&getYarnInstallTask + getDeploymentJars = this.&getDeploymentJars +} + +// Add UI tasks +ext.npmCommand = { + cmd -> + isFamily(FAMILY_WINDOWS) ? "${cmd}.cmd" : cmd +} + +// Add yarn tasks +task yarnInstall(type: Exec){ + commandLine npmCommand("yarn"), "install" +} +task yarnInstallForce(type: Exec){ + commandLine npmCommand("yarn"), "install", "--force" +} + +task npmClean(type: Exec){ + dependsOn getYarnInstallTask() + commandLine npmCommand("yarn"), "run", "clean" +} +task npmBuild(type: Exec){ + mustRunAfter npmClean + dependsOn getYarnInstallTask() + commandLine npmCommand("yarn"), "run", "build" +} +task npmTest(type: Exec){ + dependsOn getYarnInstallTask() + commandLine npmCommand("yarn"), "run", "test" +} +task npmServe(type: Exec){ + dependsOn getYarnInstallTask() + commandLine npmCommand("yarn"), "run", "serve" +} +task npmPrepare(type: Exec){ + dependsOn getYarnInstallTask() + commandLine npmCommand("yarn"), "run", "prepublishOnly" +} +task npmPublish(type: Exec){ + dependsOn getYarnInstallTask() + commandLine npmCommand("yarn"), "publish" +} +task npmServeProduction(type: Exec) { + dependsOn getYarnInstallTask() + commandLine npmCommand("yarn"), "run", "serveProduction" +} + +// Add typescript tasks +task tscWatch(type: Exec) { + commandLine npmCommand("npx"), "tsc", "-b", "--watch" +} + +// Configure Java build +plugins.withType(JavaPlugin).whenPluginAdded { + + // Use Java 17 + tasks.withType(JavaCompile) { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + def warnLogFile = file("$buildDir/${name}Warnings.log") + logging.addStandardErrorListener(new StandardOutputListener() { + void onOutput(CharSequence output) { + warnLogFile << output + } + }) + options.compilerArgs += ["-Xlint:unchecked", "-Xlint:deprecation", "-parameters"] + options.encoding = 'UTF-8' + } + + // Allow dependencyInsight checks across all projects + task allDependencyInsight(type: DependencyInsightReportTask) {} + + // JAR/ZIP base name is the fully qualified subproject name + archivesBaseName = "${rootProject.name}${path.replaceAll(":", "-")}" +} + +// POM generator diff --git a/deployment/build.gradle b/deployment/build.gradle index eabc4719d..5eb66ef30 100644 --- a/deployment/build.gradle +++ b/deployment/build.gradle @@ -6,7 +6,13 @@ dependencies { task license { doLast { - def toConcatenate = files("${project(":openremote").projectDir}/LICENSE.txt", "${rootDir}/LICENSE.txt") + def licenseFiles = new ArrayList<>() + if (findProject(":openremote")) { + licenseFiles.add("${project(":openremote").projectDir}/LICENSE.txt") + } + licenseFiles.add("${rootDir}/LICENSE.txt") + + def toConcatenate = files(licenseFiles.toArray()) def outputFileName = "${buildDir}/image/manager/app/LICENSE.txt" def output = new File(outputFileName) if (output.exists()) {