diff --git a/.gitignore b/.gitignore index 386153f9..5f94cbe2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,16 @@ .gradle build/ out/ +lib/ -.idea/dataSources.local.xml +# Unless specified, ignore all IDEA project files +.idea/ +!.idea/codeStyles/codeStyleConfig.xml +!.idea/inspectionProfiles/Project_Default.xml +!.idea/runConfigurations/Debug_plugins.xml +!.idea/compiler.xml +!.idea/misc.xml +!.idea/vcs.xml # Ignore zip files created by build src/main/resources/moduleTemplate.zip diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 5f1bdff7..00000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/workspace.xml -/shelf/ -$CACHE_FILE$ -$PRODUCT_WORKSPACE_FILE$ -gradle.xml -jarRepositories.xml -uiDesigner.xml diff --git a/README.md b/README.md index bf4c9397..410e2adf 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,13 @@ on how to do that, including how to develop and test locally and the versioning _Note: 1.28.0 and later require Gradle 7_ +### 2.6.0 +*Released*: 11 March 2024 +(Earliest compatible LabKey version: 24.2) +* Include `application.properties` in embedded distributions +* Remove version from executable server jar name: `labkeyServer.jar` +* Make `startTomcat` task work for embedded Tomcat on Windows + ### 2.5.1 *Released*: 11 March 2024 (Earliest compatible LabKey version: 24.2) diff --git a/build.gradle b/build.gradle index bb236881..62dc356d 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ dependencies { } group 'org.labkey.build' -project.version = "2.6.0-SNAPSHOT" +project.version = "2.7.0-SNAPSHOT" gradlePlugin { plugins { diff --git a/distributionResources/embedded/config/application.properties b/distributionResources/embedded/config/application.properties new file mode 100644 index 00000000..90e45d76 --- /dev/null +++ b/distributionResources/embedded/config/application.properties @@ -0,0 +1,163 @@ +server.port=8080 + +## To use ssl, update the properties below for your local installation + +#server.ssl.enabled=true +#server.ssl.enabled-protocols=TLSv1.3,TLSv1.2,TLSv1.1 +#server.ssl.protocol=TLS +#server.ssl.key-alias=tomcat +#server.ssl.key-store=@@keyStore@@ +#server.ssl.key-store-password=@@keyStorePassword@@ +## Typically either PKCS12 or JKS +#server.ssl.key-store-type=PKCS12 +#server.ssl.ciphers=HIGH:!ADH:!EXP:!SSLv2:!SSLv3:!MEDIUM:!LOW:!NULL:!aNULL + +## HTTP-only port for servers that need to handle both HTTPS (configure via server.port and server.ssl above) and HTTP +#context.httpPort=8080 + +## Database connections. All deployments need a labkeyDataSource as their primary database. Add additional external +## data sources by specifying the required properties (at least driverClassName, url, username, and password) +## with a prefix of context.resources.jdbc.. +context.resources.jdbc.labkeyDataSource.type=javax.sql.DataSource +context.resources.jdbc.labkeyDataSource.driverClassName=org.postgresql.Driver +context.resources.jdbc.labkeyDataSource.url=jdbc:postgresql://localhost/labkey +context.resources.jdbc.labkeyDataSource.username=@@jdbcUser@@ +context.resources.jdbc.labkeyDataSource.password=@@jdbcPassword@@ +context.resources.jdbc.labkeyDataSource.maxTotal=50 +context.resources.jdbc.labkeyDataSource.maxIdle=10 +context.resources.jdbc.labkeyDataSource.maxWaitMillis=120000 +context.resources.jdbc.labkeyDataSource.accessToUnderlyingConnectionAllowed=true +context.resources.jdbc.labkeyDataSource.validationQuery=SELECT 1 +#context.resources.jdbc.labkeyDataSource.logQueries=true +#context.resources.jdbc.labkeyDataSource.displayName=Alternate Display Name + +#context.resources.jdbc.@@extraJdbcDataSource@@.driverClassName=@@extraJdbcDriverClassName@@ +#context.resources.jdbc.@@extraJdbcDataSource@@.url=@@extraJdbcUrl@@ +#context.resources.jdbc.@@extraJdbcDataSource@@.username=@@extraJdbcUsername@@ +#context.resources.jdbc.@@extraJdbcDataSource@@.password=@@extraJdbcPassword@@ + +context.encryptionKey=@@encryptionKey@@ + +## By default, we deploy to the root context path. However, some servers have historically used /labkey or even /cpas +#context.contextPath=/labkey + +## Using a legacy context path provides backwards compatibility with old deployments. A typical use case would be to +## deploy to the root context (the default) and configure /labkey as the legacy path. GETs will be redirected. +## All other methods (POSTs, PUTs, etc) will be handled server-side via a servlet forward. +#context.legacyContextPath=/labkey + +## Other webapps to be deployed, most commonly to deliver a set of static files. The context path to deploy into is the +## property name after the "context.additionalWebapps." prefix, and the value is the location of the webapp on disk +#context.additionalWebapps.firstContextPath=/my/webapp/path +#context.additionalWebapps.secondContextPath=/my/other/webapp/path + +#context.oldEncryptionKey= +#context.requiredModules= +#context.pipelineConfig=/path/to/pipeline/config/dir +#context.serverGUID= +#context.bypass2FA=true +#context.workDirLocation=/path/to/desired/workDir + +mail.smtpHost=@@smtpHost@@ +mail.smtpPort=@@smtpPort@@ +mail.smtpUser=@@smtpUser@@ +#mail.smtpFrom=@@smtpFrom@@ +#mail.smtpPassword=@@smtpPassword@@ +#mail.startTlsEnable=@@smtpStartTlsEnable@@ +#mail.smtpSocketFactoryClass=@@smtpSocketFactoryClass@@ +#mail.smtpAuth=@@smtpAuth@@ + +## Optional - JMS configuration for remote ActiveMQ message management for distributed pipeline jobs +## https://www.labkey.org/Documentation/wiki-page.view?name=jmsQueue +#context.resources.jms.ConnectionFactory.type=org.apache.activemq.ActiveMQConnectionFactory +#context.resources.jms.ConnectionFactory.factory=org.apache.activemq.jndi.JNDIReferenceFactory +#context.resources.jms.ConnectionFactory.description=JMS Connection Factory +## Use an in-process ActiveMQ queue +#context.resources.jms.ConnectionFactory.brokerURL=vm://localhost?broker.persistent=false&broker.useJmx=false +## Use an out-of-process ActiveMQ queue +#context.resources.jms.ConnectionFactory.brokerURL=tcp://localhost:61616 +#context.resources.jms.ConnectionFactory.brokerName=LocalActiveMQBroker + +## Optional - LDAP configuration for LDAP group/user synchronization +## https://www.labkey.org/Documentation/wiki-page.view?name=LDAP_sync +#context.resources.ldap.ConfigFactory.type=org.labkey.premium.ldap.LdapConnectionConfigFactory +#context.resources.ldap.ConfigFactory.factory=org.labkey.premium.ldap.LdapConnectionConfigFactory +#context.resources.ldap.ConfigFactory.host=myldap.mydomain.com +#context.resources.ldap.ConfigFactory.port=389 +#context.resources.ldap.ConfigFactory.principal=cn=read_user +#context.resources.ldap.ConfigFactory.credentials=read_user_password +#context.resources.ldap.ConfigFactory.useTls=false +#context.resources.ldap.ConfigFactory.useSsl=false +#context.resources.ldap.ConfigFactory.sslProtocol=SSLv3 + +## HTTP session timeout for users - defaults to 30 minutes +#server.servlet.session.timeout=30m + +## Enable shutdown endpoint. Allows server to be shutdown with a POST to 'localhost:8081/actuator/shutdown +#management.endpoint.shutdown.enabled=true +#management.endpoints.enabled-by-default=false +#management.endpoints.web.exposure.include=* +#management.server.port=8081 + +## Don't show the Spring banner on startup +spring.main.banner-mode=off +#logging.config=path/to/alternative/log4j2.xml + +## Optional - JMS configuration for remote ActiveMQ message management for distributed pipeline jobs +## https://www.labkey.org/Documentation/wiki-page.view?name=jmsQueue +#context.resources.jms.name=jms/ConnectionFactory +#context.resources.jms.type=org.apache.activemq.ActiveMQConnectionFactory +#context.resources.jms.factory=org.apache.activemq.jndi.JNDIReferenceFactory +#context.resources.jms.description=JMS Connection Factory +#context.resources.jms.brokerURL=vm://localhost?broker.persistent=false&broker.useJmx=false +#context.resources.jms.brokerName=LocalActiveMQBroker + +## Turn on JSON-formatted HTTP access logging to stdout. See issue 48565 +## https://tomcat.apache.org/tomcat-9.0-doc/config/valve.html#JSON_Access_Log_Valve +#jsonaccesslog.enabled=true + +## Optional configuration, modeled on the non-JSON Spring Boot properties +## https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.server.server.tomcat.accesslog.buffered +#jsonaccesslog.pattern=%h %t %m %U %s %b %D %S "%{Referer}i" "%{User-Agent}i" %{LABKEY.username}s +#jsonaccesslog.condition-if=attributeName +#jsonaccesslog.condition-unless=attributeName + +## Define one or both of 'csp.report' and 'csp.enforce' to enable Content Security Policy (CSP) headers +## Do not use these examples for any production environment without understanding the meaning of each directive! + +## example usage 1 - very strict, disallows 'external' websites, disallows unsafe-inline, but only reports violations (does not enforce) + +#csp.report=\ +# default-src 'self';\ +# connect-src 'self' ${LABKEY.ALLOWED.CONNECTIONS} ;\ +# object-src 'none' ;\ +# style-src 'self' 'unsafe-inline' ;\ +# img-src 'self' data: ;\ +# font-src 'self' data: ;\ +# script-src 'unsafe-eval' 'strict-dynamic' 'nonce-${REQUEST.SCRIPT.NONCE}';\ +# base-uri 'self' ;\ +# upgrade-insecure-requests ;\ +# frame-ancestors 'self' ;\ +# report-uri https://www.labkey.org/admin-contentsecuritypolicyreport.api?${CSP.REPORT.PARAMS} ; + +## example usage 2 - less strict but enforces directives, (NOTE: unsafe-inline is still required for many modules) + +#csp.enforce=\ +# default-src 'self' https: ;\ +# connect-src 'self' https: ${LABKEY.ALLOWED.CONNECTIONS};\ +# object-src 'none' ;\ +# style-src 'self' https: 'unsafe-inline' ;\ +# img-src 'self' data: ;\ +# font-src 'self' data: ;\ +# script-src 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' 'nonce-${REQUEST.SCRIPT.NONCE}';\ +# base-uri 'self' ;\ +# upgrade-insecure-requests ;\ +# frame-ancestors 'self' ;\ +# report-uri https://www.labkey.org/admin-contentsecuritypolicyreport.api?${CSP.REPORT.PARAMS} ; + + +## Enable tomcat access log +#server.tomcat.basedir=. +#server.tomcat.accesslog.enabled=true +#server.tomcat.accesslog.directory=logs +#server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %S %I "%{Referrer}i" "%{User-Agent}i" %{LABKEY.username}s diff --git a/distributionResources/embedded/manual-upgrade.sh b/distributionResources/embedded/manual-upgrade.sh deleted file mode 100755 index 39394225..00000000 --- a/distributionResources/embedded/manual-upgrade.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -# Placeholder script for upgrading LabKey with embedded Tomcat diff --git a/src/main/groovy/org/labkey/gradle/task/ModuleDistribution.groovy b/src/main/groovy/org/labkey/gradle/task/ModuleDistribution.groovy index 50f7bb55..4b2f6839 100644 --- a/src/main/groovy/org/labkey/gradle/task/ModuleDistribution.groovy +++ b/src/main/groovy/org/labkey/gradle/task/ModuleDistribution.groovy @@ -16,7 +16,6 @@ package org.labkey.gradle.task import org.apache.commons.lang3.StringUtils - import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.Project @@ -237,7 +236,7 @@ class ModuleDistribution extends DefaultTask private String getEmbeddedTomcatJarPath() { - return BuildUtils.getBuildDirFile(project, "labkeyServer-${project.version}.jar").path + return BuildUtils.getBuildDirFile(project, "labkeyServer.jar").path } private String getTarArchivePath() @@ -422,6 +421,10 @@ class ModuleDistribution extends DefaultTask zipfileset(dir: "${BuildUtils.getBuildDirPath(project)}/") { include(name: "labkeywebapp/**") } + zipfileset(dir: "${BuildUtils.getBuildDirPath(project)}/", + prefix: "${DistributionExtension.DIST_FILE_DIR}") { + include(name: "VERSION") + } } project.copy { @@ -463,10 +466,7 @@ class ModuleDistribution extends DefaultTask include(name: "VERSION") } - tarfileset(dir: BuildUtils.getBuildDirFile(project, "embedded"), prefix: archiveName) { - // include(name: "manual-upgrade.sh") - include(name: "README.txt") - } + tarfileset(dir: "${BuildUtils.getBuildDirPath(project)}/embedded", prefix: archiveName) } } @@ -491,11 +491,7 @@ class ModuleDistribution extends DefaultTask include(name: "VERSION") } - zipfileset(dir: "${BuildUtils.getBuildDirPath(project)}/embedded/", - prefix: "${archiveName}") { - // include(name: "manual-upgrade.sh") - include(name: "README.txt") - } + zipfileset(dir: "${BuildUtils.getBuildDirPath(project)}/embedded/", prefix: "${archiveName}") } } @@ -510,6 +506,16 @@ class ModuleDistribution extends DefaultTask copy.into(project.layout.buildDirectory) copy.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE) }) + // Prefer files from 'server/configs/webapps' if they exist + File serverConfigDir = project.rootProject.file("server/configs/webapps/") + if (serverConfigDir.exists()) { + project.copy({ CopySpec copy -> + copy.from(serverConfigDir) + copy.exclude "*.xml" + copy.into(project.layout.buildDirectory) + copy.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE) + }) + } // Allow distributions to include custom README File resources = project.file("resources") if (resources.isDirectory()) { @@ -562,6 +568,8 @@ class ModuleDistribution extends DefaultTask private void writeVersionFile() { - Files.write(getVersionFile().toPath(), ((String) project.version).getBytes()) + // Include TeamCity buildUrl, if present. + def buildUrl = StringUtils.trimToEmpty(System.getenv("BUILD_URL")) + Files.write(getVersionFile().toPath(), "${project.version}\n${buildUrl}".trim().getBytes()) } } diff --git a/src/main/groovy/org/labkey/gradle/task/StartTomcat.groovy b/src/main/groovy/org/labkey/gradle/task/StartTomcat.groovy index 171276aa..7fdd970a 100644 --- a/src/main/groovy/org/labkey/gradle/task/StartTomcat.groovy +++ b/src/main/groovy/org/labkey/gradle/task/StartTomcat.groovy @@ -52,7 +52,8 @@ class StartTomcat extends DefaultTask String javaHome = TeamCityExtension.getTeamCityProperty(project, "tomcatJavaHome", System.getenv("JAVA_HOME")) if (StringUtils.isEmpty(javaHome)) throw new GradleException("JAVA_HOME must be set in order to start your embedded tomcat server.") - File javaExec = new File(javaHome, "bin/java") + File javaBin = new File(javaHome, "bin") + File javaExec = new File(javaBin, SystemUtils.IS_OS_WINDOWS ? "java.exe" : "java") if (!javaExec.exists()) throw new GradleException("Invalid value for JAVA_HOME. Could not find java command in ${javaExec}") String[] commandParts = [javaExec.getAbsolutePath()]