This is an automated email from the ASF dual-hosted git repository. jdaugherty pushed a commit to branch 7.0.x in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 09a0c5dafc33d5d96291303b4cb4ecd4115c71aa Author: James Daugherty <[email protected]> AuthorDate: Wed Jan 21 21:49:23 2026 -0500 #14887 - fix - do not include snapshots repo unless it's a snapshot for grails-shell created apps --- grails-profiles/base/profile.yml | 2 + grails-profiles/base/skeleton/build.gradle | 14 -- .../cli/profile/commands/CreateAppCommand.groovy | 152 ++++++++++++++++----- 3 files changed, 117 insertions(+), 51 deletions(-) diff --git a/grails-profiles/base/profile.yml b/grails-profiles/base/profile.yml index 1927e789a2..f1b9b54e29 100644 --- a/grails-profiles/base/profile.yml +++ b/grails-profiles/base/profile.yml @@ -17,12 +17,14 @@ skeleton: executable: ["**/gradlew*", "**/grailsw*"] binaryExtensions: ['png','gif','jpg','jpeg','ico','icns','pdf','zip','jar','class'] repositories: + - "mavenCentral()" - "https://repo.grails.org/grails/restricted" features: defaults: - events build: repositories: + - "mavenCentral()" - "https://repo.grails.org/grails/restricted" plugins: - eclipse diff --git a/grails-profiles/base/skeleton/build.gradle b/grails-profiles/base/skeleton/build.gradle index 4dfeedd453..99627b224f 100644 --- a/grails-profiles/base/skeleton/build.gradle +++ b/grails-profiles/base/skeleton/build.gradle @@ -1,13 +1,6 @@ buildscript { repositories { - mavenCentral() @buildRepositories@ - maven { - url = 'https://repository.apache.org/content/groups/snapshots' - content { - includeVersionByRegex('org[.]apache[.](grails|groovy).*', '.*', '.*-SNAPSHOT') - } - } } dependencies { classpath platform("org.apache.grails:grails-bom:$grailsVersion") @@ -21,14 +14,7 @@ group = "@grails.app.group@" @buildPlugins@ repositories { - mavenCentral() @repositories@ - maven { - url = 'https://repository.apache.org/content/groups/snapshots' - content { - includeVersionByRegex('org[.]apache[.](grails|groovy).*', '.*', '.*-SNAPSHOT') - } - } } dependencies { diff --git a/grails-shell-cli/src/main/groovy/org/grails/cli/profile/commands/CreateAppCommand.groovy b/grails-shell-cli/src/main/groovy/org/grails/cli/profile/commands/CreateAppCommand.groovy index e76937820d..9172efde5b 100644 --- a/grails-shell-cli/src/main/groovy/org/grails/cli/profile/commands/CreateAppCommand.groovy +++ b/grails-shell-cli/src/main/groovy/org/grails/cli/profile/commands/CreateAppCommand.groovy @@ -19,6 +19,8 @@ package org.grails.cli.profile.commands +import groovy.transform.EqualsAndHashCode + import grails.build.logging.GrailsConsole import grails.io.IOUtils import grails.util.Environment @@ -61,7 +63,7 @@ import java.util.stream.Stream @CompileStatic class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepositoryAware { - private static final String GRAILS_VERSION_FALLBACK_IN_IDE_ENVIRONMENTS_FOR_RUNNING_TESTS = '4.0.0.BUILD-SNAPSHOT' + private static final String GRAILS_VERSION_FALLBACK_IN_IDE_ENVIRONMENTS_FOR_RUNNING_TESTS = '7.0.0' public static final String NAME = 'create-app' public static final String PROFILE_FLAG = 'profile' public static final String FEATURES_FLAG = 'features' @@ -109,8 +111,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos if (val == true) { candidates.addAll(profileNames) return cursor - } - else if (!profileNames.contains(val)) { + } else if (!profileNames.contains(val)) { def valStr = val.toString() def candidateProfiles = profileNames.findAll { String pn -> @@ -121,16 +122,14 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos candidates.addAll(candidateProfiles) return cursor } - } - else if (lastOption.key == FEATURES_FLAG) { + } else if (lastOption.key == FEATURES_FLAG) { def val = lastOption.value def profile = profileRepository.getProfile(commandLine.hasOption(PROFILE_FLAG) ? commandLine.optionValue(PROFILE_FLAG).toString() : getDefaultProfile()) def featureNames = profile.features.collect() { Feature f -> f.name } if (val == true) { candidates.addAll(featureNames) return cursor - } - else if (!profileNames.contains(val)) { + } else if (!profileNames.contains(val)) { def valStr = val.toString() if (valStr.endsWith(',')) { def specified = valStr.split(',') @@ -212,9 +211,10 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos } Set<File> findAllFilesByName(File projectDir, String fileName) { - Set<File> files = (Set)[] + Set<File> files = (Set) [] if (projectDir.exists()) { Files.walkFileTree(projectDir.absoluteFile.toPath(), new SimpleFileVisitor<Path>() { + @Override FileVisitResult visitFile(Path path, BasicFileAttributes mainAtts) throws IOException { @@ -307,8 +307,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos File tmpDir if (location instanceof FileSystemResource) { skeletonDir = location.createRelative('skeleton').file - } - else { + } else { tmpDir = unzipProfile(ant, location) skeletonDir = new File(tmpDir, "META-INF/grails-profile/features/$f.name/skeleton") } @@ -328,15 +327,14 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos replaceBuildTokens(profileName, profileInstance, features, projectTargetDirectory) cmd.console.addStatus( - "${name == 'create-plugin' ? 'Plugin' : 'Application'} created at ${projectTargetDirectory.absolutePath}" + "${name == 'create-plugin' ? 'Plugin' : 'Application'} created at ${projectTargetDirectory.absolutePath}" ) if (profileInstance.instructions) { cmd.console.addStatus(profileInstance.instructions) } GrailsCli.tiggerAppLoad() return true - } - else { + } else { System.err.println("Cannot find profile $profileName") return false } @@ -376,13 +374,13 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos List<String> features = commandLine.optionValue('features')?.toString()?.split(',')?.toList() CreateAppCommandObject cmd = new CreateAppCommandObject( - appName: appName, - baseDir: executionContext.baseDir, - profileName: profileName, - grailsVersion: Environment.getPackage().getImplementationVersion() ?: GRAILS_VERSION_FALLBACK_IN_IDE_ENVIRONMENTS_FOR_RUNNING_TESTS, - features: features, - inplace: inPlace, - console: executionContext.console + appName: appName, + baseDir: executionContext.baseDir, + profileName: profileName, + grailsVersion: Environment.getPackage().getImplementationVersion() ?: GRAILS_VERSION_FALLBACK_IN_IDE_ENVIRONMENTS_FOR_RUNNING_TESTS, + features: features, + inplace: inPlace, + console: executionContext.console ) return this.handle(cmd) @@ -419,12 +417,8 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos AntBuilder ant = new GrailsConsoleAntBuilder() def ln = System.getProperty('line.separator') - Closure repositoryUrl = { int spaces, String repo -> - repo.startsWith('http') ? "${' ' * spaces}maven { url \"${repo}\" }" : "${' ' * spaces}${repo}" - } - - List<String> configuredRepositories = createRepositoryList(profile.repositories) - def repositories = configuredRepositories.collect(repositoryUrl.curry(4)).unique().join(ln) + List<GrailsGradleRepository> configuredRepositories = createRepositoryList(profile.repositories) + String repositories = configuredRepositories.collect { it.generate(4, ln) }.join(ln) List<Dependency> profileDependencies = profile.dependencies def dependencies = profileDependencies.findAll() { Dependency dep -> @@ -451,12 +445,12 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos .unique() .join(ln) - List<String> configuredBuildRepositories = createRepositoryList(profile.buildRepositories) + List<String> configuredBuildRepositories = new ArrayList<>(profile.buildRepositories) for (Feature f in features) { configuredBuildRepositories.addAll(f.getBuildRepositories()) } - String buildRepositories = createRepositoryList(configuredBuildRepositories).collect(repositoryUrl.curry(8)).unique().join(ln) + String buildRepositories = createRepositoryList(configuredBuildRepositories).collect { it.generate(8, ln) }.join(ln) buildDependencies = buildDependencies.collect() { Dependency dep -> String artifactStr = resolveArtifactString(dep) @@ -505,8 +499,8 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos } } - private List<String> createRepositoryList(List<String> profileRepositories) { - List<String> configuredRepositories = [] + private List<GrailsGradleRepository> createRepositoryList(List<String> baseRepositories) { + List<GrailsGradleRepository> configuredRepositories = [] String overrideRepo = System.getProperty('grails.repo.url') ?: System.getenv('GRAILS_REPO_URL') if (overrideRepo) { List<String> overrideRepos = Arrays.stream(overrideRepo.split(';')) @@ -515,11 +509,18 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos .toList() for (String overrideUrl : overrideRepos) { System.out.println("Grails repo url override detected, including repo: ${overrideUrl}") - configuredRepositories.add(overrideUrl) + configuredRepositories.add(new GrailsGradleRepository(url: overrideUrl)) } } - configuredRepositories.addAll(profileRepositories) - configuredRepositories + for (String repoUrl : baseRepositories) { + configuredRepositories.add(new GrailsGradleRepository(url: repoUrl)) + } + if (variables['grails.version'].endsWith('-SNAPSHOT')) { + GrailsGradleRepository repository = new GrailsGradleRepository(url: 'https://repository.apache.org/content/groups/snapshots', snapshotsOnly: true) + repository.includeOnly('org[.]apache[.](grails|groovy).*', '.*', '.*-SNAPSHOT') + configuredRepositories.add(repository) + } + configuredRepositories.unique() } protected String evaluateProfileName(CommandLine mainCommandLine) { @@ -543,8 +544,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos GrailsConsole.getInstance().warn(warning.toString()) } return (profile.features.findAll() { Feature f -> validFeatureNames.contains(f.name) } + profile.requiredFeatures).unique() - } - else { + } else { return (profile.defaultFeatures + profile.requiredFeatures).unique() } } @@ -660,8 +660,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos File tmpDir if (skeletonResource instanceof FileSystemResource) { skeletonDir = skeletonResource.file - } - else { + } else { // establish the JAR file name and extract tmpDir = unzipProfile(ant, skeletonResource) skeletonDir = new File(tmpDir, 'META-INF/grails-profile/skeleton') @@ -789,6 +788,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos } static class CreateAppCommandObject { + String appName File baseDir String profileName @@ -797,4 +797,82 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos boolean inplace = false GrailsConsole console } + + @EqualsAndHashCode(includes = ['url', 'includeRestriction']) + private static class GrailsGradleRepository { + + String url + + GradleRepositoryRegex includeRestriction + boolean releaseOnly + boolean snapshotsOnly + + void validate() { + if (releaseOnly && snapshotsOnly) { + throw new IllegalArgumentException('Repository cannot be both releaseOnly and snapshotsOnly') + } + } + + void includeOnly(String groupRegex, String artifactRegex, String versionRegex) { + includeRestriction = new GradleRepositoryRegex( + groupPattern: groupRegex, + artifactPattern: artifactRegex, + versionPattern: versionRegex + ) + } + + String generate(int spaces, String lineSeparator) { + validate() + + List<String> lines = ["${' ' * spaces}maven {" as String] + if (url.startsWith('http')) { + lines.add("${' ' * (spaces + 4)}url = '${url}'" as String) + } else { + // mavenLocal(), mavenCentral(), etc + lines.add("${' ' * (spaces + 4)}${url}" as String) + } + + if (includeRestriction) { + lines.add(includeRestriction.generate(spaces + 4, lineSeparator)) + } + + if (releaseOnly || snapshotsOnly) { + lines.add("${' ' * (spaces + 4)}mavenContent {" as String) + if (releaseOnly) { + lines.add("${' ' * (spaces + 8)}releasesOnly()" as String) + } else { // snapshotsOnly + lines.add("${' ' * (spaces + 8)}snapshotsOnly()" as String) + } + lines.add("${' ' * (spaces + 4)}}" as String) + } + + lines.add("${' ' * spaces}}" as String) + + return lines.join(lineSeparator) + } + } + + @EqualsAndHashCode(includes = ['groupPattern', 'artifactPattern', 'versionPattern']) + private static class GradleRepositoryRegex { + + String groupPattern = '.*' + String artifactPattern = '.*' + String versionPattern = '.*' + + private void validate() { + if (!groupPattern || !artifactPattern || !versionPattern) { + throw new IllegalArgumentException('Patterns must be defined') + } + } + + String generate(int spaces, String lineSeparator) { + validate() + + List<String> lines = [] + lines.add("${' ' * spaces}content {" as String) + lines.add("${' ' * (spaces + 4)}includeVersionByRegex('${groupPattern}', '${artifactPattern}', '${versionPattern}')" as String) + lines.add("${' ' * spaces}}" as String) + return lines.join(lineSeparator) + } + } }
