diff --git a/README.md b/README.md index 299d38b3..f78c3c84 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,11 @@ on how to do that, including how to develop and test locally and the versioning ### 4.2.0-SNAPSHOT *Released*: TBD -(Earliest compatible LabKey version: 24.10) +(Earliest compatible LabKey version: 24.11) +- Stop adding the standalone `distribution` file to distribution archives; the `distribution.properties` file now + contains the distribution name and other properties used by the webapp. +- Update all dependencies to the latest versions +- Add `version` and `buildUrl` to `distribution.properties` file ### 4.1.0 *Released*: 25 September 2024 diff --git a/build.gradle b/build.gradle index cb305a3e..20dba515 100644 --- a/build.gradle +++ b/build.gradle @@ -34,15 +34,15 @@ dependencies { api "org.apache.commons:commons-text:${commonsTextVersion}" api "commons-io:commons-io:${commonsIoVersion}" api "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" - implementation "org.apache.httpcomponents:httpcore:${httpcoreVersion}" - api "org.apache.httpcomponents:httpclient:${httpclientVersion}" + implementation "org.apache.httpcomponents.core5:httpcore5:${httpcoreVersion}" + api "org.apache.httpcomponents.client5:httpclient5:${httpclientVersion}" api "org.json:json:${jsonVersion}" implementation "com.graphql-java:graphql-java:${graphqlJavaVersion}" api "org.ajoberstar.grgit:grgit-gradle:${grgitGradleVersion}" } group 'org.labkey.build' -project.version = "4.2.0-SNAPSHOT" +project.version = "4.2.0-dependencies-SNAPSHOT" gradlePlugin { plugins { diff --git a/gradle.properties b/gradle.properties index f515986c..316f6117 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,16 +1,16 @@ artifactory_contextUrl=https://labkey.jfrog.io/artifactory -artifactoryPluginVersion=4.28.2 +artifactoryPluginVersion=5.2.5 -commonsIoVersion=2.15.1 -commonsLang3Version=3.14.0 -commonsTextVersion=1.11.0 +commonsIoVersion=2.17.0 +commonsLang3Version=3.17.0 +commonsTextVersion=1.12.0 -grgitGradleVersion=5.2.1 -graphqlJavaVersion=21.3 +grgitGradleVersion=5.2.2 +graphqlJavaVersion=22.3 -httpclientVersion=4.5.14 -httpcoreVersion=4.4.16 +httpclientVersion=5.4 +httpcoreVersion=5.3 -jacksonVersion=2.16.1 -jsonVersion=20231013 +jacksonVersion=2.18.0 +jsonVersion=20240303 diff --git a/src/main/groovy/org/labkey/gradle/plugin/MultiGit.groovy b/src/main/groovy/org/labkey/gradle/plugin/MultiGit.groovy index 5449902e..d4bb84e2 100644 --- a/src/main/groovy/org/labkey/gradle/plugin/MultiGit.groovy +++ b/src/main/groovy/org/labkey/gradle/plugin/MultiGit.groovy @@ -7,14 +7,14 @@ import org.ajoberstar.grgit.Grgit import org.ajoberstar.grgit.Status import org.ajoberstar.grgit.operation.BranchListOp import org.apache.commons.lang3.StringUtils -import org.apache.http.client.ResponseHandler -import org.apache.http.client.methods.CloseableHttpResponse -import org.apache.http.client.methods.HttpPost -import org.apache.http.entity.ContentType -import org.apache.http.entity.StringEntity -import org.apache.http.impl.client.BasicResponseHandler -import org.apache.http.impl.client.CloseableHttpClient -import org.apache.http.impl.client.HttpClients +import org.apache.hc.client5.http.classic.methods.HttpPost +import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse +import org.apache.hc.client5.http.impl.classic.HttpClients +import org.apache.hc.core5.http.ContentType +import org.apache.hc.core5.http.io.HttpClientResponseHandler +import org.apache.hc.core5.http.io.entity.StringEntity import org.gradle.api.GradleException import org.gradle.api.Plugin import org.gradle.api.Project @@ -30,20 +30,19 @@ import java.util.stream.Collectors import static org.labkey.gradle.plugin.MultiGit.RepositoryQuery.getAuthorizationToken /** - * This is an incubating feature set. Interfaces and functionality are likely to change, perhaps drastically, + * This is an incubating feature set. Interfaces and functionality are likely to change, perhaps drastically, * before it is released. * * This plugin can be used to get data about a gradle project that is comprised of multiple git repositories. * It uses the GitHub GraphQL API (https://developer.github.com/v4/) to query for a set of repositories. Using - * the properties gitTopcis, requireAllTopics, and includeArchived, a user is able to filter to a certain set - * of repositories. See the task descriptions for more info. + * the properties gitTopics, requireAllTopics, and includeArchived, a user is able to filter to a certain set + * of repositories. See the task descriptions for more info. * * In order to use this plugin, you need to create an access token for GitHub * (https://developer.github.com/v4/guides/forming-calls/#authenticating-with-graphql) * Once generated, set the GIT_ACCESS_TOKEN environment variable to this value. * * Apply this plugin at the root of the enlistment. - * */ class MultiGit implements Plugin { @@ -430,7 +429,7 @@ class MultiGit implements Plugin } else { - rootProject.logger.quiet("${this.getName()}: No branch '${branchName} found. Leaving on default branch.") + rootProject.logger.quiet("${this.getName()}: No branch '${branchName} found. Leaving on default branch.") } } } @@ -890,7 +889,7 @@ class MultiGit implements Plugin CloseableHttpResponse response = httpClient.execute(httpPost) try { - ResponseHandler handler = new BasicResponseHandler() + HttpClientResponseHandler handler = new BasicHttpClientResponseHandler() String contents = handler.handleResponse(response) project.logger.info("Response contents ${contents}") ObjectMapper mapper = new ObjectMapper() @@ -982,11 +981,11 @@ class MultiGit implements Plugin project.tasks.register("gitRepoList") { Task task -> task.group = "VCS" - task.description = "List all Git repositories. Use -Pverbose to show more details. Use -P${RepositoryQuery.TOPICS_PROPERTY} to filter to modules with certain topics. " + - "This can be a comma-separated list of topics (e.g., labkey-module,labkey-client-api). By default, all repositories with any of these topics will be listed. " + - "Use -P${RepositoryQuery.ALL_TOPICS_PROPERTY} to specify that all topics must be present. " + - "By default, only repositories that have not been archived are listed. Use -P${RepositoryQuery.INCLUDE_ARCHIVED_PROPERTY} to also include archived repositories." + - "Use -P${RepositoryQuery.INCLUDE_PRS_PROPERTY} in conjunction with -Pverbose to include info on pull requests. Use the properties as in the 'listPullRequests' tasks to filter the pull requests." + task.description = "List all Git repositories. Use -Pverbose to show more details. Use -P${RepositoryQuery.TOPICS_PROPERTY} to filter to modules with certain topics. " + + "This can be a comma-separated list of topics (e.g., labkey-module,labkey-client-api). By default, all repositories with any of these topics will be listed. " + + "Use -P${RepositoryQuery.ALL_TOPICS_PROPERTY} to specify that all topics must be present. " + + "By default, only repositories that have not been archived are listed. Use -P${RepositoryQuery.INCLUDE_ARCHIVED_PROPERTY} to also include archived repositories." + + "Use -P${RepositoryQuery.INCLUDE_PRS_PROPERTY} in conjunction with -Pverbose to include info on pull requests. Use the properties as in the 'listPullRequests' tasks to filter the pull requests." task.doLast({ RepositoryQuery query = new RepositoryQuery(project) query.setIncludeLicenseInfo(true) @@ -1043,8 +1042,8 @@ class MultiGit implements Plugin project.tasks.register("gitCheckout") { Task task -> task.group = "VCS" - task.description = "For all repositories with a current enlistment, perform a git checkout for the branch provided by the 'branch' property (e.g., -Pbranch=release18.3). " + - "If no such branch exists for a repository, leaves the enlistment as is. " + + task.description = "For all repositories with a current enlistment, perform a git checkout for the branch provided by the 'branch' property (e.g., -Pbranch=release24.11). " + + "If no such branch exists for a repository, leaves the enlistment as is. " + "Use the properties ${RepositoryQuery.TOPICS_PROPERTY}, ${RepositoryQuery.ALL_TOPICS_PROPERTY}, and ${RepositoryQuery.INCLUDE_ARCHIVED_PROPERTY} as for the 'gitRepoList' task for filtering." task.doLast({ if (!project.hasProperty('branch')) @@ -1182,7 +1181,7 @@ class MultiGit implements Plugin project.tasks.register("gitFetch") { Task task -> task.group = "VCS" - task.description = "Perform a 'git fetch' for a collection of repositories. " + + task.description = "Perform a 'git fetch' for a collection of repositories. " + "Use -PgitPrune to remove any remote-tracking references that no longer exist on the remote." + "By default, uses the projects specified in the settings.gradle file for which there is a current enlistment. " + "Use the properties ${RepositoryQuery.TOPICS_PROPERTY}, ${RepositoryQuery.ALL_TOPICS_PROPERTY}, and ${RepositoryQuery.INCLUDE_ARCHIVED_PROPERTY} as for the 'gitRepoList' task for " + @@ -1233,7 +1232,7 @@ class MultiGit implements Plugin project.tasks.register("gitEnlist") { Task task -> task.group = "VCS" - task.description = "Enlist in all of the git modules used for a running LabKey server. " + + task.description = "Enlist in all of the git modules used for a running LabKey server. " + "Use -Pbranch= to enlist in a particular branch (shortcut for using gitEnlist then gitCheckout -Pbranch=)." "Use the properties ${RepositoryQuery.TOPICS_PROPERTY}, ${RepositoryQuery.ALL_TOPICS_PROPERTY}, and ${RepositoryQuery.INCLUDE_ARCHIVED_PROPERTY} as for the 'gitRepoList' task for filtering the repository set. " + "If a moduleSet property is specified, enlist in only the modules included by that module set. Using -PmoduleSet=all is the same as providing no module set property." @@ -1316,7 +1315,7 @@ class MultiGit implements Plugin { project.logger.quiet("Already have enlistment for ${repository.getName()} in directory ${repository.getEnlistmentDir()}") } - // Hmmm. Can't get module dependencies when the project is not included in settings.gradle, + // Hmmm. Can't get module dependencies when the project is not included in settings.gradle, // So how do you bootstrap? I want to start with a minimal enlistment and end up with an // enlistment that includes all the repos I need for a given distribution repository.getModuleDependencies().forEach({ @@ -1341,6 +1340,4 @@ class MultiGit implements Plugin }) } } - - } diff --git a/src/main/groovy/org/labkey/gradle/plugin/extension/DistributionExtension.groovy b/src/main/groovy/org/labkey/gradle/plugin/extension/DistributionExtension.groovy index ee447be3..a06a1d99 100644 --- a/src/main/groovy/org/labkey/gradle/plugin/extension/DistributionExtension.groovy +++ b/src/main/groovy/org/labkey/gradle/plugin/extension/DistributionExtension.groovy @@ -22,12 +22,10 @@ import java.nio.file.Paths class DistributionExtension { - // the directory in which the file 'distribution' is placed, which contains the name of the distribution - // (used for mothership reporting and troubleshooting) + // directory that holds the 'distribution.properties' file public static final String DIST_FILE_DIR = "labkeywebapp/WEB-INF/classes" - public static final String DIST_FILE_NAME = "distribution" - public static final String VERSION_FILE_NAME = "VERSION" public static final String DIST_PROPERTIES_FILE_NAME = "distribution.properties" + public static final String VERSION_FILE_NAME = "VERSION" public static final String TAR_ARCHIVE_EXTENSION = "tar.gz" String dir = "${project.rootProject.projectDir}/dist" @@ -46,7 +44,7 @@ class DistributionExtension if (project.hasProperty("distDir")) { if (Paths.get((String) project.property('distDir')).isAbsolute()) - distDir = new File((String) project.property('distDir')); + distDir = new File((String) project.property('distDir')) else distDir = new File(project.rootDir, (String) project.property("distDir")) } diff --git a/src/main/groovy/org/labkey/gradle/task/ModuleDistribution.groovy b/src/main/groovy/org/labkey/gradle/task/ModuleDistribution.groovy index 50e497bf..3416e12f 100644 --- a/src/main/groovy/org/labkey/gradle/task/ModuleDistribution.groovy +++ b/src/main/groovy/org/labkey/gradle/task/ModuleDistribution.groovy @@ -85,7 +85,6 @@ class ModuleDistribution extends DefaultTask distFiles.add(new File(getLabKeyServerJarPath())) distFiles.add(new File(getTarArchivePath())) - distFiles.add(getDistributionFile()) distFiles.add(getVersionFile()) return distFiles @@ -284,7 +283,6 @@ class ModuleDistribution extends DefaultTask private void createDistributionFiles() { - writeDistributionFile() writeVersionFile() writeDistributionPropertiesFile() // Prefer files from 'server/configs/webapps' if they exist @@ -317,25 +315,14 @@ class ModuleDistribution extends DefaultTask project.ant.fixcrlf (srcdir: BuildUtils.getBuildDirPath(project), includes: "manual-upgrade.sh", eol: "unix") } - @Deprecated(forRemoval = true) // Not needed: distribution name is now pushed into distribution.properties - private File getDistributionFile() - { - File distExtraDir = BuildUtils.getBuildDirFile(project, DistributionExtension.DIST_FILE_DIR) - return new File(distExtraDir, DistributionExtension.DIST_FILE_NAME) - } - - @Deprecated(forRemoval = true) // Not needed: distribution name is now pushed into distribution.properties - private void writeDistributionFile() - { - Files.write(getDistributionFile().toPath(), project.name.getBytes()) - } - + @Deprecated @OutputFile File getVersionFile() { return BuildUtils.getBuildDirFile(project, DistributionExtension.VERSION_FILE_NAME) } + @Deprecated private void writeVersionFile() { // Include TeamCity buildUrl, if present. @@ -357,6 +344,12 @@ class ModuleDistribution extends DefaultTask // Assume that fileIdentifier (usually '-' + project.name, but not guaranteed) is the canonical name extraProperties.put("name", StringUtils.removeStart(getFileIdentifier(), '-')) extraProperties.put("filename", getArchiveName() + "." + DistributionExtension.TAR_ARCHIVE_EXTENSION) + extraProperties.put("version", project.version) + + // Include TeamCity buildUrl, if present. + def buildUrl = StringUtils.trimToNull(System.getenv("BUILD_URL")) + if (buildUrl != null) + extraProperties.put("buildUrl", buildUrl) getDistributionPropertiesFile().withWriter { out -> extraProperties.each { k, v -> out.println "${k}: ${v}" } diff --git a/src/main/groovy/org/labkey/gradle/task/PurgeArtifacts.groovy b/src/main/groovy/org/labkey/gradle/task/PurgeArtifacts.groovy index 48387e23..79747933 100644 --- a/src/main/groovy/org/labkey/gradle/task/PurgeArtifacts.groovy +++ b/src/main/groovy/org/labkey/gradle/task/PurgeArtifacts.groovy @@ -1,19 +1,19 @@ package org.labkey.gradle.task import org.apache.commons.lang3.StringUtils -import org.apache.http.HttpStatus -import org.apache.http.client.methods.CloseableHttpResponse -import org.apache.http.client.methods.HttpDelete -import org.apache.http.impl.client.CloseableHttpClient -import org.apache.http.impl.client.HttpClients +import org.apache.hc.client5.http.classic.methods.HttpDelete +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse +import org.apache.hc.client5.http.impl.classic.HttpClients +import org.apache.hc.core5.http.HttpStatus import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.Project import org.gradle.api.tasks.TaskAction import org.labkey.gradle.plugin.Api -import org.labkey.gradle.plugin.Module import org.labkey.gradle.plugin.FileModule import org.labkey.gradle.plugin.JavaModule +import org.labkey.gradle.plugin.Module import org.labkey.gradle.util.BuildUtils class PurgeArtifacts extends DefaultTask @@ -109,14 +109,14 @@ class PurgeArtifacts extends DefaultTask // N.B. Using Authorization Bearer with an API token does not currently work httpDelete.setHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString("${project.property('artifactory_user')}:${project.property('artifactory_password')}".getBytes())) CloseableHttpResponse response = httpClient.execute(httpDelete) - int statusCode = response.getStatusLine().getStatusCode() + int statusCode = response.getCode() if (statusCode == HttpStatus.SC_NOT_FOUND) { logger.info("No such file or directory: ${endpoint}") responseStatus = Response.NOT_FOUND } else if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) { - logger.error("Unable to delete using ${endpoint}: ${response.getStatusLine()}") + logger.error("Unable to delete using ${endpoint}: ${statusCode} ${response.getReasonPhrase()}") responseStatus = Response.ERROR } response.close() diff --git a/src/main/groovy/org/labkey/gradle/task/PurgeNpmAlphaVersions.groovy b/src/main/groovy/org/labkey/gradle/task/PurgeNpmAlphaVersions.groovy index 57314e22..52143c9b 100644 --- a/src/main/groovy/org/labkey/gradle/task/PurgeNpmAlphaVersions.groovy +++ b/src/main/groovy/org/labkey/gradle/task/PurgeNpmAlphaVersions.groovy @@ -2,11 +2,11 @@ package org.labkey.gradle.task import groovy.json.JsonSlurper import org.apache.commons.lang3.StringUtils -import org.apache.http.HttpStatus -import org.apache.http.client.methods.CloseableHttpResponse -import org.apache.http.client.methods.HttpDelete -import org.apache.http.impl.client.CloseableHttpClient -import org.apache.http.impl.client.HttpClients +import org.apache.hc.client5.http.classic.methods.HttpDelete +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse +import org.apache.hc.client5.http.impl.classic.HttpClients +import org.apache.hc.core5.http.HttpStatus import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.tasks.TaskAction @@ -123,9 +123,9 @@ class PurgeNpmAlphaVersions extends DefaultTask // N.B. Using Authorization Bearer with an API token does not currently work httpDelete.setHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString("${project.property('artifactory_user')}:${project.property('artifactory_password')}".getBytes())) CloseableHttpResponse response = httpClient.execute(httpDelete) - int statusCode = response.getStatusLine().getStatusCode() + int statusCode = response.getCode() if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) { - logger.error("Unable to delete using ${endpoint}: ${response.getStatusLine()}") + logger.error("Unable to delete using ${endpoint}: ${statusCode} ${response.getReasonPhrase()}") success = false } response.close() diff --git a/src/main/groovy/org/labkey/gradle/task/RestoreFromTrash.groovy b/src/main/groovy/org/labkey/gradle/task/RestoreFromTrash.groovy index 356eb958..fa772b4f 100644 --- a/src/main/groovy/org/labkey/gradle/task/RestoreFromTrash.groovy +++ b/src/main/groovy/org/labkey/gradle/task/RestoreFromTrash.groovy @@ -1,11 +1,11 @@ package org.labkey.gradle.task import org.apache.commons.lang3.StringUtils -import org.apache.http.HttpStatus -import org.apache.http.client.methods.CloseableHttpResponse -import org.apache.http.client.methods.HttpPost -import org.apache.http.impl.client.CloseableHttpClient -import org.apache.http.impl.client.HttpClients +import org.apache.hc.client5.http.classic.methods.HttpPost +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse +import org.apache.hc.client5.http.impl.classic.HttpClients +import org.apache.hc.core5.http.HttpStatus import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.Project @@ -95,14 +95,14 @@ class RestoreFromTrash extends DefaultTask // N.B. Using Authorization Bearer with an API token does not currently work httpPost.setHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString("${project.property('artifactory_user')}:${project.property('artifactory_password')}".getBytes())) CloseableHttpResponse response = httpClient.execute(httpPost) - int statusCode = response.getStatusLine().getStatusCode() + int statusCode = response.getCode() if (statusCode == HttpStatus.SC_NOT_FOUND) { logger.info("No such file or directory: ${endpoint}") responseStatus = Response.NOT_FOUND } else if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT && statusCode != HttpStatus.SC_ACCEPTED) { - logger.error("Unable to restore using ${endpoint}: ${response.getStatusLine()}") + logger.error("Unable to restore using ${endpoint}: ${statusCode} ${response.getReasonPhrase()}") responseStatus = Response.ERROR } response.close()