Updates following the first run of Reactor build

This commit is contained in:
Marcin Grzejszczak
2019-10-29 14:27:53 +01:00
parent c08b028389
commit 61ff4d7fa7
13 changed files with 146 additions and 77 deletions

View File

@@ -107,6 +107,7 @@ public class Releaser implements ReleaserPropertiesAware {
private void updateProjectFromBom(File project, Projects versions,
ProjectVersion versionFromScRelease, boolean assertSnapshots) {
log.info("Will update the project with versions [{}]", versions);
this.projectPomUpdater.updateProjectFromReleaseTrain(project, versions,
versionFromScRelease, assertSnapshots);
this.gradleUpdater.updateProjectFromBom(project, versions, versionFromScRelease,

View File

@@ -392,6 +392,7 @@ public class ReleaserProperties implements Serializable {
*/
private boolean updateReleaseTrainDocs = true;
// TODO: Spring Cloud specific?
/**
* If set to {@code false}, will not clone and update the release train wiki.
*/
@@ -739,6 +740,11 @@ public class ReleaserProperties implements Serializable {
*/
public static final String SYSTEM_PROPS_PLACEHOLDER = "{{systemProps}}";
/**
* Placeholder for profile. If not used, profile will be appended at the end.
*/
public static final String PROFILE_PROPS_PLACEHOLDER = "{{profile}}";
/**
* Command to be executed to build the project.
*/
@@ -1006,17 +1012,17 @@ public class ReleaserProperties implements Serializable {
/**
* Command to be executed to build the project.
*/
private String buildCommand = "./gradlew clean build publishToMavenLocal {{systemProps}}";
private String buildCommand = "./gradlew clean build publishToMavenLocal --console=plain {{systemProps}}";
/**
* Command to be executed to deploy a built project.
*/
private String deployCommand = "./gradlew clean build publish {{systemProps}}";
private String deployCommand = "./gradlew clean build publish --console=plain {{systemProps}}";
/**
* Command to be executed to build and deploy guides project only.
*/
private String deployGuidesCommand = "./gradlew clean build deployGuides {{systemProps}}";
private String deployGuidesCommand = "./gradlew clean build deployGuides --console=plain {{systemProps}}";
/**
* Command to be executed to publish documentation. If present "{{version}}" will

View File

@@ -22,20 +22,17 @@ import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.cloud.release.internal.ReleaserProperties;
class GradleBomParser implements BomParser {
private static final Pattern VERSION_PATTERN = Pattern
.compile("^([a-zA-Z0-9]+)Version$");
private final ReleaserProperties properties;
private final List<CustomBomParser> customParsers;
private final GradleProjectNameExtractor extractor = new GradleProjectNameExtractor();
GradleBomParser(ReleaserProperties releaserProperties,
List<CustomBomParser> customParsers) {
this.properties = releaserProperties;
@@ -64,28 +61,12 @@ class GradleBomParser implements BomParser {
.thisProjectRoot(thisProjectRoot).releaserProperties(this.properties)
.parsers(this.customParsers).retrieveFromBom();
properties.forEach((key, value) -> {
String projectName = projectName(substitution, key);
String projectName = this.extractor.projectName(substitution, key);
versionsFromBom.setVersion(projectName, value.toString());
});
return versionsFromBom;
}
private String projectName(Map<String, String> substitution, Object key) {
String projectName = key.toString();
if (substitution.containsKey(key)) {
projectName = substitution.get(key);
}
else {
Matcher matcher = VERSION_PATTERN.matcher(projectName);
boolean versionMatches = matcher.matches();
if (versionMatches) {
projectName = matcher.group(1);
}
}
projectName = projectName.replaceAll("([A-Z])", "-$1").toLowerCase();
return projectName;
}
Properties loadProps(File file) {
Properties props = new Properties();
try {

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2013-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.release.internal.buildsystem;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class GradleProjectNameExtractor {
private static final Pattern VERSION_PATTERN = Pattern
.compile("^([a-zA-Z0-9]+)Version$");
String projectName(Map<String, String> substitution, Object key) {
String projectName = key.toString();
if (substitution.containsKey(key)) {
projectName = substitution.get(key);
}
else {
Matcher matcher = VERSION_PATTERN.matcher(projectName);
boolean versionMatches = matcher.matches();
if (versionMatches) {
projectName = matcher.group(1);
}
}
projectName = projectName.replaceAll("([A-Z])", "-$1").toLowerCase();
return projectName;
}
}

View File

@@ -98,11 +98,13 @@ public class GradleUpdater implements ReleaserPropertiesAware {
private final List<Pattern> unacceptableVersionPatterns;
private final GradleProjectNameExtractor extractor = new GradleProjectNameExtractor();
private GradlePropertiesWalker(ReleaserProperties properties, Projects projects,
ProjectVersion versionFromScRelease, boolean assertVersions) {
ProjectVersion versionFromBom, boolean assertVersions) {
this.properties = properties;
this.projects = projects;
List<Pattern> unacceptableVersionPatterns = versionFromScRelease
List<Pattern> unacceptableVersionPatterns = versionFromBom
.unacceptableVersionPatterns();
this.unacceptableVersionPatterns = unacceptableVersionPatterns;
this.skipVersionAssert = !assertVersions
@@ -120,6 +122,7 @@ public class GradleUpdater implements ReleaserPropertiesAware {
file);
return FileVisitResult.CONTINUE;
}
String parentName = file.getParentFile().getName();
log.info("Will process the file [{}] and update its gradle properties",
file);
final String fileContents = asString(path);
@@ -128,21 +131,22 @@ public class GradleUpdater implements ReleaserPropertiesAware {
Properties props = loadProps(file);
final Map<String, String> substitution = this.properties.getGradle()
.getGradlePropsSubstitution();
// TODO: Automatically should search for e.g. [reactor-pool] ->
// [reactorPoolVersion]
// TODO: [version] -> current project version
// reactorPoolVersion, 1.0.0.BUILD-SNAPSHOT
props.forEach((key, value1) -> {
if (substitution.containsKey(key)) {
String projectName = substitution.get(key);
if (!this.projects.containsProject(projectName)) {
log.warn(
"Should update project with name [{}] but it wasn't found in the list of projects [{}]",
projectName, this.projects.asList());
return;
}
ProjectVersion value = this.projects.forName(projectName);
log.info("Replacing [{}->{}] with [{}->{}]", key, value1, key,
value);
changedString.set(changedString.get().replace(key + "=" + value1,
key + "=" + value));
String projectName = projectName(parentName, substitution, key);
if (!this.projects.containsProject(projectName)) {
log.warn(
"Should update project with name [{}] but it wasn't found in the list of projects [{}]",
projectName, this.projects.asList());
return;
}
ProjectVersion value = this.projects.forName(projectName);
log.info("Replacing [{}->{}] with [{}->{}]", key, value1, key, value);
changedString.set(changedString.get().replace(key + "=" + value1,
key + "=" + value));
});
storeString(path, changedString.get());
assertNoSnapshotsArePresent(path);
@@ -150,6 +154,15 @@ public class GradleUpdater implements ReleaserPropertiesAware {
return FileVisitResult.CONTINUE;
}
private String projectName(String parentName, Map<String, String> substitution,
Object key) {
// version -> current project version
if (key.equals("version")) {
return parentName;
}
return this.extractor.projectName(substitution, key);
}
private void assertNoSnapshotsArePresent(Path path) {
if (this.assertVersions && !this.skipVersionAssert) {
log.debug(

View File

@@ -146,7 +146,7 @@ public class ProjectPomUpdater implements ReleaserPropertiesAware {
.thisProjectRoot(projectRoot).releaserProperties(this.properties)
.projects(projects.asProjects()).merged();
if (!this.pomUpdater.shouldProjectBeUpdated(projectRoot, versionsFromBom)) {
log.info("Skipping project updating");
log.debug("Skipping project updating");
return;
}
updatePoms(projectRoot, versionsFromBom, versionFromReleaseTrain, assertVersions);

View File

@@ -255,7 +255,7 @@ class ProcessExecutor implements ReleaserPropertiesAware {
String runCommand(String[] commands, long waitTimeInMinutes) {
try {
String workingDir = this.workingDir;
log.info(
log.debug(
"Will run the command from [{}] via {} and wait for result for [{}] minutes",
workingDir, commands, waitTimeInMinutes);
ProcessBuilder builder = builder(commands, workingDir);
@@ -289,7 +289,15 @@ class ProcessExecutor implements ReleaserPropertiesAware {
}
ProcessBuilder builder(String[] commands, String workingDir) {
return new ProcessBuilder(commands).directory(new File(workingDir)).inheritIO();
// TODO: Improve this to not pass arrays in the first place
String lastArg = String.join(" ", commands);
String[] commandsWithBash = commandToExecute(lastArg);
return new ProcessBuilder(commandsWithBash).directory(new File(workingDir))
.inheritIO();
}
String[] commandToExecute(String lastArg) {
return new String[] { "/bin/bash", "-c", lastArg };
}
@Override
@@ -383,7 +391,7 @@ class CommandPicker {
String groupId() {
// makes more sense to use PomReader
if (projectType == ProjectType.GRADLE) {
return "./gradlew groupId | tail -1";
return "./gradlew groupId -q | tail -1";
}
return "./mvnw -q" + " -Dexec.executable=\"echo\""
+ " -Dexec.args=\"\\${project.groupId}\"" + " --non-recursive"
@@ -445,7 +453,7 @@ class CommandPicker {
if (command.contains(ReleaserProperties.Gradle.SYSTEM_PROPS_PLACEHOLDER)) {
return command;
}
return command + " " + ReleaserProperties.Maven.SYSTEM_PROPS_PLACEHOLDER;
return command + " " + ReleaserProperties.Gradle.SYSTEM_PROPS_PLACEHOLDER;
}
private String mavenCommandWithSystemProps(String command, ProjectVersion version,
@@ -469,13 +477,13 @@ class CommandPicker {
String trimmedCommand = command.trim();
if (version.isMilestone() || version.isRc()) {
log.info("Adding the milestone profile to the Maven build");
return trimmedCommand + " " + MavenProfile.MILESTONE.asMavenProfile()
+ profilesToString(profiles);
return withProfile(trimmedCommand, MavenProfile.MILESTONE.asMavenProfile(),
profiles);
}
else if (version.isRelease() || version.isServiceRelease()) {
log.info("Adding the central profile to the Maven build");
return trimmedCommand + " " + MavenProfile.CENTRAL.asMavenProfile()
+ profilesToString(profiles);
return withProfile(trimmedCommand, MavenProfile.CENTRAL.asMavenProfile(),
profiles);
}
else {
log.info("The build is a snapshot one - will not add any profiles");
@@ -483,6 +491,18 @@ class CommandPicker {
return trimmedCommand;
}
private String withProfile(String command, String profile, MavenProfile... profiles) {
if (command.contains(ReleaserProperties.Maven.PROFILE_PROPS_PLACEHOLDER)) {
return command.replace(ReleaserProperties.Maven.PROFILE_PROPS_PLACEHOLDER,
profile + appendProfiles(profiles));
}
return command + " " + profile + appendProfiles(profiles);
}
private String appendProfiles(MavenProfile[] profiles) {
return profiles.length > 0 ? " " + profilesToString(profiles) : "";
}
private String profilesToString(MavenProfile... profiles) {
return Arrays.stream(profiles).map(profile -> "-P" + profile)
.collect(Collectors.joining(" "));

View File

@@ -73,8 +73,9 @@ public class ProjectVersion implements Comparable<ProjectVersion> {
}
public ProjectVersion(File project) {
if (new File(project, "build.gradle").exists()) {
ProjectVersion projectVersion = gradleProject(project);
File buildGradle = new File(project, "build.gradle");
if (buildGradle.exists()) {
ProjectVersion projectVersion = gradleProject(buildGradle);
this.projectName = projectVersion.projectName;
this.version = projectVersion.version;
this.groupId = new ProjectCommandExecutor().groupId();

View File

@@ -76,7 +76,7 @@ public class Projects extends HashSet<ProjectVersion> {
}
private static String additionalErrorMessage(String projectName) {
return "Either put it in the Spring Cloud Release project or set it via the [--releaser.fixed-versions["
return "Either put it in the BOM or set it via the [--releaser.fixed-versions["
+ projectName + "]=1.0.0.RELEASE] property";
}

View File

@@ -40,7 +40,7 @@ class BuildsystemConfiguration {
@Bean
BomParser gradleBomParser() {
return new MavenBomParser(this.releaserProperties, this.customBomParsers);
return new GradleBomParser(this.releaserProperties, this.customBomParsers);
}
@Bean

View File

@@ -248,9 +248,9 @@ public class SpringReleaser {
}
ProjectVersion versionFromBom;
Projects projectsToUpdate;
log.info("Fetch from git [{}], meta release [{}]",
log.info("Fetch from git [{}], meta release [{}], project [{}]",
this.properties.getGit().isFetchVersionsFromGit(),
this.properties.getMetaRelease().isEnabled());
this.properties.getMetaRelease().isEnabled(), project);
if (this.properties.getGit().isFetchVersionsFromGit()
&& !this.properties.getMetaRelease().isEnabled()) {
printVersionRetrieval();
@@ -285,6 +285,7 @@ public class SpringReleaser {
}
ProjectsAndVersion processProject(Options options, File project, TaskType taskType) {
log.info("Processing the project in file [{}]", project);
ProjectsAndVersion projectsAndVersion = projects(project);
ProjectVersion originalVersion = new ProjectVersion(project);
final Args defaultArgs = new Args(this.releaser, project,
@@ -303,10 +304,8 @@ public class SpringReleaser {
}
private void printVersionRetrieval() {
log.info(
"\n\n\n=== RETRIEVING VERSIONS ===\n\nWill clone Spring Cloud Release"
+ " to retrieve all versions for the branch [{}]",
this.properties.getPom().getBranch());
log.info("\n\n\n=== RETRIEVING VERSIONS ===\n\nWill clone the bom"
+ " to retrieve all versions");
}
private void printSettingVersionFromFixedVersions(Projects projectsToUpdate) {

View File

@@ -33,8 +33,8 @@ final class Tasks {
throw new IllegalStateException("Can't instantiate a utility class");
}
static Task UPDATING_POMS = task("updatePoms", "u", "UPDATING POMS",
"Update poms with versions from Spring Cloud Release",
static Task UPDATING_POMS = task("updatePoms", "u", "UPDATING VERSIONS",
"Update versions from the BOM",
args -> args.releaser.updateProjectFromBom(args.project, args.projects,
args.versionFromScRelease));
static Task BUILD_PROJECT = task("build", "b", "BUILD PROJECT", "Build the project",

View File

@@ -44,7 +44,6 @@ import org.junit.rules.TemporaryFolder;
import org.mockito.BDDMockito;
import org.mockito.Mockito;
import org.springframework.boot.test.rule.OutputCapture;
import org.springframework.cloud.release.cloud.docs.SpringCloudDocsAccessor;
import org.springframework.cloud.release.cloud.github.SpringCloudGithubIssuesAccessor;
import org.springframework.cloud.release.internal.Releaser;
@@ -86,9 +85,6 @@ public class AcceptanceTests {
@Rule
public TemporaryFolder tmp = new TemporaryFolder();
@Rule
public OutputCapture capture = new OutputCapture();
TestPomReader testPomReader = new TestPomReader();
File springCloudConsulProject;
@@ -135,6 +131,9 @@ public class AcceptanceTests {
BDDMockito.given(this.saganClient.getProject(anyString()))
.willReturn(newProject());
Task.stepSkipper = () -> false;
new File("/tmp/executed_build").delete();
new File("/tmp/executed_deploy").delete();
new File("/tmp/executed_docs").delete();
}
@After
@@ -362,8 +361,9 @@ public class AcceptanceTests {
then(Arrays.asList("spring-cloud-starter-build",
"spring-cloud-consul"))
.contains(pom(project).getArtifactId());
then(this.capture.toString()).contains("executed_build",
"executed_deploy", "executed_docs");
then(new File("/tmp/executed_build")).exists();
then(new File("/tmp/executed_deploy")).exists();
then(new File("/tmp/executed_docs")).exists();
});
}
@@ -375,9 +375,9 @@ public class AcceptanceTests {
then(Arrays.asList("spring-cloud-starter-build",
"spring-cloud-consul"))
.contains(pom(project).getArtifactId());
then(this.capture.toString()).contains("executed_build");
then(this.capture.toString()).doesNotContain("executed_deploy",
"executed_docs");
then(new File("/tmp/executed_build")).exists();
then(new File("/tmp/executed_deploy")).doesNotExist();
then(new File("/tmp/executed_docs")).doesNotExist();
});
}
@@ -421,8 +421,9 @@ public class AcceptanceTests {
.filter(file -> file.getName().equals("spring-cloud-consul"))
.forEach(project -> {
then(pom(project).getArtifactId()).isEqualTo("spring-cloud-consul");
then(this.capture.toString()).contains("executed_build",
"executed_deploy", "executed_docs");
then(new File("/tmp/executed_build")).exists();
then(new File("/tmp/executed_deploy")).exists();
then(new File("/tmp/executed_docs")).exists();
});
thenSaganWasCalled();
thenDocumentationWasUpdated();
@@ -449,8 +450,9 @@ public class AcceptanceTests {
.forEach(project -> {
then(Collections.singletonList("spring-cloud-consul"))
.contains(pom(project).getArtifactId());
then(this.capture.toString()).contains("executed_build",
"executed_deploy", "executed_docs");
then(new File("/tmp/executed_build")).exists();
then(new File("/tmp/executed_deploy")).exists();
then(new File("/tmp/executed_docs")).exists();
});
thenSaganWasCalled();
thenDocumentationWasUpdated();
@@ -903,10 +905,12 @@ public class AcceptanceTests {
file("/projects/spring-cloud-static-angel/").toURI().toString());
releaserProperties.getGit().setReleaseTrainBomUrl(
file("/projects/spring-cloud-release/").toURI().toString());
releaserProperties.getMaven().setBuildCommand("echo executed_build");
releaserProperties.getMaven().setDeployCommand("echo executed_deploy");
releaserProperties.getMaven()
.setPublishDocsCommands(new String[] { "echo executed_docs" });
.setBuildCommand("echo '{{profiles}}' > /tmp/executed_build");
releaserProperties.getMaven()
.setDeployCommand("echo '{{profiles}}' > /tmp/executed_deploy");
releaserProperties.getMaven().setPublishDocsCommands(
new String[] { "echo '{{profiles}}' > /tmp/executed_docs" });
releaserProperties.getMetaRelease()
.setGitOrgUrl("file://" + this.temporaryFolder.getAbsolutePath());
releaserProperties.getMetaRelease().setEnabled(true);