From e83cda4fed947f69a7dceea2ece0665a09cdc4b2 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Fri, 18 Feb 2022 14:29:17 -0500 Subject: [PATCH 1/8] Updates for new sagain api, s-c-build 3.1 and boot 2.6 (#243) Updates releaser to use spring cloud build 3.1.0 Transitively uses boot 2.6 Updates releaser to use new Sagan API Fixes gh-196 Fixes gh-194 --- pom.xml | 6 +- .../java/releaser/ReleaserApplication.java | 3 +- .../releaser/reactor/CfConfiguration.java | 36 +- .../reactor/GenerateReleaseNotesTask.java | 160 ++++----- .../reactor/ReactorConfiguration.java | 19 +- .../RestartSiteProjectPostReleaseTask.java | 6 +- .../releaser/ReleaserApplicationTests.java | 14 +- .../reactor/GenerateReleaseNotesTaskTest.java | 148 ++++---- .../reactor/ReactorTestConfiguration.java | 7 +- ...estartSiteProjectPostReleaseTaskTests.java | 25 +- .../src/test/resources/application-test.yml | 5 +- .../java/releaser/ReleaserApplication.java | 3 +- .../buildsystem/SpringCloudBomConstants.java | 3 +- .../SpringCloudStreamMavenBomParser.java | 34 +- .../releaser/ReleaserApplicationTests.java | 3 +- .../java/releaser/ReleaserApplication.java | 3 +- .../buildsystem/SpringCloudBomConstants.java | 3 +- .../SpringCloudMavenBomParser.java | 34 +- ...loudCustomProjectDocumentationUpdater.java | 77 ++-- .../docs/SpringCloudDocsConfiguration.java | 7 +- .../SpringCloudGithubConfiguration.java | 3 +- .../cloud/github/SpringCloudGithubIssues.java | 25 +- .../releaser/ReleaserApplicationTests.java | 3 +- .../cloud/SpringCloudReleaserProperties.java | 12 +- .../SpringCloudCustomMavenBomTests.java | 65 ++-- .../SpringCloudMavenBomParserTests.java | 63 ++-- .../SpringCloudProjectPomUpdaterTests.java | 34 +- ...ustomProjectDocumentationUpdaterTests.java | 90 ++--- .../java/releaser/cloud/docs/TestUtils.java | 3 +- .../SpringCloudGithubIssuesAccessor.java | 3 +- .../github/SpringCloudGithubIssuesTests.java | 65 ++-- .../AbstractSpringCloudAcceptanceTests.java | 17 +- ...bstractSpringCloudMetaAcceptanceTests.java | 18 +- .../SpringMetaReleaseAcceptanceTests.java | 224 +++++------- .../SpringSingleProjectAcceptanceTests.java | 152 ++++---- releaser-core/pom.xml | 8 +- .../main/java/releaser/internal/Releaser.java | 141 +++----- .../releaser/internal/ReleaserProperties.java | 103 +++--- .../internal/ReleaserPropertiesUpdater.java | 52 +-- .../buildsystem/CompositeBomParser.java | 8 +- .../internal/buildsystem/CustomBomParser.java | 6 +- .../internal/buildsystem/GradleBomParser.java | 11 +- .../GradleProjectNameExtractor.java | 3 +- .../internal/buildsystem/GradleUpdater.java | 65 ++-- .../internal/buildsystem/MavenBomParser.java | 14 +- .../internal/buildsystem/PomUpdater.java | 98 ++---- .../buildsystem/ProjectPomUpdater.java | 72 ++-- .../internal/buildsystem/VersionsFromBom.java | 40 +-- .../buildsystem/VersionsFromBomBuilder.java | 26 +- .../CustomProjectDocumentationUpdater.java | 16 +- .../internal/docs/DocumentationUpdater.java | 14 +- .../docs/ProjectDocumentationUpdater.java | 34 +- .../internal/docs/ReleaseTrainContents.java | 3 +- .../docs/ReleaseTrainContentsUpdater.java | 95 ++--- .../main/java/releaser/internal/docs/Row.java | 13 +- .../java/releaser/internal/docs/Title.java | 9 +- .../java/releaser/internal/git/GitRepo.java | 76 ++-- .../internal/git/ProjectGitHandler.java | 46 +-- .../releaser/internal/git/SimpleCommit.java | 14 +- .../internal/github/CachingGithub.java | 75 ++-- .../internal/github/GithubIssueFiler.java | 18 +- .../internal/github/GithubIssues.java | 3 +- .../internal/github/GithubMilestones.java | 25 +- .../internal/github/ProjectGitHubHandler.java | 18 +- .../postrelease/PostReleaseActions.java | 134 +++---- .../internal/project/ProcessedProject.java | 9 +- .../releaser/internal/project/Project.java | 3 +- .../project/ProjectCommandExecutor.java | 196 ++++------- .../internal/project/ProjectVersion.java | 111 +++--- .../releaser/internal/project/Projects.java | 59 ++-- .../java/releaser/internal/sagan/Project.java | 71 ++-- .../java/releaser/internal/sagan/Release.java | 63 ++-- .../{ReleaseUpdate.java => ReleaseInput.java} | 42 ++- .../releaser/internal/sagan/Repository.java | 5 +- .../sagan/RestTemplateSaganClient.java | 127 ++++--- .../releaser/internal/sagan/SaganClient.java | 6 +- .../releaser/internal/sagan/SaganUpdater.java | 195 ++++------- .../internal/tech/BuildUnstableException.java | 9 +- .../internal/tech/ExecutionResult.java | 30 +- .../internal/tech/HandlebarsHelper.java | 3 +- .../releaser/internal/tech/PomReader.java | 6 +- .../internal/tech/TemporaryFileStorage.java | 11 +- .../template/BlogTemplateGenerator.java | 28 +- .../template/EmailTemplateGenerator.java | 6 +- .../internal/template/NotesGenerator.java | 10 +- .../ReleaseNotesTemplateGenerator.java | 10 +- .../internal/template/TemplateGenerator.java | 13 +- .../template/TwitterTemplateGenerator.java | 6 +- .../internal/versions/VersionsFetcher.java | 62 ++-- .../SpringCloudReleaserProperties.java | 12 +- .../internal/PomUpdateAcceptanceTests.java | 107 ++---- .../internal/ReleaserPropertiesTests.java | 9 +- .../java/releaser/internal/ReleaserTests.java | 81 ++--- .../buildsystem/GradleBomParserTests.java | 21 +- .../buildsystem/MavenBomParserTests.java | 9 +- .../internal/buildsystem/PomReaderTests.java | 12 +- .../internal/buildsystem/PomUpdaterTests.java | 328 +++++++----------- .../buildsystem/ProjectPomUpdaterTests.java | 5 +- .../buildsystem/ProjectVersionTests.java | 297 ++++++---------- .../internal/buildsystem/ProjectsTests.java | 48 +-- .../buildsystem/PropertyStorerTests.java | 3 +- .../PropertyVersionChangerTests.java | 37 +- .../internal/buildsystem/TestUtils.java | 3 +- .../buildsystem/VersionChangeAssertions.java | 6 +- .../buildsystem/VersionsFromBomTests.java | 105 ++---- .../docs/ReleaseTrainContentsParserTests.java | 7 +- .../ReleaseTrainContentsUpdaterTests.java | 62 ++-- .../java/releaser/internal/docs/RowTests.java | 6 +- .../docs/SpringCloudGhPagesParserTests.java | 81 ++--- .../releaser/internal/git/GitRepoTests.java | 32 +- .../releaser/internal/git/GitTestUtils.java | 3 +- .../internal/git/ProjectGitHandlerTests.java | 37 +- .../internal/github/GithubIssuesTests.java | 27 +- .../github/GithubMilestonesTests.java | 31 +- .../internal/gradle/GradleUpdaterTests.java | 19 +- .../postrelease/PostReleaseActionsTests.java | 125 +++---- .../project/ProjectCommandExecutorTests.java | 240 +++++-------- .../sagan/RestTemplateSaganClientTests.java | 153 ++------ .../sagan/SaganUpdaterOldDocsTest.java | 260 -------------- .../internal/sagan/SaganUpdaterTest.java | 225 ++++++------ .../template/TemplateGeneratorTests.java | 263 +++++--------- .../versions/VersionsFromBomFetcherTests.java | 24 +- releaser-spring/pom.xml | 5 + .../releaser/ReleaserCommandLineRunner.java | 4 +- .../buildsystem/BuildsystemConfiguration.java | 9 +- .../internal/github/GithubConfiguration.java | 3 +- .../releaser/internal/options/Options.java | 12 +- .../internal/options/OptionsBuilder.java | 4 +- .../internal/sagan/SaganConfiguration.java | 17 +- .../releaser/internal/spring/Arguments.java | 68 ++-- .../internal/spring/BatchConfiguration.java | 22 +- .../spring/DefaultSpringReleaser.java | 38 +- .../spring/ExecutionResultReport.java | 3 +- .../releaser/internal/spring/FlowRunner.java | 13 +- .../internal/spring/OptionsParser.java | 80 ++--- .../internal/spring/ProjectToRun.java | 6 +- .../internal/spring/ProjectsFromBom.java | 3 +- .../internal/spring/ProjectsToRunFactory.java | 81 ++--- .../spring/ReleaserConfiguration.java | 66 ++-- .../spring/SpringBatchBuildReportHandler.java | 58 ++-- .../SpringBatchExecutionResultHandler.java | 34 +- .../spring/SpringBatchFlowRunner.java | 179 ++++------ .../internal/spring/TasksToRunFactory.java | 30 +- .../spring/VersionsToBumpFactory.java | 46 +-- .../tasks/ProjectPostReleaseReleaserTask.java | 3 +- .../releaser/internal/tasks/ReleaserTask.java | 3 +- .../CompositeTasksConfiguration.java | 6 +- .../tasks/composite/DryRunCompositeTask.java | 11 +- .../composite/MetaReleaseCompositeTask.java | 3 +- .../MetaReleaseDryRunCompositeTask.java | 3 +- .../tasks/composite/ReleaseCompositeTask.java | 17 +- .../ReleaseVerboseCompositeTask.java | 3 +- .../TrainPostReleaseCompositeTask.java | 10 +- ...CloseMilestonesProjectPostReleaseTask.java | 3 +- .../CreateTemplatesTrainPostReleaseTask.java | 3 +- .../PostReleaseTasksConfiguration.java | 24 +- ...RunUpdatedSamplesTrainPostReleaseTask.java | 3 +- ...ateAllTestSamplesTrainPostReleaseTask.java | 3 +- .../UpdateGuidesTrainPostReleaseTask.java | 3 +- ...eReleaseTrainDocsTrainPostReleaseTask.java | 3 +- ...eReleaseTrainWikiTrainPostReleaseTask.java | 3 +- .../UpdateSaganProjectPostReleaseTask.java | 3 +- ...dateStartSpringIoTrainPostReleaseTask.java | 3 +- .../release/BuildProjectReleaseTask.java | 6 +- .../BumpBackToSnapshotReleaseTask.java | 3 +- .../release/DeployArtifactsReleaseTask.java | 3 +- .../tasks/release/PublishDocsReleaseTask.java | 3 +- .../release/UpdatingPomsReleaseTask.java | 3 +- .../internal/buildsystem/TestUtils.java | 6 +- .../docs/TestDocumentationUpdater.java | 8 +- .../docs/TestReleaseContentsUpdater.java | 4 +- .../releaser/internal/git/GitTestUtils.java | 3 +- .../spring/ProjectsToReleaseGroupsTests.java | 6 +- .../ReleaserPropertiesUpdaterTests.java | 7 +- .../spring/SpringBatchFlowRunnerTests.java | 39 +-- releaser-test/pom.xml | 5 + .../buildsystem/MavenBomParserAccessor.java | 3 +- .../internal/buildsystem/TestUtils.java | 6 +- .../docs/TestReleaseContentsUpdater.java | 4 +- .../releaser/internal/git/GitTestUtils.java | 3 +- .../spring/AbstractSpringAcceptanceTests.java | 59 ++-- .../releaser/internal/spring/ArgsBuilder.java | 15 +- ...tractSpringMetaReleaseAcceptanceTests.java | 70 ++-- spring-cloud-info/pom.xml | 14 +- .../InitializrSpringCloudInfoService.java | 24 +- .../cloud/info/SpringBootAndCloudVersion.java | 9 +- .../info/SpringCloudInfoApplication.java | 6 +- .../info/SpringCloudInfoRestController.java | 6 +- .../cloud/info/SpringCloudInfoService.java | 9 +- .../cloud/info/SpringCloudRelease.java | 30 +- ...SpringCloudMilestoneNotFoundException.java | 3 +- .../SpringCloudVersionNotFoundException.java | 3 +- ...InitializrSpringCloudInfoServiceTests.java | 78 ++--- .../SpringCloudInfoRestControllerTests.java | 52 ++- .../cloud/info/SpringCloudInfoTestData.java | 42 ++- 195 files changed, 2914 insertions(+), 4881 deletions(-) rename releaser-core/src/main/java/releaser/internal/sagan/{ReleaseUpdate.java => ReleaseInput.java} (52%) delete mode 100644 releaser-core/src/test/java/releaser/internal/sagan/SaganUpdaterOldDocsTest.java diff --git a/pom.xml b/pom.xml index 6297f630..136b9af1 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ org.springframework.cloud spring-cloud-build - 2.2.3.RELEASE + 3.1.0 @@ -21,7 +21,7 @@ releaser-core releaser-spring releaser-test - spring-cloud-info + projects docs @@ -41,7 +41,7 @@ 4.2.0 0.10.0-SNAPSHOT 4.0.3 - 1.0.0.BUILD-SNAPSHOT + 1.0.0-SNAPSHOT 1.1.4 5.0.4 1.1.0 diff --git a/projects/reactor/src/main/java/releaser/ReleaserApplication.java b/projects/reactor/src/main/java/releaser/ReleaserApplication.java index cb2f3aa4..cafb9dd5 100644 --- a/projects/reactor/src/main/java/releaser/ReleaserApplication.java +++ b/projects/reactor/src/main/java/releaser/ReleaserApplication.java @@ -27,8 +27,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ReleaserApplication extends ReleaserCommandLineRunner { - public ReleaserApplication(SpringReleaser releaser, - ExecutionResultHandler executionResultHandler, Parser parser) { + public ReleaserApplication(SpringReleaser releaser, ExecutionResultHandler executionResultHandler, Parser parser) { super(releaser, executionResultHandler, parser); } diff --git a/projects/reactor/src/main/java/releaser/reactor/CfConfiguration.java b/projects/reactor/src/main/java/releaser/reactor/CfConfiguration.java index 2c8335ac..baa95d95 100644 --- a/projects/reactor/src/main/java/releaser/reactor/CfConfiguration.java +++ b/projects/reactor/src/main/java/releaser/reactor/CfConfiguration.java @@ -48,39 +48,31 @@ class CfConfiguration { @Bean PasswordGrantTokenProvider tokenProvider(@Value("${cf.username}") String username, @Value("${cf.password}") String password) { - return PasswordGrantTokenProvider.builder().password(password).username(username) + return PasswordGrantTokenProvider.builder().password(password).username(username).build(); + } + + @Bean + ReactorCloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext, TokenProvider tokenProvider) { + return ReactorCloudFoundryClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider) .build(); } @Bean - ReactorCloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext, - TokenProvider tokenProvider) { - return ReactorCloudFoundryClient.builder().connectionContext(connectionContext) - .tokenProvider(tokenProvider).build(); + ReactorDopplerClient dopplerClient(ConnectionContext connectionContext, TokenProvider tokenProvider) { + return ReactorDopplerClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider).build(); } @Bean - ReactorDopplerClient dopplerClient(ConnectionContext connectionContext, - TokenProvider tokenProvider) { - return ReactorDopplerClient.builder().connectionContext(connectionContext) - .tokenProvider(tokenProvider).build(); + ReactorUaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) { + return ReactorUaaClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider).build(); } @Bean - ReactorUaaClient uaaClient(ConnectionContext connectionContext, - TokenProvider tokenProvider) { - return ReactorUaaClient.builder().connectionContext(connectionContext) - .tokenProvider(tokenProvider).build(); - } - - @Bean - DefaultCloudFoundryOperations defaultCloudFoundryOperations( - CloudFoundryClient cloudFoundryClient, DopplerClient dopplerClient, - UaaClient uaaClient, @Value("${cf.organization}") String organizationId, + DefaultCloudFoundryOperations defaultCloudFoundryOperations(CloudFoundryClient cloudFoundryClient, + DopplerClient dopplerClient, UaaClient uaaClient, @Value("${cf.organization}") String organizationId, @Value("${cf.space}") String spaceId) { - return DefaultCloudFoundryOperations.builder() - .cloudFoundryClient(cloudFoundryClient).dopplerClient(dopplerClient) - .uaaClient(uaaClient).organization(organizationId).space(spaceId).build(); + return DefaultCloudFoundryOperations.builder().cloudFoundryClient(cloudFoundryClient) + .dopplerClient(dopplerClient).uaaClient(uaaClient).organization(organizationId).space(spaceId).build(); } } diff --git a/projects/reactor/src/main/java/releaser/reactor/GenerateReleaseNotesTask.java b/projects/reactor/src/main/java/releaser/reactor/GenerateReleaseNotesTask.java index d58c1ad8..0caebefa 100644 --- a/projects/reactor/src/main/java/releaser/reactor/GenerateReleaseNotesTask.java +++ b/projects/reactor/src/main/java/releaser/reactor/GenerateReleaseNotesTask.java @@ -61,11 +61,9 @@ import releaser.internal.tech.ExecutionResult; /** * @author Simon Baslé */ -public class GenerateReleaseNotesTask - implements ProjectPostReleaseReleaserTask, DryRunReleaseReleaserTask { +public class GenerateReleaseNotesTask implements ProjectPostReleaseReleaserTask, DryRunReleaseReleaserTask { - private static final Logger log = LoggerFactory - .getLogger(GenerateReleaseNotesTask.class); + private static final Logger log = LoggerFactory.getLogger(GenerateReleaseNotesTask.class); private static final String NAME = "releaseNotes"; @@ -106,20 +104,18 @@ public class GenerateReleaseNotesTask } @Override - public ExecutionResult runTask(Arguments args) - throws BuildUnstableException, RuntimeException { + public ExecutionResult runTask(Arguments args) throws BuildUnstableException, RuntimeException { if (args.versionFromBom.isSnapshot()) { log.info("\nWon't generate notes for a snapshot version"); return ExecutionResult.success(); } - Repo repo = github.repos().get(new Coordinates.Simple( - args.properties.getGit().getOrgName(), args.projectToRun.name())); + Repo repo = github.repos() + .get(new Coordinates.Simple(args.properties.getGit().getOrgName(), args.projectToRun.name())); String releaseTag = "v" + args.versionFromBom.version; if (args.options.dryRun != Boolean.TRUE) { - Optional maybeTagSha1 = gitHandler.findTagSha1(args.project, - releaseTag); + Optional maybeTagSha1 = gitHandler.findTagSha1(args.project, releaseTag); if (maybeTagSha1.isPresent()) { String tagSha1 = maybeTagSha1.get(); try { @@ -127,16 +123,13 @@ public class GenerateReleaseNotesTask repo.git().references().get("tags/" + tagSha1).json(); } catch (IOException e) { - return ExecutionResult.failure(new IllegalStateException( - "Shouldn't create a release if tag " + releaseTag + " (sha1=" - + tagSha1 + ") not visible in Github", - e)); + return ExecutionResult.failure(new IllegalStateException("Shouldn't create a release if tag " + + releaseTag + " (sha1=" + tagSha1 + ") not visible in Github", e)); } } else { return ExecutionResult.failure(new IllegalStateException( - "Attempting to draft release note but tag not found in repository: " - + releaseTag)); + "Attempting to draft release note but tag not found in repository: " + releaseTag)); } } @@ -144,34 +137,26 @@ public class GenerateReleaseNotesTask EnumMap> entries = new EnumMap<>(Type.class); String toVersionTag = "v" + args.versionFromBom.version; - if (args.options.dryRun == Boolean.TRUE - && !gitHandler.findTagSha1(args.project, toVersionTag).isPresent()) { + if (args.options.dryRun == Boolean.TRUE && !gitHandler.findTagSha1(args.project, toVersionTag).isPresent()) { toVersionTag = "HEAD"; } // eg. 3.2.1 for current 3.2.2 - String fromVersionTag = args.versionFromBom - .computePreviousPatchTag("v", "RELEASE").orElseGet(() -> { - Pattern pattern = args.versionFromBom - .computePreviousMinorTagPattern("v", "RELEASE") - .orElseGet(() -> args.versionFromBom - .computePreviousMajorTagPattern("v", "RELEASE")); - // eg. v3.2.*.RELEASE or v3.*.*.RELEASE - log.info( - "Couldn't simply compute previous version of {}, looking through tag list with pattern {}", - args.versionFromBom.version, pattern.pattern()); + String fromVersionTag = args.versionFromBom.computePreviousPatchTag("v", "RELEASE").orElseGet(() -> { + Pattern pattern = args.versionFromBom.computePreviousMinorTagPattern("v", "RELEASE") + .orElseGet(() -> args.versionFromBom.computePreviousMajorTagPattern("v", "RELEASE")); + // eg. v3.2.*.RELEASE or v3.*.*.RELEASE + log.info("Couldn't simply compute previous version of {}, looking through tag list with pattern {}", + args.versionFromBom.version, pattern.pattern()); - List sortedTags = gitHandler - .findTagNamesMatching(args.project, pattern) - .collect(Collectors.toList()); - if (sortedTags.isEmpty()) { - throw new IllegalStateException( - "Couldn't find a tag that matches pattern " - + pattern.pattern()); - } - sortedTags.forEach(System.out::println); - return sortedTags.get(0); - }); + List sortedTags = gitHandler.findTagNamesMatching(args.project, pattern) + .collect(Collectors.toList()); + if (sortedTags.isEmpty()) { + throw new IllegalStateException("Couldn't find a tag that matches pattern " + pattern.pattern()); + } + sortedTags.forEach(System.out::println); + return sortedTags.get(0); + }); if (Boolean.TRUE == args.options.interactive) { log.info("\nComputed log range is {}..{}", fromVersionTag, toVersionTag); @@ -189,8 +174,7 @@ public class GenerateReleaseNotesTask log.info("Will fetch the log for range {}..{}", fromVersionTag, toVersionTag); // gather commits. we use tags in the format `vVERSION` - final List revCommits = gitHandler.commitsBetween(args.project, - fromVersionTag, toVersionTag); + final List revCommits = gitHandler.commitsBetween(args.project, fromVersionTag, toVersionTag); // parse and link to issues if possible, determining type for (SimpleCommit revCommit : revCommits) { @@ -202,8 +186,7 @@ public class GenerateReleaseNotesTask } // generate the notes - String notes = generateNotes(args, entries, - extractContributorMentions(repo, revCommits)); + String notes = generateNotes(args, entries, extractContributorMentions(repo, revCommits)); if (args.options.dryRun != null && args.options.dryRun) { // print out @@ -220,8 +203,7 @@ public class GenerateReleaseNotesTask JsonObject draftReleaseJson = null; try { // attempt to find gh release with this tag. stop at 2 month old releases - Instant oldestReleaseToConsider = ZonedDateTime.now().minusMonths(2) - .toInstant(); + Instant oldestReleaseToConsider = ZonedDateTime.now().minusMonths(2).toInstant(); for (Release release : repo.releases().iterate()) { JsonObject releaseJson = release.json(); // seems the created release has a wrong tag "untagged-xxxxx", we also @@ -229,8 +211,8 @@ public class GenerateReleaseNotesTask if (releaseJson.getString("tag_name").equals(releaseTag) || releaseJson.getString("name").equals(releaseTag)) { if (!releaseJson.getBoolean("draft")) { - return ExecutionResult.failure(new IllegalStateException( - "Release already exists for tag " + releaseTag)); + return ExecutionResult + .failure(new IllegalStateException("Release already exists for tag " + releaseTag)); } else { draftRelease = new Release.Smart(release); @@ -252,16 +234,14 @@ public class GenerateReleaseNotesTask } } catch (Throwable e) { - return ExecutionResult.failure(new IllegalStateException( - "Unable to try to match github releases with tag " + releaseTag, - e)); + return ExecutionResult.failure( + new IllegalStateException("Unable to try to match github releases with tag " + releaseTag, e)); } if (draftReleaseJson == null) { // create a draft release for the tag try { - Release.Smart release = new Release.Smart( - repo.releases().create(releaseTag)); + Release.Smart release = new Release.Smart(repo.releases().create(releaseTag)); release.draft(true); release.tag(releaseTag); release.name(releaseTag); @@ -279,8 +259,7 @@ public class GenerateReleaseNotesTask // update the existing draft try { // edit the release - String oldAndNewNotes = draftReleaseJson.getString("body") - + "\n\n----\nNew draft added " + String oldAndNewNotes = draftReleaseJson.getString("body") + "\n\n----\nNew draft added " + LocalDateTime.now().toString() + "\n----\n" + notes; draftRelease.body(oldAndNewNotes); return ExecutionResult.success(); @@ -295,18 +274,15 @@ public class GenerateReleaseNotesTask /** * Generate the release notes. */ - protected String generateNotes(Arguments args, - EnumMap> entries, + protected String generateNotes(Arguments args, EnumMap> entries, List contributorGithubMentions) { // TODO use a template? handlebars ! - StringBuilder notes = new StringBuilder().append(args.projectToRun.name()) - .append(" `").append(args.versionFromBom.version) - .append("` is part of **`").append(args.releaseTrain().version) + StringBuilder notes = new StringBuilder().append(args.projectToRun.name()).append(" `") + .append(args.versionFromBom.version).append("` is part of **`").append(args.releaseTrain().version) .append("` Release Train**."); notes.append("\n\n## :warning: Update considerations and deprecations"); - for (ChangelogEntry noteworthy : entries.getOrDefault(Type.NOTEWORTHY, - Collections.emptyList())) { + for (ChangelogEntry noteworthy : entries.getOrDefault(Type.NOTEWORTHY, Collections.emptyList())) { notes.append("\n - ").append(noteworthy.description); for (String issueTitle : noteworthy.associatedIssueLinksAndTitles.values()) { notes.append("\n\t - ").append(cleanupShortMessage(issueTitle)); @@ -314,8 +290,7 @@ public class GenerateReleaseNotesTask } notes.append("\n\n## :sparkles: New features and improvements"); - for (ChangelogEntry feature : entries.getOrDefault(Type.FEATURE, - Collections.emptyList())) { + for (ChangelogEntry feature : entries.getOrDefault(Type.FEATURE, Collections.emptyList())) { notes.append("\n - ").append(feature.description); for (String issueTitle : feature.associatedIssueLinksAndTitles.values()) { notes.append("\n\t - ").append(cleanupShortMessage(issueTitle)); @@ -323,8 +298,7 @@ public class GenerateReleaseNotesTask } notes.append("\n\n## :beetle: Bug fixes"); - for (ChangelogEntry bug : entries.getOrDefault(Type.BUG, - Collections.emptyList())) { + for (ChangelogEntry bug : entries.getOrDefault(Type.BUG, Collections.emptyList())) { notes.append("\n - ").append(bug.description); for (String issueTitle : bug.associatedIssueLinksAndTitles.values()) { notes.append("\n\t - ").append(cleanupShortMessage(issueTitle)); @@ -332,8 +306,7 @@ public class GenerateReleaseNotesTask } notes.append("\n\n## :book: Documentation, Tests and Build"); - for (ChangelogEntry misc : entries.getOrDefault(Type.DOC_MISC, - Collections.emptyList())) { + for (ChangelogEntry misc : entries.getOrDefault(Type.DOC_MISC, Collections.emptyList())) { notes.append("\n - ").append(misc.description); for (String issueTitle : misc.associatedIssueLinksAndTitles.values()) { notes.append("\n\t - ").append(cleanupShortMessage(issueTitle)); @@ -341,18 +314,15 @@ public class GenerateReleaseNotesTask } notes.append("\n\n## **TODO DISPATCH THESE**"); - for (ChangelogEntry unclassified : entries.getOrDefault(Type.UNCLASSIFIED, - Collections.emptyList())) { + for (ChangelogEntry unclassified : entries.getOrDefault(Type.UNCLASSIFIED, Collections.emptyList())) { notes.append("\n - ").append(unclassified.description); - for (String issueTitle : unclassified.associatedIssueLinksAndTitles - .values()) { + for (String issueTitle : unclassified.associatedIssueLinksAndTitles.values()) { notes.append("\n\t - ").append(cleanupShortMessage(issueTitle)); } } // contributors - notes.append( - "\n\n## :+1: Thanks to the following contributors that also participated to this release\n"); + notes.append("\n\n## :+1: Thanks to the following contributors that also participated to this release\n"); notes.append(String.join(", ", contributorGithubMentions)); return notes.toString(); @@ -400,8 +370,7 @@ public class GenerateReleaseNotesTask return EnumSet.copyOf(types); } - protected String commitToGithubMention(RepoCommits commitsClient, - SimpleCommit revCommit) { + protected String commitToGithubMention(RepoCommits commitsClient, SimpleCommit revCommit) { RepoCommit dumbCommit = commitsClient.get(revCommit.fullSha1); RepoCommit.Smart smartCommit = new RepoCommit.Smart(dumbCommit); try { @@ -412,17 +381,14 @@ public class GenerateReleaseNotesTask } else if (authorType == JsonValue.ValueType.NULL) { // assume author+committer, look under commit.author.name - if (commitJson.containsKey("commit") - && commitJson.getJsonObject("commit").containsKey("author")) { - return "@" + commitJson.getJsonObject("commit") - .getJsonObject("author").getString("name"); + if (commitJson.containsKey("commit") && commitJson.getJsonObject("commit").containsKey("author")) { + return "@" + commitJson.getJsonObject("commit").getJsonObject("author").getString("name"); } } // in case unexpected json, output the "sha", "commit", "author" and // "committer" - return "@RAW{\"sha\", " + commitJson.get("sha") + ", \"author\", \"" - + commitJson.get("author") + ", \"committer\", \"" - + commitJson.get("committer") + ", \"commit\", \"" + return "@RAW{\"sha\", " + commitJson.get("sha") + ", \"author\", \"" + commitJson.get("author") + + ", \"committer\", \"" + commitJson.get("committer") + ", \"commit\", \"" + commitJson.get("commit") + "}"; } catch (IOException e) { @@ -437,9 +403,8 @@ public class GenerateReleaseNotesTask */ List extractContributorMentions(Repo repo, List revCommits) { RepoCommits commitsClient = repo.commits(); - return revCommits.stream().map(c -> commitToGithubMention(commitsClient, c)) - .filter(Objects::nonNull).distinct().sorted(String.CASE_INSENSITIVE_ORDER) - .collect(Collectors.toList()); + return revCommits.stream().map(c -> commitToGithubMention(commitsClient, c)).filter(Objects::nonNull).distinct() + .sorted(String.CASE_INSENSITIVE_ORDER).collect(Collectors.toList()); } /** @@ -487,8 +452,7 @@ public class GenerateReleaseNotesTask * The labels and titles are injected in a {@link Set} of labels and {@link Map} of * hashtag issue links to issue titles. */ - protected void fetchIssueLabelsAndTitles(Issues issueClient, - Set issueNumbers, Set labelsTarget, + protected void fetchIssueLabelsAndTitles(Issues issueClient, Set issueNumbers, Set labelsTarget, Map referencedIssuesTarget) { issueNumbers.forEach(i -> { try { @@ -496,10 +460,9 @@ public class GenerateReleaseNotesTask // we have everything handy in the JSON Issue issue = issueClient.get(i); JsonObject issueJson = issue.json(); - issueJson.getJsonArray("labels").forEach(label -> labelsTarget - .add(((JsonObject) label).getString("name"))); - referencedIssuesTarget.put("#" + issueJson.getInt("number"), - issueJson.getString("title")); + issueJson.getJsonArray("labels") + .forEach(label -> labelsTarget.add(((JsonObject) label).getString("name"))); + referencedIssuesTarget.put("#" + issueJson.getInt("number"), issueJson.getString("title")); } catch (Exception e) { log.warn("Could not fetch issue information for #" + i, e); @@ -510,20 +473,17 @@ public class GenerateReleaseNotesTask /** * Extract issue information from the commit and generate the {@link ChangelogEntry}. */ - protected ChangelogEntry parseChangeLogEntry(Issues issueClient, - SimpleCommit commit) { + protected ChangelogEntry parseChangeLogEntry(Issues issueClient, SimpleCommit commit) { String cleanShortMessage = cleanupShortMessage(commit); Set issueNumbers = extractIssueNumbers(commit); Set labelsTarget = new HashSet<>(); Map referencedIssuesTarget = new LinkedHashMap<>(); - fetchIssueLabelsAndTitles(issueClient, issueNumbers, labelsTarget, - referencedIssuesTarget); + fetchIssueLabelsAndTitles(issueClient, issueNumbers, labelsTarget, referencedIssuesTarget); EnumSet types = extractTypes(labelsTarget, commit.title); - return new ChangelogEntry(types, commit.abbreviatedSha1, cleanShortMessage, - referencedIssuesTarget); + return new ChangelogEntry(types, commit.abbreviatedSha1, cleanShortMessage, referencedIssuesTarget); } /* @@ -534,8 +494,7 @@ public class GenerateReleaseNotesTask * reflecting the PR number in case there has been extensive review/discussion in that * PR. Both references would be caught by ISSUE_REF pattern below. */ - static Pattern SHORT_MESSAGE = Pattern - .compile("(?:[a-zA-Z]+ #[0-9]+)?([^\\(]+)(?:\\(#[0-9]+\\))?"); + static Pattern SHORT_MESSAGE = Pattern.compile("(?:[a-zA-Z]+ #[0-9]+)?([^\\(]+)(?:\\(#[0-9]+\\))?"); /** * A {@link Pattern} to find issue/pr numbers in a commit message, by detecting @@ -607,8 +566,7 @@ public class GenerateReleaseNotesTask } else { this.description = cleanShortMessage + " (" - + String.join(", ", this.associatedIssueLinksAndTitles.keySet()) - + ")"; + + String.join(", ", this.associatedIssueLinksAndTitles.keySet()) + ")"; } } diff --git a/projects/reactor/src/main/java/releaser/reactor/ReactorConfiguration.java b/projects/reactor/src/main/java/releaser/reactor/ReactorConfiguration.java index 43b86b74..f6d68fee 100644 --- a/projects/reactor/src/main/java/releaser/reactor/ReactorConfiguration.java +++ b/projects/reactor/src/main/java/releaser/reactor/ReactorConfiguration.java @@ -41,27 +41,24 @@ class ReactorConfiguration { } @Bean - RestartSiteProjectPostReleaseTask restartSiteProjectPostReleaseTask(Releaser releaser, - CfClient cfClient, @Value("${cf.reactorAppName}") String reactorAppName) { + RestartSiteProjectPostReleaseTask restartSiteProjectPostReleaseTask(Releaser releaser, CfClient cfClient, + @Value("${cf.reactorAppName}") String reactorAppName) { return new RestartSiteProjectPostReleaseTask(releaser, cfClient, reactorAppName); } @Bean Github githubClient(ReleaserProperties properties) { if (!StringUtils.hasText(properties.getGit().getOauthToken())) { - throw new BeanInitializationException( - "You must set the value of the OAuth token. You can do it " - + "either via the command line [--releaser.git.oauth-token=...] " - + "or put it as an env variable in [~/.bashrc] or " - + "[~/.zshrc] e.g. [export RELEASER_GIT_OAUTH_TOKEN=...]"); + throw new BeanInitializationException("You must set the value of the OAuth token. You can do it " + + "either via the command line [--releaser.git.oauth-token=...] " + + "or put it as an env variable in [~/.bashrc] or " + + "[~/.zshrc] e.g. [export RELEASER_GIT_OAUTH_TOKEN=...]"); } - return new RtGithub(new RtGithub(properties.getGit().getOauthToken()).entry() - .through(RetryWire.class)); + return new RtGithub(new RtGithub(properties.getGit().getOauthToken()).entry().through(RetryWire.class)); } @Bean - GenerateReleaseNotesTask releaseNotesTask(Github github, - ProjectGitHandler gitHandler) { + GenerateReleaseNotesTask releaseNotesTask(Github github, ProjectGitHandler gitHandler) { return new GenerateReleaseNotesTask(github, gitHandler); } diff --git a/projects/reactor/src/main/java/releaser/reactor/RestartSiteProjectPostReleaseTask.java b/projects/reactor/src/main/java/releaser/reactor/RestartSiteProjectPostReleaseTask.java index f5e51b95..8fcc4cc3 100644 --- a/projects/reactor/src/main/java/releaser/reactor/RestartSiteProjectPostReleaseTask.java +++ b/projects/reactor/src/main/java/releaser/reactor/RestartSiteProjectPostReleaseTask.java @@ -31,8 +31,7 @@ public class RestartSiteProjectPostReleaseTask extends PublishDocsReleaseTask { private final String reactorAppName; - public RestartSiteProjectPostReleaseTask(Releaser releaser, CfClient cfClient, - String reactorAppName) { + public RestartSiteProjectPostReleaseTask(Releaser releaser, CfClient cfClient, String reactorAppName) { super(releaser); this.cfClient = cfClient; this.reactorAppName = reactorAppName; @@ -58,8 +57,7 @@ class CfClient { } void restartApp(String name) { - this.cloudFoundryOperations.applications() - .restart(RestartApplicationRequest.builder().name(name).build()); + this.cloudFoundryOperations.applications().restart(RestartApplicationRequest.builder().name(name).build()); } } diff --git a/projects/reactor/src/test/java/releaser/ReleaserApplicationTests.java b/projects/reactor/src/test/java/releaser/ReleaserApplicationTests.java index 9f880058..2243e494 100644 --- a/projects/reactor/src/test/java/releaser/ReleaserApplicationTests.java +++ b/projects/reactor/src/test/java/releaser/ReleaserApplicationTests.java @@ -49,13 +49,11 @@ class ReleaserApplicationTests { @Test void should_load_generate_release_notes_in_dry_run() { - Map beans = context - .getBeansOfType(DryRunReleaseReleaserTask.class); + Map beans = context.getBeansOfType(DryRunReleaseReleaserTask.class); List inOrder = new LinkedList<>(beans.values()); inOrder.sort(AnnotationAwareOrderComparator.INSTANCE); - assertThat(inOrder).anySatisfy( - task -> assertThat(task).isInstanceOf(GenerateReleaseNotesTask.class)); + assertThat(inOrder).anySatisfy(task -> assertThat(task).isInstanceOf(GenerateReleaseNotesTask.class)); } @Test @@ -64,11 +62,9 @@ class ReleaserApplicationTests { List inOrder = new LinkedList<>(beans.values()); inOrder.sort(AnnotationAwareOrderComparator.INSTANCE); - assertThat(inOrder).anySatisfy(task -> assertThat(task) - .isInstanceOf(RestartSiteProjectPostReleaseTask.class)); - assertThat(inOrder).noneSatisfy( - task -> assertThat(task).isInstanceOf(PublishDocsReleaseTask.class) - .isNotInstanceOf(RestartSiteProjectPostReleaseTask.class)); + assertThat(inOrder).anySatisfy(task -> assertThat(task).isInstanceOf(RestartSiteProjectPostReleaseTask.class)); + assertThat(inOrder).noneSatisfy(task -> assertThat(task).isInstanceOf(PublishDocsReleaseTask.class) + .isNotInstanceOf(RestartSiteProjectPostReleaseTask.class)); } diff --git a/projects/reactor/src/test/java/releaser/reactor/GenerateReleaseNotesTaskTest.java b/projects/reactor/src/test/java/releaser/reactor/GenerateReleaseNotesTaskTest.java index fd2f7063..352d8320 100644 --- a/projects/reactor/src/test/java/releaser/reactor/GenerateReleaseNotesTaskTest.java +++ b/projects/reactor/src/test/java/releaser/reactor/GenerateReleaseNotesTaskTest.java @@ -60,23 +60,22 @@ class GenerateReleaseNotesTaskTest { @Test void extractTypeFromLabel() { - assertThat(task.extractTypes(Collections.singleton("type/bug"), "")) - .as("type/bug").containsOnly(Type.BUG); + assertThat(task.extractTypes(Collections.singleton("type/bug"), "")).as("type/bug").containsOnly(Type.BUG); - assertThat(task.extractTypes(Collections.singleton("type/enhancement"), "")) - .as("type/enhancement").containsOnly(Type.FEATURE); + assertThat(task.extractTypes(Collections.singleton("type/enhancement"), "")).as("type/enhancement") + .containsOnly(Type.FEATURE); - assertThat(task.extractTypes(Collections.singleton("type/documentation"), "")) - .as("type/documentation").containsOnly(Type.DOC_MISC); + assertThat(task.extractTypes(Collections.singleton("type/documentation"), "")).as("type/documentation") + .containsOnly(Type.DOC_MISC); - assertThat(task.extractTypes(Collections.singleton("type/chores"), "")) - .as("type/chores").containsOnly(Type.DOC_MISC); + assertThat(task.extractTypes(Collections.singleton("type/chores"), "")).as("type/chores") + .containsOnly(Type.DOC_MISC); - assertThat(task.extractTypes(Collections.singleton("warn/something"), "")) - .as("warn/*").containsOnly(Type.NOTEWORTHY); + assertThat(task.extractTypes(Collections.singleton("warn/something"), "")).as("warn/*") + .containsOnly(Type.NOTEWORTHY); - assertThat(task.extractTypes(Collections.singleton("type/whatever"), "")) - .as("type/whatever").containsOnly(Type.UNCLASSIFIED); + assertThat(task.extractTypes(Collections.singleton("type/whatever"), "")).as("type/whatever") + .containsOnly(Type.UNCLASSIFIED); } @Test @@ -87,179 +86,158 @@ class GenerateReleaseNotesTaskTest { labels.add("type/documentation"); labels.add("whatever"); - assertThat(task.extractTypes(labels, "")).as("multiple labels") - .containsOnly(Type.BUG, Type.FEATURE, Type.DOC_MISC); + assertThat(task.extractTypes(labels, "")).as("multiple labels").containsOnly(Type.BUG, Type.FEATURE, + Type.DOC_MISC); } @Test void extractMiscTypeFromBuildMessagePrefix() { String message = "[build] Foo"; - assertThat(task.extractTypes(Collections.emptySet(), message)) - .containsOnly(Type.DOC_MISC); + assertThat(task.extractTypes(Collections.emptySet(), message)).containsOnly(Type.DOC_MISC); } @Test void extractMiscTypeFromPolishMessagePrefix() { String message = "[polish] Foo"; - assertThat(task.extractTypes(Collections.emptySet(), message)) - .containsOnly(Type.DOC_MISC); + assertThat(task.extractTypes(Collections.emptySet(), message)).containsOnly(Type.DOC_MISC); } @Test void extractMiscTypeFromDocMessagePrefix() { String message = "[doc] Foo"; - assertThat(task.extractTypes(Collections.emptySet(), message)) - .containsOnly(Type.DOC_MISC); + assertThat(task.extractTypes(Collections.emptySet(), message)).containsOnly(Type.DOC_MISC); } @Test void extractUnclassifiedTypeFromRandomMessagePrefix() { String message = "fix #123 There was a [bug], needed to [polish] the [doc]"; - assertThat(task.extractTypes(Collections.emptySet(), message)) - .containsOnly(Type.UNCLASSIFIED); + assertThat(task.extractTypes(Collections.emptySet(), message)).containsOnly(Type.UNCLASSIFIED); } @Test void noTitleCleanupFromMergeCommit() { - SimpleCommit mergeCommit = new SimpleCommit("sha1", "fullsha1", - "merge #123 into 3.3 (#123)", "merge #123 into 3.3", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", true); + SimpleCommit mergeCommit = new SimpleCommit("sha1", "fullsha1", "merge #123 into 3.3 (#123)", + "merge #123 into 3.3", "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", true); - assertThat(task.cleanupShortMessage(mergeCommit)) - .isEqualTo("merge #123 into 3.3 (#123)"); + assertThat(task.cleanupShortMessage(mergeCommit)).isEqualTo("merge #123 into 3.3 (#123)"); } @Test void titleCleanupFixPrefix() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "fix #123 Text from title", "fix #123 Some more text", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "fix #123 Text from title", + "fix #123 Some more text", "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", + false); assertThat(task.cleanupShortMessage(commit)).isEqualTo("Text from title"); } @Test void titleCleanupSeePrefix() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "see #123 Text from title", "see #123 Some more text", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "see #123 Text from title", + "see #123 Some more text", "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", + false); assertThat(task.cleanupShortMessage(commit)).isEqualTo("Text from title"); } @Test void titleCleanupPrStyleSuffix() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "Commit without issue (#123)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "Commit without issue (#123)", "fullMessage", + "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); assertThat(task.cleanupShortMessage(commit)).isEqualTo("Commit without issue"); } @Test void titleCleanupPrStyleSuffixNoSpace() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "Commit without issue(#123)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "Commit without issue(#123)", "fullMessage", + "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); assertThat(task.cleanupShortMessage(commit)).isEqualTo("Commit without issue"); } @Test void titleCleanupBothPrefixAndSuffix() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "prefix #123 Commit title (#123)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "prefix #123 Commit title (#123)", "fullMessage", + "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); assertThat(task.cleanupShortMessage(commit)).isEqualTo("Commit title"); } @Test void issueNumberTitlePrefix() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "prefix #123 Commit title", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "prefix #123 Commit title", "fullMessage", + "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); assertThat(task.extractIssueNumbers(commit)).containsOnly(123); } @Test void issueNumberTitlePrStyleSuffix() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "Commit title (#123)", - "fullMessage", "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", - "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "Commit title (#123)", "fullMessage", "Simon Baslé", + "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); assertThat(task.extractIssueNumbers(commit)).containsOnly(123); } @Test void issueNumberTitlePrefixAndSuffix() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "prefix #123 Commit title (#456)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "prefix #123 Commit title (#456)", "fullMessage", + "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); assertThat(task.extractIssueNumbers(commit)).containsOnly(123, 456); } @Test void issueNumberTitleNotSeparatedBySpace() { - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "prefix#123Commit title(#456)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "prefix#123Commit title(#456)", "fullMessage", + "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); assertThat(task.extractIssueNumbers(commit)).containsOnly(123, 456); } - static final VoidAnswer4, Set, Map> MOCK_FETCH_ISSUES = ( - ignore1, issues, ignore2, resolved) -> issues - .forEach(i -> resolved.put("#" + i, "alternative title for " + i)); + static final VoidAnswer4, Set, Map> MOCK_FETCH_ISSUES = (ignore1, + issues, ignore2, resolved) -> issues.forEach(i -> resolved.put("#" + i, "alternative title for " + i)); static final Issues MOCK_ISSUES = Mockito.mock(Issues.class); @Test void generateChangelogDescriptionSingleIssueTwice() throws IOException { final GenerateReleaseNotesTask spy = Mockito.spy(task); - doAnswer(answerVoid(MOCK_FETCH_ISSUES)).when(spy).fetchIssueLabelsAndTitles(any(), - any(), any(), any()); + doAnswer(answerVoid(MOCK_FETCH_ISSUES)).when(spy).fetchIssueLabelsAndTitles(any(), any(), any(), any()); - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "prefix #123 Commit title (#123)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "prefix #123 Commit title (#123)", "fullMessage", + "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); - assertThat(spy.parseChangeLogEntry(githubClient.randomRepo().issues(), - commit).description).isEqualTo("Commit title (#123)"); + assertThat(spy.parseChangeLogEntry(githubClient.randomRepo().issues(), commit).description) + .isEqualTo("Commit title (#123)"); } @Test void generateChangelogDescriptionTwoIssues() throws IOException { final GenerateReleaseNotesTask spy = Mockito.spy(task); - doAnswer(answerVoid(MOCK_FETCH_ISSUES)).when(spy).fetchIssueLabelsAndTitles(any(), - any(), any(), any()); + doAnswer(answerVoid(MOCK_FETCH_ISSUES)).when(spy).fetchIssueLabelsAndTitles(any(), any(), any(), any()); - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "prefix #123 Commit title (#456)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "prefix #123 Commit title (#456)", "fullMessage", + "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); - assertThat(spy.parseChangeLogEntry(MOCK_ISSUES, commit).description) - .isEqualTo("Commit title (#123, #456)"); + assertThat(spy.parseChangeLogEntry(MOCK_ISSUES, commit).description).isEqualTo("Commit title (#123, #456)"); } @Test void generateChangelogDescriptionTwoIssuesNoSpace() throws IOException { final GenerateReleaseNotesTask spy = Mockito.spy(task); - doAnswer(answerVoid(MOCK_FETCH_ISSUES)).when(spy).fetchIssueLabelsAndTitles(any(), - any(), any(), any()); + doAnswer(answerVoid(MOCK_FETCH_ISSUES)).when(spy).fetchIssueLabelsAndTitles(any(), any(), any(), any()); - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "prefix #123Commit title no space(#456)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "prefix #123Commit title no space(#456)", + "fullMessage", "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); - assertThat(spy.parseChangeLogEntry(githubClient.randomRepo().issues(), - commit).description).isEqualTo("Commit title no space (#123, #456)"); + assertThat(spy.parseChangeLogEntry(githubClient.randomRepo().issues(), commit).description) + .isEqualTo("Commit title no space (#123, #456)"); } @Test @@ -267,12 +245,11 @@ class GenerateReleaseNotesTaskTest { final GenerateReleaseNotesTask spy = Mockito.spy(task); doNothing().when(spy).fetchIssueLabelsAndTitles(any(), any(), any(), any()); - SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", - "prefix #123 Commit title no space(#456)", "fullMessage", "Simon Baslé", - "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); + SimpleCommit commit = new SimpleCommit("sha1", "fullsha1", "prefix #123 Commit title no space(#456)", + "fullMessage", "Simon Baslé", "sbasle@pivotal.io", "Simon Baslé", "sbasle@pivotal.io", false); - assertThat(spy.parseChangeLogEntry(githubClient.randomRepo().issues(), - commit).description).isEqualTo("Commit title no space (sha1)"); + assertThat(spy.parseChangeLogEntry(githubClient.randomRepo().issues(), commit).description) + .isEqualTo("Commit title no space (sha1)"); } @Test @@ -284,9 +261,8 @@ class GenerateReleaseNotesTaskTest { assertThatExceptionOfType(Exception.class).as("github client fails") .isThrownBy(() -> new Issue.Smart(issuesClient.get(123)).title()); - assertThatCode(() -> task.fetchIssueLabelsAndTitles(issuesClient, - Collections.singleton(123), labels, associatedIssues)) - .as("fetching just does nothing").doesNotThrowAnyException(); + assertThatCode(() -> task.fetchIssueLabelsAndTitles(issuesClient, Collections.singleton(123), labels, + associatedIssues)).as("fetching just does nothing").doesNotThrowAnyException(); assertThat(labels).as("labels").isEmpty(); assertThat(associatedIssues).as("associated issues").isEmpty(); diff --git a/projects/reactor/src/test/java/releaser/reactor/ReactorTestConfiguration.java b/projects/reactor/src/test/java/releaser/reactor/ReactorTestConfiguration.java index 53d3d88b..e0afcd95 100644 --- a/projects/reactor/src/test/java/releaser/reactor/ReactorTestConfiguration.java +++ b/projects/reactor/src/test/java/releaser/reactor/ReactorTestConfiguration.java @@ -46,14 +46,13 @@ import org.springframework.context.annotation.Profile; public class ReactorTestConfiguration { @Bean - RestartSiteProjectPostReleaseTask restartSiteProjectPostReleaseTask(Releaser releaser, - CfClient cfClient, @Value("${cf.reactorAppName}") String reactorAppName) { + RestartSiteProjectPostReleaseTask restartSiteProjectPostReleaseTask(Releaser releaser, CfClient cfClient, + @Value("${cf.reactorAppName}") String reactorAppName) { return new RestartSiteProjectPostReleaseTask(releaser, cfClient, reactorAppName); } @Bean - GenerateReleaseNotesTask releaseNotesTask(Github github, - ProjectGitHandler gitHandler) { + GenerateReleaseNotesTask releaseNotesTask(Github github, ProjectGitHandler gitHandler) { return new GenerateReleaseNotesTask(github, gitHandler); } diff --git a/projects/reactor/src/test/java/releaser/reactor/RestartSiteProjectPostReleaseTaskTests.java b/projects/reactor/src/test/java/releaser/reactor/RestartSiteProjectPostReleaseTaskTests.java index 5c63cf29..099ef13f 100644 --- a/projects/reactor/src/test/java/releaser/reactor/RestartSiteProjectPostReleaseTaskTests.java +++ b/projects/reactor/src/test/java/releaser/reactor/RestartSiteProjectPostReleaseTaskTests.java @@ -16,8 +16,6 @@ package releaser.reactor; -import static org.junit.jupiter.api.Assertions.fail; - import org.assertj.core.api.BDDAssertions; import org.junit.jupiter.api.Test; import org.mockito.BDDMockito; @@ -34,6 +32,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; +import static org.junit.jupiter.api.Assertions.fail; + @SpringBootTest @ActiveProfiles("test") class RestartSiteProjectPostReleaseTaskTests { @@ -51,16 +51,13 @@ class RestartSiteProjectPostReleaseTaskTests { ExecutionResult result = task.runTask(arguments); BDDAssertions.then(result.isSuccess()).isTrue(); - BDDMockito.then(this.cfClient).should() - .restartApp(BDDMockito.eq("projectreactor")); + BDDMockito.then(this.cfClient).should().restartApp(BDDMockito.eq("projectreactor")); } @Test void should_fail_if_original_version_is_null() { - ProjectToRun p = new ProjectToRun(null, - new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "1.0.0")), - null, new ReleaserProperties(), - BDDMockito.mock(Options.class)) { + ProjectToRun p = new ProjectToRun(null, new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "1.0.0")), + null, new ReleaserProperties(), BDDMockito.mock(Options.class)) { @Override public String name() { return "reactor-core"; @@ -86,10 +83,8 @@ class RestartSiteProjectPostReleaseTaskTests { } private ProjectToRun reactorCoreProject() { - return new ProjectToRun(null, - new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "1.0.0")), - new ProjectVersion("foo", "1.0.0"), new ReleaserProperties(), - BDDMockito.mock(Options.class)) { + return new ProjectToRun(null, new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "1.0.0")), + new ProjectVersion("foo", "1.0.0"), new ReleaserProperties(), BDDMockito.mock(Options.class)) { @Override public String name() { return "reactor-core"; @@ -98,10 +93,8 @@ class RestartSiteProjectPostReleaseTaskTests { } private ProjectToRun nonReactorCoreProject() { - return new ProjectToRun(null, - new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "1.0.0")), - new ProjectVersion("foo", "1.0.0"), new ReleaserProperties(), - BDDMockito.mock(Options.class)) { + return new ProjectToRun(null, new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "1.0.0")), + new ProjectVersion("foo", "1.0.0"), new ReleaserProperties(), BDDMockito.mock(Options.class)) { @Override public String name() { return "whatever"; diff --git a/projects/reactor/src/test/resources/application-test.yml b/projects/reactor/src/test/resources/application-test.yml index f6d7d3f2..79678c85 100644 --- a/projects/reactor/src/test/resources/application-test.yml +++ b/projects/reactor/src/test/resources/application-test.yml @@ -1,6 +1,3 @@ cf: username: foo - password: bar -spring: - profiles: - active: test \ No newline at end of file + password: bar \ No newline at end of file diff --git a/projects/spring-cloud-stream/src/main/java/releaser/ReleaserApplication.java b/projects/spring-cloud-stream/src/main/java/releaser/ReleaserApplication.java index cb2f3aa4..cafb9dd5 100644 --- a/projects/spring-cloud-stream/src/main/java/releaser/ReleaserApplication.java +++ b/projects/spring-cloud-stream/src/main/java/releaser/ReleaserApplication.java @@ -27,8 +27,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ReleaserApplication extends ReleaserCommandLineRunner { - public ReleaserApplication(SpringReleaser releaser, - ExecutionResultHandler executionResultHandler, Parser parser) { + public ReleaserApplication(SpringReleaser releaser, ExecutionResultHandler executionResultHandler, Parser parser) { super(releaser, executionResultHandler, parser); } diff --git a/projects/spring-cloud-stream/src/main/java/releaser/cloud/buildsystem/SpringCloudBomConstants.java b/projects/spring-cloud-stream/src/main/java/releaser/cloud/buildsystem/SpringCloudBomConstants.java index a3698d1e..ca887bcb 100644 --- a/projects/spring-cloud-stream/src/main/java/releaser/cloud/buildsystem/SpringCloudBomConstants.java +++ b/projects/spring-cloud-stream/src/main/java/releaser/cloud/buildsystem/SpringCloudBomConstants.java @@ -24,8 +24,7 @@ final class SpringCloudBomConstants { // boot static final String SPRING_BOOT = "spring-boot"; static final String BOOT_STARTER_ARTIFACT_ID = "spring-boot-starter"; - static final String BOOT_STARTER_PARENT_ARTIFACT_ID = BOOT_STARTER_ARTIFACT_ID - + "-parent"; + static final String BOOT_STARTER_PARENT_ARTIFACT_ID = BOOT_STARTER_ARTIFACT_ID + "-parent"; static final String BOOT_DEPENDENCIES_ARTIFACT_ID = "spring-boot-dependencies"; // sc-build diff --git a/projects/spring-cloud-stream/src/main/java/releaser/cloud/buildsystem/SpringCloudStreamMavenBomParser.java b/projects/spring-cloud-stream/src/main/java/releaser/cloud/buildsystem/SpringCloudStreamMavenBomParser.java index 629448ad..6b42e6c9 100644 --- a/projects/spring-cloud-stream/src/main/java/releaser/cloud/buildsystem/SpringCloudStreamMavenBomParser.java +++ b/projects/spring-cloud-stream/src/main/java/releaser/cloud/buildsystem/SpringCloudStreamMavenBomParser.java @@ -51,17 +51,15 @@ import static releaser.cloud.buildsystem.SpringCloudBomConstants.STREAM_STARTER_ class SpringCloudStreamMavenBomParser implements CustomBomParser { - private static final Logger log = LoggerFactory - .getLogger(SpringCloudStreamMavenBomParser.class); + private static final Logger log = LoggerFactory.getLogger(SpringCloudStreamMavenBomParser.class); @Override public VersionsFromBom parseBom(File root, ReleaserProperties properties) { VersionsFromBom springCloudBuild = springCloudBuild(root, properties); VersionsFromBom boot = bootVersion(root, properties); - log.debug("Added Spring Cloud Build [{}] and boot versions [{}]", - springCloudBuild, boot); - return new VersionsFromBomBuilder().thisProjectRoot(root) - .releaserProperties(properties).projects(springCloudBuild, boot).merged(); + log.debug("Added Spring Cloud Build [{}] and boot versions [{}]", springCloudBuild, boot); + return new VersionsFromBomBuilder().thisProjectRoot(root).releaserProperties(properties) + .projects(springCloudBuild, boot).merged(); } private VersionsFromBom springCloudBuild(File root, ReleaserProperties properties) { @@ -69,8 +67,8 @@ class SpringCloudStreamMavenBomParser implements CustomBomParser { if (StringUtils.isEmpty(buildVersion)) { return VersionsFromBom.EMPTY_VERSION; } - VersionsFromBom scBuild = new VersionsFromBomBuilder().thisProjectRoot(root) - .releaserProperties(properties).merged(); + VersionsFromBom scBuild = new VersionsFromBomBuilder().thisProjectRoot(root).releaserProperties(properties) + .merged(); scBuild.add(BUILD_ARTIFACT_ID, buildVersion); scBuild.add(CLOUD_DEPENDENCIES_PARENT_ARTIFACT_ID, buildVersion); return scBuild; @@ -87,11 +85,9 @@ class SpringCloudStreamMavenBomParser implements CustomBomParser { } Model model = PomReader.pom(root, properties.getPom().getThisTrainBom()); String buildArtifact = model.getParent().getArtifactId(); - log.debug("[{}] artifact id is equal to [{}]", - CLOUD_DEPENDENCIES_PARENT_ARTIFACT_ID, buildArtifact); + log.debug("[{}] artifact id is equal to [{}]", CLOUD_DEPENDENCIES_PARENT_ARTIFACT_ID, buildArtifact); if (!CLOUD_DEPENDENCIES_PARENT_ARTIFACT_ID.equals(buildArtifact)) { - throw new IllegalStateException( - "The pom doesn't have a [spring-cloud-dependencies-parent] artifact id"); + throw new IllegalStateException("The pom doesn't have a [spring-cloud-dependencies-parent] artifact id"); } buildVersion = model.getParent().getVersion(); log.debug("Spring Cloud Build version is equal to [{}]", buildVersion); @@ -103,8 +99,7 @@ class SpringCloudStreamMavenBomParser implements CustomBomParser { if (StringUtils.hasText(bootVersion)) { return bootVersion; } - String pomWithBootStarterParent = properties.getPom() - .getPomWithBootStarterParent(); + String pomWithBootStarterParent = properties.getPom().getPomWithBootStarterParent(); File pom = new File(root, pomWithBootStarterParent); if (!pom.exists()) { return ""; @@ -117,8 +112,8 @@ class SpringCloudStreamMavenBomParser implements CustomBomParser { log.debug("Boot artifact id is equal to [{}]", bootArtifactId); if (!BOOT_STARTER_PARENT_ARTIFACT_ID.equals(bootArtifactId)) { if (log.isDebugEnabled()) { - throw new IllegalStateException("The pom doesn't have a [" - + BOOT_STARTER_PARENT_ARTIFACT_ID + "] artifact id"); + throw new IllegalStateException( + "The pom doesn't have a [" + BOOT_STARTER_PARENT_ARTIFACT_ID + "] artifact id"); } return ""; } @@ -131,8 +126,8 @@ class SpringCloudStreamMavenBomParser implements CustomBomParser { return VersionsFromBom.EMPTY_VERSION; } log.debug("Boot version is equal to [{}]", bootVersion); - VersionsFromBom versionsFromBom = new VersionsFromBomBuilder() - .thisProjectRoot(root).releaserProperties(properties).merged(); + VersionsFromBom versionsFromBom = new VersionsFromBomBuilder().thisProjectRoot(root) + .releaserProperties(properties).merged(); versionsFromBom.add(SPRING_BOOT, bootVersion); versionsFromBom.add(BOOT_STARTER_PARENT_ARTIFACT_ID, bootVersion); versionsFromBom.add(BOOT_DEPENDENCIES_ARTIFACT_ID, bootVersion); @@ -140,8 +135,7 @@ class SpringCloudStreamMavenBomParser implements CustomBomParser { } @Override - public Set setVersion(Set projects, String projectName, - String version) { + public Set setVersion(Set projects, String projectName, String version) { Set newProjects = new LinkedHashSet<>(projects); switch (projectName) { case SPRING_BOOT: diff --git a/projects/spring-cloud-stream/src/test/java/releaser/ReleaserApplicationTests.java b/projects/spring-cloud-stream/src/test/java/releaser/ReleaserApplicationTests.java index 21e3527a..c3dd22bc 100644 --- a/projects/spring-cloud-stream/src/test/java/releaser/ReleaserApplicationTests.java +++ b/projects/spring-cloud-stream/src/test/java/releaser/ReleaserApplicationTests.java @@ -27,8 +27,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -@SpringBootTest( - classes = { ReleaserApplicationTests.Config.class, ReleaserApplication.class }, +@SpringBootTest(classes = { ReleaserApplicationTests.Config.class, ReleaserApplication.class }, properties = { "releaser.sagan.update-sagan=false" }) class ReleaserApplicationTests { diff --git a/projects/spring-cloud/src/main/java/releaser/ReleaserApplication.java b/projects/spring-cloud/src/main/java/releaser/ReleaserApplication.java index cb2f3aa4..cafb9dd5 100644 --- a/projects/spring-cloud/src/main/java/releaser/ReleaserApplication.java +++ b/projects/spring-cloud/src/main/java/releaser/ReleaserApplication.java @@ -27,8 +27,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ReleaserApplication extends ReleaserCommandLineRunner { - public ReleaserApplication(SpringReleaser releaser, - ExecutionResultHandler executionResultHandler, Parser parser) { + public ReleaserApplication(SpringReleaser releaser, ExecutionResultHandler executionResultHandler, Parser parser) { super(releaser, executionResultHandler, parser); } diff --git a/projects/spring-cloud/src/main/java/releaser/cloud/buildsystem/SpringCloudBomConstants.java b/projects/spring-cloud/src/main/java/releaser/cloud/buildsystem/SpringCloudBomConstants.java index 46973e09..d7341ff8 100644 --- a/projects/spring-cloud/src/main/java/releaser/cloud/buildsystem/SpringCloudBomConstants.java +++ b/projects/spring-cloud/src/main/java/releaser/cloud/buildsystem/SpringCloudBomConstants.java @@ -24,8 +24,7 @@ final class SpringCloudBomConstants { // boot static final String SPRING_BOOT = "spring-boot"; static final String BOOT_STARTER_ARTIFACT_ID = "spring-boot-starter"; - static final String BOOT_STARTER_PARENT_ARTIFACT_ID = BOOT_STARTER_ARTIFACT_ID - + "-parent"; + static final String BOOT_STARTER_PARENT_ARTIFACT_ID = BOOT_STARTER_ARTIFACT_ID + "-parent"; static final String BOOT_DEPENDENCIES_ARTIFACT_ID = "spring-boot-dependencies"; // sc-build diff --git a/projects/spring-cloud/src/main/java/releaser/cloud/buildsystem/SpringCloudMavenBomParser.java b/projects/spring-cloud/src/main/java/releaser/cloud/buildsystem/SpringCloudMavenBomParser.java index a04dba99..48c9af0d 100644 --- a/projects/spring-cloud/src/main/java/releaser/cloud/buildsystem/SpringCloudMavenBomParser.java +++ b/projects/spring-cloud/src/main/java/releaser/cloud/buildsystem/SpringCloudMavenBomParser.java @@ -52,17 +52,15 @@ import static releaser.cloud.buildsystem.SpringCloudBomConstants.STREAM_STARTER_ class SpringCloudMavenBomParser implements CustomBomParser { - private static final Logger log = LoggerFactory - .getLogger(SpringCloudMavenBomParser.class); + private static final Logger log = LoggerFactory.getLogger(SpringCloudMavenBomParser.class); @Override public VersionsFromBom parseBom(File root, ReleaserProperties properties) { VersionsFromBom springCloudBuild = springCloudBuild(root, properties); VersionsFromBom boot = bootVersion(root, properties); - log.debug("Added Spring Cloud Build [{}] and boot versions [{}]", - springCloudBuild, boot); - return new VersionsFromBomBuilder().thisProjectRoot(root) - .releaserProperties(properties).projects(springCloudBuild, boot).merged(); + log.debug("Added Spring Cloud Build [{}] and boot versions [{}]", springCloudBuild, boot); + return new VersionsFromBomBuilder().thisProjectRoot(root).releaserProperties(properties) + .projects(springCloudBuild, boot).merged(); } private VersionsFromBom springCloudBuild(File root, ReleaserProperties properties) { @@ -70,8 +68,8 @@ class SpringCloudMavenBomParser implements CustomBomParser { if (StringUtils.isEmpty(buildVersion)) { return VersionsFromBom.EMPTY_VERSION; } - VersionsFromBom scBuild = new VersionsFromBomBuilder().thisProjectRoot(root) - .releaserProperties(properties).merged(); + VersionsFromBom scBuild = new VersionsFromBomBuilder().thisProjectRoot(root).releaserProperties(properties) + .merged(); scBuild.add(BUILD_ARTIFACT_ID, buildVersion); scBuild.add(CLOUD_DEPENDENCIES_PARENT_ARTIFACT_ID, buildVersion); return scBuild; @@ -88,11 +86,9 @@ class SpringCloudMavenBomParser implements CustomBomParser { } Model model = PomReader.pom(root, properties.getPom().getThisTrainBom()); String buildArtifact = model.getParent().getArtifactId(); - log.debug("[{}] artifact id is equal to [{}]", - CLOUD_DEPENDENCIES_PARENT_ARTIFACT_ID, buildArtifact); + log.debug("[{}] artifact id is equal to [{}]", CLOUD_DEPENDENCIES_PARENT_ARTIFACT_ID, buildArtifact); if (!CLOUD_DEPENDENCIES_PARENT_ARTIFACT_ID.equals(buildArtifact)) { - throw new IllegalStateException( - "The pom doesn't have a [spring-cloud-dependencies-parent] artifact id"); + throw new IllegalStateException("The pom doesn't have a [spring-cloud-dependencies-parent] artifact id"); } buildVersion = model.getParent().getVersion(); log.debug("Spring Cloud Build version is equal to [{}]", buildVersion); @@ -104,8 +100,7 @@ class SpringCloudMavenBomParser implements CustomBomParser { if (StringUtils.hasText(bootVersion)) { return bootVersion; } - String pomWithBootStarterParent = properties.getPom() - .getPomWithBootStarterParent(); + String pomWithBootStarterParent = properties.getPom().getPomWithBootStarterParent(); File pom = new File(root, pomWithBootStarterParent); if (!pom.exists()) { return ""; @@ -118,8 +113,8 @@ class SpringCloudMavenBomParser implements CustomBomParser { log.debug("Boot artifact id is equal to [{}]", bootArtifactId); if (!BOOT_STARTER_PARENT_ARTIFACT_ID.equals(bootArtifactId)) { if (log.isDebugEnabled()) { - throw new IllegalStateException("The pom doesn't have a [" - + BOOT_STARTER_PARENT_ARTIFACT_ID + "] artifact id"); + throw new IllegalStateException( + "The pom doesn't have a [" + BOOT_STARTER_PARENT_ARTIFACT_ID + "] artifact id"); } return ""; } @@ -132,8 +127,8 @@ class SpringCloudMavenBomParser implements CustomBomParser { return VersionsFromBom.EMPTY_VERSION; } log.debug("Boot version is equal to [{}]", bootVersion); - VersionsFromBom versionsFromBom = new VersionsFromBomBuilder() - .thisProjectRoot(root).releaserProperties(properties).merged(); + VersionsFromBom versionsFromBom = new VersionsFromBomBuilder().thisProjectRoot(root) + .releaserProperties(properties).merged(); versionsFromBom.add(SPRING_BOOT, bootVersion); versionsFromBom.add(BOOT_STARTER_PARENT_ARTIFACT_ID, bootVersion); versionsFromBom.add(BOOT_DEPENDENCIES_ARTIFACT_ID, bootVersion); @@ -141,8 +136,7 @@ class SpringCloudMavenBomParser implements CustomBomParser { } @Override - public Set setVersion(Set projects, String projectName, - String version) { + public Set setVersion(Set projects, String projectName, String version) { Set newProjects = new LinkedHashSet<>(projects); switch (projectName) { case SPRING_BOOT: diff --git a/projects/spring-cloud/src/main/java/releaser/cloud/docs/SpringCloudCustomProjectDocumentationUpdater.java b/projects/spring-cloud/src/main/java/releaser/cloud/docs/SpringCloudCustomProjectDocumentationUpdater.java index f996909b..d79639a3 100644 --- a/projects/spring-cloud/src/main/java/releaser/cloud/docs/SpringCloudCustomProjectDocumentationUpdater.java +++ b/projects/spring-cloud/src/main/java/releaser/cloud/docs/SpringCloudCustomProjectDocumentationUpdater.java @@ -35,18 +35,15 @@ import org.springframework.util.StringUtils; /** * @author Marcin Grzejszczak */ -class SpringCloudCustomProjectDocumentationUpdater - implements CustomProjectDocumentationUpdater { +class SpringCloudCustomProjectDocumentationUpdater implements CustomProjectDocumentationUpdater { - private static final Logger log = LoggerFactory - .getLogger(SpringCloudCustomProjectDocumentationUpdater.class); + private static final Logger log = LoggerFactory.getLogger(SpringCloudCustomProjectDocumentationUpdater.class); private final ProjectGitHandler gitHandler; private final ReleaserProperties releaserProperties; - SpringCloudCustomProjectDocumentationUpdater(ProjectGitHandler gitHandler, - ReleaserProperties releaserProperties) { + SpringCloudCustomProjectDocumentationUpdater(ProjectGitHandler gitHandler, ReleaserProperties releaserProperties) { this.gitHandler = gitHandler; this.releaserProperties = releaserProperties; } @@ -60,11 +57,10 @@ class SpringCloudCustomProjectDocumentationUpdater * used */ @Override - public File updateDocsRepoForReleaseTrain(File clonedDocumentationProject, - ProjectVersion currentProject, Projects projects, String bomBranch) { + public File updateDocsRepoForReleaseTrain(File clonedDocumentationProject, ProjectVersion currentProject, + Projects projects, String bomBranch) { if (!currentProject.projectName.startsWith("spring-cloud")) { - log.info( - "Skipping updating docs for project [{}] that does not start with spring-cloud prefix", + log.info("Skipping updating docs for project [{}] that does not start with spring-cloud prefix", currentProject.projectName); return clonedDocumentationProject; } @@ -72,12 +68,10 @@ class SpringCloudCustomProjectDocumentationUpdater ProjectVersion releaseTrainProject = new ProjectVersion( this.releaserProperties.getMetaRelease().getReleaseTrainProjectName(), branchToReleaseVersion(bomBranch)); - File currentReleaseFolder = new File(clonedDocumentationProject, - currentFolder(releaseTrainProject)); + File currentReleaseFolder = new File(clonedDocumentationProject, currentFolder(releaseTrainProject)); // remove the old way removeAFolderWithRedirection(currentReleaseFolder); - File docsRepo = updateTheDocsRepo(releaseTrainProject, clonedDocumentationProject, - currentReleaseFolder); + File docsRepo = updateTheDocsRepo(releaseTrainProject, clonedDocumentationProject, currentReleaseFolder); return pushChanges(docsRepo); } @@ -89,8 +83,8 @@ class SpringCloudCustomProjectDocumentationUpdater * used */ @Override - public File updateDocsRepoForSingleProject(File clonedDocumentationProject, - ProjectVersion currentProject, Projects projects) { + public File updateDocsRepoForSingleProject(File clonedDocumentationProject, ProjectVersion currentProject, + Projects projects) { if (!projects.containsProject(currentProject.projectName)) { log.warn( "Can't update the documentation repo for project [{}] cause it's not present on the projects list {}", @@ -98,23 +92,18 @@ class SpringCloudCustomProjectDocumentationUpdater return clonedDocumentationProject; } if (!currentProject.projectName.startsWith("spring-cloud")) { - log.info( - "Skipping updating docs for project [{}] that does not start with spring-cloud prefix", + log.info("Skipping updating docs for project [{}] that does not start with spring-cloud prefix", currentProject.projectName); return clonedDocumentationProject; } - log.info("Updating link to documentation for project [{}]", - currentProject.projectName); - ProjectVersion currentProjectVersion = projects - .forName(currentProject.projectName); - File currentProjectReleaseFolder = new File(clonedDocumentationProject, - currentFolder(currentProjectVersion)); + log.info("Updating link to documentation for project [{}]", currentProject.projectName); + ProjectVersion currentProjectVersion = projects.forName(currentProject.projectName); + File currentProjectReleaseFolder = new File(clonedDocumentationProject, currentFolder(currentProjectVersion)); removeAFolderWithRedirection(currentProjectReleaseFolder); try { - updateTheDocsRepo(currentProjectVersion, clonedDocumentationProject, - currentProjectReleaseFolder); - log.info("Processed [{}] for project with name [{}]", - currentProjectReleaseFolder, currentProjectVersion.projectName); + updateTheDocsRepo(currentProjectVersion, clonedDocumentationProject, currentProjectReleaseFolder); + log.info("Processed [{}] for project with name [{}]", currentProjectReleaseFolder, + currentProjectVersion.projectName); } catch (Exception ex) { log.warn("Exception occurred while trying o update the symlink of a project [" @@ -140,14 +129,13 @@ class SpringCloudCustomProjectDocumentationUpdater releaseTrain = currentProjectVersion.isReleaseTrain(); } catch (IllegalStateException ex) { - log.warn("Exception occurred while trying to resolve if version [" - + currentProjectVersion + "] is a release train", ex); + log.warn("Exception occurred while trying to resolve if version [" + currentProjectVersion + + "] is a release train", ex); releaseTrain = false; } // release train -> static/current // project -> static/spring-cloud-sleuth/current - return releaseTrain ? "current" - : (StringUtils.hasText(projectName) ? projectName : "") + "/current"; + return releaseTrain ? "current" : (StringUtils.hasText(projectName) ? projectName : "") + "/current"; } String linkToVersion(File file) { @@ -176,33 +164,28 @@ class SpringCloudCustomProjectDocumentationUpdater return docsRepo; } - private File updateTheDocsRepo(ProjectVersion projectVersion, - File documentationProject, File currentVersionFolder) { + private File updateTheDocsRepo(ProjectVersion projectVersion, File documentationProject, + File currentVersionFolder) { try { String storedVersion = linkToVersion(currentVersionFolder); String currentVersion = projectVersion.version; - boolean newerVersion = StringUtils.isEmpty(storedVersion) - || isMoreMature(storedVersion, currentVersion); + boolean newerVersion = StringUtils.isEmpty(storedVersion) || isMoreMature(storedVersion, currentVersion); if (!newerVersion) { - log.info("Current version [{}] is not newer than the stored one [{}]", - currentVersion, storedVersion); + log.info("Current version [{}] is not newer than the stored one [{}]", currentVersion, storedVersion); return documentationProject; } boolean deleted = Files.deleteIfExists(currentVersionFolder.toPath()) || FileSystemUtils.deleteRecursively(currentVersionFolder.toPath()); if (deleted) { - log.info("Deleted current version folder link at [{}]", - currentVersionFolder); + log.info("Deleted current version folder link at [{}]", currentVersionFolder); } boolean creatingParentDirs = currentVersionFolder.getParentFile().mkdirs(); if (!creatingParentDirs) { - log.warn("Failed to create parent directory of [{}]", - currentVersionFolder); + log.warn("Failed to create parent directory of [{}]", currentVersionFolder); } File newTarget = new File(projectVersion.version); Files.createSymbolicLink(currentVersionFolder.toPath(), newTarget.toPath()); - log.info("Updated the link [{}] to point to [{}]", - currentVersionFolder.toPath(), + log.info("Updated the link [{}] to point to [{}]", currentVersionFolder.toPath(), Files.readSymbolicLink(currentVersionFolder.toPath())); return commitChanges(currentVersion, documentationProject); } @@ -212,8 +195,7 @@ class SpringCloudCustomProjectDocumentationUpdater } private boolean isMoreMature(String storedVersion, String currentVersion) { - return new ProjectVersion("project", currentVersion) - .isMoreMature(new ProjectVersion("project", storedVersion)); + return new ProjectVersion("project", currentVersion).isMoreMature(new ProjectVersion("project", storedVersion)); } private String branchToReleaseVersion(String branch) { @@ -223,8 +205,7 @@ class SpringCloudCustomProjectDocumentationUpdater return branch; } - private File commitChanges(String currentVersion, File documentationProject) - throws IOException { + private File commitChanges(String currentVersion, File documentationProject) throws IOException { log.info("Updated the symbolic links"); this.gitHandler.commit(documentationProject, "Updating the link to the current version to [" + currentVersion + "]"); diff --git a/projects/spring-cloud/src/main/java/releaser/cloud/docs/SpringCloudDocsConfiguration.java b/projects/spring-cloud/src/main/java/releaser/cloud/docs/SpringCloudDocsConfiguration.java index 64004340..c81c12c8 100644 --- a/projects/spring-cloud/src/main/java/releaser/cloud/docs/SpringCloudDocsConfiguration.java +++ b/projects/spring-cloud/src/main/java/releaser/cloud/docs/SpringCloudDocsConfiguration.java @@ -26,10 +26,9 @@ import org.springframework.context.annotation.Configuration; class SpringCloudDocsConfiguration { @Bean - SpringCloudCustomProjectDocumentationUpdater springCloudCustomProjectDocumentationUpdater( - ProjectGitHandler handler, ReleaserProperties releaserProperties) { - return new SpringCloudCustomProjectDocumentationUpdater(handler, - releaserProperties); + SpringCloudCustomProjectDocumentationUpdater springCloudCustomProjectDocumentationUpdater(ProjectGitHandler handler, + ReleaserProperties releaserProperties) { + return new SpringCloudCustomProjectDocumentationUpdater(handler, releaserProperties); } } diff --git a/projects/spring-cloud/src/main/java/releaser/cloud/github/SpringCloudGithubConfiguration.java b/projects/spring-cloud/src/main/java/releaser/cloud/github/SpringCloudGithubConfiguration.java index 3e6f00c0..4bcb04c6 100644 --- a/projects/spring-cloud/src/main/java/releaser/cloud/github/SpringCloudGithubConfiguration.java +++ b/projects/spring-cloud/src/main/java/releaser/cloud/github/SpringCloudGithubConfiguration.java @@ -25,8 +25,7 @@ import org.springframework.context.annotation.Configuration; class SpringCloudGithubConfiguration { @Bean - SpringCloudGithubIssues springCloudGithubIssues( - ReleaserProperties releaserProperties) { + SpringCloudGithubIssues springCloudGithubIssues(ReleaserProperties releaserProperties) { return new SpringCloudGithubIssues(releaserProperties); } diff --git a/projects/spring-cloud/src/main/java/releaser/cloud/github/SpringCloudGithubIssues.java b/projects/spring-cloud/src/main/java/releaser/cloud/github/SpringCloudGithubIssues.java index b0261b42..76c0d99b 100644 --- a/projects/spring-cloud/src/main/java/releaser/cloud/github/SpringCloudGithubIssues.java +++ b/projects/spring-cloud/src/main/java/releaser/cloud/github/SpringCloudGithubIssues.java @@ -47,16 +47,14 @@ class SpringCloudGithubIssues implements CustomGithubIssues { public void fileIssueInSpringGuides(Projects projects, ProjectVersion version) { String user = "spring-guides"; String repo = "getting-started-guides"; - this.githubIssueFiler.fileAGitHubIssue(user, repo, version, issueTitle(), - guidesIssueText(projects)); + this.githubIssueFiler.fileAGitHubIssue(user, repo, version, issueTitle(), guidesIssueText(projects)); } @Override public void fileIssueInStartSpringIo(Projects projects, ProjectVersion version) { String user = "spring-io"; String repo = "start.spring.io"; - this.githubIssueFiler.fileAGitHubIssue(user, repo, version, issueTitle(), - startSpringIoIssueText(projects)); + this.githubIssueFiler.fileAGitHubIssue(user, repo, version, issueTitle(), startSpringIoIssueText(projects)); } private String issueTitle() { @@ -72,21 +70,18 @@ class SpringCloudGithubIssues implements CustomGithubIssues { } private String startSpringIoIssueText(Projects projects) { - String springBootVersion = projects.containsProject("spring-boot") - ? projects.forName("spring-boot").version : ""; - return "Release train [" - + this.properties.getMetaRelease().getReleaseTrainProjectName() - + "] in version [" + parsedVersion() - + "] released with the Spring Boot version [`" + springBootVersion + "`]"; + String springBootVersion = projects.containsProject("spring-boot") ? projects.forName("spring-boot").version + : ""; + return "Release train [" + this.properties.getMetaRelease().getReleaseTrainProjectName() + "] in version [" + + parsedVersion() + "] released with the Spring Boot version [`" + springBootVersion + "`]"; } private String guidesIssueText(Projects projects) { StringBuilder builder = new StringBuilder().append("Release train [") - .append(this.properties.getMetaRelease().getReleaseTrainProjectName()) - .append("] in version [").append(parsedVersion()) - .append("] released with the following projects:").append("\n\n"); - projects.forEach(project -> builder.append(project.projectName).append(" : ") - .append("`").append(project.version).append("`").append("\n")); + .append(this.properties.getMetaRelease().getReleaseTrainProjectName()).append("] in version [") + .append(parsedVersion()).append("] released with the following projects:").append("\n\n"); + projects.forEach(project -> builder.append(project.projectName).append(" : ").append("`") + .append(project.version).append("`").append("\n")); return builder.toString(); } diff --git a/projects/spring-cloud/src/test/java/releaser/ReleaserApplicationTests.java b/projects/spring-cloud/src/test/java/releaser/ReleaserApplicationTests.java index 21e3527a..c3dd22bc 100644 --- a/projects/spring-cloud/src/test/java/releaser/ReleaserApplicationTests.java +++ b/projects/spring-cloud/src/test/java/releaser/ReleaserApplicationTests.java @@ -27,8 +27,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -@SpringBootTest( - classes = { ReleaserApplicationTests.Config.class, ReleaserApplication.class }, +@SpringBootTest(classes = { ReleaserApplicationTests.Config.class, ReleaserApplication.class }, properties = { "releaser.sagan.update-sagan=false" }) class ReleaserApplicationTests { diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/SpringCloudReleaserProperties.java b/projects/spring-cloud/src/test/java/releaser/cloud/SpringCloudReleaserProperties.java index a950b984..97db06dc 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/SpringCloudReleaserProperties.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/SpringCloudReleaserProperties.java @@ -32,17 +32,13 @@ public class SpringCloudReleaserProperties { public static ReleaserProperties get() { try { - File releaserConfig = new File(SpringCloudReleaserProperties.class - .getResource("/application.yml").toURI()); + File releaserConfig = new File(SpringCloudReleaserProperties.class.getResource("/application.yml").toURI()); YamlPropertiesFactoryBean yamlProcessor = new YamlPropertiesFactoryBean(); yamlProcessor.setResources(new FileSystemResource(releaserConfig)); Properties properties = yamlProcessor.getObject(); - ReleaserProperties releaserProperties = new Binder( - new MapConfigurationPropertySource(properties.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().toString(), - e -> e.getValue().toString())))) - .bind("releaser", ReleaserProperties.class) - .get(); + ReleaserProperties releaserProperties = new Binder(new MapConfigurationPropertySource(properties.entrySet() + .stream().collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString())))) + .bind("releaser", ReleaserProperties.class).get(); return releaserProperties; } catch (URISyntaxException e) { diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudCustomMavenBomTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudCustomMavenBomTests.java index e988b750..1862dcf4 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudCustomMavenBomTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudCustomMavenBomTests.java @@ -37,80 +37,59 @@ public class SpringCloudCustomMavenBomTests { @Test public void should_add_boot_to_versions_when_version_is_created() { - List bomParsers = Collections - .singletonList(new SpringCloudMavenBomParser()); + List bomParsers = Collections.singletonList(new SpringCloudMavenBomParser()); VersionsFromBom customVersionsFromBom = new VersionsFromBomBuilder() - .releaserProperties(SpringCloudReleaserProperties.get()) - .parsers(bomParsers).projects(springCloudBuildProjects()) - .retrieveFromBom(); + .releaserProperties(SpringCloudReleaserProperties.get()).parsers(bomParsers) + .projects(springCloudBuildProjects()).retrieveFromBom(); customVersionsFromBom.setVersion("spring-boot", "1.2.3.RELEASE"); - then(customVersionsFromBom.versionForProject("spring-boot")) - .isEqualTo("1.2.3.RELEASE"); - then(customVersionsFromBom.versionForProject("spring-boot-starter-parent")) - .isEqualTo("1.2.3.RELEASE"); - then(customVersionsFromBom.versionForProject("spring-boot-dependencies")) - .isEqualTo("1.2.3.RELEASE"); + then(customVersionsFromBom.versionForProject("spring-boot")).isEqualTo("1.2.3.RELEASE"); + then(customVersionsFromBom.versionForProject("spring-boot-starter-parent")).isEqualTo("1.2.3.RELEASE"); + then(customVersionsFromBom.versionForProject("spring-boot-dependencies")).isEqualTo("1.2.3.RELEASE"); } @Test public void should_update_projects_for_boot() { - VersionsFromBom versionsFromBom = mixedVersions().setVersion("spring-boot", - "3.0.0"); + VersionsFromBom versionsFromBom = mixedVersions().setVersion("spring-boot", "3.0.0"); then(versionsFromBom.versionForProject("spring-boot")).isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-boot-starter-parent")) - .isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-boot-dependencies")) - .isEqualTo("3.0.0"); + then(versionsFromBom.versionForProject("spring-boot-starter-parent")).isEqualTo("3.0.0"); + then(versionsFromBom.versionForProject("spring-boot-dependencies")).isEqualTo("3.0.0"); - versionsFromBom = mixedVersions().setVersion("spring-boot-starter-parent", - "3.0.0"); + versionsFromBom = mixedVersions().setVersion("spring-boot-starter-parent", "3.0.0"); then(versionsFromBom.versionForProject("spring-boot")).isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-boot-starter-parent")) - .isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-boot-dependencies")) - .isEqualTo("3.0.0"); + then(versionsFromBom.versionForProject("spring-boot-starter-parent")).isEqualTo("3.0.0"); + then(versionsFromBom.versionForProject("spring-boot-dependencies")).isEqualTo("3.0.0"); versionsFromBom = mixedVersions().setVersion("spring-boot-dependencies", "3.0.0"); then(versionsFromBom.versionForProject("spring-boot")).isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-boot-starter-parent")) - .isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-boot-dependencies")) - .isEqualTo("3.0.0"); + then(versionsFromBom.versionForProject("spring-boot-starter-parent")).isEqualTo("3.0.0"); + then(versionsFromBom.versionForProject("spring-boot-dependencies")).isEqualTo("3.0.0"); } @Test public void should_update_projects_for_build() { - VersionsFromBom versionsFromBom = mixedVersions().setVersion("spring-cloud-build", - "3.0.0"); + VersionsFromBom versionsFromBom = mixedVersions().setVersion("spring-cloud-build", "3.0.0"); then(versionsFromBom.versionForProject("spring-cloud-build")).isEqualTo("3.0.0"); versionsFromBom = mixedVersions().setVersion("spring-cloud-build", "3.0.0"); - then(versionsFromBom.versionForProject("spring-cloud-dependencies-parent")) - .isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-cloud-dependencies")) - .isEqualTo("Greenwich.RELEASE"); + then(versionsFromBom.versionForProject("spring-cloud-dependencies-parent")).isEqualTo("3.0.0"); + then(versionsFromBom.versionForProject("spring-cloud-dependencies")).isEqualTo("Greenwich.RELEASE"); - versionsFromBom = mixedVersions().setVersion("spring-cloud-dependencies-parent", - "3.0.0"); + versionsFromBom = mixedVersions().setVersion("spring-cloud-dependencies-parent", "3.0.0"); then(versionsFromBom.versionForProject("spring-cloud-build")).isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-cloud-dependencies-parent")) - .isEqualTo("3.0.0"); - then(versionsFromBom.versionForProject("spring-cloud-dependencies")) - .isEqualTo("Greenwich.RELEASE"); + then(versionsFromBom.versionForProject("spring-cloud-dependencies-parent")).isEqualTo("3.0.0"); + then(versionsFromBom.versionForProject("spring-cloud-dependencies")).isEqualTo("Greenwich.RELEASE"); } private VersionsFromBom mixedVersions() { - return new VersionsFromBomBuilder() - .releaserProperties(SpringCloudReleaserProperties.get()) - .parsers(Collections.singletonList(new SpringCloudMavenBomParser())) - .projects(mixedProjects()).merged(); + return new VersionsFromBomBuilder().releaserProperties(SpringCloudReleaserProperties.get()) + .parsers(Collections.singletonList(new SpringCloudMavenBomParser())).projects(mixedProjects()).merged(); } Set springCloudBuildProjects() { diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudMavenBomParserTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudMavenBomParserTests.java index 717ae82c..3eca8aa0 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudMavenBomParserTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudMavenBomParserTests.java @@ -57,31 +57,26 @@ public class SpringCloudMavenBomParserTests { this.tmpFolder = this.tmp.newFolder(); TestUtils.prepareLocalRepo(); FileSystemUtils.copyRecursively(file("/projects"), this.tmpFolder); - this.springCloudReleaseProject = new File(this.tmpFolder, - "/spring-cloud-release"); + this.springCloudReleaseProject = new File(this.tmpFolder, "/spring-cloud-release"); } private File file(String relativePath) throws URISyntaxException { - return new File( - SpringCloudMavenBomParserTests.class.getResource(relativePath).toURI()); + return new File(SpringCloudMavenBomParserTests.class.getResource(relativePath).toURI()); } @Test public void should_throw_exception_when_null_is_passed_to_boot() { this.properties.getPom().setPomWithBootStarterParent(null); this.properties.getPom().setThisTrainBom(null); - BomParser parser = MavenBomParserAccessor.bomParser(this.properties, - new SpringCloudMavenBomParser()); + BomParser parser = MavenBomParserAccessor.bomParser(this.properties, new SpringCloudMavenBomParser()); thenThrownBy(() -> parser.versionsFromBom(this.springCloudReleaseProject)) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Pom is not present"); + .isInstanceOf(IllegalStateException.class).hasMessageContaining("Pom is not present"); } @Test public void should_populate_sc_release_version() { - BomParser parser = MavenBomParserAccessor.bomParser(this.properties, - new SpringCloudMavenBomParser()); + BomParser parser = MavenBomParserAccessor.bomParser(this.properties, new SpringCloudMavenBomParser()); String scReleaseVersion = parser.versionsFromBom(this.springCloudReleaseProject) .versionForProject("spring-cloud-release"); @@ -91,22 +86,18 @@ public class SpringCloudMavenBomParserTests { @Test public void should_populate_boot_version() { - BomParser parser = MavenBomParserAccessor.bomParser(this.properties, - new SpringCloudMavenBomParser()); + BomParser parser = MavenBomParserAccessor.bomParser(this.properties, new SpringCloudMavenBomParser()); - String bootVersion = parser.versionsFromBom(this.springCloudReleaseProject) - .versionForProject("spring-boot"); + String bootVersion = parser.versionsFromBom(this.springCloudReleaseProject).versionForProject("spring-boot"); then(bootVersion).isNotBlank(); } @Test public void should_throw_exception_when_cloud_pom_is_missing() { - BomParser parser = MavenBomParserAccessor.bomParser(this.properties, - new SpringCloudMavenBomParser()); + BomParser parser = MavenBomParserAccessor.bomParser(this.properties, new SpringCloudMavenBomParser()); - thenThrownBy(() -> parser.versionsFromBom(new File("."))) - .isInstanceOf(IllegalStateException.class) + thenThrownBy(() -> parser.versionsFromBom(new File("."))).isInstanceOf(IllegalStateException.class) .hasMessageContaining("Pom is not present"); } @@ -114,54 +105,44 @@ public class SpringCloudMavenBomParserTests { public void should_throw_exception_when_null_is_passed_to_cloud() { this.properties.getPom().setPomWithBootStarterParent(null); this.properties.getPom().setThisTrainBom(null); - BomParser parser = MavenBomParserAccessor.bomParser(this.properties, - new SpringCloudMavenBomParser()); + BomParser parser = MavenBomParserAccessor.bomParser(this.properties, new SpringCloudMavenBomParser()); thenThrownBy(() -> parser.versionsFromBom(this.springCloudReleaseProject)) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Pom is not present"); + .isInstanceOf(IllegalStateException.class).hasMessageContaining("Pom is not present"); } @Test public void should_throw_exception_when_cloud_version_is_missing_in_pom() { this.properties.getPom().setPomWithBootStarterParent("pom.xml"); this.properties.getPom().setThisTrainBom("pom.xml"); - BomParser parser = MavenBomParserAccessor.bomParser(this.properties, - new SpringCloudMavenBomParser()); + BomParser parser = MavenBomParserAccessor.bomParser(this.properties, new SpringCloudMavenBomParser()); thenThrownBy(() -> parser.versionsFromBom(this.springCloudReleaseProject)) - .isInstanceOf(IllegalStateException.class).hasMessageContaining( - "The pom doesn't have a [spring-cloud-dependencies-parent] artifact id"); + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("The pom doesn't have a [spring-cloud-dependencies-parent] artifact id"); } @Test public void should_populate_cloud_version() { - BomParser parser = MavenBomParserAccessor.bomParser(this.properties, - new SpringCloudMavenBomParser()); + BomParser parser = MavenBomParserAccessor.bomParser(this.properties, new SpringCloudMavenBomParser()); - VersionsFromBom cloudVersionsFromBom = parser - .versionsFromBom(this.springCloudReleaseProject); + VersionsFromBom cloudVersionsFromBom = parser.versionsFromBom(this.springCloudReleaseProject); thenAllCloudVersionsSet(cloudVersionsFromBom); } private void thenAllCloudVersionsSet(VersionsFromBom cloudVersionsFromBom) { - Arrays.asList("spring-cloud-bus", "spring-cloud-contract", - "spring-cloud-cloudfoundry", "spring-cloud-commons", - "spring-cloud-config", "spring-cloud-netflix", "spring-cloud-security", - "spring-cloud-consul", "spring-cloud-sleuth", "spring-cloud-stream", - "spring-cloud-task", "spring-cloud-vault", "spring-cloud-zookeeper") - .forEach(s -> then(cloudVersionsFromBom.versionForProject(s)) - .isNotBlank()); + Arrays.asList("spring-cloud-bus", "spring-cloud-contract", "spring-cloud-cloudfoundry", "spring-cloud-commons", + "spring-cloud-config", "spring-cloud-netflix", "spring-cloud-security", "spring-cloud-consul", + "spring-cloud-sleuth", "spring-cloud-stream", "spring-cloud-task", "spring-cloud-vault", + "spring-cloud-zookeeper").forEach(s -> then(cloudVersionsFromBom.versionForProject(s)).isNotBlank()); } @Test public void should_populate_boot_and_cloud_version() { - BomParser parser = MavenBomParserAccessor.bomParser(this.properties, - new SpringCloudMavenBomParser()); + BomParser parser = MavenBomParserAccessor.bomParser(this.properties, new SpringCloudMavenBomParser()); - VersionsFromBom cloudVersionsFromBom = parser - .versionsFromBom(this.springCloudReleaseProject); + VersionsFromBom cloudVersionsFromBom = parser.versionsFromBom(this.springCloudReleaseProject); then(cloudVersionsFromBom.versionForProject("spring-boot")).isNotBlank(); then(cloudVersionsFromBom.versionForProject("spring-cloud-build")).isNotBlank(); diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudProjectPomUpdaterTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudProjectPomUpdaterTests.java index ef0ef6d3..af473ad9 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudProjectPomUpdaterTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/buildsystem/SpringCloudProjectPomUpdaterTests.java @@ -36,41 +36,31 @@ public class SpringCloudProjectPomUpdaterTests { public void should_convert_fixed_versions_to_updated_fixed_versions() { ReleaserProperties properties = SpringCloudReleaserProperties.get(); properties.getFixedVersions().put("spring-cloud-task", "2.0.0.RELEASE"); - properties.getFixedVersions().put("spring-cloud-openfeign", - "2.0.1.BUILD-SNAPSHOT"); + properties.getFixedVersions().put("spring-cloud-openfeign", "2.0.1.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-consul", "2.0.1.BUILD-SNAPSHOT"); - properties.getFixedVersions().put("spring-cloud-zookeeper", - "2.0.1.BUILD-SNAPSHOT"); + properties.getFixedVersions().put("spring-cloud-zookeeper", "2.0.1.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-stream", "Elmhurst.RELEASE"); properties.getFixedVersions().put("spring-cloud-config", "2.0.1.BUILD-SNAPSHOT"); - properties.getFixedVersions().put("spring-cloud-cloudfoundry", - "2.0.1.BUILD-SNAPSHOT"); + properties.getFixedVersions().put("spring-cloud-cloudfoundry", "2.0.1.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-netflix", "2.0.1.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-vault", "2.0.1.BUILD-SNAPSHOT"); - properties.getFixedVersions().put("spring-cloud-security", - "2.0.1.BUILD-SNAPSHOT"); + properties.getFixedVersions().put("spring-cloud-security", "2.0.1.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-commons", "2.0.1.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-sleuth", "2.0.1.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-aws", "2.0.1.BUILD-SNAPSHOT"); - properties.getFixedVersions().put("spring-cloud-contract", - "2.0.1.BUILD-SNAPSHOT"); - properties.getFixedVersions().put("spring-cloud-release", - "Finchley.BUILD-SNAPSHOT"); + properties.getFixedVersions().put("spring-cloud-contract", "2.0.1.BUILD-SNAPSHOT"); + properties.getFixedVersions().put("spring-cloud-release", "Finchley.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-build", "2.0.3.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-cloud-bus", "2.0.1.BUILD-SNAPSHOT"); - properties.getFixedVersions().put("spring-cloud-function", - "1.0.0.BUILD-SNAPSHOT"); - properties.getFixedVersions().put("spring-cloud-starter-build", - "Finchley.BUILD-SNAPSHOT"); + properties.getFixedVersions().put("spring-cloud-function", "1.0.0.BUILD-SNAPSHOT"); + properties.getFixedVersions().put("spring-cloud-starter-build", "Finchley.BUILD-SNAPSHOT"); properties.getFixedVersions().put("spring-boot", "2.0.3.RELEASE"); properties.getFixedVersions().put("spring-cloud-gateway", "2.0.1.BUILD-SNAPSHOT"); - ProjectPomUpdater updater = new ProjectPomUpdater(properties, - Collections.singletonList(MavenBomParserAccessor.bomParser(properties, - new SpringCloudMavenBomParser()))); + ProjectPomUpdater updater = new ProjectPomUpdater(properties, Collections + .singletonList(MavenBomParserAccessor.bomParser(properties, new SpringCloudMavenBomParser()))); - Map fixedVersions = updater.fixedVersions().stream() - .collect(Collectors.toMap(projectVersion -> projectVersion.projectName, - projectVersion -> projectVersion.version)); + Map fixedVersions = updater.fixedVersions().stream().collect(Collectors + .toMap(projectVersion -> projectVersion.projectName, projectVersion -> projectVersion.version)); BDDAssertions.then(fixedVersions).containsEntry("spring-boot", "2.0.3.RELEASE") .containsEntry("spring-boot-dependencies", "2.0.3.RELEASE") diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/docs/SpringCloudCustomProjectDocumentationUpdaterTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/docs/SpringCloudCustomProjectDocumentationUpdaterTests.java index bf7dcf57..0a086610 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/docs/SpringCloudCustomProjectDocumentationUpdaterTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/docs/SpringCloudCustomProjectDocumentationUpdaterTests.java @@ -70,23 +70,17 @@ public class SpringCloudCustomProjectDocumentationUpdaterTests { .getResource("/projects/spring-cloud-static").toURI()); TestUtils.prepareLocalRepo(); FileSystemUtils.copyRecursively(file("/projects"), this.tmpFolder); - this.properties.getGit().setDocumentationUrl( - file("/projects/spring-cloud-static/").toURI().toString()); + this.properties.getGit().setDocumentationUrl(file("/projects/spring-cloud-static/").toURI().toString()); this.handler = new ProjectGitHandler(this.properties); this.clonedDocProject = this.handler.cloneDocumentationProject(); this.gitHubHandler = new ProjectGitHubHandler(this.properties, - Collections.singletonList( - SpringCloudGithubIssuesAccessor.springCloud(this.properties))); + Collections.singletonList(SpringCloudGithubIssuesAccessor.springCloud(this.properties))); } @NotNull - private DocumentationUpdater projectDocumentationUpdater( - ReleaserProperties properties) { - return new DocumentationUpdater(this.handler, properties, - templateGenerator(properties), - Collections.singletonList( - new SpringCloudCustomProjectDocumentationUpdater(this.handler, - properties))); + private DocumentationUpdater projectDocumentationUpdater(ReleaserProperties properties) { + return new DocumentationUpdater(this.handler, properties, templateGenerator(properties), + Collections.singletonList(new SpringCloudCustomProjectDocumentationUpdater(this.handler, properties))); } @NotNull @@ -97,56 +91,43 @@ public class SpringCloudCustomProjectDocumentationUpdaterTests { @Test public void should_not_update_current_version_in_the_docs_if_current_release_starts_with_v_and_then_lower_letter_than_the_stored_release() throws URISyntaxException, IOException { - ProjectVersion releaseTrainVersion = new ProjectVersion("spring-cloud-release", - "Finchley.SR33"); + ProjectVersion releaseTrainVersion = new ProjectVersion("spring-cloud-release", "Finchley.SR33"); ReleaserProperties properties = new ReleaserProperties(); - properties.getGit().setDocumentationUrl( - file("/projects/spring-cloud-static/").toURI().toString()); + properties.getGit().setDocumentationUrl(file("/projects/spring-cloud-static/").toURI().toString()); - File updatedDocs = new SpringCloudCustomProjectDocumentationUpdater( - new ProjectGitHandler(properties), properties) - .updateDocsRepoForReleaseTrain(this.clonedDocProject, - releaseTrainVersion, projects(), "vFinchley.SR33"); + File updatedDocs = new SpringCloudCustomProjectDocumentationUpdater(new ProjectGitHandler(properties), + properties).updateDocsRepoForReleaseTrain(this.clonedDocProject, releaseTrainVersion, projects(), + "vFinchley.SR33"); - BDDAssertions.then(new File(updatedDocs, "current/index.html").toPath()) - .doesNotExist(); + BDDAssertions.then(new File(updatedDocs, "current/index.html").toPath()).doesNotExist(); Path current = new File(updatedDocs, "current/").toPath(); BDDAssertions.then(current).isSymbolicLink(); - BDDAssertions.then(Files.readSymbolicLink(current).toString()) - .isEqualTo("Finchley.SR33"); + BDDAssertions.then(Files.readSymbolicLink(current).toString()).isEqualTo("Finchley.SR33"); releaseTrainVersion = new ProjectVersion("spring-cloud-release", "Angel.SR33"); properties = new ReleaserProperties(); - properties.getGit().setDocumentationUrl( - file("/projects/spring-cloud-static/").toURI().toString()); + properties.getGit().setDocumentationUrl(file("/projects/spring-cloud-static/").toURI().toString()); - updatedDocs = new SpringCloudCustomProjectDocumentationUpdater( - new ProjectGitHandler(properties), properties) - .updateDocsRepoForReleaseTrain(this.clonedDocProject, - releaseTrainVersion, projects(), "vAngel.SR33"); + updatedDocs = new SpringCloudCustomProjectDocumentationUpdater(new ProjectGitHandler(properties), properties) + .updateDocsRepoForReleaseTrain(this.clonedDocProject, releaseTrainVersion, projects(), "vAngel.SR33"); - BDDAssertions.then(new File(updatedDocs, "current/index.html").toPath()) - .doesNotExist(); + BDDAssertions.then(new File(updatedDocs, "current/index.html").toPath()).doesNotExist(); current = new File(updatedDocs, "current/").toPath(); BDDAssertions.then(current).isSymbolicLink(); - BDDAssertions.then(Files.readSymbolicLink(current).toString()) - .isNotEqualTo("Angel.SR33"); + BDDAssertions.then(Files.readSymbolicLink(current).toString()).isNotEqualTo("Angel.SR33"); } @Test public void should_not_commit_if_the_same_version_is_already_there() { - ProjectVersion releaseTrainVersion = new ProjectVersion("spring-cloud-release", - "Dalston.SR3"); + ProjectVersion releaseTrainVersion = new ProjectVersion("spring-cloud-release", "Dalston.SR3"); ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setDocumentationUrl(this.clonedDocProject.toURI().toString()); ProjectGitHandler handler = BDDMockito.spy(new ProjectGitHandler(properties)); new SpringCloudCustomProjectDocumentationUpdater(handler, properties) - .updateDocsRepoForReleaseTrain(this.clonedDocProject, releaseTrainVersion, - projects(), "vDalston.SR3"); + .updateDocsRepoForReleaseTrain(this.clonedDocProject, releaseTrainVersion, projects(), "vDalston.SR3"); - BDDMockito.then(handler).should(BDDMockito.never()) - .commit(BDDMockito.any(File.class), BDDMockito.anyString()); + BDDMockito.then(handler).should(BDDMockito.never()).commit(BDDMockito.any(File.class), BDDMockito.anyString()); } @Test @@ -157,11 +138,9 @@ public class SpringCloudCustomProjectDocumentationUpdaterTests { ProjectGitHandler handler = BDDMockito.spy(new ProjectGitHandler(properties)); new SpringCloudCustomProjectDocumentationUpdater(handler, properties) - .updateDocsRepoForReleaseTrain(this.clonedDocProject, springBootVersion, - bootProject(), "vDalston.SR3"); + .updateDocsRepoForReleaseTrain(this.clonedDocProject, springBootVersion, bootProject(), "vDalston.SR3"); - BDDMockito.then(handler).should(BDDMockito.never()) - .commit(BDDMockito.any(File.class), BDDMockito.anyString()); + BDDMockito.then(handler).should(BDDMockito.never()).commit(BDDMockito.any(File.class), BDDMockito.anyString()); } @Test @@ -172,37 +151,30 @@ public class SpringCloudCustomProjectDocumentationUpdaterTests { ProjectGitHandler handler = BDDMockito.spy(new ProjectGitHandler(properties)); new SpringCloudCustomProjectDocumentationUpdater(handler, properties) - .updateDocsRepoForSingleProject(this.clonedDocProject, springBootVersion, - bootProject()); + .updateDocsRepoForSingleProject(this.clonedDocProject, springBootVersion, bootProject()); - BDDMockito.then(handler).should(BDDMockito.never()) - .commit(BDDMockito.any(File.class), BDDMockito.anyString()); + BDDMockito.then(handler).should(BDDMockito.never()).commit(BDDMockito.any(File.class), BDDMockito.anyString()); } @Test public void should_not_update_current_version_in_the_docs_if_current_release_starts_with_lower_letter_than_the_stored_release() throws IOException { - ProjectVersion releaseTrainVersion = new ProjectVersion("spring-cloud-release", - "Angel.SR33"); + ProjectVersion releaseTrainVersion = new ProjectVersion("spring-cloud-release", "Angel.SR33"); ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setDocumentationUrl(this.clonedDocProject.toURI().toString()); - File updatedDocs = new SpringCloudCustomProjectDocumentationUpdater( - new ProjectGitHandler(properties), properties) - .updateDocsRepoForReleaseTrain(this.clonedDocProject, - releaseTrainVersion, projects(), "Angel.SR33"); + File updatedDocs = new SpringCloudCustomProjectDocumentationUpdater(new ProjectGitHandler(properties), + properties).updateDocsRepoForReleaseTrain(this.clonedDocProject, releaseTrainVersion, projects(), + "Angel.SR33"); - BDDAssertions.then(new File(updatedDocs, "current/index.html").toPath()) - .doesNotExist(); + BDDAssertions.then(new File(updatedDocs, "current/index.html").toPath()).doesNotExist(); Path current = new File(updatedDocs, "current/").toPath(); BDDAssertions.then(current).isSymbolicLink(); - BDDAssertions.then(Files.readSymbolicLink(current).toString()) - .isNotEqualTo("Angel.SR33"); + BDDAssertions.then(Files.readSymbolicLink(current).toString()).isNotEqualTo("Angel.SR33"); } private File file(String relativePath) throws URISyntaxException { - return new File(SpringCloudCustomProjectDocumentationUpdater.class - .getResource(relativePath).toURI()); + return new File(SpringCloudCustomProjectDocumentationUpdater.class.getResource(relativePath).toURI()); } private Projects projects() { diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/docs/TestUtils.java b/projects/spring-cloud/src/test/java/releaser/cloud/docs/TestUtils.java index c7427e57..10a25694 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/docs/TestUtils.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/docs/TestUtils.java @@ -36,8 +36,7 @@ public final class TestUtils { prepareLocalRepo("target/test-classes/projects/", "spring-cloud-static"); } - private static void prepareLocalRepo(String buildDir, String repoPath) - throws IOException { + private static void prepareLocalRepo(String buildDir, String repoPath) throws IOException { File dotGit = new File(buildDir + repoPath + "/.git"); File git = new File(buildDir + repoPath + "/git"); if (git.exists()) { diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/github/SpringCloudGithubIssuesAccessor.java b/projects/spring-cloud/src/test/java/releaser/cloud/github/SpringCloudGithubIssuesAccessor.java index 6690e67b..d8e9c03c 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/github/SpringCloudGithubIssuesAccessor.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/github/SpringCloudGithubIssuesAccessor.java @@ -22,8 +22,7 @@ import releaser.internal.github.CustomGithubIssues; public class SpringCloudGithubIssuesAccessor { - public static CustomGithubIssues springCloud(Github github, - ReleaserProperties releaserProperties) { + public static CustomGithubIssues springCloud(Github github, ReleaserProperties releaserProperties) { return new SpringCloudGithubIssues(github, releaserProperties); } diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/github/SpringCloudGithubIssuesTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/github/SpringCloudGithubIssuesTests.java index 59f30a75..9b3d7e83 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/github/SpringCloudGithubIssuesTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/github/SpringCloudGithubIssuesTests.java @@ -74,14 +74,12 @@ public class SpringCloudGithubIssuesTests { Github github = BDDMockito.mock(Github.class); CustomGithubIssues githubIssues = new SpringCloudGithubIssues(github, properties); - githubIssues - .fileIssueInSpringGuides( - new Projects(new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"), - new ProjectVersion("spring-cloud-build", - "2.0.0.BUILD-SNAPSHOT")), - new ProjectVersion("sc-release", "Edgware.BUILD-SNAPSHOT")); + githubIssues.fileIssueInSpringGuides( + new Projects(new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-build", "2.0.0.BUILD-SNAPSHOT")), + new ProjectVersion("sc-release", "Edgware.BUILD-SNAPSHOT")); - BDDMockito.then(github).shouldHaveZeroInteractions(); + BDDMockito.then(github).shouldHaveNoInteractions(); } @Test @@ -92,20 +90,18 @@ public class SpringCloudGithubIssuesTests { issues.fileIssueInSpringGuides( new Projects(new ProjectVersion("spring-cloud-foo", "1.0.0.RELEASE"), new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE"), - new ProjectVersion("bar", "2.0.0.RELEASE"), - new ProjectVersion("baz", "3.0.0.RELEASE")), + new ProjectVersion("bar", "2.0.0.RELEASE"), new ProjectVersion("baz", "3.0.0.RELEASE")), new ProjectVersion("sc-release", "Edgware.RELEASE")); - Issue issue = this.github.repos() - .get(new Coordinates.Simple("spring-guides", "getting-started-guides")) + Issue issue = this.github.repos().get(new Coordinates.Simple("spring-guides", "getting-started-guides")) .issues().get(1); then(issue.exists()).isTrue(); Issue.Smart smartIssue = new Issue.Smart(issue); then(smartIssue.title()).isEqualTo("Upgrade to Spring Cloud Edgware.RELEASE"); then(smartIssue.body()).contains( "Release train [spring-cloud-release] in version [Edgware.RELEASE] released with the following projects") - .contains("spring-cloud-foo : `1.0.0.RELEASE`") - .contains("bar : `2.0.0.RELEASE`").contains("baz : `3.0.0.RELEASE`"); + .contains("spring-cloud-foo : `1.0.0.RELEASE`").contains("bar : `2.0.0.RELEASE`") + .contains("baz : `3.0.0.RELEASE`"); } @Test @@ -114,16 +110,13 @@ public class SpringCloudGithubIssuesTests { CustomGithubIssues issues = new SpringCloudGithubIssues(github, properties); thenThrownBy(() -> issues.fileIssueInSpringGuides( - new Projects(Collections.singletonList( - new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE"))), - nonGaSleuthProject())).isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining( - "You have to pass Github OAuth token for milestone closing to be operational"); + new Projects(Collections.singletonList(new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE"))), + nonGaSleuthProject())).isInstanceOf(IllegalArgumentException.class).hasMessageContaining( + "You have to pass Github OAuth token for milestone closing to be operational"); } @Test - public void should_not_do_anything_for_non_release_train_version_when_updating_startspringio() - throws IOException { + public void should_not_do_anything_for_non_release_train_version_when_updating_startspringio() throws IOException { setupStartSpringIo(); Github github = BDDMockito.mock(Github.class); CustomGithubIssues issues = new SpringCloudGithubIssues(github, properties); @@ -133,27 +126,21 @@ public class SpringCloudGithubIssuesTests { new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE")), new ProjectVersion("sc-release", "Edgware.BUILD-SNAPSHOT")); - BDDMockito.then(github).shouldHaveZeroInteractions(); + BDDMockito.then(github).shouldHaveNoInteractions(); } @Test - public void should_file_an_issue_for_release_version_when_updating_startspringio() - throws IOException { + public void should_file_an_issue_for_release_version_when_updating_startspringio() throws IOException { setupStartSpringIo(); CustomGithubIssues issues = new SpringCloudGithubIssues(github, properties); properties.getPom().setBranch("vEdgware.RELEASE"); - issues.fileIssueInStartSpringIo( - new Projects(new ProjectVersion("spring-cloud-foo", "1.0.0.RELEASE"), - new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE"), - new ProjectVersion("bar", "2.0.0.RELEASE"), - new ProjectVersion("baz", "3.0.0.RELEASE"), - new ProjectVersion("spring-boot", "1.2.3.RELEASE")), + issues.fileIssueInStartSpringIo(new Projects(new ProjectVersion("spring-cloud-foo", "1.0.0.RELEASE"), + new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE"), new ProjectVersion("bar", "2.0.0.RELEASE"), + new ProjectVersion("baz", "3.0.0.RELEASE"), new ProjectVersion("spring-boot", "1.2.3.RELEASE")), new ProjectVersion("sc-release", "Edgware.RELEASE")); - Issue issue = this.github.repos() - .get(new Coordinates.Simple("spring-io", "start.spring.io")).issues() - .get(1); + Issue issue = this.github.repos().get(new Coordinates.Simple("spring-io", "start.spring.io")).issues().get(1); then(issue.exists()).isTrue(); Issue.Smart smartIssue = new Issue.Smart(issue); then(smartIssue.title()).isEqualTo("Upgrade to Spring Cloud Edgware.RELEASE"); @@ -162,23 +149,19 @@ public class SpringCloudGithubIssuesTests { } @Test - public void should_throw_exception_when_no_token_was_passed_when_updating_startspringio() - throws IOException { + public void should_throw_exception_when_no_token_was_passed_when_updating_startspringio() throws IOException { setupStartSpringIo(); properties.getGit().setOauthToken(""); CustomGithubIssues issues = new SpringCloudGithubIssues(github, properties); thenThrownBy(() -> issues.fileIssueInStartSpringIo( - new Projects(Collections.singletonList( - new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE"))), - nonGaSleuthProject())).isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining( - "You have to pass Github OAuth token for milestone closing to be operational"); + new Projects(Collections.singletonList(new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE"))), + nonGaSleuthProject())).isInstanceOf(IllegalArgumentException.class).hasMessageContaining( + "You have to pass Github OAuth token for milestone closing to be operational"); } private Repo createGettingStartedGuides(MkGithub github) throws IOException { - return github.repos() - .create(new Repos.RepoCreate("getting-started-guides", false)); + return github.repos().create(new Repos.RepoCreate("getting-started-guides", false)); } private Repo createStartSpringIo(MkGithub github) throws IOException { diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/spring/AbstractSpringCloudAcceptanceTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/spring/AbstractSpringCloudAcceptanceTests.java index 2d5c9609..b00ca0fd 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/spring/AbstractSpringCloudAcceptanceTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/spring/AbstractSpringCloudAcceptanceTests.java @@ -36,10 +36,10 @@ public class AbstractSpringCloudAcceptanceTests extends AbstractSpringAcceptance @Before public void setupCloud() throws Exception { this.temporaryFolder = this.tmp.newFolder(); - this.springCloudConsulProject = new File(AbstractSpringAcceptanceTests.class - .getResource("/projects/spring-cloud-consul").toURI()); - this.springCloudBuildProject = new File(AbstractSpringAcceptanceTests.class - .getResource("/projects/spring-cloud-build").toURI()); + this.springCloudConsulProject = new File( + AbstractSpringAcceptanceTests.class.getResource("/projects/spring-cloud-consul").toURI()); + this.springCloudBuildProject = new File( + AbstractSpringAcceptanceTests.class.getResource("/projects/spring-cloud-build").toURI()); TestUtils.prepareLocalRepo(); FileSystemUtils.copyRecursively(file("/projects/"), this.temporaryFolder); } @@ -51,12 +51,9 @@ public class AbstractSpringCloudAcceptanceTests extends AbstractSpringAcceptance public void thenAllDryRunStepsWereExecutedForEachProject( NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler) { nonAssertingTestProjectGitHandler.clonedProjects.stream() - .filter(f -> !f.getName().contains("angel") - && !f.getName().equals("spring-cloud")) - .forEach(project -> { - then(Arrays.asList("spring-cloud-starter-build", - "spring-cloud-consul")) - .contains(pom(project).getArtifactId()); + .filter(f -> !f.getName().contains("angel") && !f.getName().equals("spring-cloud")).forEach(project -> { + then(Arrays.asList("spring-cloud-starter-build", "spring-cloud-consul")) + .contains(pom(project).getArtifactId()); then(new File("/tmp/executed_build")).exists(); then(new File("/tmp/executed_deploy")).doesNotExist(); then(new File("/tmp/executed_docs")).doesNotExist(); diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/spring/meta/AbstractSpringCloudMetaAcceptanceTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/spring/meta/AbstractSpringCloudMetaAcceptanceTests.java index cde22ce3..6ad8de2e 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/spring/meta/AbstractSpringCloudMetaAcceptanceTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/spring/meta/AbstractSpringCloudMetaAcceptanceTests.java @@ -24,8 +24,7 @@ import releaser.internal.spring.meta.AbstractSpringMetaReleaseAcceptanceTests; import static org.assertj.core.api.BDDAssertions.then; -public class AbstractSpringCloudMetaAcceptanceTests - extends AbstractSpringMetaReleaseAcceptanceTests { +public class AbstractSpringCloudMetaAcceptanceTests extends AbstractSpringMetaReleaseAcceptanceTests { public File springCloudConsulProject; @@ -34,11 +33,9 @@ public class AbstractSpringCloudMetaAcceptanceTests @Before public void setupCloud() throws Exception { this.springCloudConsulProject = new File( - AbstractSpringCloudMetaAcceptanceTests.class - .getResource("/projects/spring-cloud-consul").toURI()); + AbstractSpringCloudMetaAcceptanceTests.class.getResource("/projects/spring-cloud-consul").toURI()); this.springCloudBuildProject = new File( - AbstractSpringCloudMetaAcceptanceTests.class - .getResource("/projects/spring-cloud-build").toURI()); + AbstractSpringCloudMetaAcceptanceTests.class.getResource("/projects/spring-cloud-build").toURI()); } public void consulPomParentVersionIsEqualTo(File project, String expected) { @@ -48,12 +45,9 @@ public class AbstractSpringCloudMetaAcceptanceTests public void thenAllDryRunStepsWereExecutedForEachProject( NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler) { nonAssertingTestProjectGitHandler.clonedProjects.stream() - .filter(f -> !f.getName().contains("angel") - && !f.getName().equals("spring-cloud")) - .forEach(project -> { - then(Arrays.asList("spring-cloud-starter-build", - "spring-cloud-consul")) - .contains(pom(project).getArtifactId()); + .filter(f -> !f.getName().contains("angel") && !f.getName().equals("spring-cloud")).forEach(project -> { + then(Arrays.asList("spring-cloud-starter-build", "spring-cloud-consul")) + .contains(pom(project).getArtifactId()); then(new File("/tmp/executed_build")).exists(); then(new File("/tmp/executed_deploy")).doesNotExist(); then(new File("/tmp/executed_docs")).doesNotExist(); diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/spring/meta/SpringMetaReleaseAcceptanceTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/spring/meta/SpringMetaReleaseAcceptanceTests.java index 9fafc02c..20dd81e3 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/spring/meta/SpringMetaReleaseAcceptanceTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/spring/meta/SpringMetaReleaseAcceptanceTests.java @@ -54,18 +54,18 @@ import org.springframework.context.annotation.Configuration; import org.springframework.util.FileSystemUtils; import static org.assertj.core.api.BDDAssertions.then; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.BDDMockito.given; /** * @author Marcin Grzejszczak */ -public class SpringMetaReleaseAcceptanceTests - extends AbstractSpringCloudMetaAcceptanceTests { +public class SpringMetaReleaseAcceptanceTests extends AbstractSpringCloudMetaAcceptanceTests { @Test - public void should_perform_a_meta_release_of_sc_release_and_consul() - throws Exception { + public void should_perform_a_meta_release_of_sc_release_and_consul() throws Exception { checkoutReleaseTrainBranch("/projects/spring-cloud-release/", "Greenwich"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); @@ -73,21 +73,18 @@ public class SpringMetaReleaseAcceptanceTests GitTestUtils.setOriginOnProjectToTmp(origin, project); run(defaultRunner(), - properties("debug=true").properties("test.metarelease=true") - .properties(metaReleaseArgs(project).bomBranch("vGreenwich.SR2") - .addFixedVersions(edgwareSr10()).build()), + properties("debugx=true").properties("test.metarelease=true").properties( + metaReleaseArgs(project).bomBranch("vGreenwich.SR2").addFixedVersions(edgwareSr10()).build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler = context .getBean(NonAssertingTestProjectGitHandler.class); SaganUpdater saganUpdater = context.getBean(SaganUpdater.class); - PostReleaseActions postReleaseActions = context - .getBean(PostReleaseActions.class); + PostReleaseActions postReleaseActions = context.getBean(PostReleaseActions.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); - ExecutionResult result = releaser - .release(new OptionsBuilder().metaRelease(true).options()); + ExecutionResult result = releaser.release(new OptionsBuilder().metaRelease(true).options()); // print results testExecutionResultHandler.accept(result); @@ -97,46 +94,41 @@ public class SpringMetaReleaseAcceptanceTests // consul, release then(nonAssertingTestProjectGitHandler.clonedProjects).hasSize(2); // don't want to verify the docs - thenAllStepsWereExecutedForEachProject( - nonAssertingTestProjectGitHandler); + thenAllStepsWereExecutedForEachProject(nonAssertingTestProjectGitHandler); thenSaganWasCalled(saganUpdater); - then(clonedProject(nonAssertingTestProjectGitHandler, - "spring-cloud-consul").tagList().call()).extracting("name") - .contains("refs/tags/v5.3.5.RELEASE"); + then(clonedProject(nonAssertingTestProjectGitHandler, "spring-cloud-consul").tagList().call()) + .extracting("name").contains("refs/tags/v5.3.5.RELEASE"); thenRunUpdatedTestsWereCalled(postReleaseActions); thenUpdateReleaseTrainDocsWasCalled(postReleaseActions); }); } @Test - public void should_perform_a_meta_release_of_sc_release_and_consul_in_parallel() - throws Exception { + public void should_perform_a_meta_release_of_sc_release_and_consul_in_parallel() throws Exception { checkoutReleaseTrainBranch("/projects/spring-cloud-release/", "Greenwich"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); File project = cloneToTemporaryDirectory(tmpFile("spring-cloud-consul")); GitTestUtils.setOriginOnProjectToTmp(origin, project); - run(defaultRunner(), properties("debug=true").properties("test.metarelease=true") - .properties(metaReleaseArgsForParallel(project) - .bomBranch("vGreenwich.SR2").addFixedVersions(edgwareSr10()) - .metaReleaseGroups("example1,example2", - "spring-cloud-build,spring-cloud-consul,spring-cloud-release") - .build()), + run(defaultRunner(), + properties("debugx=true").properties("test.metarelease=true") + .properties(metaReleaseArgsForParallel(project).bomBranch("vGreenwich.SR2") + .addFixedVersions(edgwareSr10()) + .metaReleaseGroups("example1,example2", + "spring-cloud-build,spring-cloud-consul,spring-cloud-release") + .build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler = context .getBean(NonAssertingTestProjectGitHandler.class); SaganUpdater saganUpdater = context.getBean(SaganUpdater.class); - DocumentationUpdater testDocumentationUpdater = context - .getBean(DocumentationUpdater.class); - PostReleaseActions postReleaseActions = context - .getBean(PostReleaseActions.class); + DocumentationUpdater testDocumentationUpdater = context.getBean(DocumentationUpdater.class); + PostReleaseActions postReleaseActions = context.getBean(PostReleaseActions.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); - ExecutionResult result = releaser - .release(new OptionsBuilder().metaRelease(true).options()); + ExecutionResult result = releaser.release(new OptionsBuilder().metaRelease(true).options()); // print results testExecutionResultHandler.accept(result); @@ -150,17 +142,15 @@ public class SpringMetaReleaseAcceptanceTests // thenAllStepsWereExecutedForEachProject( // nonAssertingTestProjectGitHandler); thenSaganWasCalled(saganUpdater); - then(clonedProject(nonAssertingTestProjectGitHandler, - "spring-cloud-consul").tagList().call()).extracting("name") - .contains("refs/tags/v5.3.5.RELEASE"); + then(clonedProject(nonAssertingTestProjectGitHandler, "spring-cloud-consul").tagList().call()) + .extracting("name").contains("refs/tags/v5.3.5.RELEASE"); thenRunUpdatedTestsWereCalled(postReleaseActions); thenUpdateReleaseTrainDocsWasCalled(postReleaseActions); }); } @Test - public void should_perform_a_meta_release_dry_run_of_sc_release_and_consul() - throws Exception { + public void should_perform_a_meta_release_dry_run_of_sc_release_and_consul() throws Exception { checkoutReleaseTrainBranch("/projects/spring-cloud-release/", "Greenwich"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); @@ -168,23 +158,20 @@ public class SpringMetaReleaseAcceptanceTests GitTestUtils.setOriginOnProjectToTmp(origin, project); run(defaultRunner(), - properties("debug=true").properties("test.metarelease=true") - .properties(metaReleaseArgs(project).bomBranch("vGreenwich.SR2") - .addFixedVersions(edgwareSr10()).build()), + properties("debugx=true").properties("test.metarelease=true").properties( + metaReleaseArgs(project).bomBranch("vGreenwich.SR2").addFixedVersions(edgwareSr10()).build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler = context .getBean(NonAssertingTestProjectGitHandler.class); SaganUpdater saganUpdater = context.getBean(SaganUpdater.class); - DocumentationUpdater testDocumentationUpdater = context - .getBean(DocumentationUpdater.class); - PostReleaseActions postReleaseActions = context - .getBean(PostReleaseActions.class); + DocumentationUpdater testDocumentationUpdater = context.getBean(DocumentationUpdater.class); + PostReleaseActions postReleaseActions = context.getBean(PostReleaseActions.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); - ExecutionResult result = releaser.release(new OptionsBuilder() - .metaRelease(true).dryRun(true).options()); + ExecutionResult result = releaser + .release(new OptionsBuilder().metaRelease(true).dryRun(true).options()); // print results testExecutionResultHandler.accept(result); @@ -194,20 +181,17 @@ public class SpringMetaReleaseAcceptanceTests // consul, release then(nonAssertingTestProjectGitHandler.clonedProjects).hasSize(2); // only dry run tasks were called - thenAllDryRunStepsWereExecutedForEachProject( - nonAssertingTestProjectGitHandler); + thenAllDryRunStepsWereExecutedForEachProject(nonAssertingTestProjectGitHandler); thenSaganWasNotCalled(saganUpdater); - then(clonedProject(nonAssertingTestProjectGitHandler, - "spring-cloud-consul").tagList().call()).extracting("name") - .doesNotContain("refs/tags/v5.3.5.RELEASE"); + then(clonedProject(nonAssertingTestProjectGitHandler, "spring-cloud-consul").tagList().call()) + .extracting("name").doesNotContain("refs/tags/v5.3.5.RELEASE"); thenRunUpdatedTestsWereNotCalled(postReleaseActions); thenUpdateReleaseTrainDocsWasNotCalled(postReleaseActions); }); } @Test - public void should_not_release_any_projects_when_they_are_on_list_of_projects_to_skip() - throws Exception { + public void should_not_release_any_projects_when_they_are_on_list_of_projects_to_skip() throws Exception { checkoutReleaseTrainBranch("/projects/spring-cloud-release/", "Greenwich"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); @@ -215,23 +199,17 @@ public class SpringMetaReleaseAcceptanceTests GitTestUtils.setOriginOnProjectToTmp(origin, project); File temporaryDestination = this.tmp.newFolder(); - run(defaultRunner(), - properties("debug=true") - .properties("test.metarelease=true", "test.mockBuild=true") - .properties(metaReleaseArgs(project).bomBranch("Greenwich") - .addFixedVersions(consulAndReleaseSnapshots()) - .updateReleaseTrainWiki(false) - .cloneDestinationDirectory(temporaryDestination) - .projectsToSkip("spring-cloud-consul").build()), + run(defaultRunner(), properties("debugx=true").properties("test.metarelease=true", "test.mockBuild=true") + .properties(metaReleaseArgs(project).bomBranch("Greenwich") + .addFixedVersions(consulAndReleaseSnapshots()).updateReleaseTrainWiki(false) + .cloneDestinationDirectory(temporaryDestination).projectsToSkip("spring-cloud-consul").build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); - BuildProjectReleaseTask build = context - .getBean(BuildProjectReleaseTask.class); + BuildProjectReleaseTask build = context.getBean(BuildProjectReleaseTask.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); - ExecutionResult result = releaser - .release(new OptionsBuilder().metaRelease(true).options()); + ExecutionResult result = releaser.release(new OptionsBuilder().metaRelease(true).options()); // print results testExecutionResultHandler.accept(result); @@ -244,8 +222,7 @@ public class SpringMetaReleaseAcceptanceTests } @Test - public void should_perform_a_meta_release_of_consul_only_when_run_from_got_passed() - throws Exception { + public void should_perform_a_meta_release_of_consul_only_when_run_from_got_passed() throws Exception { checkoutReleaseTrainBranch("/projects/spring-cloud-release/", "Greenwich"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); @@ -254,24 +231,20 @@ public class SpringMetaReleaseAcceptanceTests File temporaryDestination = this.tmp.newFolder(); run(defaultRunner(), - properties("debug=true") - .properties("test.metarelease=true", "test.mockBuild=true") + properties("debugx=true").properties("test.metarelease=true", "test.mockBuild=true") .properties(metaReleaseArgs(project).bomBranch("Greenwich") .addFixedVersions(releaseConsulBuildSnapshots()) .cloneDestinationDirectory(temporaryDestination).build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); - BuildProjectReleaseTask build = context - .getBean(BuildProjectReleaseTask.class); + BuildProjectReleaseTask build = context.getBean(BuildProjectReleaseTask.class); SaganUpdater saganUpdater = context.getBean(SaganUpdater.class); - DocumentationUpdater testDocumentationUpdater = context - .getBean(DocumentationUpdater.class); + DocumentationUpdater testDocumentationUpdater = context.getBean(DocumentationUpdater.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); ExecutionResult result = releaser - .release(new OptionsBuilder().startFrom("spring-cloud-consul") - .metaRelease(true).options()); + .release(new OptionsBuilder().startFrom("spring-cloud-consul").metaRelease(true).options()); // print results testExecutionResultHandler.accept(result); @@ -290,8 +263,7 @@ public class SpringMetaReleaseAcceptanceTests } @Test - public void should_perform_a_meta_release_of_consul_only_when_task_names_got_passed() - throws Exception { + public void should_perform_a_meta_release_of_consul_only_when_task_names_got_passed() throws Exception { checkoutReleaseTrainBranch("/projects/spring-cloud-release/", "Greenwich"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); @@ -300,24 +272,20 @@ public class SpringMetaReleaseAcceptanceTests File temporaryDestination = this.tmp.newFolder(); run(defaultRunner(), - properties("debug=true") - .properties("test.metarelease=true", "test.mockBuild=true") + properties("debugx=true").properties("test.metarelease=true", "test.mockBuild=true") .properties(metaReleaseArgs(project).bomBranch("Greenwich") .addFixedVersions(releaseConsulBuildSnapshots()) .cloneDestinationDirectory(temporaryDestination).build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); - BuildProjectReleaseTask build = context - .getBean(BuildProjectReleaseTask.class); + BuildProjectReleaseTask build = context.getBean(BuildProjectReleaseTask.class); SaganUpdater saganUpdater = context.getBean(SaganUpdater.class); - DocumentationUpdater testDocumentationUpdater = context - .getBean(DocumentationUpdater.class); + DocumentationUpdater testDocumentationUpdater = context.getBean(DocumentationUpdater.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); ExecutionResult result = releaser.release(new OptionsBuilder() - .taskNames(Collections.singletonList("spring-cloud-consul")) - .metaRelease(true).options()); + .taskNames(Collections.singletonList("spring-cloud-consul")).metaRelease(true).options()); // print results testExecutionResultHandler.accept(result); @@ -336,19 +304,18 @@ public class SpringMetaReleaseAcceptanceTests } @Test - public void should_not_execute_any_subsequent_task_when_first_one_fails() - throws Exception { + public void should_not_execute_any_subsequent_task_when_first_one_fails() throws Exception { checkoutReleaseTrainBranch("/projects/spring-cloud-release/", "Greenwich"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); File project = cloneToTemporaryDirectory(tmpFile("spring-cloud-consul")); GitTestUtils.setOriginOnProjectToTmp(origin, project); - run(failingBuildRunner(), properties("debug=true") + run(failingBuildRunner(), properties("debugx=true") .properties("test.metarelease=true", "test.metarelease.failing=true", "releaser.flow.default-enabled=false") - .properties(metaReleaseArgs(project).bomBranch("vGreenwich.SR2") - .addFixedVersions(edgwareSr10()).build()), + .properties( + metaReleaseArgs(project).bomBranch("vGreenwich.SR2").addFixedVersions(edgwareSr10()).build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler = context @@ -357,11 +324,9 @@ public class SpringMetaReleaseAcceptanceTests .getBean(TestExecutionResultHandler.class); FirstTask firstTask = context.getBean(FirstTask.class); SecondTask secondTask = context.getBean(SecondTask.class); - PostReleaseTask postReleaseTask = context - .getBean(PostReleaseTask.class); + PostReleaseTask postReleaseTask = context.getBean(PostReleaseTask.class); - ExecutionResult result = releaser - .release(new OptionsBuilder().metaRelease(true).options()); + ExecutionResult result = releaser.release(new OptionsBuilder().metaRelease(true).options()); // print results testExecutionResultHandler.accept(result); @@ -370,48 +335,40 @@ public class SpringMetaReleaseAcceptanceTests then(result.isFailureOrUnstable()).isTrue(); // consul then(nonAssertingTestProjectGitHandler.clonedProjects).hasSize(1); - BDDMockito.then(firstTask).should().runTask(BDDMockito.argThat( - arg -> arg.project.getName().equals("spring-cloud-consul"))); + BDDMockito.then(firstTask).should() + .runTask(BDDMockito.argThat(arg -> arg.project.getName().equals("spring-cloud-consul"))); BDDMockito.then(firstTask).should(BDDMockito.never()) - .runTask(BDDMockito.argThat(arg -> arg.project.getName() - .equals("spring-cloud-release"))); - BDDMockito.then(secondTask).should(BDDMockito.never()) - .runTask(BDDMockito.any(Arguments.class)); + .runTask(BDDMockito.argThat(arg -> arg.project.getName().equals("spring-cloud-release"))); + BDDMockito.then(secondTask).should(BDDMockito.never()).runTask(BDDMockito.any(Arguments.class)); BDDMockito.then(postReleaseTask).should(BDDMockito.never()) .runTask(BDDMockito.any(Arguments.class)); }); } private SpringApplicationBuilder defaultRunner() { - return new SpringApplicationBuilder(MetaReleaseConfig.class, - MetaReleaseScanningConfiguration.class).web(WebApplicationType.NONE) - .properties("spring.jmx.enabled=false"); + return new SpringApplicationBuilder(MetaReleaseConfig.class, MetaReleaseScanningConfiguration.class) + .web(WebApplicationType.NONE).properties("spring.jmx.enabled=false"); } private SpringApplicationBuilder failingBuildRunner() { - return new SpringApplicationBuilder( - SpringMetaReleaseAcceptanceTests.MetaReleaseConfig.class, + return new SpringApplicationBuilder(SpringMetaReleaseAcceptanceTests.MetaReleaseConfig.class, SpringMetaReleaseAcceptanceTests.MetaReleaseFailingTasksScanningConfiguration.class) - .web(WebApplicationType.NONE) - .properties("spring.jmx.enabled=false"); + .web(WebApplicationType.NONE).properties("spring.jmx.enabled=false"); } private void thenWikiPageWasUpdated(DocumentationUpdater documentationUpdater) { - BDDMockito.then(documentationUpdater).should() - .updateReleaseTrainWiki(BDDMockito.any(Projects.class)); + BDDMockito.then(documentationUpdater).should().updateReleaseTrainWiki(BDDMockito.any(Projects.class)); } - private void thenBuildWasCalledFor(BuildProjectReleaseTask build, - String projectName) { - BDDMockito.then(build).should().apply(argThat( - argument -> argument.originalVersion.projectName.equals(projectName) + private void thenBuildWasCalledFor(BuildProjectReleaseTask build, String projectName) { + BDDMockito.then(build).should() + .apply(argThat(argument -> argument.originalVersion.projectName.equals(projectName) || argument.project.getAbsolutePath().endsWith(projectName))); } - private void thenBuildWasNeverCalledFor(BuildProjectReleaseTask build, - String projectName) { - BDDMockito.then(build).should(BDDMockito.never()).apply(argThat( - argument -> argument.originalVersion.projectName.equals(projectName) + private void thenBuildWasNeverCalledFor(BuildProjectReleaseTask build, String projectName) { + BDDMockito.then(build).should(BDDMockito.never()) + .apply(argThat(argument -> argument.originalVersion.projectName.equals(projectName) || argument.project.getAbsolutePath().endsWith(projectName))); } @@ -438,8 +395,9 @@ public class SpringMetaReleaseAcceptanceTests @Bean SaganClient testSaganClient() { SaganClient saganClient = BDDMockito.mock(SaganClient.class); - BDDMockito.given(saganClient.getProject(anyString())) - .willReturn(newProject()); + given(saganClient.getProject(anyString())).willReturn(newProject()); + given(saganClient.addRelease(anyString(), any())).willReturn(true); + given(saganClient.deleteRelease(anyString(), anyString())).willReturn(true); return saganClient; } @@ -450,33 +408,27 @@ public class SpringMetaReleaseAcceptanceTests } @Bean - SaganUpdater testSaganUpdater(SaganClient saganClient, - ReleaserProperties properties) { + SaganUpdater testSaganUpdater(SaganClient saganClient, ReleaserProperties properties) { return BDDMockito.spy(new SaganUpdater(saganClient, properties)); } @Bean PostReleaseActions myPostReleaseActions() { - return BDDMockito - .mock(PostReleaseActions.class, - invocation -> invocation.getMethod().getReturnType() - .equals(ExecutionResult.class) - ? ExecutionResult.success() : null); + return BDDMockito.mock(PostReleaseActions.class, + invocation -> invocation.getMethod().getReturnType().equals(ExecutionResult.class) + ? ExecutionResult.success() : null); } @Bean - NonAssertingTestProjectGitHubHandler testProjectGitHubHandler( - ReleaserProperties releaserProperties) { + NonAssertingTestProjectGitHubHandler testProjectGitHubHandler(ReleaserProperties releaserProperties) { return new NonAssertingTestProjectGitHubHandler(releaserProperties); } @Bean - NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler( - ReleaserProperties releaserProperties, + NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler(ReleaserProperties releaserProperties, @Value("${test.projectName}") String projectName) { return new NonAssertingTestProjectGitHandler(releaserProperties, - file -> FileSystemUtils - .deleteRecursively(new File(file, projectName))); + file -> FileSystemUtils.deleteRecursively(new File(file, projectName))); } @Bean @@ -487,8 +439,7 @@ public class SpringMetaReleaseAcceptanceTests } @Configuration - @ConditionalOnProperty(value = "test.metarelease", havingValue = "true", - matchIfMissing = true) + @ConditionalOnProperty(value = "test.metarelease", havingValue = "true", matchIfMissing = true) @ComponentScan({ "releaser.internal", "releaser.cloud" }) static class MetaReleaseScanningConfiguration { @@ -551,8 +502,7 @@ class FirstTask implements ReleaseReleaserTask { } @Override - public ExecutionResult runTask(Arguments args) - throws BuildUnstableException, RuntimeException { + public ExecutionResult runTask(Arguments args) throws BuildUnstableException, RuntimeException { return ExecutionResult.failure(new IllegalStateException("Failure")); } @@ -586,8 +536,7 @@ class SecondTask implements ReleaseReleaserTask { } @Override - public ExecutionResult runTask(Arguments args) - throws BuildUnstableException, RuntimeException { + public ExecutionResult runTask(Arguments args) throws BuildUnstableException, RuntimeException { return ExecutionResult.success(); } @@ -621,8 +570,7 @@ class PostReleaseTask implements TrainPostReleaseReleaserTask { } @Override - public ExecutionResult runTask(Arguments args) - throws BuildUnstableException, RuntimeException { + public ExecutionResult runTask(Arguments args) throws BuildUnstableException, RuntimeException { return ExecutionResult.success(); } diff --git a/projects/spring-cloud/src/test/java/releaser/cloud/spring/single/SpringSingleProjectAcceptanceTests.java b/projects/spring-cloud/src/test/java/releaser/cloud/spring/single/SpringSingleProjectAcceptanceTests.java index 8a0e25a7..6557da25 100644 --- a/projects/spring-cloud/src/test/java/releaser/cloud/spring/single/SpringSingleProjectAcceptanceTests.java +++ b/projects/spring-cloud/src/test/java/releaser/cloud/spring/single/SpringSingleProjectAcceptanceTests.java @@ -49,34 +49,33 @@ import org.springframework.context.annotation.Configuration; import org.springframework.util.FileSystemUtils; import static org.assertj.core.api.BDDAssertions.then; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; /** * @author Marcin Grzejszczak */ -public class SpringSingleProjectAcceptanceTests - extends AbstractSpringCloudAcceptanceTests { +public class SpringSingleProjectAcceptanceTests extends AbstractSpringCloudAcceptanceTests { SpringApplicationBuilder runner = new SpringApplicationBuilder( SpringSingleProjectAcceptanceTests.SingleProjectReleaseConfig.class, - SpringSingleProjectAcceptanceTests.SingleProjectScanningConfiguration.class) - .web(WebApplicationType.NONE).properties("spring.jmx.enabled=false"); + SpringSingleProjectAcceptanceTests.SingleProjectScanningConfiguration.class).web(WebApplicationType.NONE) + .properties("spring.jmx.enabled=false"); @Test - public void should_fail_to_perform_a_release_of_consul_when_sc_release_contains_snapshots() - throws Exception { - checkoutReleaseTrainBranch("/projects/spring-cloud-release-with-snapshot/", - "vCamden.SR5.BROKEN"); + public void should_fail_to_perform_a_release_of_consul_when_sc_release_contains_snapshots() throws Exception { + checkoutReleaseTrainBranch("/projects/spring-cloud-release-with-snapshot/", "vCamden.SR5.BROKEN"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); File project = cloneToTemporaryDirectory(tmpFile("spring-cloud-consul")); GitTestUtils.setOriginOnProjectToTmp(origin, project); run(this.runner, - properties("debug=true").properties(new ArgsBuilder(project, this.tmp) + properties("debugx=true").properties(new ArgsBuilder(project, this.tmp) .releaseTrainUrl("/projects/spring-cloud-release-with-snapshot/") - .bomBranch("vCamden.SR5.BROKEN").expectedVersion("1.1.2.RELEASE") - .build()), + .bomBranch("vCamden.SR5.BROKEN").expectedVersion("1.1.2.RELEASE").build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); BDDAssertions.thenThrownBy(releaser::release).hasMessageContaining( @@ -94,28 +93,23 @@ public class SpringSingleProjectAcceptanceTests GitTestUtils.setOriginOnProjectToTmp(origin, project); run(this.runner, - properties("debug=true").properties(new ArgsBuilder(project, this.tmp) - .releaseTrainUrl("/projects/spring-cloud-release/") - .bomBranch("vGreenwich.SR2").expectedVersion("2.1.2.RELEASE") - .build()), + properties("debugx=true").properties( + new ArgsBuilder(project, this.tmp).releaseTrainUrl("/projects/spring-cloud-release/") + .bomBranch("vGreenwich.SR2").expectedVersion("2.1.2.RELEASE").build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); - TestProjectGitHubHandler gitHubHandler = context - .getBean(TestProjectGitHubHandler.class); + TestProjectGitHubHandler gitHubHandler = context.getBean(TestProjectGitHubHandler.class); SaganClient saganClient = context.getBean(SaganClient.class); - PostReleaseActions postReleaseActions = context - .getBean(PostReleaseActions.class); + PostReleaseActions postReleaseActions = context.getBean(PostReleaseActions.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); - ExecutionResult result = releaser - .release(new OptionsBuilder().interactive(true).options()); + ExecutionResult result = releaser.release(new OptionsBuilder().interactive(true).options()); Iterable commits = listOfCommits(project); Iterator iterator = commits.iterator(); tagIsPresentInOrigin(origin, "v2.1.2.RELEASE"); - commitIsPresent(iterator, - "Bumping versions to 2.1.3.SNAPSHOT after release"); + commitIsPresent(iterator, "Bumping versions to 2.1.3.SNAPSHOT after release"); commitIsPresent(iterator, "Going back to snapshots"); commitIsPresent(iterator, "Update SNAPSHOT to 2.1.2.RELEASE"); pomVersionIsEqualTo(project, "2.1.3.SNAPSHOT"); @@ -127,11 +121,10 @@ public class SpringSingleProjectAcceptanceTests then(releaseNotesTemplate()).doesNotExist(); // once for updating GA // second time to update SNAPSHOT - BDDMockito.then(saganClient).should(BDDMockito.times(2)) - .updateRelease(BDDMockito.eq("spring-cloud-consul"), - BDDMockito.anyList()); - BDDMockito.then(saganClient).should() - .deleteRelease("spring-cloud-consul", "2.1.2.BUILD-SNAPSHOT"); + BDDMockito.then(saganClient).should(times(2)).addRelease(BDDMockito.eq("spring-cloud-consul"), + BDDMockito.any()); + BDDMockito.then(saganClient).should(times(2)).getProject("spring-cloud-consul"); + BDDMockito.then(saganClient).should().deleteRelease("spring-cloud-consul", "2.1.2.BUILD-SNAPSHOT"); then(gitHubHandler.issueCreatedInSpringGuides).isFalse(); then(gitHubHandler.issueCreatedInStartSpringIo).isFalse(); thenRunUpdatedTestsWereNotCalled(postReleaseActions); @@ -152,34 +145,28 @@ public class SpringSingleProjectAcceptanceTests GitTestUtils.setOriginOnProjectToTmp(origin, project); run(this.runner, - properties("debug=true").properties(new ArgsBuilder(project, this.tmp) - .releaseTrainUrl("/projects/spring-cloud-release/") - .bomBranch("vGreenwich.SR2").projectName("spring-cloud-build") - .expectedVersion("2.1.6.RELEASE").build()), + properties("debugx=true").properties(new ArgsBuilder(project, this.tmp) + .releaseTrainUrl("/projects/spring-cloud-release/").bomBranch("vGreenwich.SR2") + .projectName("spring-cloud-build").expectedVersion("2.1.6.RELEASE").build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); - TestProjectGitHubHandler gitHubHandler = context - .getBean(TestProjectGitHubHandler.class); + TestProjectGitHubHandler gitHubHandler = context.getBean(TestProjectGitHubHandler.class); SaganClient saganClient = context.getBean(SaganClient.class); - PostReleaseActions postReleaseActions = context - .getBean(PostReleaseActions.class); + PostReleaseActions postReleaseActions = context.getBean(PostReleaseActions.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); - ExecutionResult result = releaser - .release(new OptionsBuilder().interactive(true).options()); + ExecutionResult result = releaser.release(new OptionsBuilder().interactive(true).options()); Iterable commits = listOfCommits(project); Iterator iterator = commits.iterator(); tagIsPresentInOrigin(origin, "v2.1.6.RELEASE"); // we're running against camden sc-release - commitIsPresent(iterator, - "Bumping versions to 2.1.7.SNAPSHOT after release"); + commitIsPresent(iterator, "Bumping versions to 2.1.7.SNAPSHOT after release"); commitIsPresent(iterator, "Going back to snapshots"); commitIsPresent(iterator, "Update SNAPSHOT to 2.1.6.RELEASE"); pomVersionIsEqualTo(project, "2.1.7.SNAPSHOT"); - pomParentVersionIsEqualTo(project, "spring-cloud-build-dependencies", - "2.1.6.RELEASE"); + pomParentVersionIsEqualTo(project, "spring-cloud-build-dependencies", "2.1.6.RELEASE"); then(gitHubHandler.closedMilestones).isTrue(); then(emailTemplate()).doesNotExist(); then(blogTemplate()).doesNotExist(); @@ -187,11 +174,9 @@ public class SpringSingleProjectAcceptanceTests then(releaseNotesTemplate()).doesNotExist(); // once for updating GA // second time to update SNAPSHOT - BDDMockito.then(saganClient).should(BDDMockito.times(2)) - .updateRelease(BDDMockito.eq("spring-cloud-build"), - BDDMockito.anyList()); - BDDMockito.then(saganClient).should() - .deleteRelease("spring-cloud-build", "2.1.6.BUILD-SNAPSHOT"); + BDDMockito.then(saganClient).should(times(2)).addRelease(BDDMockito.eq("spring-cloud-build"), + BDDMockito.any()); + BDDMockito.then(saganClient).should().deleteRelease("spring-cloud-build", "2.1.6.BUILD-SNAPSHOT"); then(gitHubHandler.issueCreatedInSpringGuides).isFalse(); then(gitHubHandler.issueCreatedInStartSpringIo).isFalse(); thenRunUpdatedTestsWereNotCalled(postReleaseActions); @@ -211,26 +196,22 @@ public class SpringSingleProjectAcceptanceTests GitTestUtils.setOriginOnProjectToTmp(origin, project); run(this.runner, - properties("debug=true").properties(new ArgsBuilder(project, this.tmp) - .releaseTrainUrl("/projects/spring-cloud-release/") - .bomBranch("vDalston.RC1").expectedVersion("1.2.0.RC1").build()), + properties("debugx=true").properties( + new ArgsBuilder(project, this.tmp).releaseTrainUrl("/projects/spring-cloud-release/") + .bomBranch("vDalston.RC1").expectedVersion("1.2.0.RC1").build()), context -> { SpringReleaser releaser = context.getBean(SpringReleaser.class); - TestProjectGitHubHandler gitHubHandler = context - .getBean(TestProjectGitHubHandler.class); + TestProjectGitHubHandler gitHubHandler = context.getBean(TestProjectGitHubHandler.class); SaganClient saganClient = context.getBean(SaganClient.class); - PostReleaseActions postReleaseActions = context - .getBean(PostReleaseActions.class); + PostReleaseActions postReleaseActions = context.getBean(PostReleaseActions.class); TestExecutionResultHandler testExecutionResultHandler = context .getBean(TestExecutionResultHandler.class); - ExecutionResult result = releaser - .release(new OptionsBuilder().interactive(true).options()); + ExecutionResult result = releaser.release(new OptionsBuilder().interactive(true).options()); Iterable commits = listOfCommits(project); tagIsPresentInOrigin(origin, "v1.2.0.RC1"); - commitIsNotPresent(commits, - "Bumping versions to 1.2.1.SNAPSHOT after release"); + commitIsNotPresent(commits, "Bumping versions to 1.2.1.SNAPSHOT after release"); Iterator iterator = listOfCommits(project).iterator(); commitIsPresent(iterator, "Going back to snapshots"); commitIsPresent(iterator, "Update SNAPSHOT to 1.2.0.RC1"); @@ -241,12 +222,11 @@ public class SpringSingleProjectAcceptanceTests then(blogTemplate()).doesNotExist(); then(tweetTemplate()).doesNotExist(); then(releaseNotesTemplate()).doesNotExist(); - BDDMockito.then(saganClient).should().updateRelease( - BDDMockito.eq("spring-cloud-consul"), BDDMockito.anyList()); - BDDMockito.then(saganClient).should() - .deleteRelease("spring-cloud-consul", "1.2.0.M8"); - BDDMockito.then(saganClient).should() - .deleteRelease("spring-cloud-consul", "1.2.0.RC1"); + BDDMockito.then(saganClient).should().addRelease(BDDMockito.eq("spring-cloud-consul"), + BDDMockito.any()); + BDDMockito.then(saganClient).should(times(2)).getProject("spring-cloud-consul"); + BDDMockito.then(saganClient).should().deleteRelease("spring-cloud-consul", "1.2.0.M8"); + BDDMockito.then(saganClient).should().deleteRelease("spring-cloud-consul", "1.2.0.SNAPSHOT"); // we update guides only for SR / RELEASE then(gitHubHandler.issueCreatedInSpringGuides).isFalse(); then(gitHubHandler.issueCreatedInStartSpringIo).isFalse(); @@ -259,8 +239,7 @@ public class SpringSingleProjectAcceptanceTests } @Test - public void should_not_clone_when_option_not_to_clone_was_switched_on() - throws Exception { + public void should_not_clone_when_option_not_to_clone_was_switched_on() throws Exception { checkoutReleaseTrainBranch("/projects/spring-cloud-release/", "master"); File origin = cloneToTemporaryDirectory(this.springCloudConsulProject); assertThatClonedConsulProjectIsInSnapshots(origin); @@ -269,12 +248,11 @@ public class SpringSingleProjectAcceptanceTests final File temporaryDestination = this.tmp.newFolder(); run(this.runner, - properties("debug=true").properties(new ArgsBuilder(project, this.tmp) - .releaseTrainUrl("/projects/spring-cloud-release/") - .bomBranch("vCamden.SR5").expectedVersion("1.1.2.RELEASE") + properties("debugx=true").properties(new ArgsBuilder(project, this.tmp) + .releaseTrainUrl("/projects/spring-cloud-release/").bomBranch("vCamden.SR5") + .expectedVersion("1.1.2.RELEASE") // just build - .chosenOption("6").fetchVersionsFromGit(false) - .cloneDestinationDirectory(temporaryDestination) + .chosenOption("6").fetchVersionsFromGit(false).cloneDestinationDirectory(temporaryDestination) .addFixedVersion("spring-cloud-release", "Finchley.RELEASE") .addFixedVersion("spring-cloud-consul", "2.3.4.RELEASE").build()), context -> { @@ -288,8 +266,7 @@ public class SpringSingleProjectAcceptanceTests private void assertThatClonedBuildProjectIsInSnapshots(File origin) { pomVersionIsEqualTo(origin, "1.3.7.BUILD-SNAPSHOT"); - pomParentVersionIsEqualTo(origin, "spring-cloud-build-dependencies", - "1.5.9.RELEASE"); + pomParentVersionIsEqualTo(origin, "spring-cloud-build-dependencies", "1.5.9.RELEASE"); } // @formatter:on @@ -305,8 +282,7 @@ public class SpringSingleProjectAcceptanceTests boolean issueCreatedInStartSpringIo = false; - TestProjectGitHubHandler(ReleaserProperties properties, String expectedVersion, - String projectName) { + TestProjectGitHubHandler(ReleaserProperties properties, String expectedVersion, String projectName) { super(properties, Collections.emptyList()); this.expectedVersion = expectedVersion; this.projectName = projectName; @@ -325,8 +301,7 @@ public class SpringSingleProjectAcceptanceTests } @Override - public void createIssueInStartSpringIo(Projects projects, - ProjectVersion version) { + public void createIssueInStartSpringIo(Projects projects, ProjectVersion version) { this.issueCreatedInStartSpringIo = true; } @@ -339,15 +314,15 @@ public class SpringSingleProjectAcceptanceTests @Configuration @EnableAutoConfiguration - @ConditionalOnProperty(value = "test.metarelease", havingValue = "false", - matchIfMissing = true) + @ConditionalOnProperty(value = "test.metarelease", havingValue = "false", matchIfMissing = true) static class SingleProjectReleaseConfig extends DefaultTestConfiguration { @Bean SaganClient testSaganClient() { SaganClient saganClient = BDDMockito.mock(SaganClient.class); - BDDMockito.given(saganClient.getProject(anyString())) - .willReturn(newProject()); + given(saganClient.getProject(anyString())).willReturn(newProject()); + given(saganClient.addRelease(anyString(), any())).willReturn(true); + given(saganClient.deleteRelease(anyString(), anyString())).willReturn(true); return saganClient; } @@ -357,21 +332,17 @@ public class SpringSingleProjectAcceptanceTests } @Bean - TestProjectGitHubHandler testProjectGitHubHandler( - ReleaserProperties releaserProperties, + TestProjectGitHubHandler testProjectGitHubHandler(ReleaserProperties releaserProperties, @Value("${test.expectedVersion}") String expectedVersion, @Value("${test.projectName}") String projectName) { - return new TestProjectGitHubHandler(releaserProperties, expectedVersion, - projectName); + return new TestProjectGitHubHandler(releaserProperties, expectedVersion, projectName); } @Bean - NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler( - ReleaserProperties releaserProperties, + NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler(ReleaserProperties releaserProperties, @Value("${test.projectName}") String projectName) { return new NonAssertingTestProjectGitHandler(releaserProperties, - file -> FileSystemUtils - .deleteRecursively(new File(file, projectName))); + file -> FileSystemUtils.deleteRecursively(new File(file, projectName))); } @Bean @@ -382,8 +353,7 @@ public class SpringSingleProjectAcceptanceTests } @Configuration - @ConditionalOnProperty(value = "test.metarelease", havingValue = "false", - matchIfMissing = true) + @ConditionalOnProperty(value = "test.metarelease", havingValue = "false", matchIfMissing = true) @ComponentScan({ "releaser.internal", "releaser.cloud" }) static class SingleProjectScanningConfiguration { diff --git a/releaser-core/pom.xml b/releaser-core/pom.xml index 44fd792e..98b6e7bd 100644 --- a/releaser-core/pom.xml +++ b/releaser-core/pom.xml @@ -115,9 +115,13 @@ ${awaitility.version} test - - sagan + org.junit.vintage + junit-vintage-engine + test + + + io.spring.sagan sagan-site stubs ${sagan-site.version} diff --git a/releaser-core/src/main/java/releaser/internal/Releaser.java b/releaser-core/src/main/java/releaser/internal/Releaser.java index 859abba4..cacb48d2 100644 --- a/releaser-core/src/main/java/releaser/internal/Releaser.java +++ b/releaser-core/src/main/java/releaser/internal/Releaser.java @@ -69,12 +69,9 @@ public class Releaser { private ReleaserProperties releaserProperties; - public Releaser(ReleaserProperties releaserProperties, - ProjectPomUpdater projectPomUpdater, - ProjectCommandExecutor projectCommandExecutor, - ProjectGitHandler projectGitHandler, - ProjectGitHubHandler projectGitHubHandler, - TemplateGenerator templateGenerator, GradleUpdater gradleUpdater, + public Releaser(ReleaserProperties releaserProperties, ProjectPomUpdater projectPomUpdater, + ProjectCommandExecutor projectCommandExecutor, ProjectGitHandler projectGitHandler, + ProjectGitHubHandler projectGitHubHandler, TemplateGenerator templateGenerator, GradleUpdater gradleUpdater, SaganUpdater saganUpdater, DocumentationUpdater documentationUpdater, PostReleaseActions postReleaseActions) { this.releaserProperties = releaserProperties; @@ -101,56 +98,51 @@ public class Releaser { return this.projectPomUpdater.fixedVersions(); } - public ExecutionResult updateProjectFromBom(File project, Projects versions, - ProjectVersion versionFromBom) { + public ExecutionResult updateProjectFromBom(File project, Projects versions, ProjectVersion versionFromBom) { return updateProjectFromBom(project, versions, versionFromBom, ASSERT_SNAPSHOTS); } - private ExecutionResult updateProjectFromBom(File project, Projects versions, - ProjectVersion versionFromBom, boolean assertSnapshots) { + private ExecutionResult updateProjectFromBom(File project, Projects versions, ProjectVersion versionFromBom, + boolean assertSnapshots) { log.info("Will update the project with versions [{}]", versions); - ReleaserProperties updatedProperties = new ReleaserPropertiesUpdater() - .updateProperties(this.releaserProperties, project); - this.projectPomUpdater.updateProjectFromReleaseTrain(project, versions, - versionFromBom, assertSnapshots); - this.gradleUpdater.updateProjectFromReleaseTrain(updatedProperties, project, - versions, versionFromBom, assertSnapshots); + ReleaserProperties updatedProperties = new ReleaserPropertiesUpdater().updateProperties(this.releaserProperties, + project); + this.projectPomUpdater.updateProjectFromReleaseTrain(project, versions, versionFromBom, assertSnapshots); + this.gradleUpdater.updateProjectFromReleaseTrain(updatedProperties, project, versions, versionFromBom, + assertSnapshots); ProjectVersion changedVersion = new ProjectVersion(project); log.info("\n\nProject was successfully updated to [{}]", changedVersion.version); return ExecutionResult.success(); } - public ExecutionResult buildProject(ReleaserProperties properties, - ProjectVersion originalVersion, ProjectVersion versionFromBom) { + public ExecutionResult buildProject(ReleaserProperties properties, ProjectVersion originalVersion, + ProjectVersion versionFromBom) { this.projectCommandExecutor.build(properties, originalVersion, versionFromBom); log.info("\nProject was successfully built"); return ExecutionResult.success(); } - public ExecutionResult commitAndPushTags(File project, - ProjectVersion changedVersion) { + public ExecutionResult commitAndPushTags(File project, ProjectVersion changedVersion) { this.projectGitHandler.commitAndTagIfApplicable(project, changedVersion); log.info("\nCommit was made and tag was pushed successfully"); return ExecutionResult.success(); } - public ExecutionResult deploy(ReleaserProperties properties, - ProjectVersion originalVersion, ProjectVersion versionFromBom) { + public ExecutionResult deploy(ReleaserProperties properties, ProjectVersion originalVersion, + ProjectVersion versionFromBom) { this.projectCommandExecutor.deploy(properties, originalVersion, versionFromBom); log.info("\nThe artifact was deployed successfully"); return ExecutionResult.success(); } - public ExecutionResult publishDocs(ReleaserProperties properties, - ProjectVersion originalVersion, ProjectVersion changedVersion) { - this.projectCommandExecutor.publishDocs(properties, originalVersion, - changedVersion); + public ExecutionResult publishDocs(ReleaserProperties properties, ProjectVersion originalVersion, + ProjectVersion changedVersion) { + this.projectCommandExecutor.publishDocs(properties, originalVersion, changedVersion); log.info("\nThe docs were published successfully"); return ExecutionResult.success(); } - public ExecutionResult rollbackReleaseVersion(File project, Projects projects, - ProjectVersion scReleaseVersion) { + public ExecutionResult rollbackReleaseVersion(File project, Projects projects, ProjectVersion scReleaseVersion) { if (scReleaseVersion.isSnapshot()) { log.info("\nWon't rollback a snapshot version"); return ExecutionResult.skipped(); @@ -158,34 +150,29 @@ public class Releaser { this.projectGitHandler.revertChangesIfApplicable(project, scReleaseVersion); ProjectVersion originalVersion = originalVersion(project); log.info("Original project version is [{}]", originalVersion); - if ((scReleaseVersion.isRelease() || scReleaseVersion.isServiceRelease()) - && originalVersion.isSnapshot()) { + if ((scReleaseVersion.isRelease() || scReleaseVersion.isServiceRelease()) && originalVersion.isSnapshot()) { updateBumpedVersions(project, projects, originalVersion); } else { - log.info( - "\nSuccessfully reverted the commit and came back to snapshot versions"); + log.info("\nSuccessfully reverted the commit and came back to snapshot versions"); } return ExecutionResult.success(); } - private ExecutionResult updateBumpedVersions(File project, Projects projects, - ProjectVersion originalVersion) { + private ExecutionResult updateBumpedVersions(File project, Projects projects, ProjectVersion originalVersion) { Projects newProjects = Projects.forRollback(releaserProperties, projects); ProjectVersion bumpedProject = bumpProject(originalVersion, newProjects); log.info("Will bump versions \n{}", newProjects); - updateProjectFromBom(project, newProjects, originalVersion, - SKIP_SNAPSHOT_ASSERTION); + updateProjectFromBom(project, newProjects, originalVersion, SKIP_SNAPSHOT_ASSERTION); this.projectGitHandler.commitAfterBumpingVersions(project, bumpedProject); log.info("\nSuccessfully reverted the commit and bumped snapshot versions"); return ExecutionResult.success(); } - private ProjectVersion bumpProject(ProjectVersion originalVersion, - Projects newProjects) { + private ProjectVersion bumpProject(ProjectVersion originalVersion, Projects newProjects) { return newProjects.containsProject(originalVersion.projectName) - ? newProjects.forName(originalVersion.projectName) : new ProjectVersion( - originalVersion.projectName, originalVersion.bumpedVersion()); + ? newProjects.forName(originalVersion.projectName) + : new ProjectVersion(originalVersion.projectName, originalVersion.bumpedVersion()); } ProjectVersion originalVersion(File project) { @@ -214,10 +201,8 @@ public class Releaser { } public ExecutionResult createEmail(ProjectVersion releaseVersion, Projects projects) { - Assert.notNull(releaseVersion, - "You must provide a release version for your project"); - Assert.notNull(releaseVersion.version, - "You must provide a release version for your project"); + Assert.notNull(releaseVersion, "You must provide a release version for your project"); + Assert.notNull(releaseVersion.version, "You must provide a release version for your project"); if (releaseVersion.isSnapshot()) { log.info("\nWon't create email template for a SNAPSHOT version"); return ExecutionResult.skipped(); @@ -229,13 +214,11 @@ public class Releaser { return ExecutionResult.success(); } else { - return ExecutionResult.unstable( - new BuildUnstableException("Failed to create an email template")); + return ExecutionResult.unstable(new BuildUnstableException("Failed to create an email template")); } } catch (Exception ex) { - return ExecutionResult.unstable( - new BuildUnstableException("Failed to create an email template", ex)); + return ExecutionResult.unstable(new BuildUnstableException("Failed to create an email template", ex)); } } @@ -251,53 +234,44 @@ public class Releaser { return ExecutionResult.success(); } else { - return ExecutionResult.unstable( - new BuildUnstableException("Failed to create a blog template")); + return ExecutionResult.unstable(new BuildUnstableException("Failed to create a blog template")); } } catch (Exception ex) { - return ExecutionResult.unstable( - new BuildUnstableException("Failed to create a blog template", ex)); + return ExecutionResult.unstable(new BuildUnstableException("Failed to create a blog template", ex)); } } - public ExecutionResult updateSpringGuides(ProjectVersion releaseVersion, - Projects projects, List processedProjects) { + public ExecutionResult updateSpringGuides(ProjectVersion releaseVersion, Projects projects, + List processedProjects) { if (!(releaseVersion.isRelease() || releaseVersion.isServiceRelease())) { - log.info( - "\nWon't update Spring Guides for a non Release / Service Release version"); + log.info("\nWon't update Spring Guides for a non Release / Service Release version"); return ExecutionResult.skipped(); } - Exception springGuidesException = createIssueInSpringGuides(releaseVersion, - projects); + Exception springGuidesException = createIssueInSpringGuides(releaseVersion, projects); Exception deployGuidesException = deployGuides(processedProjects); if (springGuidesException != null || deployGuidesException != null) { - return ExecutionResult.unstable(new BuildUnstableException( - "Failed to update Spring Guides. Spring Guides updated successfully [" - + (springGuidesException != null) - + "] deployed guides successfully [" + return ExecutionResult.unstable( + new BuildUnstableException("Failed to update Spring Guides. Spring Guides updated successfully [" + + (springGuidesException != null) + "] deployed guides successfully [" + (deployGuidesException != null) + "]")); } return ExecutionResult.success(); } - public ExecutionResult updateStartSpringIo(ProjectVersion releaseVersion, - Projects projects) { + public ExecutionResult updateStartSpringIo(ProjectVersion releaseVersion, Projects projects) { if (!(releaseVersion.isRelease() || releaseVersion.isServiceRelease())) { - log.info( - "\nWon't update start.spring.io for a non Release / Service Release version"); + log.info("\nWon't update start.spring.io for a non Release / Service Release version"); return ExecutionResult.skipped(); } Exception exception = createIssueInStartSpringIo(releaseVersion, projects); if (exception != null) { - return ExecutionResult.unstable( - new BuildUnstableException("Failed to update start.spring.io")); + return ExecutionResult.unstable(new BuildUnstableException("Failed to update start.spring.io")); } return ExecutionResult.success(); } - private Exception createIssueInSpringGuides(ProjectVersion releaseVersion, - Projects projects) { + private Exception createIssueInSpringGuides(ProjectVersion releaseVersion, Projects projects) { try { this.projectGitHubHandler.createIssueInSpringGuides(projects, releaseVersion); log.info("\nSuccessfully created an issue in Spring Guides"); @@ -309,18 +283,15 @@ public class Releaser { } } - private Exception createIssueInStartSpringIo(ProjectVersion releaseVersion, - Projects projects) { + private Exception createIssueInStartSpringIo(ProjectVersion releaseVersion, Projects projects) { try { - this.projectGitHubHandler.createIssueInStartSpringIo(projects, - releaseVersion); + this.projectGitHubHandler.createIssueInStartSpringIo(projects, releaseVersion); log.info("\nSuccessfully created an issue in start.spring.io"); return null; } catch (Exception ex) { log.error("Failed to update start.spring.io repo", ex); - return new BuildUnstableException("Failed to update start.spring.io repo", - ex); + return new BuildUnstableException("Failed to update start.spring.io repo", ex); } } @@ -348,18 +319,15 @@ public class Releaser { return ExecutionResult.success(); } else { - return ExecutionResult.unstable( - new BuildUnstableException("Failed to create a tweet template")); + return ExecutionResult.unstable(new BuildUnstableException("Failed to create a tweet template")); } } catch (Exception ex) { - return ExecutionResult.unstable( - new BuildUnstableException("Failed to create a tweet template", ex)); + return ExecutionResult.unstable(new BuildUnstableException("Failed to create a tweet template", ex)); } } - public ExecutionResult createReleaseNotes(ProjectVersion releaseVersion, - Projects projects) { + public ExecutionResult createReleaseNotes(ProjectVersion releaseVersion, Projects projects) { if (releaseVersion.isSnapshot()) { log.info("\nWon't create release notes for a SNAPSHOT version"); return ExecutionResult.skipped(); @@ -370,18 +338,15 @@ public class Releaser { return ExecutionResult.success(); } catch (Exception ex) { - return ExecutionResult.unstable( - new BuildUnstableException("Failed to create release notes", ex)); + return ExecutionResult.unstable(new BuildUnstableException("Failed to create release notes", ex)); } } - public ExecutionResult updateSagan(File project, ProjectVersion releaseVersion, - Projects projects) { + public ExecutionResult updateSagan(File project, ProjectVersion releaseVersion, Projects projects) { String currentBranch = this.projectGitHandler.currentBranch(project); ProjectVersion originalVersion = new ProjectVersion(project); try { - return this.saganUpdater.updateSagan(project, currentBranch, originalVersion, - releaseVersion, projects); + return this.saganUpdater.updateSagan(project, currentBranch, originalVersion, releaseVersion, projects); } catch (Exception ex) { return ExecutionResult.unstable(new BuildUnstableException(ex)); diff --git a/releaser-core/src/main/java/releaser/internal/ReleaserProperties.java b/releaser-core/src/main/java/releaser/internal/ReleaserProperties.java index 1061db9d..3dab2f5d 100644 --- a/releaser-core/src/main/java/releaser/internal/ReleaserProperties.java +++ b/releaser-core/src/main/java/releaser/internal/ReleaserProperties.java @@ -87,8 +87,7 @@ public class ReleaserProperties implements Serializable { private MetaRelease metaRelease = new MetaRelease(); public String getWorkingDir() { - return StringUtils.hasText(this.workingDir) ? this.workingDir - : System.getProperty("user.dir"); + return StringUtils.hasText(this.workingDir) ? this.workingDir : System.getProperty("user.dir"); } public void setWorkingDir(String workingDir) { @@ -201,10 +200,9 @@ public class ReleaserProperties implements Serializable { @Override public String toString() { - return "ReleaserProperties{" + "workingDir='" + this.workingDir + '\'' + ", git=" - + this.git + ", pom=" + this.pom + ", maven=" + this.maven + ", gradle=" - + this.gradle + ", sagan=" + this.sagan + ", fixedVersions=" - + this.fixedVersions + ", metaRelease=" + this.metaRelease + ", template=" + return "ReleaserProperties{" + "workingDir='" + this.workingDir + '\'' + ", git=" + this.git + ", pom=" + + this.pom + ", maven=" + this.maven + ", gradle=" + this.gradle + ", sagan=" + this.sagan + + ", fixedVersions=" + this.fixedVersions + ", metaRelease=" + this.metaRelease + ", template=" + this.template + ", versions=" + this.versions + '}'; } @@ -362,8 +360,7 @@ public class ReleaserProperties implements Serializable { return this.releaseTrainDependencyNames; } - public void setReleaseTrainDependencyNames( - List releaseTrainDependencyNames) { + public void setReleaseTrainDependencyNames(List releaseTrainDependencyNames) { this.releaseTrainDependencyNames = releaseTrainDependencyNames; } @@ -401,12 +398,10 @@ public class ReleaserProperties implements Serializable { @Override public String toString() { - return "MetaRelease{" + "enabled=" + enabled + ", releaseTrainProjectName='" - + releaseTrainProjectName + '\'' + ", releaseTrainDependencyNames=" - + releaseTrainDependencyNames + ", gitOrgUrl='" + gitOrgUrl + '\'' - + ", projectsToSkip=" + projectsToSkip + ", releaseGroups=" - + releaseGroups + ", releaseGroupTimeoutInMinutes=" - + releaseGroupTimeoutInMinutes + ", releaseGroupThreadCount=" + return "MetaRelease{" + "enabled=" + enabled + ", releaseTrainProjectName='" + releaseTrainProjectName + + '\'' + ", releaseTrainDependencyNames=" + releaseTrainDependencyNames + ", gitOrgUrl='" + + gitOrgUrl + '\'' + ", projectsToSkip=" + projectsToSkip + ", releaseGroups=" + releaseGroups + + ", releaseGroupTimeoutInMinutes=" + releaseGroupTimeoutInMinutes + ", releaseGroupThreadCount=" + releaseGroupThreadCount + '}'; } @@ -823,21 +818,16 @@ public class ReleaserProperties implements Serializable { @Override public String toString() { - return "Git{" + "releaseTrainBomUrl='" + this.releaseTrainBomUrl + '\'' - + ", documentationUrl='" + this.documentationUrl + '\'' - + ", documentationBranch='" + this.documentationBranch + '\'' - + ", releaseTrainBranch='" + this.releaseTrainBranch + '\'' - + ", releaseTrainWikiUrl='" + this.releaseTrainWikiUrl + '\'' - + ", updateDocumentationRepo=" + this.updateDocumentationRepo - + ", springProjectUrl=" + this.springProjectUrl - + ", springProjectBranch=" + this.springProjectBranch - + ", releaseTrainWikiPagePrefix=" + this.releaseTrainWikiPagePrefix - + ", cloneDestinationDir='" + this.cloneDestinationDir + '\'' - + ", fetchVersionsFromGit=" + this.fetchVersionsFromGit - + ", numberOfCheckedMilestones=" + this.numberOfCheckedMilestones - + ", updateSpringGuides=" + this.updateSpringGuides - + ", updateSpringProject=" + this.updateSpringProject - + ", sampleUrlsSize=" + this.allTestSampleUrls.size() + '}'; + return "Git{" + "releaseTrainBomUrl='" + this.releaseTrainBomUrl + '\'' + ", documentationUrl='" + + this.documentationUrl + '\'' + ", documentationBranch='" + this.documentationBranch + '\'' + + ", releaseTrainBranch='" + this.releaseTrainBranch + '\'' + ", releaseTrainWikiUrl='" + + this.releaseTrainWikiUrl + '\'' + ", updateDocumentationRepo=" + this.updateDocumentationRepo + + ", springProjectUrl=" + this.springProjectUrl + ", springProjectBranch=" + + this.springProjectBranch + ", releaseTrainWikiPagePrefix=" + this.releaseTrainWikiPagePrefix + + ", cloneDestinationDir='" + this.cloneDestinationDir + '\'' + ", fetchVersionsFromGit=" + + this.fetchVersionsFromGit + ", numberOfCheckedMilestones=" + this.numberOfCheckedMilestones + + ", updateSpringGuides=" + this.updateSpringGuides + ", updateSpringProject=" + + this.updateSpringProject + ", sampleUrlsSize=" + this.allTestSampleUrls.size() + '}'; } } @@ -918,11 +908,10 @@ public class ReleaserProperties implements Serializable { @Override public String toString() { - return "Pom{" + "branch='" + this.branch + '\'' - + ", pomWithBootStarterParent='" + this.pomWithBootStarterParent - + '\'' + ", thisTrainBom='" + this.thisTrainBom + '\'' - + ", bomVersionPattern='" + this.bomVersionPattern + '\'' - + ", ignoredPomRegex=" + this.ignoredPomRegex + '}'; + return "Pom{" + "branch='" + this.branch + '\'' + ", pomWithBootStarterParent='" + + this.pomWithBootStarterParent + '\'' + ", thisTrainBom='" + this.thisTrainBom + '\'' + + ", bomVersionPattern='" + this.bomVersionPattern + '\'' + ", ignoredPomRegex=" + + this.ignoredPomRegex + '}'; } } @@ -1039,8 +1028,7 @@ public class ReleaserProperties implements Serializable { } @Override - public void setGenerateReleaseTrainDocsCommand( - String generateReleaseTrainDocsCommand) { + public void setGenerateReleaseTrainDocsCommand(String generateReleaseTrainDocsCommand) { this.generateReleaseTrainDocsCommand = generateReleaseTrainDocsCommand; } @@ -1056,12 +1044,10 @@ public class ReleaserProperties implements Serializable { @Override public String toString() { - return "Maven{" + "buildCommand='" + this.buildCommand + '\'' - + ", deployCommand='" + this.deployCommand + '\'' - + ", publishDocsCommand=" + this.publishDocsCommand - + "generateReleaseTrainDocsCommand='" - + this.generateReleaseTrainDocsCommand + '\'' + ", waitTimeInMinutes=" - + this.waitTimeInMinutes + '}'; + return "Maven{" + "buildCommand='" + this.buildCommand + '\'' + ", deployCommand='" + this.deployCommand + + '\'' + ", publishDocsCommand=" + this.publishDocsCommand + "generateReleaseTrainDocsCommand='" + + this.generateReleaseTrainDocsCommand + '\'' + ", waitTimeInMinutes=" + this.waitTimeInMinutes + + '}'; } } @@ -1173,8 +1159,7 @@ public class ReleaserProperties implements Serializable { } @Override - public void setGenerateReleaseTrainDocsCommand( - String generateReleaseTrainDocsCommand) { + public void setGenerateReleaseTrainDocsCommand(String generateReleaseTrainDocsCommand) { this.generateReleaseTrainDocsCommand = generateReleaseTrainDocsCommand; } @@ -1190,12 +1175,10 @@ public class ReleaserProperties implements Serializable { @Override public String toString() { - return "Bash{" + "buildCommand='" + this.buildCommand + '\'' - + ", deployCommand='" + this.deployCommand + '\'' - + ", publishDocsCommand=" + this.publishDocsCommand - + "generateReleaseTrainDocsCommand='" - + this.generateReleaseTrainDocsCommand + '\'' + ", waitTimeInMinutes=" - + this.waitTimeInMinutes + '}'; + return "Bash{" + "buildCommand='" + this.buildCommand + '\'' + ", deployCommand='" + this.deployCommand + + '\'' + ", publishDocsCommand=" + this.publishDocsCommand + "generateReleaseTrainDocsCommand='" + + this.generateReleaseTrainDocsCommand + '\'' + ", waitTimeInMinutes=" + this.waitTimeInMinutes + + '}'; } } @@ -1328,8 +1311,7 @@ public class ReleaserProperties implements Serializable { } @Override - public void setGenerateReleaseTrainDocsCommand( - String generateReleaseTrainDocsCommand) { + public void setGenerateReleaseTrainDocsCommand(String generateReleaseTrainDocsCommand) { this.generateReleaseTrainDocsCommand = generateReleaseTrainDocsCommand; } @@ -1347,8 +1329,7 @@ public class ReleaserProperties implements Serializable { return this.gradlePropsSubstitution; } - public void setGradlePropsSubstitution( - Map gradlePropsSubstitution) { + public void setGradlePropsSubstitution(Map gradlePropsSubstitution) { this.gradlePropsSubstitution = gradlePropsSubstitution; } @@ -1364,15 +1345,13 @@ public class ReleaserProperties implements Serializable { public String toString() { return new StringJoiner(", ", Gradle.class.getSimpleName() + "[", "]") .add("gradlePropsSubstitution=" + gradlePropsSubstitution) - .add("ignoredGradleRegex=" + ignoredGradleRegex) - .add("buildCommand='" + buildCommand + "'") + .add("ignoredGradleRegex=" + ignoredGradleRegex).add("buildCommand='" + buildCommand + "'") .add("deployCommand='" + deployCommand + "'") .add("deployGuidesCommand='" + deployGuidesCommand + "'") .add("publishDocsCommand=" + publishDocsCommand) - .add("generateReleaseTrainDocsCommand='" - + generateReleaseTrainDocsCommand + "'") - .add("systemProperties='" + systemProperties + "'") - .add("waitTimeInMinutes=" + waitTimeInMinutes).toString(); + .add("generateReleaseTrainDocsCommand='" + generateReleaseTrainDocsCommand + "'") + .add("systemProperties='" + systemProperties + "'").add("waitTimeInMinutes=" + waitTimeInMinutes) + .toString(); } } @@ -1519,8 +1498,8 @@ public class ReleaserProperties implements Serializable { @Override public String toString() { - return "Versions{" + "allVersionsFileUrl='" + this.allVersionsFileUrl + '\'' - + ", bomName='" + this.bomName + '\'' + '}'; + return "Versions{" + "allVersionsFileUrl='" + this.allVersionsFileUrl + '\'' + ", bomName='" + this.bomName + + '\'' + '}'; } } diff --git a/releaser-core/src/main/java/releaser/internal/ReleaserPropertiesUpdater.java b/releaser-core/src/main/java/releaser/internal/ReleaserPropertiesUpdater.java index d8633992..837fe4dc 100644 --- a/releaser-core/src/main/java/releaser/internal/ReleaserPropertiesUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/ReleaserPropertiesUpdater.java @@ -41,13 +41,11 @@ import org.springframework.util.StringUtils; */ public class ReleaserPropertiesUpdater implements Closeable { - private static final Logger log = LoggerFactory - .getLogger(ReleaserPropertiesUpdater.class); + private static final Logger log = LoggerFactory.getLogger(ReleaserPropertiesUpdater.class); private static final Map CACHE = new ConcurrentHashMap<>(); - public ReleaserProperties updateProperties(ReleaserProperties properties, - File clonedProjectFromOrg) { + public ReleaserProperties updateProperties(ReleaserProperties properties, File clonedProjectFromOrg) { return CACHE.computeIfAbsent(clonedProjectFromOrg, file -> { ReleaserProperties props = updatePropertiesFromFile(properties.copy(), file); props.setWorkingDir(clonedProjectFromOrg.getAbsolutePath()); @@ -56,8 +54,7 @@ public class ReleaserPropertiesUpdater implements Closeable { }); } - private ReleaserProperties updatePropertiesFromFile(ReleaserProperties copy, - File clonedProjectFromOrg) { + private ReleaserProperties updatePropertiesFromFile(ReleaserProperties copy, File clonedProjectFromOrg) { File releaserConfig = releaserConfig(clonedProjectFromOrg); if (releaserConfig.exists()) { try { @@ -66,11 +63,8 @@ public class ReleaserPropertiesUpdater implements Closeable { Properties properties = yamlProcessor.getObject(); ReleaserProperties releaserProperties = new Binder( new MapConfigurationPropertySource(properties.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().toString(), - e -> e.getValue().toString())))) - .bind("releaser", - ReleaserProperties.class) - .get(); + .collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString())))) + .bind("releaser", ReleaserProperties.class).get(); log.info("config/releaser.yml found. Will update the current properties"); overrideProperties(releaserProperties, copy); } @@ -79,17 +73,14 @@ public class ReleaserPropertiesUpdater implements Closeable { } } else { - log.info( - "No config/releaser.yml found. Will NOT update the current properties"); + log.info("No config/releaser.yml found. Will NOT update the current properties"); } - log.info("Updating working directory to [{}]", - clonedProjectFromOrg.getAbsolutePath()); + log.info("Updating working directory to [{}]", clonedProjectFromOrg.getAbsolutePath()); copy.setWorkingDir(clonedProjectFromOrg.getAbsolutePath()); return copy; } - private void overrideProperties(ReleaserProperties fromProject, - ReleaserProperties copy) { + private void overrideProperties(ReleaserProperties fromProject, ReleaserProperties copy) { overrideCommandIfPresent(fromProject.getMaven(), copy.getMaven()); overrideCommandIfPresent(fromProject.getGradle(), copy.getGradle()); overrideMapIfPresent(() -> fromProject.getGradle().getGradlePropsSubstitution(), @@ -101,45 +92,36 @@ public class ReleaserPropertiesUpdater implements Closeable { private void overrideCommandIfPresent(ReleaserProperties.Command fromProject, ReleaserProperties.Command commandCopy) { - overrideStringIfPresent(fromProject::getBuildCommand, - commandCopy::setBuildCommand); - overrideStringIfPresent(fromProject::getDeployCommand, - commandCopy::setDeployCommand); + overrideStringIfPresent(fromProject::getBuildCommand, commandCopy::setBuildCommand); + overrideStringIfPresent(fromProject::getDeployCommand, commandCopy::setDeployCommand); overrideStringIfPresent(fromProject::getGenerateReleaseTrainDocsCommand, commandCopy::setGenerateReleaseTrainDocsCommand); - overrideStringIfPresent(fromProject::getPublishDocsCommand, - commandCopy::setPublishDocsCommand); - overrideStringIfPresent(fromProject::getDeployGuidesCommand, - commandCopy::setDeployGuidesCommand); - overrideStringIfPresent(fromProject::getSystemProperties, - commandCopy::setSystemProperties); + overrideStringIfPresent(fromProject::getPublishDocsCommand, commandCopy::setPublishDocsCommand); + overrideStringIfPresent(fromProject::getDeployGuidesCommand, commandCopy::setDeployGuidesCommand); + overrideStringIfPresent(fromProject::getSystemProperties, commandCopy::setSystemProperties); } - private void overrideStringIfPresent(Supplier predicate, - Consumer consumer) { + private void overrideStringIfPresent(Supplier predicate, Consumer consumer) { if (StringUtils.hasText(predicate.get())) { consumer.accept(predicate.get()); } } - private void overrideArrayIfPresent(Supplier predicate, - Consumer consumer) { + private void overrideArrayIfPresent(Supplier predicate, Consumer consumer) { String[] strings = predicate.get(); if (strings.length > 0) { consumer.accept(strings); } } - private void overrideMapIfPresent(Supplier> predicate, - Consumer> consumer) { + private void overrideMapIfPresent(Supplier> predicate, Consumer> consumer) { Map strings = predicate.get(); if (!strings.isEmpty()) { consumer.accept(strings); } } - private void overrideListIfPresent(Supplier> predicate, - Consumer> consumer) { + private void overrideListIfPresent(Supplier> predicate, Consumer> consumer) { List strings = predicate.get(); if (!strings.isEmpty()) { consumer.accept(strings); diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/CompositeBomParser.java b/releaser-core/src/main/java/releaser/internal/buildsystem/CompositeBomParser.java index 4c978c0d..4c1d6448 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/CompositeBomParser.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/CompositeBomParser.java @@ -39,15 +39,13 @@ class CompositeBomParser implements BomParser { } private BomParser firstMatching(File thisProjectRoot) { - return this.parsers.stream().filter(b -> b.isApplicable(thisProjectRoot)) - .findFirst().orElseThrow( - () -> new IllegalStateException("Can't find a matching parser")); + return this.parsers.stream().filter(b -> b.isApplicable(thisProjectRoot)).findFirst() + .orElseThrow(() -> new IllegalStateException("Can't find a matching parser")); } @Override public List customBomParsers() { - return this.parsers.stream().flatMap(b -> b.customBomParsers().stream()) - .collect(Collectors.toList()); + return this.parsers.stream().flatMap(b -> b.customBomParsers().stream()).collect(Collectors.toList()); } } diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/CustomBomParser.java b/releaser-core/src/main/java/releaser/internal/buildsystem/CustomBomParser.java index 425c5790..ae9daf03 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/CustomBomParser.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/CustomBomParser.java @@ -28,8 +28,7 @@ import releaser.internal.project.Project; */ public interface CustomBomParser { - CustomBomParser NO_OP = (thisProjectRoot, - properties) -> VersionsFromBom.EMPTY_VERSION; + CustomBomParser NO_OP = (thisProjectRoot, properties) -> VersionsFromBom.EMPTY_VERSION; /** * When parsing a part of the BOM pom, one can add custom logic to perform project @@ -48,8 +47,7 @@ public interface CustomBomParser { * @param version - version of the project * @return - a new collection with the modified versions from bom */ - default Set setVersion(Set projects, String projectName, - String version) { + default Set setVersion(Set projects, String projectName, String version) { return new LinkedHashSet<>(projects); } diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/GradleBomParser.java b/releaser-core/src/main/java/releaser/internal/buildsystem/GradleBomParser.java index 43818eeb..ec7e3233 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/GradleBomParser.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/GradleBomParser.java @@ -33,8 +33,7 @@ class GradleBomParser implements BomParser { private final GradleProjectNameExtractor extractor = new GradleProjectNameExtractor(); - GradleBomParser(ReleaserProperties releaserProperties, - List customParsers) { + GradleBomParser(ReleaserProperties releaserProperties, List customParsers) { this.properties = releaserProperties; this.customParsers = customParsers; } @@ -55,11 +54,9 @@ class GradleBomParser implements BomParser { return VersionsFromBom.EMPTY_VERSION; } Properties properties = loadProps(gradleProperties); - final Map substitution = this.properties.getGradle() - .getGradlePropsSubstitution(); - VersionsFromBom versionsFromBom = new VersionsFromBomBuilder() - .thisProjectRoot(thisProjectRoot).releaserProperties(this.properties) - .parsers(this.customParsers).retrieveFromBom(); + final Map substitution = this.properties.getGradle().getGradlePropsSubstitution(); + VersionsFromBom versionsFromBom = new VersionsFromBomBuilder().thisProjectRoot(thisProjectRoot) + .releaserProperties(this.properties).parsers(this.customParsers).retrieveFromBom(); properties.forEach((key, value) -> { String projectName = this.extractor.projectName(substitution, key); versionsFromBom.setVersion(projectName, value.toString()); diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/GradleProjectNameExtractor.java b/releaser-core/src/main/java/releaser/internal/buildsystem/GradleProjectNameExtractor.java index 2ab074c2..ee133fec 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/GradleProjectNameExtractor.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/GradleProjectNameExtractor.java @@ -22,8 +22,7 @@ import java.util.regex.Pattern; class GradleProjectNameExtractor { - private static final Pattern VERSION_PATTERN = Pattern - .compile("^([a-zA-Z0-9]+)Version$"); + private static final Pattern VERSION_PATTERN = Pattern.compile("^([a-zA-Z0-9]+)Version$"); String projectName(Map substitution, Object key) { String projectName = key.toString(); diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/GradleUpdater.java b/releaser-core/src/main/java/releaser/internal/buildsystem/GradleUpdater.java index 0db4ca0a..31cfdfcb 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/GradleUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/GradleUpdater.java @@ -55,18 +55,16 @@ public class GradleUpdater { * @param versionFromBom - version for the project from Spring Cloud Release * @param assertVersions - should snapshots / milestone / rc presence be asserted */ - public void updateProjectFromReleaseTrain(ReleaserProperties properties, - File projectRoot, Projects projects, ProjectVersion versionFromBom, - boolean assertVersions) { - processAllGradleProps(properties, projectRoot, projects, versionFromBom, - assertVersions); + public void updateProjectFromReleaseTrain(ReleaserProperties properties, File projectRoot, Projects projects, + ProjectVersion versionFromBom, boolean assertVersions) { + processAllGradleProps(properties, projectRoot, projects, versionFromBom, assertVersions); } - private void processAllGradleProps(ReleaserProperties properties, File projectRoot, - Projects projects, ProjectVersion versionFromBom, boolean assertVersions) { + private void processAllGradleProps(ReleaserProperties properties, File projectRoot, Projects projects, + ProjectVersion versionFromBom, boolean assertVersions) { try { - Files.walkFileTree(projectRoot.toPath(), new GradlePropertiesWalker( - properties, projects, versionFromBom, assertVersions)); + Files.walkFileTree(projectRoot.toPath(), + new GradlePropertiesWalker(properties, projects, versionFromBom, assertVersions)); } catch (IOException e) { throw new IllegalStateException(e); @@ -89,15 +87,13 @@ public class GradleUpdater { private final GradleProjectNameExtractor extractor = new GradleProjectNameExtractor(); - private GradlePropertiesWalker(ReleaserProperties properties, Projects projects, - ProjectVersion versionFromBom, boolean assertVersions) { + private GradlePropertiesWalker(ReleaserProperties properties, Projects projects, ProjectVersion versionFromBom, + boolean assertVersions) { this.properties = properties; this.projects = projects; - List unacceptableVersionPatterns = versionFromBom - .unacceptableVersionPatterns(); + List unacceptableVersionPatterns = versionFromBom.unacceptableVersionPatterns(); this.unacceptableVersionPatterns = unacceptableVersionPatterns; - this.skipVersionAssert = !assertVersions - || unacceptableVersionPatterns.isEmpty(); + this.skipVersionAssert = !assertVersions || unacceptableVersionPatterns.isEmpty(); this.assertVersions = assertVersions; } @@ -106,20 +102,15 @@ public class GradleUpdater { File file = path.toFile(); if (GRADLE_PROPERTIES.equals(file.getName())) { if (pathIgnored(file)) { - log.debug( - "Ignoring file [{}] since it's on a list of patterns to ignore", - file); + log.debug("Ignoring file [{}] since it's on a list of patterns to ignore", file); return FileVisitResult.CONTINUE; } String parentName = file.getParentFile().getName(); - log.info("Will process the file [{}] and update its gradle properties", - file); + log.info("Will process the file [{}] and update its gradle properties", file); final String fileContents = asString(path); - final AtomicReference changedString = new AtomicReference<>( - fileContents); + final AtomicReference changedString = new AtomicReference<>(fileContents); Properties props = loadProps(file); - final Map substitution = this.properties.getGradle() - .getGradlePropsSubstitution(); + final Map substitution = this.properties.getGradle().getGradlePropsSubstitution(); props.forEach((key, value1) -> { String projectName = projectName(parentName, substitution, key); if (!this.projects.containsProject(projectName)) { @@ -130,10 +121,8 @@ public class GradleUpdater { } ProjectVersion value = this.projects.forName(projectName); if (!value.version.equalsIgnoreCase(value1.toString())) { - log.info("Replacing [{}->{}] with [{}->{}]", key, value1, key, - value); - changedString.set(changedString.get().replace(key + "=" + value1, - key + "=" + value)); + log.info("Replacing [{}->{}] with [{}->{}]", key, value1, key, value); + changedString.set(changedString.get().replace(key + "=" + value1, key + "=" + value)); } }); storeString(path, changedString.get()); @@ -142,8 +131,7 @@ public class GradleUpdater { return FileVisitResult.CONTINUE; } - private String projectName(String parentName, Map substitution, - Object key) { + private String projectName(String parentName, Map substitution, Object key) { // version -> current project version if (key.equals("version")) { return parentName; @@ -155,21 +143,18 @@ public class GradleUpdater { if (this.assertVersions && !this.skipVersionAssert) { log.debug( "Update should check if no wrong versions remained in the gradle prop. List of wrong patterns: {}", - this.unacceptableVersionPatterns.stream().map(Pattern::pattern) - .collect(Collectors.toList())); + this.unacceptableVersionPatterns.stream().map(Pattern::pattern).collect(Collectors.toList())); Scanner scanner = new Scanner(asString(path)); int lineNumber = 0; while (scanner.hasNextLine()) { String line = scanner.nextLine(); lineNumber++; Pattern matchingPattern = this.unacceptableVersionPatterns.stream() - .filter(pattern -> pattern.matcher(line).matches()) - .findFirst().orElse(null); + .filter(pattern -> pattern.matcher(line).matches()).findFirst().orElse(null); if (matchingPattern != null) { - throw new IllegalStateException("The file [" + path - + "] matches the [ " + matchingPattern.pattern() - + "] pattern in line number [" + lineNumber + "]\n\n" - + line); + throw new IllegalStateException( + "The file [" + path + "] matches the [ " + matchingPattern.pattern() + + "] pattern in line number [" + lineNumber + "]\n\n" + line); } } log.info("No invalid versions remained in the gradle properties"); @@ -178,8 +163,8 @@ public class GradleUpdater { private boolean pathIgnored(File file) { String path = file.getPath(); - return this.assertVersions && this.properties.getGradle() - .getIgnoredGradleRegex().stream().anyMatch(path::matches); + return this.assertVersions + && this.properties.getGradle().getIgnoredGradleRegex().stream().anyMatch(path::matches); } private Properties loadProps(File file) { diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/MavenBomParser.java b/releaser-core/src/main/java/releaser/internal/buildsystem/MavenBomParser.java index ba106ada..494e11ae 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/MavenBomParser.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/MavenBomParser.java @@ -50,10 +50,8 @@ class MavenBomParser implements BomParser { MavenBomParser(ReleaserProperties properties, List customParsers) { this.thisTrainBomLocation = properties.getPom().getThisTrainBom(); - this.versionPattern = StringUtils - .hasText(properties.getPom().getBomVersionPattern()) - ? Pattern.compile(properties.getPom().getBomVersionPattern()) - : Pattern.compile(".*"); + this.versionPattern = StringUtils.hasText(properties.getPom().getBomVersionPattern()) + ? Pattern.compile(properties.getPom().getBomVersionPattern()) : Pattern.compile(".*"); this.properties = properties; this.customParsers = customParsers; } @@ -71,13 +69,11 @@ class MavenBomParser implements BomParser { if (model == null) { return VersionsFromBom.EMPTY_VERSION; } - Set projects = model.getProperties().entrySet().stream() - .filter(propertyMatchesVersionPattern()).map(toProject()) - .collect(Collectors.toSet()); + Set projects = model.getProperties().entrySet().stream().filter(propertyMatchesVersionPattern()) + .map(toProject()).collect(Collectors.toSet()); String releaseTrainProjectVersion = model.getVersion(); projects.add( - new Project(this.properties.getMetaRelease().getReleaseTrainProjectName(), - releaseTrainProjectVersion)); + new Project(this.properties.getMetaRelease().getReleaseTrainProjectName(), releaseTrainProjectVersion)); // @formatter:off return new VersionsFromBomBuilder() .thisProjectRoot(thisProjectRoot) diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/PomUpdater.java b/releaser-core/src/main/java/releaser/internal/buildsystem/PomUpdater.java index 712d9f58..41706f26 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/PomUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/PomUpdater.java @@ -75,13 +75,10 @@ class PomUpdater { } String artifactId = artifactId(model); if (!versionsFromBom.shouldBeUpdated(artifactId)) { - log.info( - "Skipping project [{}] since it's not on the list of projects to update", - model.getArtifactId()); + log.info("Skipping project [{}] since it's not on the list of projects to update", model.getArtifactId()); return false; } - log.info("Project [{}] will have its dependencies updated", - model.getArtifactId()); + log.info("Project [{}] will have its dependencies updated", model.getArtifactId()); return true; } @@ -95,8 +92,7 @@ class PomUpdater { return false; } boolean plugins = model.getBuild().getPlugins().stream() - .filter(plugin -> "maven-deploy-plugin" - .equalsIgnoreCase(plugin.getArtifactId())) + .filter(plugin -> "maven-deploy-plugin".equalsIgnoreCase(plugin.getArtifactId())) .map(this::skipFromConfiguration).findFirst().orElse(false); if (plugins) { return true; @@ -105,8 +101,7 @@ class PomUpdater { return false; } return model.getBuild().getPluginManagement().getPlugins().stream() - .filter(plugin -> "maven-deploy-plugin" - .equalsIgnoreCase(plugin.getArtifactId())) + .filter(plugin -> "maven-deploy-plugin".equalsIgnoreCase(plugin.getArtifactId())) .map(this::skipFromConfiguration).findFirst().orElse(false); } @@ -131,8 +126,7 @@ class PomUpdater { if (!parent) { return model.getArtifactId(); } - return model.getArtifactId().substring(0, - model.getArtifactId().indexOf("-parent")); + return model.getArtifactId().substring(0, model.getArtifactId().indexOf("-parent")); } ModelWrapper readModel(File pom) { @@ -146,14 +140,11 @@ class PomUpdater { * @param versionsFromBom - versions to update * @return updated model */ - ModelWrapper updateModel(ModelWrapper rootPom, File pom, - VersionsFromBom versionsFromBom) { + ModelWrapper updateModel(ModelWrapper rootPom, File pom, VersionsFromBom versionsFromBom) { Model model = PomReader.readPom(pom); List sourceChanges = new ArrayList<>(); - sourceChanges = updateParentIfPossible(rootPom, versionsFromBom, model, - sourceChanges); - sourceChanges = updateVersionIfPossible(rootPom, versionsFromBom, model, - sourceChanges); + sourceChanges = updateParentIfPossible(rootPom, versionsFromBom, model, sourceChanges); + sourceChanges = updateVersionIfPossible(rootPom, versionsFromBom, model, sourceChanges); return new ModelWrapper(model, sourceChanges, versionsFromBom, pom); } @@ -162,8 +153,7 @@ class PomUpdater { * changes in the model. * @return - the pom file */ - File overwritePomIfDirty(ModelWrapper updatedPomModel, - VersionsFromBom versionsFromBom, File pom) { + File overwritePomIfDirty(ModelWrapper updatedPomModel, VersionsFromBom versionsFromBom, File pom) { if (updatedPomModel.isDirty()) { log.debug("There were changes in the pom so file will be overridden"); this.pomWriter.write(updatedPomModel, versionsFromBom, pom); @@ -172,9 +162,8 @@ class PomUpdater { return pom; } - private List updateParentIfPossible(ModelWrapper wrapper, - VersionsFromBom versionsFromBom, Model model, - List sourceChanges) { + private List updateParentIfPossible(ModelWrapper wrapper, VersionsFromBom versionsFromBom, + Model model, List sourceChanges) { String rootProjectName = wrapper.projectName(); List changes = new ArrayList<>(sourceChanges); if (model.getParent() == null || isEmpty(model.getParent().getVersion())) { @@ -183,8 +172,7 @@ class PomUpdater { } String parentGroupId = model.getParent().getGroupId(); String parentArtifactId = model.getParent().getArtifactId(); - log.debug("Searching for a version of parent [{}:{}]", parentGroupId, - parentArtifactId); + log.debug("Searching for a version of parent [{}:{}]", parentGroupId, parentArtifactId); String oldVersion = model.getParent().getVersion(); String version = versionsFromBom.versionForProject(parentArtifactId); log.debug("Found version is [{}]", version); @@ -193,38 +181,32 @@ class PomUpdater { version = versionsFromBom.versionForProject(rootProjectName); } else { - log.warn("There is no info on the [{}:{}] version", parentGroupId, - parentArtifactId); + log.warn("There is no info on the [{}:{}] version", parentGroupId, parentArtifactId); return changes; } } if (oldVersion.equals(version)) { - log.debug( - "Won't update the version of parent [{}:{}] since you're already using the proper one", + log.debug("Won't update the version of parent [{}:{}] since you're already using the proper one", parentGroupId, parentArtifactId); return changes; } - log.info("Setting version of parent [{}] to [{}] for module [{}]", - parentArtifactId, version, model.getArtifactId()); + log.info("Setting version of parent [{}] to [{}] for module [{}]", parentArtifactId, version, + model.getArtifactId()); if (hasText(version)) { - changes.add(new VersionChange(parentGroupId, parentArtifactId, oldVersion, - version)); + changes.add(new VersionChange(parentGroupId, parentArtifactId, oldVersion, version)); } return changes; } - private List updateVersionIfPossible(ModelWrapper wrapper, - VersionsFromBom versionsFromBom, Model model, - List sourceChanges) { + private List updateVersionIfPossible(ModelWrapper wrapper, VersionsFromBom versionsFromBom, + Model model, List sourceChanges) { String rootProjectName = wrapper.projectName(); String rootProjectGroupId = wrapper.groupId(); List changes = new ArrayList<>(sourceChanges); String groupId = groupId(model); String artifactId = model.getArtifactId(); - if (model.getGroupId() != null - && !model.getGroupId().equals(rootProjectGroupId)) { - log.info( - "Will not update project [{}] since its group id [{}] is not equal the parent group id [{}]", + if (model.getGroupId() != null && !model.getGroupId().equals(rootProjectGroupId)) { + log.info("Will not update project [{}] since its group id [{}] is not equal the parent group id [{}]", model.getArtifactId(), model.getGroupId(), rootProjectGroupId); return changes; } @@ -233,15 +215,13 @@ class PomUpdater { String version = versionsFromBom.versionForProject(rootProjectName); log.debug("Found version is [{}]", version); if (isEmpty(version) || isEmpty(model.getVersion())) { - log.debug( - "There was no version set for project [{}], skipping version setting for module [{}]", + log.debug("There was no version set for project [{}], skipping version setting for module [{}]", rootProjectName, model.getArtifactId()); return changes; } if (oldVersion.equals(version)) { - log.debug( - "Won't update the version of module [{}]:[{}] since you're already using the proper one", - groupId, artifactId); + log.debug("Won't update the version of module [{}]:[{}] since you're already using the proper one", groupId, + artifactId); return changes; } log.info("Setting [{}] version to [{}]", artifactId, version); @@ -271,8 +251,7 @@ class ModelWrapper { final File rootFile; - ModelWrapper(Model model, List sourceChanges, - VersionsFromBom versionsFromBom, File rootFile) { + ModelWrapper(Model model, List sourceChanges, VersionsFromBom versionsFromBom, File rootFile) { this.model = model; this.versionsFromBom = versionsFromBom; this.sourceChanges.addAll(sourceChanges); @@ -303,8 +282,7 @@ class ModelWrapper { } boolean isDirty() { - return !this.sourceChanges.isEmpty() - || this.versionsFromBom.shouldSetProperty(this.model.getProperties()); + return !this.sourceChanges.isEmpty() || this.versionsFromBom.shouldSetProperty(this.model.getProperties()); } } @@ -322,17 +300,13 @@ class PomWriter { LoggerToMavenLog loggerToMavenLog = new LoggerToMavenLog(PomWriter.log); versionChangerFactory.setLog(loggerToMavenLog); versionChangerFactory.setModel(wrapper.model); - log.info( - "Applying version / parent / plugin / project changes to the pom [{}]", - pom); - VersionChanger changer = versionChangerFactory.newVersionChanger(true, true, - true, true); + log.info("Applying version / parent / plugin / project changes to the pom [{}]", pom); + VersionChanger changer = versionChangerFactory.newVersionChanger(true, true, true, true); for (VersionChange versionChange : wrapper.sourceChanges) { changer.apply(versionChange); } log.debug("Applying properties changes to the pom [{}]", pom); - new PropertyVersionChanger(wrapper, versionsFromBom, parsedPom, - loggerToMavenLog).apply(null); + new PropertyVersionChanger(wrapper, versionsFromBom, parsedPom, loggerToMavenLog).apply(null); try (BufferedWriter bw = new BufferedWriter(new FileWriter(pom))) { bw.write(input.toString()); } @@ -370,15 +344,15 @@ class PropertyVersionChanger extends AbstractVersionChanger { private final PropertyStorer propertyStorer; - PropertyVersionChanger(ModelWrapper wrapper, VersionsFromBom versionsFromBom, - ModifiedPomXMLEventReader pom, Log log) { + PropertyVersionChanger(ModelWrapper wrapper, VersionsFromBom versionsFromBom, ModifiedPomXMLEventReader pom, + Log log) { super(wrapper.model, pom, log); this.versionsFromBom = versionsFromBom; this.propertyStorer = new PropertyStorer(log, pom); } - PropertyVersionChanger(ModelWrapper wrapper, VersionsFromBom versionsFromBom, - ModifiedPomXMLEventReader pom, Log log, PropertyStorer propertyStorer) { + PropertyVersionChanger(ModelWrapper wrapper, VersionsFromBom versionsFromBom, ModifiedPomXMLEventReader pom, + Log log, PropertyStorer propertyStorer) { super(wrapper.model, pom, log); this.versionsFromBom = versionsFromBom; this.propertyStorer = propertyStorer; @@ -417,8 +391,7 @@ class PropertyStorer { void setPropertyVersionIfApplicable(Project project) { String propertyName = propertyName(project); if (setPropertyVersion(propertyName, project.version)) { - this.log.info("Updating property [" + propertyName + "] to version [" - + project.version + "]"); + this.log.info("Updating property [" + propertyName + "] to version [" + project.version + "]"); } } @@ -429,8 +402,7 @@ class PropertyStorer { private boolean setPropertyVersion(String propertyName, String version) { try { if (StringUtils.isEmpty(version)) { - this.log.warn( - "Version for [" + propertyName + "] is empty. Will not set it"); + this.log.warn("Version for [" + propertyName + "] is empty. Will not set it"); return false; } return PomHelper.setPropertyVersion(this.pom, null, propertyName, version); diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/ProjectPomUpdater.java b/releaser-core/src/main/java/releaser/internal/buildsystem/ProjectPomUpdater.java index abe97711..1a3e5e28 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/ProjectPomUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/ProjectPomUpdater.java @@ -46,8 +46,7 @@ import releaser.internal.project.Projects; */ public class ProjectPomUpdater implements Closeable { - private static final List IGNORED_SNAPSHOT_LINE_PATTERNS = Arrays.asList( - "^.*replace=.*$", + private static final List IGNORED_SNAPSHOT_LINE_PATTERNS = Arrays.asList("^.*replace=.*$", // issue [#80] "^[\\s]*.*$"); @@ -79,8 +78,7 @@ public class ProjectPomUpdater implements Closeable { * @return projects retrieved from the release train bom */ public Projects retrieveVersionsFromReleaseTrainBom() { - return retrieveVersionsFromReleaseTrainBom(this.properties.getPom().getBranch(), - UPDATE_FIXED_VERSIONS); + return retrieveVersionsFromReleaseTrainBom(this.properties.getPom().getBranch(), UPDATE_FIXED_VERSIONS); } /** @@ -92,12 +90,10 @@ public class ProjectPomUpdater implements Closeable { * @return projects retrieved from the release train bom */ // TODO: I don't like this flag but don't have a better idea - public Projects retrieveVersionsFromReleaseTrainBom(String branch, - boolean updateFixedVersions) { + public Projects retrieveVersionsFromReleaseTrainBom(String branch, boolean updateFixedVersions) { VersionsFromBom versionsFromBom = cachedVersionFromBom(branch); if (updateFixedVersions) { - log.info("Will update the following versions manually [{}]", - this.properties.getFixedVersions()); + log.info("Will update the following versions manually [{}]", this.properties.getFixedVersions()); this.properties.getFixedVersions().forEach(versionsFromBom::setVersion); } log.info("Retrieved the following versions\n{}", versionsFromBom); @@ -121,14 +117,12 @@ public class ProjectPomUpdater implements Closeable { */ public Projects fixedVersions() { Set projects = this.properties.getFixedVersions().entrySet().stream() - .map(entry -> new Project(entry.getKey(), entry.getValue())) - .collect(Collectors.toSet()); + .map(entry -> new Project(entry.getKey(), entry.getValue())).collect(Collectors.toSet()); if (log.isDebugEnabled()) { log.debug("Will apply the following fixed versions {}", projects); } return new VersionsFromBomBuilder().releaserProperties(this.properties) - .parsers(compositeBomParser().customBomParsers()).projects(projects) - .merged().toProjectVersions(); + .parsers(compositeBomParser().customBomParsers()).projects(projects).merged().toProjectVersions(); } /** @@ -143,9 +137,8 @@ public class ProjectPomUpdater implements Closeable { */ public void updateProjectFromReleaseTrain(File projectRoot, Projects projects, ProjectVersion versionFromReleaseTrain, boolean assertVersions) { - VersionsFromBom versionsFromBom = new VersionsFromBomBuilder() - .thisProjectRoot(projectRoot).releaserProperties(this.properties) - .projects(projects.asProjects()).merged(); + VersionsFromBom versionsFromBom = new VersionsFromBomBuilder().thisProjectRoot(projectRoot) + .releaserProperties(this.properties).projects(projects.asProjects()).merged(); if (!this.pomUpdater.shouldProjectBeUpdated(projectRoot, versionsFromBom)) { log.debug("Skipping project updating"); return; @@ -153,16 +146,16 @@ public class ProjectPomUpdater implements Closeable { updatePoms(projectRoot, versionsFromBom, versionFromReleaseTrain, assertVersions); } - private void updatePoms(File projectRoot, VersionsFromBom projects, - ProjectVersion versionFromScRelease, boolean assertVersions) { + private void updatePoms(File projectRoot, VersionsFromBom projects, ProjectVersion versionFromScRelease, + boolean assertVersions) { File rootPom = new File(projectRoot, "pom.xml"); if (!rootPom.exists()) { log.info("No pom.xml present, skipping!"); return; } ModelWrapper rootPomModel = this.pomUpdater.readModel(rootPom); - processAllPoms(projectRoot, new PomWalker(rootPomModel, projects, this.pomUpdater, - this.properties, versionFromScRelease, assertVersions)); + processAllPoms(projectRoot, new PomWalker(rootPomModel, projects, this.pomUpdater, this.properties, + versionFromScRelease, assertVersions)); } private void processAllPoms(File projectRoot, PomWalker pomWalker) { @@ -197,18 +190,15 @@ public class ProjectPomUpdater implements Closeable { private final List unacceptableVersionPatterns; - private PomWalker(ModelWrapper rootPom, VersionsFromBom projects, - PomUpdater pomUpdater, ReleaserProperties properties, - ProjectVersion versionFromScRelease, boolean assertVersions) { + private PomWalker(ModelWrapper rootPom, VersionsFromBom projects, PomUpdater pomUpdater, + ReleaserProperties properties, ProjectVersion versionFromScRelease, boolean assertVersions) { this.rootPom = rootPom; this.versionsFromBom = projects; this.pomUpdater = pomUpdater; this.properties = properties; - List unacceptableVersionPatterns = versionFromScRelease - .unacceptableVersionPatterns(); + List unacceptableVersionPatterns = versionFromScRelease.unacceptableVersionPatterns(); this.unacceptableVersionPatterns = unacceptableVersionPatterns; - this.skipVersionAssert = !assertVersions - || unacceptableVersionPatterns.isEmpty(); + this.skipVersionAssert = !assertVersions || unacceptableVersionPatterns.isEmpty(); this.assertVersions = assertVersions; } @@ -217,28 +207,21 @@ public class ProjectPomUpdater implements Closeable { File file = path.toFile(); if (POM_XML.equals(file.getName())) { if (pathIgnored(file)) { - log.debug( - "Ignoring file [{}] since it's on a list of patterns to ignore", - file); + log.debug("Ignoring file [{}] since it's on a list of patterns to ignore", file); return FileVisitResult.CONTINUE; } - ModelWrapper model = this.pomUpdater.updateModel(this.rootPom, file, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(this.rootPom, file, this.versionsFromBom); this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, file); - if (this.assertVersions && !this.skipVersionAssert - && !this.pomUpdater.hasSkipDeployment(model.model)) { - log.debug( - "Update is a non-snapshot one. Checking if no snapshot versions remained in the pom"); + if (this.assertVersions && !this.skipVersionAssert && !this.pomUpdater.hasSkipDeployment(model.model)) { + log.debug("Update is a non-snapshot one. Checking if no snapshot versions remained in the pom"); String text = asString(path); Scanner scanner = new Scanner(text); int lineNumber = 0; while (scanner.hasNextLine()) { String line = scanner.nextLine(); lineNumber++; - Pattern matchingPattern = this.unacceptableVersionPatterns - .stream() - .filter(pattern -> IGNORED_SNAPSHOT_LINE_PATTERNS.stream() - .noneMatch(line::matches) + Pattern matchingPattern = this.unacceptableVersionPatterns.stream() + .filter(pattern -> IGNORED_SNAPSHOT_LINE_PATTERNS.stream().noneMatch(line::matches) && !line.contains(SPECIAL_LINE_IGNORING_COMMENT) && pattern.matcher(line).lookingAt()) .findFirst().orElse(null); @@ -246,10 +229,9 @@ public class ProjectPomUpdater implements Closeable { if (log.isDebugEnabled()) { log.debug("File text \n" + text); } - throw new IllegalStateException("The file [" + path - + "] matches the [ " + matchingPattern.pattern() - + "] pattern in line number [" + lineNumber + "]\n\n" - + line); + throw new IllegalStateException( + "The file [" + path + "] matches the [ " + matchingPattern.pattern() + + "] pattern in line number [" + lineNumber + "]\n\n" + line); } } log.info("No invalid versions remained in the pom"); @@ -260,8 +242,8 @@ public class ProjectPomUpdater implements Closeable { private boolean pathIgnored(File file) { String path = file.getPath(); - return this.assertVersions && this.properties.getPom().getIgnoredPomRegex() - .stream().anyMatch(path::matches); + return this.assertVersions + && this.properties.getPom().getIgnoredPomRegex().stream().anyMatch(path::matches); } private String asString(Path path) { diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/VersionsFromBom.java b/releaser-core/src/main/java/releaser/internal/buildsystem/VersionsFromBom.java index 16430296..7fbce8c9 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/VersionsFromBom.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/VersionsFromBom.java @@ -56,15 +56,13 @@ public class VersionsFromBom { this.parser = parser; } - VersionsFromBom(ReleaserProperties releaserProperties, CustomBomParser parser, - Set projects) { + VersionsFromBom(ReleaserProperties releaserProperties, CustomBomParser parser, Set projects) { this.properties = releaserProperties; this.parser = parser; projects.forEach(project -> setVersion(project.name, project.version)); } - VersionsFromBom(ReleaserProperties releaserProperties, CustomBomParser parser, - VersionsFromBom... projects) { + VersionsFromBom(ReleaserProperties releaserProperties, CustomBomParser parser, VersionsFromBom... projects) { this.properties = releaserProperties; this.parser = parser; Arrays.stream(projects).forEach(p -> this.projects.addAll(p.projects)); @@ -84,23 +82,20 @@ public class VersionsFromBom { } public String versionForProject(String projectName) { - return this.projects.stream().filter(project -> nameMatches(projectName, project)) - .findFirst().orElse(Project.EMPTY_PROJECT).version; + return this.projects.stream().filter(project -> nameMatches(projectName, project)).findFirst() + .orElse(Project.EMPTY_PROJECT).version; } public boolean shouldBeUpdated(String projectName) { - return this.projects.stream() - .anyMatch(project -> nameMatches(projectName, project)); + return this.projects.stream().anyMatch(project -> nameMatches(projectName, project)); } public boolean shouldSetProperty(Properties properties) { - return this.projects.stream() - .anyMatch(project -> properties.containsKey(project.name + ".version")); + return this.projects.stream().anyMatch(project -> properties.containsKey(project.name + ".version")); } public Projects toProjectVersions() { - return this.projects.stream() - .map(project -> new ProjectVersion(project.name, project.version)) + return this.projects.stream().map(project -> new ProjectVersion(project.name, project.version)) .collect(Collectors.toCollection(Projects::new)); } @@ -114,23 +109,18 @@ public class VersionsFromBom { } boolean parent = matchesNameWithSuffix(projectName, "-parent", project); boolean bomArtifactId = comparisonOfBomArtifactAndParent(projectName, project); - return !bomArtifactId && (parent - || matchesNameWithSuffix(projectName, "-dependencies", project)); + return !bomArtifactId && (parent || matchesNameWithSuffix(projectName, "-dependencies", project)); } - private boolean comparisonOfBomArtifactAndParent(String projectName, - Project project) { - return artifactOrParent(projectName, project.name) - || artifactOrParent(project.name, projectName); + private boolean comparisonOfBomArtifactAndParent(String projectName, Project project) { + return artifactOrParent(projectName, project.name) || artifactOrParent(project.name, projectName); } private boolean artifactOrParent(String projectName, String otherProjectName) { - return projectName.equals(dependenciesArtifactId()) - && otherProjectName.equals(dependenciesParentArtifactId()); + return projectName.equals(dependenciesArtifactId()) && otherProjectName.equals(dependenciesParentArtifactId()); } - private boolean matchesNameWithSuffix(String projectName, String suffix, - Project project) { + private boolean matchesNameWithSuffix(String projectName, String suffix, Project project) { boolean containsSuffix = projectName.endsWith(suffix); if (!containsSuffix) { return false; @@ -157,8 +147,7 @@ public class VersionsFromBom { } private List bomVersionProjectNames() { - List names = new ArrayList<>( - this.properties.getMetaRelease().getReleaseTrainDependencyNames()); + List names = new ArrayList<>(this.properties.getMetaRelease().getReleaseTrainDependencyNames()); names.add(this.properties.getMetaRelease().getReleaseTrainProjectName()); return names; } @@ -184,8 +173,7 @@ public class VersionsFromBom { @Override public String toString() { - return "Projects=\n\t" + this.projects.stream().map(Object::toString) - .collect(Collectors.joining("\n\t")); + return "Projects=\n\t" + this.projects.stream().map(Object::toString).collect(Collectors.joining("\n\t")); } } diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/VersionsFromBomBuilder.java b/releaser-core/src/main/java/releaser/internal/buildsystem/VersionsFromBomBuilder.java index f749ff84..731d2615 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/VersionsFromBomBuilder.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/VersionsFromBomBuilder.java @@ -42,8 +42,7 @@ public class VersionsFromBomBuilder { return this; } - public VersionsFromBomBuilder releaserProperties( - ReleaserProperties releaserProperties) { + public VersionsFromBomBuilder releaserProperties(ReleaserProperties releaserProperties) { this.releaserProperties = releaserProperties; return this; } @@ -68,8 +67,7 @@ public class VersionsFromBomBuilder { if (!this.projects.isEmpty()) { return new VersionsFromBom(this.releaserProperties, bomParser, this.projects); } - return new VersionsFromBom(this.releaserProperties, bomParser, - this.versionsFromBom); + return new VersionsFromBom(this.releaserProperties, bomParser, this.versionsFromBom); } public VersionsFromBom retrieveFromBom() { @@ -77,13 +75,11 @@ public class VersionsFromBomBuilder { CustomBomParser bomParser = parser(); VersionsFromBom versionsFromBom = versionsFromBom(bomParser); VersionsFromBom customParsing = customParsing(thisProjectRoot); - return new VersionsFromBom(this.releaserProperties, bomParser, versionsFromBom, - customParsing); + return new VersionsFromBom(this.releaserProperties, bomParser, versionsFromBom, customParsing); } private File thisProjectRoot() { - return this.thisProjectRoot != null ? this.thisProjectRoot - : new File(this.releaserProperties.getWorkingDir()); + return this.thisProjectRoot != null ? this.thisProjectRoot : new File(this.releaserProperties.getWorkingDir()); } private CustomBomParser parser() { @@ -95,20 +91,16 @@ public class VersionsFromBomBuilder { return new VersionsFromBom(this.releaserProperties, bomParser, this.projects); } else if (this.versionsFromBom.length != 0) { - return new VersionsFromBom(this.releaserProperties, bomParser, - this.versionsFromBom); + return new VersionsFromBom(this.releaserProperties, bomParser, this.versionsFromBom); } return new VersionsFromBom(this.releaserProperties, bomParser); } private VersionsFromBom customParsing(File thisProjectRoot) { - return this.parsers.stream() - .map(p -> p.parseBom(thisProjectRoot, this.releaserProperties)) - .reduce((versionsFromBom, - versionsFromBom2) -> new VersionsFromBomBuilder() - .parsers(this.parsers).thisProjectRoot(thisProjectRoot) - .releaserProperties(this.releaserProperties) - .projects(versionsFromBom, versionsFromBom2).merged()) + return this.parsers.stream().map(p -> p.parseBom(thisProjectRoot, this.releaserProperties)) + .reduce((versionsFromBom, versionsFromBom2) -> new VersionsFromBomBuilder().parsers(this.parsers) + .thisProjectRoot(thisProjectRoot).releaserProperties(this.releaserProperties) + .projects(versionsFromBom, versionsFromBom2).merged()) .orElse(VersionsFromBom.EMPTY_VERSION); } diff --git a/releaser-core/src/main/java/releaser/internal/docs/CustomProjectDocumentationUpdater.java b/releaser-core/src/main/java/releaser/internal/docs/CustomProjectDocumentationUpdater.java index 67214269..8b34037a 100644 --- a/releaser-core/src/main/java/releaser/internal/docs/CustomProjectDocumentationUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/docs/CustomProjectDocumentationUpdater.java @@ -32,14 +32,14 @@ public interface CustomProjectDocumentationUpdater { CustomProjectDocumentationUpdater NO_OP = new CustomProjectDocumentationUpdater() { @Override - public File updateDocsRepoForReleaseTrain(File clonedDocumentationProject, - ProjectVersion currentProject, Projects projects, String bomBranch) { + public File updateDocsRepoForReleaseTrain(File clonedDocumentationProject, ProjectVersion currentProject, + Projects projects, String bomBranch) { return clonedDocumentationProject; } @Override - public File updateDocsRepoForSingleProject(File clonedDocumentationProject, - ProjectVersion currentProject, Projects projects) { + public File updateDocsRepoForSingleProject(File clonedDocumentationProject, ProjectVersion currentProject, + Projects projects) { return clonedDocumentationProject; } }; @@ -53,8 +53,8 @@ public interface CustomProjectDocumentationUpdater { * @return {@link File cloned temporary directory} - {@code null} if wrong version is * used */ - File updateDocsRepoForReleaseTrain(File clonedDocumentationProject, - ProjectVersion currentProject, Projects projects, String bomBranch); + File updateDocsRepoForReleaseTrain(File clonedDocumentationProject, ProjectVersion currentProject, + Projects projects, String bomBranch); /** * Updates the documentation repository for a single project. @@ -64,7 +64,7 @@ public interface CustomProjectDocumentationUpdater { * @return {@link File cloned temporary directory} - {@code null} if wrong version is * used */ - File updateDocsRepoForSingleProject(File clonedDocumentationProject, - ProjectVersion currentProject, Projects projects); + File updateDocsRepoForSingleProject(File clonedDocumentationProject, ProjectVersion currentProject, + Projects projects); } diff --git a/releaser-core/src/main/java/releaser/internal/docs/DocumentationUpdater.java b/releaser-core/src/main/java/releaser/internal/docs/DocumentationUpdater.java index c347e938..f4fa8f7c 100644 --- a/releaser-core/src/main/java/releaser/internal/docs/DocumentationUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/docs/DocumentationUpdater.java @@ -33,17 +33,13 @@ public class DocumentationUpdater { private final ReleaseTrainContentsUpdater releaseTrainContentsUpdater; - public DocumentationUpdater(ProjectGitHandler gitHandler, - ReleaserProperties properties, TemplateGenerator templateGenerator, - List updaters) { - this.projectDocumentationUpdater = new ProjectDocumentationUpdater(properties, - gitHandler, updaters); - this.releaseTrainContentsUpdater = new ReleaseTrainContentsUpdater(properties, - gitHandler, templateGenerator); + public DocumentationUpdater(ProjectGitHandler gitHandler, ReleaserProperties properties, + TemplateGenerator templateGenerator, List updaters) { + this.projectDocumentationUpdater = new ProjectDocumentationUpdater(properties, gitHandler, updaters); + this.releaseTrainContentsUpdater = new ReleaseTrainContentsUpdater(properties, gitHandler, templateGenerator); } - DocumentationUpdater(ProjectDocumentationUpdater updater, - ReleaseTrainContentsUpdater contentsUpdater) { + DocumentationUpdater(ProjectDocumentationUpdater updater, ReleaseTrainContentsUpdater contentsUpdater) { this.projectDocumentationUpdater = updater; this.releaseTrainContentsUpdater = contentsUpdater; } diff --git a/releaser-core/src/main/java/releaser/internal/docs/ProjectDocumentationUpdater.java b/releaser-core/src/main/java/releaser/internal/docs/ProjectDocumentationUpdater.java index 3d0262e9..272ece92 100644 --- a/releaser-core/src/main/java/releaser/internal/docs/ProjectDocumentationUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/docs/ProjectDocumentationUpdater.java @@ -31,8 +31,7 @@ import releaser.internal.project.Projects; */ class ProjectDocumentationUpdater { - private static final Logger log = LoggerFactory - .getLogger(ProjectDocumentationUpdater.class); + private static final Logger log = LoggerFactory.getLogger(ProjectDocumentationUpdater.class); private final ProjectGitHandler gitHandler; @@ -40,8 +39,7 @@ class ProjectDocumentationUpdater { private final ReleaserProperties properties; - ProjectDocumentationUpdater(ReleaserProperties properties, - ProjectGitHandler gitHandler, + ProjectDocumentationUpdater(ReleaserProperties properties, ProjectGitHandler gitHandler, List updaters) { this.gitHandler = gitHandler; this.properties = properties; @@ -50,44 +48,38 @@ class ProjectDocumentationUpdater { // Not needed any more cause all projects publish to docs.spring.io @Deprecated - public File updateDocsRepo(Projects projects, ProjectVersion currentProject, - String bomBranch) { + public File updateDocsRepo(Projects projects, ProjectVersion currentProject, String bomBranch) { if (!shouldUpdate(currentProject)) { return null; } File documentationProject = this.gitHandler.cloneDocumentationProject(); log.debug("Cloning the doc project to [{}]", documentationProject); - CustomProjectDocumentationUpdater updater = this.updaters.isEmpty() - ? CustomProjectDocumentationUpdater.NO_OP : this.updaters.get(0); - return updater.updateDocsRepoForReleaseTrain(documentationProject, currentProject, - projects, bomBranch); + CustomProjectDocumentationUpdater updater = this.updaters.isEmpty() ? CustomProjectDocumentationUpdater.NO_OP + : this.updaters.get(0); + return updater.updateDocsRepoForReleaseTrain(documentationProject, currentProject, projects, bomBranch); } // Not needed any more cause all projects publish to docs.spring.io @Deprecated - public File updateDocsRepoForSingleProject(Projects projects, - ProjectVersion currentProject) { + public File updateDocsRepoForSingleProject(Projects projects, ProjectVersion currentProject) { if (!shouldUpdate(currentProject)) { return null; } File documentationProject = this.gitHandler.cloneDocumentationProject(); log.debug("Cloning the doc project to [{}]", documentationProject); - CustomProjectDocumentationUpdater updater = this.updaters.isEmpty() - ? CustomProjectDocumentationUpdater.NO_OP : this.updaters.get(0); - return updater.updateDocsRepoForSingleProject(documentationProject, - currentProject, projects); + CustomProjectDocumentationUpdater updater = this.updaters.isEmpty() ? CustomProjectDocumentationUpdater.NO_OP + : this.updaters.get(0); + return updater.updateDocsRepoForSingleProject(documentationProject, currentProject, projects); } private boolean shouldUpdate(ProjectVersion currentProject) { if (!this.properties.getGit().isUpdateDocumentationRepo()) { - log.info( - "Will not update documentation repository, since the switch to do so " - + "is off. Set [releaser.git.update-documentation-repo] to [true] to change that"); + log.info("Will not update documentation repository, since the switch to do so " + + "is off. Set [releaser.git.update-documentation-repo] to [true] to change that"); return false; } if (!currentProject.isReleaseOrServiceRelease()) { - log.info( - "Will not update documentation repository for non release or service release [{}]", + log.info("Will not update documentation repository for non release or service release [{}]", currentProject.version); return false; } diff --git a/releaser-core/src/main/java/releaser/internal/docs/ReleaseTrainContents.java b/releaser-core/src/main/java/releaser/internal/docs/ReleaseTrainContents.java index 2d853dde..53068696 100644 --- a/releaser-core/src/main/java/releaser/internal/docs/ReleaseTrainContents.java +++ b/releaser-core/src/main/java/releaser/internal/docs/ReleaseTrainContents.java @@ -39,8 +39,7 @@ public class ReleaseTrainContents { return false; } ReleaseTrainContents contents = (ReleaseTrainContents) o; - return Objects.equals(this.title, contents.title) - && Objects.equals(this.rows, contents.rows); + return Objects.equals(this.title, contents.title) && Objects.equals(this.rows, contents.rows); } @Override diff --git a/releaser-core/src/main/java/releaser/internal/docs/ReleaseTrainContentsUpdater.java b/releaser-core/src/main/java/releaser/internal/docs/ReleaseTrainContentsUpdater.java index 3b5211fd..293b221e 100644 --- a/releaser-core/src/main/java/releaser/internal/docs/ReleaseTrainContentsUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/docs/ReleaseTrainContentsUpdater.java @@ -39,8 +39,7 @@ import org.springframework.util.StringUtils; // TODO: [SPRING-CLOUD] class ReleaseTrainContentsUpdater { - private static final Logger log = LoggerFactory - .getLogger(ReleaseTrainContentsUpdater.class); + private static final Logger log = LoggerFactory.getLogger(ReleaseTrainContentsUpdater.class); private final ReleaseTrainContentsGitHandler handler; @@ -63,45 +62,33 @@ class ReleaseTrainContentsUpdater { * @param projects - set of project with versions to assert against */ File updateReleaseTrainWiki(Projects projects) { - if (!this.properties.getGit().isUpdateReleaseTrainWiki() - || !this.properties.getMetaRelease().isEnabled()) { - log.info( - "Will not clone and update the release train wiki, since the switch to do so " - + "is off or it's not a meta-release. Set [releaser.git.update-release-train-wiki] to [true] to change that"); + if (!this.properties.getGit().isUpdateReleaseTrainWiki() || !this.properties.getMetaRelease().isEnabled()) { + log.info("Will not clone and update the release train wiki, since the switch to do so " + + "is off or it's not a meta-release. Set [releaser.git.update-release-train-wiki] to [true] to change that"); return null; } File releaseTrainWiki = this.handler.cloneReleaseTrainWiki(); ProjectVersion releaseTrain = projects.releaseTrain(this.properties); // When using calver this need to be a major plus minor (ie if the release is // 2020.0.1, the name of the wiki page is 2020.0) - String releaseTrainName = releaseTrain.isCalver() ? releaseTrain.majorAndMinor() - : releaseTrain.major(); + String releaseTrainName = releaseTrain.isCalver() ? releaseTrain.majorAndMinor() : releaseTrain.major(); String wikiPagePrefix = this.properties.getGit().getReleaseTrainWikiPagePrefix(); - String releaseTrainDocFileName = releaseTrainDocFileName(releaseTrainName, - wikiPagePrefix); - log.info("Reading the file [{}] for the current release train", - releaseTrainDocFileName); - File releaseTrainDocFile = releaseTrainDocFile(releaseTrainWiki, - releaseTrainDocFileName); - String releaseVersionFromCurrentFile = this.parser - .latestReleaseTrainFromWiki(releaseTrainDocFile); - log.info("Latest release train version in the file is [{}]", - releaseVersionFromCurrentFile); - if (!isThisReleaseTrainVersionNewer(releaseTrain, - releaseVersionFromCurrentFile)) { - log.info( - "Current release train version [{}] is not " - + "newer than the version taken from the wiki [{}]", + String releaseTrainDocFileName = releaseTrainDocFileName(releaseTrainName, wikiPagePrefix); + log.info("Reading the file [{}] for the current release train", releaseTrainDocFileName); + File releaseTrainDocFile = releaseTrainDocFile(releaseTrainWiki, releaseTrainDocFileName); + String releaseVersionFromCurrentFile = this.parser.latestReleaseTrainFromWiki(releaseTrainDocFile); + log.info("Latest release train version in the file is [{}]", releaseVersionFromCurrentFile); + if (!isThisReleaseTrainVersionNewer(releaseTrain, releaseVersionFromCurrentFile)) { + log.info("Current release train version [{}] is not " + "newer than the version taken from the wiki [{}]", releaseTrain.version, releaseVersionFromCurrentFile); return releaseTrainWiki; } - return generateNewWikiEntry(projects, releaseTrainWiki, releaseTrain, - releaseTrainName, releaseTrainDocFile, releaseVersionFromCurrentFile); + return generateNewWikiEntry(projects, releaseTrainWiki, releaseTrain, releaseTrainName, releaseTrainDocFile, + releaseVersionFromCurrentFile); } - private File generateNewWikiEntry(Projects projects, File releaseTrainWiki, - ProjectVersion releaseTrain, String releaseTrainName, - File releaseTrainDocFile, String releaseVersionFromCurrentFile) { + private File generateNewWikiEntry(Projects projects, File releaseTrainWiki, ProjectVersion releaseTrain, + String releaseTrainName, File releaseTrainDocFile, String releaseVersionFromCurrentFile) { File releaseNotes = this.templateGenerator.releaseNotes(projects); try { List lines = Files.readAllLines(releaseTrainDocFile.toPath()); @@ -111,53 +98,43 @@ class ReleaseTrainContentsUpdater { break; } } - return insertNewWikiContentBeforeTheLatestRelease(releaseTrainWiki, - releaseTrain, releaseTrainName, releaseTrainDocFile, releaseNotes, - lines, lineIndex); + return insertNewWikiContentBeforeTheLatestRelease(releaseTrainWiki, releaseTrain, releaseTrainName, + releaseTrainDocFile, releaseNotes, lines, lineIndex); } catch (IOException ex) { throw new IllegalStateException(ex); } } - private File insertNewWikiContentBeforeTheLatestRelease(File releaseTrainWiki, - ProjectVersion releaseTrain, String releaseTrainName, - File releaseTrainDocFile, File releaseNotes, List lines, - int lineIndex) throws IOException { - String newContent = new StringJoiner("\n") - .add(String.join("\n", lines.subList(0, lineIndex))).add("\n") + private File insertNewWikiContentBeforeTheLatestRelease(File releaseTrainWiki, ProjectVersion releaseTrain, + String releaseTrainName, File releaseTrainDocFile, File releaseNotes, List lines, int lineIndex) + throws IOException { + String newContent = new StringJoiner("\n").add(String.join("\n", lines.subList(0, lineIndex))).add("\n") .add(new String(Files.readAllBytes(releaseNotes.toPath()))) - .add(String.join("\n", lines.subList(lineIndex, lines.size()))) - .toString(); + .add(String.join("\n", lines.subList(lineIndex, lines.size()))).toString(); Files.write(releaseTrainDocFile.toPath(), newContent.getBytes()); - log.info("Successfully stored new wiki contents for release train [{}]", - releaseTrainName); + log.info("Successfully stored new wiki contents for release train [{}]", releaseTrainName); this.handler.commitAndPushChanges(releaseTrainWiki, releaseTrain); return releaseTrainWiki; } - private String releaseTrainDocFileName(String releaseTrainName, - String wikiPagePrefix) { - return new StringJoiner("-").add(wikiPagePrefix).add(releaseTrainName) - .add("Release-Notes.md").toString(); + private String releaseTrainDocFileName(String releaseTrainName, String wikiPagePrefix) { + return new StringJoiner("-").add(wikiPagePrefix).add(releaseTrainName).add("Release-Notes.md").toString(); } - private boolean isThisReleaseTrainVersionNewer(ProjectVersion releaseTrain, - String releaseVersionFromCurrentFile) { + private boolean isThisReleaseTrainVersionNewer(ProjectVersion releaseTrain, String releaseVersionFromCurrentFile) { if (StringUtils.hasText(releaseVersionFromCurrentFile)) { return releaseTrain.compareToReleaseTrain(releaseVersionFromCurrentFile) > 0; } return true; } - private File releaseTrainDocFile(File releaseTrainWiki, - String releaseTrainDocFileName) { + private File releaseTrainDocFile(File releaseTrainWiki, String releaseTrainDocFileName) { File releaseTrainDocFile = new File(releaseTrainWiki, releaseTrainDocFileName); if (!releaseTrainDocFile.exists()) { try { if (!releaseTrainDocFile.createNewFile()) { - throw new IllegalStateException( - "Failed to create releae train doc file"); + throw new IllegalStateException("Failed to create releae train doc file"); } } catch (IOException e) { @@ -171,8 +148,7 @@ class ReleaseTrainContentsUpdater { class ReleaseTrainContentsGitHandler { - private static final Logger log = LoggerFactory - .getLogger(ReleaseTrainContentsGitHandler.class); + private static final Logger log = LoggerFactory.getLogger(ReleaseTrainContentsGitHandler.class); private static final String PROJECT_PAGE_UPDATED_COMMIT_MSG = "Updating project page to release train [%s]"; @@ -188,8 +164,7 @@ class ReleaseTrainContentsGitHandler { void commitAndPushChanges(File repo, ProjectVersion releaseTrain) { log.debug("Committing and pushing changes"); - this.handler.commit(repo, - String.format(PROJECT_PAGE_UPDATED_COMMIT_MSG, releaseTrain.version)); + this.handler.commit(repo, String.format(PROJECT_PAGE_UPDATED_COMMIT_MSG, releaseTrain.version)); this.handler.pushCurrentBranch(repo); } @@ -197,8 +172,7 @@ class ReleaseTrainContentsGitHandler { class ReleaseTrainContentsParser { - private static final Logger log = LoggerFactory - .getLogger(ReleaseTrainContentsParser.class); + private static final Logger log = LoggerFactory.getLogger(ReleaseTrainContentsParser.class); ReleaseTrainContents parseProjectPage(File rawHtml) { try { @@ -230,9 +204,8 @@ class ReleaseTrainContentsParser { return Files.readAllLines(rawMd.toPath()).stream() // We want to find only headers like # Finchley.RELEASE and not any // custom headers - .filter(s -> s.trim().startsWith("#") && s.contains(".")) - .map(s -> s.substring(1).trim()).filter(ProjectVersion::isValid) - .findFirst().orElse(""); + .filter(s -> s.trim().startsWith("#") && s.contains(".")).map(s -> s.substring(1).trim()) + .filter(ProjectVersion::isValid).findFirst().orElse(""); } catch (IOException e) { throw new IllegalStateException(e); diff --git a/releaser-core/src/main/java/releaser/internal/docs/Row.java b/releaser-core/src/main/java/releaser/internal/docs/Row.java index c0bc6ff9..ae24cced 100644 --- a/releaser-core/src/main/java/releaser/internal/docs/Row.java +++ b/releaser-core/src/main/java/releaser/internal/docs/Row.java @@ -45,8 +45,7 @@ public class Row { this.currentSnapshotVersion = row[initialIndex + 3].trim(); } - Row(String componentName, String lastGaVersion, String currentGaVersion, - String currentSnapshotVersion) { + Row(String componentName, String lastGaVersion, String currentGaVersion, String currentSnapshotVersion) { this.componentName = componentName.trim(); this.lastGaVersion = lastGaVersion.trim(); this.currentGaVersion = currentGaVersion.trim(); @@ -56,8 +55,7 @@ public class Row { static List fromProjects(Projects projects, boolean lastGa) { return projects.stream() .map(v -> new Row(v.projectName, lastGa ? versionOrEmptyForGa(v) : "", - !lastGa ? versionOrEmptyForGa(v) : "", - v.isSnapshot() ? v.version : "")) + !lastGa ? versionOrEmptyForGa(v) : "", v.isSnapshot() ? v.version : "")) .collect(Collectors.toCollection(LinkedList::new)); } @@ -76,14 +74,13 @@ public class Row { Row row = (Row) o; return Objects.equals(this.componentName, row.componentName) && Objects.equals(this.lastGaVersion, row.lastGaVersion) - && Objects.equals(this.currentGaVersion, row.currentGaVersion) && Objects - .equals(this.currentSnapshotVersion, row.currentSnapshotVersion); + && Objects.equals(this.currentGaVersion, row.currentGaVersion) + && Objects.equals(this.currentSnapshotVersion, row.currentSnapshotVersion); } @Override public int hashCode() { - return Objects.hash(this.componentName, this.lastGaVersion, this.currentGaVersion, - this.currentSnapshotVersion); + return Objects.hash(this.componentName, this.lastGaVersion, this.currentGaVersion, this.currentSnapshotVersion); } public String getComponentName() { diff --git a/releaser-core/src/main/java/releaser/internal/docs/Title.java b/releaser-core/src/main/java/releaser/internal/docs/Title.java index 5e948ab5..3cee4132 100644 --- a/releaser-core/src/main/java/releaser/internal/docs/Title.java +++ b/releaser-core/src/main/java/releaser/internal/docs/Title.java @@ -36,8 +36,7 @@ public class Title { this.currentSnapshotTrainName = row[initialIndex + 2].trim(); } - Title(String lastGaTrainName, String currentGaTrainName, - String currentSnapshotTrainName) { + Title(String lastGaTrainName, String currentGaTrainName, String currentSnapshotTrainName) { this.lastGaTrainName = lastGaTrainName.trim(); this.currentGaTrainName = currentGaTrainName.trim(); this.currentSnapshotTrainName = currentSnapshotTrainName.trim(); @@ -54,14 +53,12 @@ public class Title { Title title = (Title) o; return Objects.equals(this.lastGaTrainName, title.lastGaTrainName) && Objects.equals(this.currentGaTrainName, title.currentGaTrainName) - && Objects.equals(this.currentSnapshotTrainName, - title.currentSnapshotTrainName); + && Objects.equals(this.currentSnapshotTrainName, title.currentSnapshotTrainName); } @Override public int hashCode() { - return Objects.hash(this.lastGaTrainName, this.currentGaTrainName, - this.currentSnapshotTrainName); + return Objects.hash(this.lastGaTrainName, this.currentGaTrainName, this.currentSnapshotTrainName); } public String getLastGaTrainName() { diff --git a/releaser-core/src/main/java/releaser/internal/git/GitRepo.java b/releaser-core/src/main/java/releaser/internal/git/GitRepo.java index 2ffb7bf7..26a4b800 100644 --- a/releaser-core/src/main/java/releaser/internal/git/GitRepo.java +++ b/releaser-core/src/main/java/releaser/internal/git/GitRepo.java @@ -109,8 +109,7 @@ class GitRepo { */ File cloneProject(URIish projectUri) { try { - log.info("Cloning repo from [{}] to [{}]", projectUri, - humanishDestination(projectUri, this.basedir)); + log.info("Cloning repo from [{}] to [{}]", projectUri, humanishDestination(projectUri, this.basedir)); Git git = cloneToBasedir(projectUri, this.basedir); if (git != null) { git.close(); @@ -190,9 +189,8 @@ class GitRepo { */ Optional findTagIdByName(String tagName, boolean unpeel) { try (Git git = this.gitFactory.open(file(this.basedir))) { - return git.tagList().call().stream() - .filter(ref -> ref.getName().equals("refs/tags/" + tagName)) - .findFirst().map(ref -> { + return git.tagList().call().stream().filter(ref -> ref.getName().equals("refs/tags/" + tagName)).findFirst() + .map(ref -> { if (ref.isPeeled() && unpeel) { return ref.getPeeledObjectId(); } @@ -200,8 +198,7 @@ class GitRepo { }); } catch (Exception e) { - throw new IllegalStateException( - "Unable to fetch git tag id for refs/tags/" + tagName, e); + throw new IllegalStateException("Unable to fetch git tag id for refs/tags/" + tagName, e); } } @@ -212,8 +209,7 @@ class GitRepo { */ List log(String from, String to) { try (Git git = this.gitFactory.open(file(this.basedir))) { - final Optional fromRevisionOptional = findTagOrBranchHeadRevision(git, - from); + final Optional fromRevisionOptional = findTagOrBranchHeadRevision(git, from); final Optional toRevisionOptional = findTagOrBranchHeadRevision(git, to); ObjectId fromRevision; @@ -249,8 +245,7 @@ class GitRepo { return commits; } catch (Exception e) { - throw new IllegalStateException( - "Unable to fetch git log for " + from + ".." + to, e); + throw new IllegalStateException("Unable to fetch git log for " + from + ".." + to, e); } } @@ -279,8 +274,7 @@ class GitRepo { } return d2.compareTo(d1); // more recent first }); - return allTagsNewestFirst.stream() - .map(ref -> Repository.shortenRefName(ref.getName())); + return allTagsNewestFirst.stream().map(ref -> Repository.shortenRefName(ref.getName())); } catch (Exception e) { throw new IllegalStateException("Unable to fetch git tags", e); @@ -290,29 +284,24 @@ class GitRepo { /** * Look for a tag with the given name, and if not found looks for a branch. */ - private Optional findTagOrBranchHeadRevision(Git git, String tagOrBranch) - throws GitAPIException, IOException { + private Optional findTagOrBranchHeadRevision(Git git, String tagOrBranch) throws GitAPIException, IOException { if (tagOrBranch.equals("HEAD")) { return Optional.of(git.getRepository().exactRef(Constants.HEAD).getTarget()); } final Optional tag = git.tagList().call().stream() - .filter(ref -> ref.getName().equals("refs/tags/" + tagOrBranch)) - .findFirst(); + .filter(ref -> ref.getName().equals("refs/tags/" + tagOrBranch)).findFirst(); if (tag.isPresent()) { return tag; } - return git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call() - .stream().filter(ref -> ref.getName().equals("refs/heads/" + tagOrBranch)) - .findFirst(); + return git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call().stream() + .filter(ref -> ref.getName().equals("refs/heads/" + tagOrBranch)).findFirst(); } boolean hasBranch(String branch) { try (Git git = this.gitFactory.open(file(this.basedir))) { - List refs = git.branchList().setListMode(ListBranchCommand.ListMode.ALL) - .call(); - boolean present = refs.stream() - .anyMatch(ref -> branch.equals(nameOfBranch(ref.getName()))); + List refs = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call(); + boolean present = refs.stream().anyMatch(ref -> branch.equals(nameOfBranch(ref.getName()))); if (log.isDebugEnabled()) { log.debug("Branch [{}] is present [{}]", branch, present); } @@ -335,8 +324,7 @@ class GitRepo { log.info("Printing [{}] last commits for branch [{}]", maxCount, currentBranch); Iterable commits = git.log().setMaxCount(maxCount).call(); for (RevCommit commit : commits) { - log.info("Name [{}], msg [{}]", commit.getId().name(), - commit.getShortMessage()); + log.info("Name [{}], msg [{}]", commit.getId().name(), commit.getShortMessage()); } } @@ -402,9 +390,8 @@ class GitRepo { String id = commit.getId().getName(); if (!shortMessage.contains("Update SNAPSHOT to ")) { throw new IllegalStateException( - "Won't revert the commit with id [" + id + "] " + "and message [" - + shortMessage + "]. Only commit that updated " - + "snapshot to another version can be reverted"); + "Won't revert the commit with id [" + id + "] " + "and message [" + shortMessage + + "]. Only commit that updated " + "snapshot to another version can be reverted"); } log.debug("The commit to be reverted is [{}]", commit); git.revert().include(commit).call(); @@ -429,10 +416,8 @@ class GitRepo { return ResourceUtils.getFile(project.toURI()).getAbsoluteFile(); } - private Git cloneToBasedir(URIish projectUrl, File destinationFolder) - throws GitAPIException { - CloneCommand command = this.gitFactory.getCloneCommandByCloneRepository() - .setURI(projectUrl.toString() + ".git") + private Git cloneToBasedir(URIish projectUrl, File destinationFolder) throws GitAPIException { + CloneCommand command = this.gitFactory.getCloneCommandByCloneRepository().setURI(projectUrl.toString() + ".git") .setDirectory(humanishDestination(projectUrl, destinationFolder)); try { return command.call(); @@ -500,8 +485,7 @@ class GitRepo { } private void trackBranch(CheckoutCommand checkout, String label) { - checkout.setCreateBranch(true).setName(label) - .setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK) + checkout.setCreateBranch(true).setName(label).setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK) .setStartPoint("origin/" + label); } @@ -513,8 +497,7 @@ class GitRepo { return containsBranch(git, label, null); } - private boolean containsBranch(Git git, String label, - ListBranchCommand.ListMode listMode) throws GitAPIException { + private boolean containsBranch(Git git, String label, ListBranchCommand.ListMode listMode) throws GitAPIException { ListBranchCommand command = git.branchList(); if (listMode != null) { command.setListMode(listMode); @@ -564,17 +547,14 @@ class GitRepo { log.info("Successfully connected to an agent"); } catch (AgentProxyException e) { - log.error( - "Exception occurred while trying to connect to agent. Will create" - + "the default JSch connection", - e); + log.error("Exception occurred while trying to connect to agent. Will create" + + "the default JSch connection", e); return super.createDefaultJSch(fs); } final JSch jsch = super.createDefaultJSch(fs); if (connector != null) { JSch.setConfig("PreferredAuthentications", "publickey,password"); - IdentityRepository identityRepository = new RemoteIdentityRepository( - connector); + IdentityRepository identityRepository = new RemoteIdentityRepository(connector); jsch.setIdentityRepository(identityRepository); } return jsch; @@ -592,8 +572,7 @@ class GitRepo { JGitFactory(ReleaserProperties releaserProperties) { if (StringUtils.hasText(releaserProperties.getGit().getUsername())) { - log.info( - "Passed username and password - will set a custom credentials provider"); + log.info("Passed username and password - will set a custom credentials provider"); this.provider = credentialsProvider(releaserProperties); } else { @@ -608,8 +587,8 @@ class GitRepo { } CredentialsProvider credentialsProvider(ReleaserProperties properties) { - return new UsernamePasswordCredentialsProvider( - properties.getGit().getUsername(), properties.getGit().getPassword()); + return new UsernamePasswordCredentialsProvider(properties.getGit().getUsername(), + properties.getGit().getPassword()); } CloneCommand getCloneCommandByCloneRepository() { @@ -618,8 +597,7 @@ class GitRepo { } PushCommand push(Git git) { - return git.push().setCredentialsProvider(this.provider) - .setTransportConfigCallback(this.callback); + return git.push().setCredentialsProvider(this.provider).setTransportConfigCallback(this.callback); } Git open(File file) { diff --git a/releaser-core/src/main/java/releaser/internal/git/ProjectGitHandler.java b/releaser-core/src/main/java/releaser/internal/git/ProjectGitHandler.java index e8c52abd..db871883 100644 --- a/releaser-core/src/main/java/releaser/internal/git/ProjectGitHandler.java +++ b/releaser-core/src/main/java/releaser/internal/git/ProjectGitHandler.java @@ -70,13 +70,11 @@ public class ProjectGitHandler implements Closeable { public void commitAndTagIfApplicable(File project, ProjectVersion version) { GitRepo gitRepo = gitRepo(project); if (version.isSnapshot()) { - log.info("Snapshot version [{}] found. Will only commit the changed poms", - version); + log.info("Snapshot version [{}] found. Will only commit the changed poms", version); gitRepo.commit(MSG); } else { - log.info( - "NON-snapshot version [{}] found. Will commit the changed poms, tag the version and push the tag", + log.info("NON-snapshot version [{}] found. Will commit the changed poms, tag the version and push the tag", version); gitRepo.commit(String.format(PRE_RELEASE_MSG, version.version)); String tagName = "v" + version.version; @@ -87,8 +85,7 @@ public class ProjectGitHandler implements Closeable { public void commitAfterBumpingVersions(File project, ProjectVersion bumpedVersion) { if (bumpedVersion.isSnapshot()) { - log.info("Snapshot version [{}] found. Will only commit the changed poms", - bumpedVersion); + log.info("Snapshot version [{}] found. Will only commit the changed poms", bumpedVersion); commit(project, String.format(POST_RELEASE_BUMP_MSG, bumpedVersion)); } else { @@ -120,8 +117,7 @@ public class ProjectGitHandler implements Closeable { } public File cloneReleaseTrainDocumentationProject(String branch) { - return cloneAndCheckOut(this.properties.getGit().getReleaseTrainDocsUrl(), - branch); + return cloneAndCheckOut(this.properties.getGit().getReleaseTrainDocsUrl(), branch); } public File cloneDocumentationProject() { @@ -134,8 +130,7 @@ public class ProjectGitHandler implements Closeable { this.properties.getGit().getSpringProjectBranch()); } - private File cloneAndCheckOut(String springProjectUrl, - String springProjectUrlBranch) { + private File cloneAndCheckOut(String springProjectUrl, String springProjectUrlBranch) { File clonedProject = cloneProject(springProjectUrl); checkout(clonedProject, springProjectUrlBranch); return clonedProject; @@ -160,8 +155,7 @@ public class ProjectGitHandler implements Closeable { String releaseTrainBranch = this.properties.getGit().getReleaseTrainBranch(); if (!StringUtils.isEmpty(releaseTrainBranch)) { if (log.isDebugEnabled()) { - log.debug("Checking out configured release train branch {}", - releaseTrainBranch); + log.debug("Checking out configured release train branch {}", releaseTrainBranch); } if (gitRepo(clonedProject).hasBranch(releaseTrainBranch)) { log.info("Branch [{}] exists. Will check it out", releaseTrainBranch); @@ -171,8 +165,7 @@ public class ProjectGitHandler implements Closeable { } String version = this.properties.getFixedVersions().get(projectName); if (StringUtils.isEmpty(version)) { - throw new IllegalStateException( - "You haven't provided a version for project [" + projectName + "]"); + throw new IllegalStateException("You haven't provided a version for project [" + projectName + "]"); } return findAndCheckOutBranchForVersion(clonedProject, new String[] { version }); } @@ -200,11 +193,10 @@ public class ProjectGitHandler implements Closeable { log.debug("Checking versions {} for project [{}]", versions, clonedProject); } String branchToCheckout = Arrays.stream(versions).map(this::branchFromVersion) - .map(version -> gitRepo(clonedProject).hasBranch(version) ? version : "") - .filter(StringUtils::hasText).findFirst().orElse("main"); + .map(version -> gitRepo(clonedProject).hasBranch(version) ? version : "").filter(StringUtils::hasText) + .findFirst().orElse("main"); if ("main".equals(branchToCheckout)) { - log.info( - "None of the versions {} matches a branch. Assuming that should work with main branch", + log.info("None of the versions {} matches a branch. Assuming that should work with main branch", (Object) versions); return clonedProject; } @@ -221,10 +213,8 @@ public class ProjectGitHandler implements Closeable { * @param toRef the ref to go to (tag, branch or sha1) * @return the list of revisions between these two references */ - public List commitsBetween(File clonedProject, String fromRef, - String toRef) { - return gitRepo(clonedProject).log(fromRef, toRef).stream().map(SimpleCommit::new) - .collect(Collectors.toList()); + public List commitsBetween(File clonedProject, String fromRef, String toRef) { + return gitRepo(clonedProject).log(fromRef, toRef).stream().map(SimpleCommit::new).collect(Collectors.toList()); } /** @@ -234,8 +224,7 @@ public class ProjectGitHandler implements Closeable { * @return an {@link Optional} that is valued with the sha1, if found */ public Optional findTagSha1(File clonedProject, String tagName) { - return gitRepo(clonedProject).findTagIdByName(tagName, false) - .map(AnyObjectId::getName); + return gitRepo(clonedProject).findTagIdByName(tagName, false).map(AnyObjectId::getName); } private String suffixNonHttpRepo(String orgUrl) { @@ -248,8 +237,7 @@ public class ProjectGitHandler implements Closeable { // retrieve from cache // reset any changes and fetch the latest data File destinationDir = destinationDir(); - File clonedProject = CACHE.computeIfAbsent(urIish, - urIish1 -> gitRepo(destinationDir).cloneProject(urIish)); + File clonedProject = CACHE.computeIfAbsent(urIish, urIish1 -> gitRepo(destinationDir).cloneProject(urIish)); if (clonedProject.exists()) { log.info( "Project has already been cloned. Will try to reset the current branch and fetch the latest changes."); @@ -309,8 +297,7 @@ public class ProjectGitHandler implements Closeable { // [Camden] -> [Camden.x] return splitVersion[0]; } - throw new IllegalStateException( - "Wrong version [" + version + "]. Can't extract semver pieces of it"); + throw new IllegalStateException("Wrong version [" + version + "]. Can't extract semver pieces of it"); } @@ -347,8 +334,7 @@ public class ProjectGitHandler implements Closeable { * @return a {@link Stream} of the tags whose name match the given {@link Pattern} */ public Stream findTagNamesMatching(File clonedProject, Pattern tagPattern) { - return gitRepo(clonedProject).listTags() - .filter(tagName -> tagPattern.matcher(tagName).matches()); + return gitRepo(clonedProject).listTags().filter(tagName -> tagPattern.matcher(tagName).matches()); } } diff --git a/releaser-core/src/main/java/releaser/internal/git/SimpleCommit.java b/releaser-core/src/main/java/releaser/internal/git/SimpleCommit.java index 8accf3ca..d2a7e730 100644 --- a/releaser-core/src/main/java/releaser/internal/git/SimpleCommit.java +++ b/releaser-core/src/main/java/releaser/internal/git/SimpleCommit.java @@ -71,12 +71,9 @@ public class SimpleCommit { public final boolean isMergeCommit; SimpleCommit(RevCommit revCommit) { - this(revCommit.abbreviate(8).name(), revCommit.name(), - revCommit.getShortMessage(), revCommit.getFullMessage(), - revCommit.getAuthorIdent().getName(), - revCommit.getAuthorIdent().getEmailAddress(), - revCommit.getCommitterIdent().getName(), - revCommit.getCommitterIdent().getEmailAddress(), + this(revCommit.abbreviate(8).name(), revCommit.name(), revCommit.getShortMessage(), revCommit.getFullMessage(), + revCommit.getAuthorIdent().getName(), revCommit.getAuthorIdent().getEmailAddress(), + revCommit.getCommitterIdent().getName(), revCommit.getCommitterIdent().getEmailAddress(), revCommit.getParentCount() > 1); } @@ -92,9 +89,8 @@ public class SimpleCommit { * @param committerEmail the email of the commit's committer * @param isMergeCommit is the commit a merge commit (with 2 parents) */ - public SimpleCommit(String abbreviatedSha1, String fullSha1, String title, - String fullMessage, String authorName, String authorEmail, - String committerName, String committerEmail, boolean isMergeCommit) { + public SimpleCommit(String abbreviatedSha1, String fullSha1, String title, String fullMessage, String authorName, + String authorEmail, String committerName, String committerEmail, boolean isMergeCommit) { this.abbreviatedSha1 = abbreviatedSha1; this.fullSha1 = fullSha1; this.title = title; diff --git a/releaser-core/src/main/java/releaser/internal/github/CachingGithub.java b/releaser-core/src/main/java/releaser/internal/github/CachingGithub.java index a9ebfc79..03973e7a 100644 --- a/releaser-core/src/main/java/releaser/internal/github/CachingGithub.java +++ b/releaser-core/src/main/java/releaser/internal/github/CachingGithub.java @@ -167,8 +167,7 @@ class CachingRepos implements Repos, Closeable { @Override public Repo get(Coordinates coordinates) { - return CACHE.computeIfAbsent(coordinates, - o -> new CachingRepo(this.delegate.get(coordinates))); + return CACHE.computeIfAbsent(coordinates, o -> new CachingRepo(this.delegate.get(coordinates))); } @Override @@ -216,47 +215,40 @@ class CachingRepo implements Repo, Closeable { @Override public Coordinates coordinates() { - return (Coordinates) CACHE.computeIfAbsent( - new RepoKey(this.delegate, "coordinates"), + return (Coordinates) CACHE.computeIfAbsent(new RepoKey(this.delegate, "coordinates"), s -> this.delegate.coordinates()); } @Override public Issues issues() { - return (Issues) CACHE.computeIfAbsent(new RepoKey(this.delegate, "issues"), - s -> this.delegate.issues()); + return (Issues) CACHE.computeIfAbsent(new RepoKey(this.delegate, "issues"), s -> this.delegate.issues()); } @Override public Milestones milestones() { - return (Milestones) CACHE.computeIfAbsent( - new RepoKey(this.delegate, "milestones"), + return (Milestones) CACHE.computeIfAbsent(new RepoKey(this.delegate, "milestones"), s -> this.delegate.milestones()); } @Override public Pulls pulls() { - return (Pulls) CACHE.computeIfAbsent(new RepoKey(this.delegate, "pulls"), - s -> this.delegate.pulls()); + return (Pulls) CACHE.computeIfAbsent(new RepoKey(this.delegate, "pulls"), s -> this.delegate.pulls()); } @Override public Hooks hooks() { - return (Hooks) CACHE.computeIfAbsent(new RepoKey(this.delegate, "hooks"), - s -> this.delegate.hooks()); + return (Hooks) CACHE.computeIfAbsent(new RepoKey(this.delegate, "hooks"), s -> this.delegate.hooks()); } @Override public IssueEvents issueEvents() { - return (IssueEvents) CACHE.computeIfAbsent( - new RepoKey(this.delegate, "issueEvents"), + return (IssueEvents) CACHE.computeIfAbsent(new RepoKey(this.delegate, "issueEvents"), s -> this.delegate.issueEvents()); } @Override public Labels labels() { - return (Labels) CACHE.computeIfAbsent(new RepoKey(this.delegate, "labels"), - s -> this.delegate.labels()); + return (Labels) CACHE.computeIfAbsent(new RepoKey(this.delegate, "labels"), s -> this.delegate.labels()); } @Override @@ -267,63 +259,54 @@ class CachingRepo implements Repo, Closeable { @Override public Releases releases() { - return (Releases) CACHE.computeIfAbsent(new RepoKey(this.delegate, "releases"), - s -> this.delegate.releases()); + return (Releases) CACHE.computeIfAbsent(new RepoKey(this.delegate, "releases"), s -> this.delegate.releases()); } @Override public DeployKeys keys() { - return (DeployKeys) CACHE.computeIfAbsent(new RepoKey(this.delegate, "keys"), - s -> this.delegate.keys()); + return (DeployKeys) CACHE.computeIfAbsent(new RepoKey(this.delegate, "keys"), s -> this.delegate.keys()); } @Override public Forks forks() { - return (Forks) CACHE.computeIfAbsent(new RepoKey(this.delegate, "forks"), - s -> this.delegate.forks()); + return (Forks) CACHE.computeIfAbsent(new RepoKey(this.delegate, "forks"), s -> this.delegate.forks()); } @Override public RepoCommits commits() { - return (RepoCommits) CACHE.computeIfAbsent( - new RepoKey(this.delegate, "repoCommits"), s -> this.delegate.commits()); + return (RepoCommits) CACHE.computeIfAbsent(new RepoKey(this.delegate, "repoCommits"), + s -> this.delegate.commits()); } @Override public Branches branches() { - return (Branches) CACHE.computeIfAbsent(new RepoKey(this.delegate, "branches"), - s -> this.delegate.branches()); + return (Branches) CACHE.computeIfAbsent(new RepoKey(this.delegate, "branches"), s -> this.delegate.branches()); } @Override public Contents contents() { - return (Contents) CACHE.computeIfAbsent(new RepoKey(this.delegate, "contents"), - s -> this.delegate.contents()); + return (Contents) CACHE.computeIfAbsent(new RepoKey(this.delegate, "contents"), s -> this.delegate.contents()); } @Override public Collaborators collaborators() { - return (Collaborators) CACHE.computeIfAbsent( - new RepoKey(this.delegate, "collaborators"), + return (Collaborators) CACHE.computeIfAbsent(new RepoKey(this.delegate, "collaborators"), s -> this.delegate.collaborators()); } @Override public Git git() { - return (Git) CACHE.computeIfAbsent(new RepoKey(this.delegate, "git"), - s -> this.delegate.git()); + return (Git) CACHE.computeIfAbsent(new RepoKey(this.delegate, "git"), s -> this.delegate.git()); } @Override public Stars stars() { - return (Stars) CACHE.computeIfAbsent(new RepoKey(this.delegate, "stars"), - s -> this.delegate.stars()); + return (Stars) CACHE.computeIfAbsent(new RepoKey(this.delegate, "stars"), s -> this.delegate.stars()); } @Override public Notifications notifications() { - return (Notifications) CACHE.computeIfAbsent( - new RepoKey(this.delegate, "notifications"), + return (Notifications) CACHE.computeIfAbsent(new RepoKey(this.delegate, "notifications"), s -> this.delegate.notifications()); } @@ -334,15 +317,14 @@ class CachingRepo implements Repo, Closeable { @Override public JsonObject json() throws IOException { - return (JsonObject) CACHE.computeIfAbsent(new RepoKey(this.delegate, "json"), - s -> { - try { - return this.delegate.json(); - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - }); + return (JsonObject) CACHE.computeIfAbsent(new RepoKey(this.delegate, "json"), s -> { + try { + return this.delegate.json(); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + }); } @Override @@ -382,8 +364,7 @@ class RepoKey { return false; } RepoKey repoKey = (RepoKey) o; - return Objects.equals(this.repo, repoKey.repo) - && Objects.equals(this.key, repoKey.key); + return Objects.equals(this.repo, repoKey.repo) && Objects.equals(this.key, repoKey.key); } @Override diff --git a/releaser-core/src/main/java/releaser/internal/github/GithubIssueFiler.java b/releaser-core/src/main/java/releaser/internal/github/GithubIssueFiler.java index be118c88..43946c32 100644 --- a/releaser-core/src/main/java/releaser/internal/github/GithubIssueFiler.java +++ b/releaser-core/src/main/java/releaser/internal/github/GithubIssueFiler.java @@ -47,8 +47,8 @@ public class GithubIssueFiler { private final ReleaserProperties properties; public GithubIssueFiler(ReleaserProperties properties) { - this(new RtGithub(new RtGithub(properties.getGit().getOauthToken()).entry() - .through(RetryWire.class)), properties); + this(new RtGithub(new RtGithub(properties.getGit().getOauthToken()).entry().through(RetryWire.class)), + properties); } public GithubIssueFiler(Github github, ReleaserProperties properties) { @@ -56,22 +56,20 @@ public class GithubIssueFiler { this.properties = properties; } - public void fileAGitHubIssue(String user, String repo, ProjectVersion version, - String issueTitle, String issueText) { + public void fileAGitHubIssue(String user, String repo, ProjectVersion version, String issueTitle, + String issueText) { Assert.hasText(this.properties.getGit().getOauthToken(), "You have to pass Github OAuth token for milestone closing to be operational"); // do this only for RELEASE & SR if (version.isSnapshot()) { - log.info( - "Github issue creation will occur only for non snapshot versions. Your version is [{}]", + log.info("Github issue creation will occur only for non snapshot versions. Your version is [{}]", parsedVersion()); return; } fileAGithubIssue(user, repo, issueTitle, issueText); } - private void fileAGithubIssue(String user, String repo, String issueTitle, - String issueText) { + private void fileAGithubIssue(String user, String repo, String issueTitle, String issueText) { Repo ghRepo = this.github.repos().get(new Coordinates.Simple(user, repo)); // check if the issue is not already there boolean issueAlreadyFiled = issueAlreadyFiled(ghRepo, issueTitle); @@ -81,9 +79,7 @@ public class GithubIssueFiler { } try { int number = ghRepo.issues().create(issueTitle, issueText).number(); - log.info( - "Successfully created an issue with " - + "title [{}] for the [{}/{}] GitHub repository" + number, + log.info("Successfully created an issue with " + "title [{}] for the [{}/{}] GitHub repository" + number, issueTitle, user, repo); } catch (IOException e) { diff --git a/releaser-core/src/main/java/releaser/internal/github/GithubIssues.java b/releaser-core/src/main/java/releaser/internal/github/GithubIssues.java index 000cd7f0..86655b0a 100644 --- a/releaser-core/src/main/java/releaser/internal/github/GithubIssues.java +++ b/releaser-core/src/main/java/releaser/internal/github/GithubIssues.java @@ -33,8 +33,7 @@ class GithubIssues { } private CustomGithubIssues customGithubIssues() { - return this.customGithubIssues.isEmpty() ? CustomGithubIssues.NO_OP - : this.customGithubIssues.get(0); + return this.customGithubIssues.isEmpty() ? CustomGithubIssues.NO_OP : this.customGithubIssues.get(0); } void fileIssueInSpringGuides(Projects projects, ProjectVersion version) { diff --git a/releaser-core/src/main/java/releaser/internal/github/GithubMilestones.java b/releaser-core/src/main/java/releaser/internal/github/GithubMilestones.java index d443eb20..8075e36f 100644 --- a/releaser-core/src/main/java/releaser/internal/github/GithubMilestones.java +++ b/releaser-core/src/main/java/releaser/internal/github/GithubMilestones.java @@ -51,8 +51,8 @@ class GithubMilestones { private final ReleaserProperties properties; GithubMilestones(ReleaserProperties properties) { - this(new RtGithub(new RtGithub(properties.getGit().getOauthToken()).entry() - .through(RetryWire.class)), properties); + this(new RtGithub(new RtGithub(properties.getGit().getOauthToken()).entry().through(RetryWire.class)), + properties); } GithubMilestones(Github github, ReleaserProperties properties) { @@ -95,8 +95,7 @@ class GithubMilestones { try { int counter = 0; for (Milestone milestone : milestones) { - if (counter++ >= this.properties.getGit() - .getNumberOfCheckedMilestones()) { + if (counter++ >= this.properties.getGit().getNumberOfCheckedMilestones()) { log.warn( "No matching milestones were found within the provided threshold [{}] of checked milestones", this.properties.getGit().getNumberOfCheckedMilestones()); @@ -104,8 +103,7 @@ class GithubMilestones { } Milestone.Smart smartMilestone = new Milestone.Smart(milestone); String title = milestoneTitle(smartMilestone); - if (tagVersion.equals(title) - || numericVersion(tagVersion).equals(title)) { + if (tagVersion.equals(title) || numericVersion(tagVersion).equals(title)) { log.info("Found a matching milestone [{}]", smartMilestone.number()); return smartMilestone; } @@ -127,15 +125,13 @@ class GithubMilestones { Assert.hasText(this.properties.getGit().getOauthToken(), "You have to pass Github OAuth token for milestone closing to be operational"); String tagVersion = version.version; - Milestone.Smart foundMilestone = matchingMilestone(tagVersion, - closedMilestones(version)); + Milestone.Smart foundMilestone = matchingMilestone(tagVersion, closedMilestones(version)); String foundUrl = ""; if (foundMilestone != null) { try { URL url = foundMilestoneUrl(foundMilestone); log.info("Found a matching milestone with issues URL [{}]", url); - foundUrl = url.toString() - .replace("https://api.github.com/repos", "https://github.com") + foundUrl = url.toString().replace("https://api.github.com/repos", "https://github.com") .replace("milestones", "milestone") + "?closed=1"; } catch (IOException e) { @@ -150,8 +146,7 @@ class GithubMilestones { } private String numericVersion(String version) { - return version.contains("RELEASE") - ? version.substring(0, version.lastIndexOf(".")) : ""; + return version.contains("RELEASE") ? version.substring(0, version.lastIndexOf(".")) : ""; } String milestoneTitle(Milestone.Smart milestone) throws IOException { @@ -162,11 +157,9 @@ class GithubMilestones { return milestone.url(); } - private Iterable getMilestones(ProjectVersion version, - Map map) { + private Iterable getMilestones(ProjectVersion version, Map map) { try { - return this.github.repos() - .get(new Coordinates.Simple(org(), version.projectName)).milestones() + return this.github.repos().get(new Coordinates.Simple(org(), version.projectName)).milestones() .iterate(map); } catch (AssertionError e) { diff --git a/releaser-core/src/main/java/releaser/internal/github/ProjectGitHubHandler.java b/releaser-core/src/main/java/releaser/internal/github/ProjectGitHubHandler.java index 9d146165..1fbd7a51 100644 --- a/releaser-core/src/main/java/releaser/internal/github/ProjectGitHubHandler.java +++ b/releaser-core/src/main/java/releaser/internal/github/ProjectGitHubHandler.java @@ -40,8 +40,7 @@ public class ProjectGitHubHandler { private final ReleaserProperties properties; - public ProjectGitHubHandler(ReleaserProperties properties, - List customGithubIssues) { + public ProjectGitHubHandler(ReleaserProperties properties, List customGithubIssues) { this.properties = properties; this.githubMilestones = new GithubMilestones(properties); this.githubIssues = new GithubIssues(customGithubIssues); @@ -54,9 +53,8 @@ public class ProjectGitHubHandler { public void closeMilestone(ProjectVersion releaseVersion) { if (!this.properties.getGit().isUpdateGithubMilestones()) { - log.info( - "Will not update the release train documentation, since the switch to do so " - + "is off. Set [releaser.git.update-github-milestones] to [true] to change that"); + log.info("Will not update the release train documentation, since the switch to do so " + + "is off. Set [releaser.git.update-github-milestones] to [true] to change that"); return; } this.githubMilestones.closeMilestone(releaseVersion); @@ -64,9 +62,8 @@ public class ProjectGitHubHandler { public void createIssueInSpringGuides(Projects projects, ProjectVersion version) { if (!this.properties.getGit().isUpdateSpringGuides()) { - log.info( - "Will not update the release train documentation, since the switch to do so " - + "is off. Set [releaser.git.update-spring-guides] to [true] to change that"); + log.info("Will not update the release train documentation, since the switch to do so " + + "is off. Set [releaser.git.update-spring-guides] to [true] to change that"); return; } this.githubIssues.fileIssueInSpringGuides(projects, version); @@ -74,9 +71,8 @@ public class ProjectGitHubHandler { public void createIssueInStartSpringIo(Projects projects, ProjectVersion version) { if (!this.properties.getGit().isUpdateStartSpringIo()) { - log.info( - "Will not update the release train documentation, since the switch to do so " - + "is off. Set [releaser.git.update-start-spring-io] to [true] to change that"); + log.info("Will not update the release train documentation, since the switch to do so " + + "is off. Set [releaser.git.update-start-spring-io] to [true] to change that"); return; } this.githubIssues.fileIssueInStartSpringIo(projects, version); diff --git a/releaser-core/src/main/java/releaser/internal/postrelease/PostReleaseActions.java b/releaser-core/src/main/java/releaser/internal/postrelease/PostReleaseActions.java index a0113220..8b56bce2 100644 --- a/releaser-core/src/main/java/releaser/internal/postrelease/PostReleaseActions.java +++ b/releaser-core/src/main/java/releaser/internal/postrelease/PostReleaseActions.java @@ -68,11 +68,9 @@ public class PostReleaseActions implements Closeable { private final ReleaserPropertiesUpdater releaserPropertiesUpdater; - public PostReleaseActions(ProjectGitHandler projectGitHandler, - ProjectPomUpdater projectPomUpdater, GradleUpdater gradleUpdater, - ProjectCommandExecutor projectCommandExecutor, ReleaserProperties properties, - VersionsFetcher versionsFetcher, - ReleaserPropertiesUpdater releaserPropertiesUpdater) { + public PostReleaseActions(ProjectGitHandler projectGitHandler, ProjectPomUpdater projectPomUpdater, + GradleUpdater gradleUpdater, ProjectCommandExecutor projectCommandExecutor, ReleaserProperties properties, + VersionsFetcher versionsFetcher, ReleaserPropertiesUpdater releaserPropertiesUpdater) { this.projectGitHandler = projectGitHandler; this.projectPomUpdater = projectPomUpdater; this.gradleUpdater = gradleUpdater; @@ -90,19 +88,15 @@ public class PostReleaseActions implements Closeable { */ public ExecutionResult deployGuides(List processedProjects) { if (!this.properties.getGit().isUpdateSpringGuides()) { - log.info( - "Will not build and deploy latest Spring Guides, since the switch to do so " - + "is off. Set [releaser.git.update-spring-guides] to [true] to change that"); + log.info("Will not build and deploy latest Spring Guides, since the switch to do so " + + "is off. Set [releaser.git.update-spring-guides] to [true] to change that"); return ExecutionResult.skipped(); } List latestGaProcessedProjects = processedProjects.stream() - .filter(processedProject -> this.versionsFetcher - .isLatestGa(processedProject.newProjectVersion)) + .filter(processedProject -> this.versionsFetcher.isLatestGa(processedProject.newProjectVersion)) .collect(Collectors.toList()); - log.info("Found the following latest ga processed projects " - + latestGaProcessedProjects); - List projectUrlAndExceptions = runDeployGuides( - latestGaProcessedProjects); + log.info("Found the following latest ga processed projects " + latestGaProcessedProjects); + List projectUrlAndExceptions = runDeployGuides(latestGaProcessedProjects); log.info("Deployed all guides!"); assertExceptions(projectUrlAndExceptions); return ExecutionResult.success(); @@ -114,8 +108,7 @@ public class PostReleaseActions implements Closeable { * @return result of the execution */ public ExecutionResult runUpdatedTests(Projects projects) { - if (!this.properties.getGit().isRunUpdatedSamples() - || !this.properties.getMetaRelease().isEnabled()) { + if (!this.properties.getGit().isRunUpdatedSamples() || !this.properties.getMetaRelease().isEnabled()) { log.info("Will not update and run test samples, since the switch to do so " + "is off. Set [releaser.git.run-updated-samples] to [true] to change that"); return ExecutionResult.skipped(); @@ -124,11 +117,9 @@ public class PostReleaseActions implements Closeable { ReleaserProperties projectProps = projectProps(file); ProjectVersion projectVersion = newProjectVersion(file); String releaseTrainVersion = projects.releaseTrain(projectProps).version; - Projects newProjects = addVersionForTestsProject(projects, projectVersion, - releaseTrainVersion); + Projects newProjects = addVersionForTestsProject(projects, projectVersion, releaseTrainVersion); updateWithVersions(file, newProjects); - this.projectCommandExecutor.build(projectProps, projectVersion, projectVersion, - file.getAbsolutePath()); + this.projectCommandExecutor.build(projectProps, projectVersion, projectVersion, file.getAbsolutePath()); return ExecutionResult.success(); } @@ -144,15 +135,13 @@ public class PostReleaseActions implements Closeable { * @return result of the execution */ public ExecutionResult updateAllTestSamples(Projects projects) { - if (!this.properties.getGit().isUpdateAllTestSamples() - || !this.properties.getMetaRelease().isEnabled()) { + if (!this.properties.getGit().isUpdateAllTestSamples() || !this.properties.getMetaRelease().isEnabled()) { log.info("Will not update all test samples, since the switch to do so " + "is off. Set [releaser.git.update-all-test-samples] to [true] to change that"); return ExecutionResult.skipped(); } - List projectUrlAndExceptions = this.properties.getGit() - .getAllTestSampleUrls().entrySet().stream() - .map(e -> updateAllProjects(projects, e)).map(this::getResult) + List projectUrlAndExceptions = this.properties.getGit().getAllTestSampleUrls() + .entrySet().stream().map(e -> updateAllProjects(projects, e)).map(this::getResult) .flatMap(Collection::stream).collect(Collectors.toList()); log.info("Updated all samples!"); assertExceptions(projectUrlAndExceptions); @@ -160,41 +149,30 @@ public class PostReleaseActions implements Closeable { } private void assertExceptions(List projectUrlAndExceptions) { - String exceptionMessages = projectUrlAndExceptions.stream() - .filter(ProjectUrlAndException::hasException) - .map(e -> "Project [" + e.key + "] for url [" + e.url + "] " - + "has exception [\n\n" - + Arrays.stream(NestedExceptionUtils.getMostSpecificCause(e.ex) - .getStackTrace()).map(StackTraceElement::toString) - .collect(Collectors.joining("\n")) + String exceptionMessages = projectUrlAndExceptions.stream().filter(ProjectUrlAndException::hasException) + .map(e -> "Project [" + e.key + "] for url [" + e.url + "] " + "has exception [\n\n" + + Arrays.stream(NestedExceptionUtils.getMostSpecificCause(e.ex).getStackTrace()) + .map(StackTraceElement::toString).collect(Collectors.joining("\n")) + "]") .collect(Collectors.joining("\n")); if (StringUtils.hasText(exceptionMessages)) { throw new IllegalStateException( - "Exceptions were found while running post release tasks\n" - + exceptionMessages); + "Exceptions were found while running post release tasks\n" + exceptionMessages); } else { log.info("No exceptions were found while running post release tasks"); } } - private List runDeployGuides( - List latestGaProcessedProjects) { + private List runDeployGuides(List latestGaProcessedProjects) { return latestGaProcessedProjects.stream() - .map(processedProject -> run(processedProject.projectName(), "", - () -> SERVICE.submit(() -> { - String tagName = processedProject.newProjectVersion - .releaseTagName(); - File clonedProject = this.projectGitHandler - .cloneProjectFromOrg(processedProject.projectName()); - this.projectGitHandler.checkout(clonedProject, tagName); - projectBuilder(processedProject).deployGuides( - processedProject.propertiesForProject, - processedProject.originalProjectVersion, - processedProject.newProjectVersion); - }))) - .map(this::getSingleResult).collect(Collectors.toList()); + .map(processedProject -> run(processedProject.projectName(), "", () -> SERVICE.submit(() -> { + String tagName = processedProject.newProjectVersion.releaseTagName(); + File clonedProject = this.projectGitHandler.cloneProjectFromOrg(processedProject.projectName()); + this.projectGitHandler.checkout(clonedProject, tagName); + projectBuilder(processedProject).deployGuides(processedProject.propertiesForProject, + processedProject.originalProjectVersion, processedProject.newProjectVersion); + }))).map(this::getSingleResult).collect(Collectors.toList()); } ProjectCommandExecutor projectBuilder(ProcessedProject processedProject) { @@ -206,45 +184,37 @@ public class PostReleaseActions implements Closeable { return SERVICE.submit(() -> { String key = e.getKey(); List value = e.getValue(); - log.info("Running version update for project [{}] and samples {}", key, - value); + log.info("Running version update for project [{}] and samples {}", key, value); ProjectVersion projectVersionForReleaseTrain = projects.forName(key); Projects postRelease = getPostReleaseProjects(projects); log.info("Versions to update the samples with \n" + postRelease.stream() - .map(v -> "[" + v.projectName + " => " + v.version + "]") - .collect(Collectors.joining("\n"))); + .map(v -> "[" + v.projectName + " => " + v.version + "]").collect(Collectors.joining("\n"))); return value.stream() .map(url -> run(key, url, - () -> commitUpdatedProject(projects, key, - projectVersionForReleaseTrain, postRelease, url))) + () -> commitUpdatedProject(projects, key, projectVersionForReleaseTrain, postRelease, url))) .map(this::getSingleResult).collect(Collectors.toList()); }); } Projects getPostReleaseProjects(Projects projects) { - return projects.postReleaseSnapshotVersion( - this.properties.getMetaRelease().getProjectsToSkip()); + return projects.postReleaseSnapshotVersion(this.properties.getMetaRelease().getProjectsToSkip()); } - private void commitUpdatedProject(Projects projects, String key, - ProjectVersion projectVersionForReleaseTrain, Projects postRelease, - String url) { + private void commitUpdatedProject(Projects projects, String key, ProjectVersion projectVersionForReleaseTrain, + Projects postRelease, String url) { String releaseTrainVersion = projects.releaseTrain(this.properties).version; String projectVersion = projects.forName(key).version; log.info( "Running version update for project [{}], url [{}], " + "release train version [{}] and project version [{}]", key, url, releaseTrainVersion, projectVersion); - File file = this.projectGitHandler.cloneAndGuessBranch(url, releaseTrainVersion, - projectVersion); + File file = this.projectGitHandler.cloneAndGuessBranch(url, releaseTrainVersion, projectVersion); Projects newPostRelease = new Projects(postRelease); ProjectVersion newProjectVersion = newProjectVersion(file); newPostRelease.add(newProjectVersion); updateWithVersions(file, newPostRelease); - this.projectGitHandler.commit(file, - "Updated versions after [" + releaseTrainVersion + "] " - + "release train and [" + projectVersionForReleaseTrain.version - + "] [" + key + "] project release"); + this.projectGitHandler.commit(file, "Updated versions after [" + releaseTrainVersion + "] " + + "release train and [" + projectVersionForReleaseTrain.version + "] [" + key + "] project release"); this.projectGitHandler.pushCurrentBranch(file); } @@ -261,20 +231,17 @@ public class PostReleaseActions implements Closeable { ProjectVersion projectVersion = ProjectVersion.notMavenProject(file); String name = projectVersion.projectName; String version = projectVersion.version; - log.warn( - "Exception occurred while trying to read the pom file. Will assume that the project name is [" - + name + "] and version [" + version + "]", - ex); + log.warn("Exception occurred while trying to read the pom file. Will assume that the project name is [" + + name + "] and version [" + version + "]", ex); return projectVersion; } } private void updateWithVersions(File file, Projects newPostRelease) { ReleaserProperties updatedProperties = updatedProperties(file); - this.projectPomUpdater.updateProjectFromReleaseTrain(file, newPostRelease, + this.projectPomUpdater.updateProjectFromReleaseTrain(file, newPostRelease, newProjectVersion(file), false); + this.gradleUpdater.updateProjectFromReleaseTrain(updatedProperties, file, newPostRelease, newProjectVersion(file), false); - this.gradleUpdater.updateProjectFromReleaseTrain(updatedProperties, file, - newPostRelease, newProjectVersion(file), false); } private ProjectAndFuture run(String key, String url, Runnable runnable) { @@ -293,8 +260,7 @@ public class PostReleaseActions implements Closeable { return new ProjectUrlAndException(projectAndFuture.key, projectAndFuture.url, e); } - private List getResult( - Future> future) { + private List getResult(Future> future) { try { return future.get(10, TimeUnit.MINUTES); } @@ -309,11 +275,9 @@ public class PostReleaseActions implements Closeable { * @return result of the execution */ public ExecutionResult generateReleaseTrainDocumentation(Projects projects) { - if (!this.properties.getGit().isUpdateReleaseTrainDocs() - || !this.properties.getMetaRelease().isEnabled()) { - log.info( - "Will not update the release train documentation, since the switch to do so " - + "is off. Set [releaser.git.update-release-train-docs] to [true] to change that"); + if (!this.properties.getGit().isUpdateReleaseTrainDocs() || !this.properties.getMetaRelease().isEnabled()) { + log.info("Will not update the release train documentation, since the switch to do so " + + "is off. Set [releaser.git.update-release-train-docs] to [true] to change that"); return ExecutionResult.skipped(); } ProjectVersion releaseTrain = projects.releaseTrain(this.properties); @@ -328,16 +292,14 @@ public class PostReleaseActions implements Closeable { } ReleaserProperties projectProps = projectProps(file); String releaseTrainVersion = releaseTrain.version; - this.projectCommandExecutor.generateReleaseTrainDocs(projectProps, - releaseTrainVersion, file.getAbsolutePath()); + this.projectCommandExecutor.generateReleaseTrainDocs(projectProps, releaseTrainVersion, file.getAbsolutePath()); return ExecutionResult.success(); } - private Projects addVersionForTestsProject(Projects projects, - ProjectVersion projectVersion, String releaseTrainVersion) { + private Projects addVersionForTestsProject(Projects projects, ProjectVersion projectVersion, + String releaseTrainVersion) { Projects newProjects = new Projects(projects); - newProjects - .add(new ProjectVersion(projectVersion.projectName, releaseTrainVersion)); + newProjects.add(new ProjectVersion(projectVersion.projectName, releaseTrainVersion)); return newProjects; } diff --git a/releaser-core/src/main/java/releaser/internal/project/ProcessedProject.java b/releaser-core/src/main/java/releaser/internal/project/ProcessedProject.java index 63429c05..5d3b056b 100644 --- a/releaser-core/src/main/java/releaser/internal/project/ProcessedProject.java +++ b/releaser-core/src/main/java/releaser/internal/project/ProcessedProject.java @@ -44,8 +44,8 @@ public class ProcessedProject implements Serializable { */ public final ProjectVersion originalProjectVersion; - public ProcessedProject(ReleaserProperties propertiesForProject, - ProjectVersion newProjectVersion, ProjectVersion originalProjectVersion) { + public ProcessedProject(ReleaserProperties propertiesForProject, ProjectVersion newProjectVersion, + ProjectVersion originalProjectVersion) { this.propertiesForProject = propertiesForProject; this.newProjectVersion = newProjectVersion; this.originalProjectVersion = originalProjectVersion; @@ -53,9 +53,8 @@ public class ProcessedProject implements Serializable { @Override public String toString() { - return "ProcessedProject{" + "name=" + this.newProjectVersion.projectName - + ",version=" + this.newProjectVersion.version + '}' - + ",originalProjectVersion=" + this.originalProjectVersion + '}'; + return "ProcessedProject{" + "name=" + this.newProjectVersion.projectName + ",version=" + + this.newProjectVersion.version + '}' + ",originalProjectVersion=" + this.originalProjectVersion + '}'; } public String projectName() { diff --git a/releaser-core/src/main/java/releaser/internal/project/Project.java b/releaser-core/src/main/java/releaser/internal/project/Project.java index a04894dc..63c49bba 100644 --- a/releaser-core/src/main/java/releaser/internal/project/Project.java +++ b/releaser-core/src/main/java/releaser/internal/project/Project.java @@ -55,8 +55,7 @@ public class Project { if (this.name != null ? !this.name.equals(project.name) : project.name != null) { return false; } - return this.version != null ? this.version.equals(project.version) - : project.version == null; + return this.version != null ? this.version.equals(project.version) : project.version == null; } @Override diff --git a/releaser-core/src/main/java/releaser/internal/project/ProjectCommandExecutor.java b/releaser-core/src/main/java/releaser/internal/project/ProjectCommandExecutor.java index acbd592e..e24553b1 100644 --- a/releaser-core/src/main/java/releaser/internal/project/ProjectCommandExecutor.java +++ b/releaser-core/src/main/java/releaser/internal/project/ProjectCommandExecutor.java @@ -48,8 +48,7 @@ import org.springframework.util.StringUtils; */ public class ProjectCommandExecutor { - private static final Logger log = LoggerFactory - .getLogger(ProjectCommandExecutor.class); + private static final Logger log = LoggerFactory.getLogger(ProjectCommandExecutor.class); private static final String VERSION_MUSTACHE = "{{version}}"; @@ -59,8 +58,7 @@ public class ProjectCommandExecutor { public void build(ReleaserProperties properties, ProjectVersion originalVersion, ProjectVersion versionFromReleaseTrain) { - build(properties, originalVersion, versionFromReleaseTrain, - properties.getWorkingDir()); + build(properties, originalVersion, versionFromReleaseTrain, properties.getWorkingDir()); } public String version(ReleaserProperties properties) { @@ -73,8 +71,7 @@ public class ProjectCommandExecutor { new CommandPicker(properties, properties.getWorkingDir()).groupId()); } - private String executeCommandWithOutput(ReleaserProperties properties, - String command) { + private String executeCommandWithOutput(ReleaserProperties properties, String command) { try { String projectRoot = properties.getWorkingDir(); String[] commands = command.split(" "); @@ -91,27 +88,22 @@ public class ProjectCommandExecutor { public void build(ReleaserProperties properties, ProjectVersion originalVersion, ProjectVersion versionFromReleaseTrain, String projectRoot) { try { - String command = new CommandPicker(properties, projectRoot) - .buildCommand(versionFromReleaseTrain); - String[] commands = replaceAllPlaceHolders(originalVersion, - versionFromReleaseTrain, command).split(" "); + String command = new CommandPicker(properties, projectRoot).buildCommand(versionFromReleaseTrain); + String[] commands = replaceAllPlaceHolders(originalVersion, versionFromReleaseTrain, command).split(" "); runCommand(properties, projectRoot, commands); assertNoHtmlFilesInDocsContainUnresolvedTags(projectRoot); log.info("No HTML files from docs contain unresolved tags"); } catch (Exception e) { - String message = properties + "\n" + originalVersion + "\n" - + versionFromReleaseTrain + "\n" + projectRoot; + String message = properties + "\n" + originalVersion + "\n" + versionFromReleaseTrain + "\n" + projectRoot; throw new IllegalStateException(message, e); } } - public void generateReleaseTrainDocs(ReleaserProperties properties, String version, - String projectRoot) { + public void generateReleaseTrainDocs(ReleaserProperties properties, String version, String projectRoot) { try { String updatedCommand = new CommandPicker(properties, projectRoot) - .generateReleaseTrainDocsCommand( - new ProjectVersion(new File(projectRoot))) + .generateReleaseTrainDocsCommand(new ProjectVersion(new File(projectRoot))) .replace(VERSION_MUSTACHE, version); runCommand(properties, projectRoot, updatedCommand.split(" ")); assertNoHtmlFilesInDocsContainUnresolvedTags(properties.getWorkingDir()); @@ -135,25 +127,20 @@ public class ProjectCommandExecutor { } } - public void deploy(ReleaserProperties properties, ProjectVersion originalVersion, - ProjectVersion version) { + public void deploy(ReleaserProperties properties, ProjectVersion originalVersion, ProjectVersion version) { doDeploy(properties, originalVersion, version, - new CommandPicker(properties, properties.getWorkingDir()) - .deployCommand(version)); + new CommandPicker(properties, properties.getWorkingDir()).deployCommand(version)); } - public void deployGuides(ReleaserProperties properties, - ProjectVersion originalVersion, ProjectVersion version) { + public void deployGuides(ReleaserProperties properties, ProjectVersion originalVersion, ProjectVersion version) { doDeploy(properties, originalVersion, version, - new CommandPicker(properties, properties.getWorkingDir()) - .deployGuidesCommand(version)); + new CommandPicker(properties, properties.getWorkingDir()).deployGuidesCommand(version)); } - private void doDeploy(ReleaserProperties properties, ProjectVersion originalVersion, - ProjectVersion changedVersion, String command) { + private void doDeploy(ReleaserProperties properties, ProjectVersion originalVersion, ProjectVersion changedVersion, + String command) { try { - String replacedCommand = replaceAllPlaceHolders(originalVersion, - changedVersion, command); + String replacedCommand = replaceAllPlaceHolders(originalVersion, changedVersion, command); String[] commands = replacedCommand.split(" "); runCommand(properties, commands); log.info("The project has successfully been deployed"); @@ -167,21 +154,16 @@ public class ProjectCommandExecutor { runCommand(properties, properties.getWorkingDir(), commands); } - private void runCommand(ReleaserProperties properties, String projectRoot, - String[] commands) { + private void runCommand(ReleaserProperties properties, String projectRoot, String[] commands) { String[] substitutedCommands = substituteSystemProps(properties, commands); - long waitTimeInMinutes = new CommandPicker(properties, projectRoot) - .waitTimeInMinutes(); + long waitTimeInMinutes = new CommandPicker(properties, projectRoot).waitTimeInMinutes(); executor(projectRoot).runCommand(substitutedCommands, waitTimeInMinutes); } - private String captureCommandOutput(ReleaserProperties properties, String projectRoot, - String[] commands) { + private String captureCommandOutput(ReleaserProperties properties, String projectRoot, String[] commands) { String[] substitutedCommands = substituteSystemProps(properties, commands); - long waitTimeInMinutes = new CommandPicker(properties, projectRoot) - .waitTimeInMinutes(); - return executor(projectRoot).runCommandWithOutput(substitutedCommands, - waitTimeInMinutes); + long waitTimeInMinutes = new CommandPicker(properties, projectRoot).waitTimeInMinutes(); + return executor(projectRoot).runCommandWithOutput(substitutedCommands, waitTimeInMinutes); } ReleaserProcessExecutor executor(String workDir) { @@ -191,15 +173,11 @@ public class ProjectCommandExecutor { public void publishDocs(ReleaserProperties properties, ProjectVersion originalVersion, ProjectVersion changedVersion) { try { - String providedCommand = new CommandPicker(properties) - .publishDocsCommand(changedVersion); - log.info("Executing command(s) for publishing docs " + providedCommand + " / " - + properties); - String[] providedCommands = StringUtils - .delimitedListToStringArray(providedCommand, "&&"); + String providedCommand = new CommandPicker(properties).publishDocsCommand(changedVersion); + log.info("Executing command(s) for publishing docs " + providedCommand + " / " + properties); + String[] providedCommands = StringUtils.delimitedListToStringArray(providedCommand, "&&"); for (String command : providedCommands) { - command = replaceAllPlaceHolders(originalVersion, changedVersion, - command.trim()); + command = replaceAllPlaceHolders(originalVersion, changedVersion, command.trim()); String[] commands = command.split(" "); runCommand(properties, commands); } @@ -210,8 +188,8 @@ public class ProjectCommandExecutor { } } - private String replaceAllPlaceHolders(ProjectVersion originalVersion, - ProjectVersion changedVersion, String command) { + private String replaceAllPlaceHolders(ProjectVersion originalVersion, ProjectVersion changedVersion, + String command) { return command.replace(VERSION_MUSTACHE, changedVersion.version) .replace(NEXT_VERSION_MUSTACHE, changedVersion.bumpedVersion()) .replace(OLD_VERSION_MUSTACHE, originalVersion.version); @@ -221,24 +199,18 @@ public class ProjectCommandExecutor { * We need to insert the system properties as a list of -Dkey=value entries instead of * just pasting the String that contains these values. */ - private String[] substituteSystemProps(ReleaserProperties properties, - String... commands) { + private String[] substituteSystemProps(ReleaserProperties properties, String... commands) { String systemProperties = new CommandPicker(properties).systemProperties(); - String systemPropertiesPlaceholder = new CommandPicker(properties) - .systemPropertiesPlaceholder(); + String systemPropertiesPlaceholder = new CommandPicker(properties).systemPropertiesPlaceholder(); boolean containsSystemProps = systemProperties.contains("-D"); - String[] splitSystemProps = StringUtils - .delimitedListToStringArray(systemProperties, "-D"); + String[] splitSystemProps = StringUtils.delimitedListToStringArray(systemProperties, "-D"); // first element might be empty even though the second one contains values if (splitSystemProps.length > 1) { splitSystemProps = StringUtils.isEmpty(splitSystemProps[0]) - ? Arrays.copyOfRange(splitSystemProps, 1, splitSystemProps.length) - : splitSystemProps; + ? Arrays.copyOfRange(splitSystemProps, 1, splitSystemProps.length) : splitSystemProps; } - String[] systemPropsWithPrefix = containsSystemProps ? Arrays - .stream(splitSystemProps).map(s -> "-D" + s.trim()) - .collect(Collectors.toList()).toArray(new String[splitSystemProps.length]) - : splitSystemProps; + String[] systemPropsWithPrefix = containsSystemProps ? Arrays.stream(splitSystemProps).map(s -> "-D" + s.trim()) + .collect(Collectors.toList()).toArray(new String[splitSystemProps.length]) : splitSystemProps; final AtomicInteger index = new AtomicInteger(-1); for (int i = 0; i < commands.length; i++) { if (commands[i].contains(systemPropertiesPlaceholder)) { @@ -249,8 +221,7 @@ public class ProjectCommandExecutor { return toCommandList(systemPropsWithPrefix, index, commands); } - private String[] toCommandList(String[] systemPropsWithPrefix, AtomicInteger index, - String[] commands) { + private String[] toCommandList(String[] systemPropsWithPrefix, AtomicInteger index, String[] commands) { List commandsList = new ArrayList<>(Arrays.asList(commands)); List systemPropsList = Arrays.asList(systemPropsWithPrefix); if (index.get() != -1) { @@ -273,8 +244,7 @@ public class ProjectCommandExecutor { class ReleaserProcessExecutor { - private static final Logger log = LoggerFactory - .getLogger(ReleaserProcessExecutor.class); + private static final Logger log = LoggerFactory.getLogger(ReleaserProcessExecutor.class); private static String[] OS_OPERATORS = { "|", "<", ">", "||", "&&" }; @@ -294,17 +264,15 @@ class ReleaserProcessExecutor { private ProcessResult doRunCommand(String[] commands, long waitTimeInMinutes) { String workingDir = this.workingDir; - log.info("Will run the command from [{}] and wait for result for [{}] minutes", - workingDir, waitTimeInMinutes); + log.info("Will run the command from [{}] and wait for result for [{}] minutes", workingDir, waitTimeInMinutes); try { - ProcessExecutor processExecutor = processExecutor(commands, workingDir) - .timeout(waitTimeInMinutes, TimeUnit.MINUTES); + ProcessExecutor processExecutor = processExecutor(commands, workingDir).timeout(waitTimeInMinutes, + TimeUnit.MINUTES); final ProcessResult processResult = doExecute(processExecutor); int processExitValue = processResult.getExitValue(); if (processExitValue != 0) { - throw new IllegalStateException("The process has exited with exit code [" - + processExitValue + "]"); + throw new IllegalStateException("The process has exited with exit code [" + processExitValue + "]"); } return processResult; } @@ -312,10 +280,8 @@ class ReleaserProcessExecutor { throw new IllegalStateException("Process execution failed", e); } catch (TimeoutException e) { - log.error("The command hasn't managed to finish in [{}] minutes", - waitTimeInMinutes); - throw new IllegalStateException("Process waiting time of [" - + waitTimeInMinutes + "] minutes exceeded", e); + log.error("The command hasn't managed to finish in [{}] minutes", waitTimeInMinutes); + throw new IllegalStateException("Process waiting time of [" + waitTimeInMinutes + "] minutes exceeded", e); } } @@ -331,15 +297,13 @@ class ReleaserProcessExecutor { commandsToRun = commandToExecute(lastArg); } log.info("Will run the command [{}]", Arrays.toString(commandsToRun)); - return new ProcessExecutor().command(commandsToRun).destroyOnExit() - .readOutput(true) + return new ProcessExecutor().command(commandsToRun).destroyOnExit().readOutput(true) // releaser.commands logger should be configured to redirect // only to a file (with additivity=false). ideally the root logger should // append to same file on top of whatever root appender, so that file // contains the most output .redirectOutputAlsoTo(Slf4jStream.of("releaser.commands").asInfo()) - .redirectErrorAlsoTo(Slf4jStream.of("releaser.commands").asWarn()) - .directory(new File(workingDir)); + .redirectErrorAlsoTo(Slf4jStream.of("releaser.commands").asWarn()).directory(new File(workingDir)); } String[] commandToExecute(String lastArg) { @@ -389,12 +353,10 @@ class CommandPicker { public String publishDocsCommand(ProjectVersion version) { if (projectType == ProjectType.GRADLE) { - return mavenCommandWithSystemProps( - releaserProperties.getGradle().getPublishDocsCommand(), version); + return mavenCommandWithSystemProps(releaserProperties.getGradle().getPublishDocsCommand(), version); } else if (projectType == ProjectType.MAVEN) { - return mavenCommandWithSystemProps( - releaserProperties.getMaven().getPublishDocsCommand(), version); + return mavenCommandWithSystemProps(releaserProperties.getMaven().getPublishDocsCommand(), version); } return releaserProperties.getBash().getPublishDocsCommand(); } @@ -411,12 +373,10 @@ class CommandPicker { String buildCommand(ProjectVersion version) { if (projectType == ProjectType.GRADLE) { - return gradleCommandWithSystemProps( - releaserProperties.getGradle().getBuildCommand()); + return gradleCommandWithSystemProps(releaserProperties.getGradle().getBuildCommand()); } else if (projectType == ProjectType.MAVEN) { - return mavenCommandWithSystemProps( - releaserProperties.getMaven().getBuildCommand(), version); + return mavenCommandWithSystemProps(releaserProperties.getMaven().getBuildCommand(), version); } return bashCommandWithSystemProps(releaserProperties.getBash().getBuildCommand()); } @@ -426,9 +386,8 @@ class CommandPicker { if (projectType == ProjectType.GRADLE) { return "./gradlew properties | grep version: | awk '{print $2}'"; } - return "./mvnw -q" + " -Dexec.executable=\"echo\"" - + " -Dexec.args=\"\\${project.version}\"" + " --non-recursive" - + " org.codehaus.mojo:exec-maven-plugin:1.3.1:exec | tail -1"; + return "./mvnw -q" + " -Dexec.executable=\"echo\"" + " -Dexec.args=\"\\${project.version}\"" + + " --non-recursive" + " org.codehaus.mojo:exec-maven-plugin:1.3.1:exec | tail -1"; } String groupId() { @@ -436,50 +395,40 @@ class CommandPicker { if (projectType == ProjectType.GRADLE) { return "./gradlew groupId -q | tail -1"; } - return "./mvnw -q" + " -Dexec.executable=\"echo\"" - + " -Dexec.args=\"\\${project.groupId}\"" + " --non-recursive" - + " org.codehaus.mojo:exec-maven-plugin:1.3.1:exec | tail -1"; + return "./mvnw -q" + " -Dexec.executable=\"echo\"" + " -Dexec.args=\"\\${project.groupId}\"" + + " --non-recursive" + " org.codehaus.mojo:exec-maven-plugin:1.3.1:exec | tail -1"; } String generateReleaseTrainDocsCommand(ProjectVersion version) { if (projectType == ProjectType.GRADLE) { - return gradleCommandWithSystemProps( - releaserProperties.getGradle().getGenerateReleaseTrainDocsCommand()); + return gradleCommandWithSystemProps(releaserProperties.getGradle().getGenerateReleaseTrainDocsCommand()); } else if (projectType == ProjectType.MAVEN) { - return mavenCommandWithSystemProps( - releaserProperties.getMaven().getGenerateReleaseTrainDocsCommand(), + return mavenCommandWithSystemProps(releaserProperties.getMaven().getGenerateReleaseTrainDocsCommand(), version); } - return bashCommandWithSystemProps( - releaserProperties.getBash().getGenerateReleaseTrainDocsCommand()); + return bashCommandWithSystemProps(releaserProperties.getBash().getGenerateReleaseTrainDocsCommand()); } String deployCommand(ProjectVersion version) { if (projectType == ProjectType.GRADLE) { - return gradleCommandWithSystemProps( - releaserProperties.getGradle().getDeployCommand()); + return gradleCommandWithSystemProps(releaserProperties.getGradle().getDeployCommand()); } else if (projectType == ProjectType.MAVEN) { - return mavenCommandWithSystemProps( - releaserProperties.getMaven().getDeployCommand(), version); + return mavenCommandWithSystemProps(releaserProperties.getMaven().getDeployCommand(), version); } - return bashCommandWithSystemProps( - releaserProperties.getBash().getDeployCommand()); + return bashCommandWithSystemProps(releaserProperties.getBash().getDeployCommand()); } String deployGuidesCommand(ProjectVersion version) { if (projectType == ProjectType.GRADLE) { - return gradleCommandWithSystemProps( - releaserProperties.getGradle().getDeployGuidesCommand()); + return gradleCommandWithSystemProps(releaserProperties.getGradle().getDeployGuidesCommand()); } else if (projectType == ProjectType.MAVEN) { - return mavenCommandWithSystemProps( - releaserProperties.getMaven().getDeployGuidesCommand(), version, + return mavenCommandWithSystemProps(releaserProperties.getMaven().getDeployGuidesCommand(), version, MavenProfile.GUIDES, MavenProfile.INTEGRATION); } - return bashCommandWithSystemProps( - releaserProperties.getBash().getDeployGuidesCommand()); + return bashCommandWithSystemProps(releaserProperties.getBash().getDeployGuidesCommand()); } long waitTimeInMinutes() { @@ -499,13 +448,11 @@ class CommandPicker { return command + " " + ReleaserProperties.Gradle.SYSTEM_PROPS_PLACEHOLDER; } - private String mavenCommandWithSystemProps(String command, ProjectVersion version, - MavenProfile... profiles) { + private String mavenCommandWithSystemProps(String command, ProjectVersion version, MavenProfile... profiles) { if (command.contains(ReleaserProperties.Maven.SYSTEM_PROPS_PLACEHOLDER)) { return appendMavenProfile(command, version, profiles); } - return appendMavenProfile(command, version, profiles) + " " - + ReleaserProperties.Maven.SYSTEM_PROPS_PLACEHOLDER; + return appendMavenProfile(command, version, profiles) + " " + ReleaserProperties.Maven.SYSTEM_PROPS_PLACEHOLDER; } private String bashCommandWithSystemProps(String command) { @@ -515,22 +462,18 @@ class CommandPicker { return command + " " + ReleaserProperties.Maven.SYSTEM_PROPS_PLACEHOLDER; } - private String appendMavenProfile(String command, ProjectVersion version, - MavenProfile... profiles) { + private String appendMavenProfile(String command, ProjectVersion version, MavenProfile... profiles) { String trimmedCommand = command.trim(); if (version.isMilestone() || version.isRc()) { log.info("Adding the milestone profile to the Maven build"); - return withProfile(trimmedCommand, MavenProfile.MILESTONE.asMavenProfile(), - 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 withProfile(trimmedCommand, MavenProfile.CENTRAL.asMavenProfile(), - profiles); + return withProfile(trimmedCommand, MavenProfile.CENTRAL.asMavenProfile(), profiles); } else { - log.info("The version [" + version.toString() - + "] is a snapshot one - will not add any profiles"); + log.info("The version [" + version.toString() + "] is a snapshot one - will not add any profiles"); } return trimmedCommand; } @@ -548,8 +491,7 @@ class CommandPicker { } private String profilesToString(MavenProfile... profiles) { - return Arrays.stream(profiles).map(profile -> "-P" + profile) - .collect(Collectors.joining(" ")); + return Arrays.stream(profiles).map(profile -> "-P" + profile).collect(Collectors.joining(" ")); } private enum ProjectType { @@ -602,10 +544,8 @@ class HtmlFileWalker extends SimpleFileVisitor { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attr) { File file = path.toFile(); - if (file.getName().endsWith(HTML_EXTENSION) - && asString(file).contains("Unresolved")) { - throw new IllegalStateException( - "File [" + file + "] contains a tag that wasn't resolved properly"); + if (file.getName().endsWith(HTML_EXTENSION) && asString(file).contains("Unresolved")) { + throw new IllegalStateException("File [" + file + "] contains a tag that wasn't resolved properly"); } return FileVisitResult.CONTINUE; } diff --git a/releaser-core/src/main/java/releaser/internal/project/ProjectVersion.java b/releaser-core/src/main/java/releaser/internal/project/ProjectVersion.java index 0d532da5..be0a9394 100644 --- a/releaser-core/src/main/java/releaser/internal/project/ProjectVersion.java +++ b/releaser-core/src/main/java/releaser/internal/project/ProjectVersion.java @@ -51,8 +51,7 @@ public class ProjectVersion implements Comparable, Serializable private static final Logger log = LoggerFactory.getLogger(ProjectVersion.class); - private static final Pattern SNAPSHOT_PATTERN = Pattern - .compile("^.*[\\.|\\-](BUILD-)?SNAPSHOT.*$"); + private static final Pattern SNAPSHOT_PATTERN = Pattern.compile("^.*[\\.|\\-](BUILD-)?SNAPSHOT.*$"); private static final String MILESTONE_REGEX = "^.*[\\.|\\-]M[0-9]+.*$"; @@ -62,12 +61,11 @@ public class ProjectVersion implements Comparable, Serializable private static final String SR_REGEX = "^.*[\\.|\\-]SR[0-9]+.*$"; - private static final Pattern SEMVER_PATTERN = Pattern - .compile("(\\d+)\\.(\\d+)\\.(\\d+)"); + private static final Pattern SEMVER_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)"); private static final List VALID_PATTERNS = Arrays.asList(SNAPSHOT_PATTERN, - Pattern.compile(MILESTONE_REGEX), Pattern.compile(RC_REGEX), - Pattern.compile(RELEASE_REGEX), Pattern.compile(SR_REGEX)); + Pattern.compile(MILESTONE_REGEX), Pattern.compile(RC_REGEX), Pattern.compile(RELEASE_REGEX), + Pattern.compile(SR_REGEX)); /** * Name of the project. @@ -164,8 +162,7 @@ public class ProjectVersion implements Comparable, Serializable if (StringUtils.hasText(model.getGroupId())) { return model.getGroupId(); } - if (model.getParent() != null - && StringUtils.hasText(model.getParent().getGroupId())) { + if (model.getParent() != null && StringUtils.hasText(model.getParent().getGroupId())) { return model.getParent().getGroupId(); } return ""; @@ -222,8 +219,7 @@ public class ProjectVersion implements Comparable, Serializable int indexOfFirstHyphen = version.indexOf("-"); boolean buildSnapshot = version.endsWith("BUILD-SNAPSHOT"); - if (numberOfHyphens == 1 && !buildSnapshot - || (numberOfHyphens > 1 && buildSnapshot)) { + if (numberOfHyphens == 1 && !buildSnapshot || (numberOfHyphens > 1 && buildSnapshot)) { // Dysprosium or 1.0.0 String versionName = version.substring(0, indexOfFirstHyphen); boolean hasDots = versionName.contains("."); @@ -243,8 +239,7 @@ public class ProjectVersion implements Comparable, Serializable return SplitVersion.hyphen(newArray); } else { - throw new UnsupportedOperationException( - "Unknown version [" + version + "]"); + throw new UnsupportedOperationException("Unknown version [" + version + "]"); } } return null; @@ -319,8 +314,7 @@ public class ProjectVersion implements Comparable, Serializable } public String majorAndMinor() { - return this.assertVersion().major + this.assertVersion().delimiter - + this.assertVersion().minor; + return this.assertVersion().major + this.assertVersion().delimiter + this.assertVersion().minor; } /** @@ -345,15 +339,14 @@ public class ProjectVersion implements Comparable, Serializable patch = Integer.parseInt(splitVersion.patch); } catch (NumberFormatException nfe) { - throw new IllegalArgumentException("Version " + this.version - + " doesn't contain a numerical PATCH number", nfe); + throw new IllegalArgumentException("Version " + this.version + " doesn't contain a numerical PATCH number", + nfe); } if (patch == 0) { return Optional.empty(); } - return Optional.of(prefix + splitVersion.major + splitVersion.delimiter - + splitVersion.minor + splitVersion.delimiter + (patch - 1) - + splitVersion.delimiter + suffix); + return Optional.of(prefix + splitVersion.major + splitVersion.delimiter + splitVersion.minor + + splitVersion.delimiter + (patch - 1) + splitVersion.delimiter + suffix); } /** @@ -368,8 +361,7 @@ public class ProjectVersion implements Comparable, Serializable * previous MAJOR.MINOR, or empty if current MINOR is 0 * @see #computePreviousMajorTagPattern(String, String) */ - public Optional computePreviousMinorTagPattern(String prefix, - String suffix) { + public Optional computePreviousMinorTagPattern(String prefix, String suffix) { SplitVersion splitVersion = this.assertVersion(); if (suffix.isEmpty()) { suffix = splitVersion.suffix; @@ -380,17 +372,15 @@ public class ProjectVersion implements Comparable, Serializable minor = Integer.parseInt(splitVersion.minor); } catch (NumberFormatException nfe) { - throw new IllegalArgumentException("Version " + this.version - + " doesn't contain a numerical MINOR number", nfe); + throw new IllegalArgumentException("Version " + this.version + " doesn't contain a numerical MINOR number", + nfe); } if (minor == 0) { return Optional.empty(); } - Pattern p = Pattern - .compile(Pattern - .quote(prefix + splitVersion.major + splitVersion.delimiter - + (minor - 1) + splitVersion.delimiter) - + "\\d+" + quotedSuffix); + Pattern p = Pattern.compile(Pattern + .quote(prefix + splitVersion.major + splitVersion.delimiter + (minor - 1) + splitVersion.delimiter) + + "\\d+" + quotedSuffix); return Optional.of(p); } @@ -414,16 +404,14 @@ public class ProjectVersion implements Comparable, Serializable major = Integer.parseInt(splitVersion.major); } catch (NumberFormatException nfe) { - throw new IllegalArgumentException("Version " + this.version - + " doesn't contain a numerical MAJOR number", nfe); + throw new IllegalArgumentException("Version " + this.version + " doesn't contain a numerical MAJOR number", + nfe); } if (major == 0) { - throw new IllegalArgumentException( - "Cannot compute previous MAJOR pattern with MAJOR of 0"); + throw new IllegalArgumentException("Cannot compute previous MAJOR pattern with MAJOR of 0"); } - return Pattern.compile( - Pattern.quote(prefix + (major - 1) + splitVersion.delimiter) + "\\d+" - + Pattern.quote(splitVersion.delimiter) + "\\d+" + quotedSuffix); + return Pattern.compile(Pattern.quote(prefix + (major - 1) + splitVersion.delimiter) + "\\d+" + + Pattern.quote(splitVersion.delimiter) + "\\d+" + quotedSuffix); } public boolean isSnapshot() { @@ -511,8 +499,7 @@ public class ProjectVersion implements Comparable, Serializable private ReleaseType releaseTypeForReleaseTrain() { try { SplitVersion splitVersion = assertVersion(); - if (StringUtils.isEmpty(splitVersion.suffix) - && StringUtils.hasText(splitVersion.patch)) { + if (StringUtils.isEmpty(splitVersion.suffix) && StringUtils.hasText(splitVersion.patch)) { if ("0".equals(splitVersion.patch)) { return ReleaseType.RELEASE; } @@ -537,8 +524,7 @@ public class ProjectVersion implements Comparable, Serializable SplitVersion thatSplit = that.assertVersion(); int releaseTypeComparison = this.releaseType.compareTo(that.releaseType); boolean thisReleaseTypeHigher = releaseTypeComparison > 0; - boolean bothGa = this.isReleaseOrServiceRelease() - && that.isReleaseOrServiceRelease(); + boolean bothGa = this.isReleaseOrServiceRelease() && that.isReleaseOrServiceRelease(); // 1.0.1.M2 vs 1.0.0.RELEASE (x) if (thisReleaseTypeHigher && !bothGa) { return 1; @@ -587,8 +573,7 @@ public class ProjectVersion implements Comparable, Serializable else if (thisVersion.isOldReleaseTrain()) { return false; } - return thisVersion.major.equals(thatVersion.major) - && thisVersion.minor.equals(thatVersion.minor); + return thisVersion.major.equals(thatVersion.major) && thisVersion.minor.equals(thatVersion.minor); } private void assertVersionSet() { @@ -598,8 +583,7 @@ public class ProjectVersion implements Comparable, Serializable } public int compareToReleaseTrain(String version) { - return new TrainVersionNumber(this) - .compareTo(new TrainVersionNumber(new ProjectVersion(version))); + return new TrainVersionNumber(this).compareTo(new TrainVersionNumber(new ProjectVersion(version))); } /** @@ -613,11 +597,24 @@ public class ProjectVersion implements Comparable, Serializable return ""; } + /** + * @return the snapshot format of the current version. + */ + public String toSnapshotVersion() { + return assertVersion().withSnapshot().print(); + } + @Override public String toString() { return this.version; } + public String toPrettyString() { + return new ToStringCreator(this).append("projectName", projectName).append("version", version) + .append("groupId", groupId).append("artifactId", artifactId).append("releaseType", releaseType) + .toString(); + } + @Override public boolean equals(Object o) { if (this == o) { @@ -643,8 +640,7 @@ public class ProjectVersion implements Comparable, Serializable return Collections.singletonList(SNAPSHOT_PATTERN); } // treat like GA - return Arrays.asList(SNAPSHOT_PATTERN, Pattern.compile(MILESTONE_REGEX), - Pattern.compile(RC_REGEX)); + return Arrays.asList(SNAPSHOT_PATTERN, Pattern.compile(MILESTONE_REGEX), Pattern.compile(RC_REGEX)); } @Override @@ -675,8 +671,7 @@ public class ProjectVersion implements Comparable, Serializable // 1.0.0.RELEASE // 1.0.0-RELEASE - private SplitVersion(String major, String minor, String patch, String delimiter, - String suffix) { + private SplitVersion(String major, String minor, String patch, String delimiter, String suffix) { this.major = major; this.minor = minor; this.patch = patch; @@ -764,15 +759,13 @@ public class ProjectVersion implements Comparable, Serializable private SplitVersion fullVersionWithIncrementedPatch() { int incrementedPatch = Integer.parseInt(patch) + 1; - return new SplitVersion(major, minor, Integer.toString(incrementedPatch), - delimiter, suffix); + return new SplitVersion(major, minor, Integer.toString(incrementedPatch), delimiter, suffix); } String print() { // Finchley.SR2 if (StringUtils.isEmpty(minor)) { - return StringUtils.isEmpty(suffix) ? major - : String.format("%s%s%s", major, delimiter, suffix); + return StringUtils.isEmpty(suffix) ? major : String.format("%s%s%s", major, delimiter, suffix); } else if (StringUtils.isEmpty(suffix)) { return String.format("%s.%s.%s", major, minor, patch); @@ -790,11 +783,10 @@ public class ProjectVersion implements Comparable, Serializable private boolean tooFewElements() { // 1 is wrong but Finchley-SR3 is ok - return StringUtils.isEmpty(minor) && StringUtils.isEmpty(patch) - && StringUtils.isEmpty(suffix); + return StringUtils.isEmpty(minor) && StringUtils.isEmpty(patch) && StringUtils.isEmpty(suffix); } - private SplitVersion withSnapshot() { + public SplitVersion withSnapshot() { return new SplitVersion(major, minor, patch, delimiter, suffix()); } @@ -807,9 +799,8 @@ public class ProjectVersion implements Comparable, Serializable @Override public String toString() { - return new ToStringCreator(this).append("major", major).append("minor", minor) - .append("patch", patch).append("delimiter", delimiter) - .append("suffix", suffix).toString(); + return new ToStringCreator(this).append("major", major).append("minor", minor).append("patch", patch) + .append("delimiter", delimiter).append("suffix", suffix).toString(); } @@ -859,11 +850,9 @@ public class ProjectVersion implements Comparable, Serializable } } - private int compareWithOldTrain(ProjectVersion oldTrain, - ProjectVersion thatVersion) { + private int compareWithOldTrain(ProjectVersion oldTrain, ProjectVersion thatVersion) { // Hoxton.SR5 > 2020.0.0-M5 - if (oldTrain.isReleaseOrServiceRelease() - && !thatVersion.isReleaseOrServiceRelease()) { + if (oldTrain.isReleaseOrServiceRelease() && !thatVersion.isReleaseOrServiceRelease()) { return 1; } // Hoxton.SR5 < 2020.0.0-RELEASE diff --git a/releaser-core/src/main/java/releaser/internal/project/Projects.java b/releaser-core/src/main/java/releaser/internal/project/Projects.java index c15ddccd..44358fd5 100644 --- a/releaser-core/src/main/java/releaser/internal/project/Projects.java +++ b/releaser-core/src/main/java/releaser/internal/project/Projects.java @@ -40,8 +40,7 @@ public class Projects extends HashSet { @SuppressWarnings("unchecked") public Projects(ProjectVersion... versions) { - addAll(new HashSet<>(Arrays.stream(versions).filter(Objects::nonNull) - .collect(Collectors.toList()))); + addAll(new HashSet<>(Arrays.stream(versions).filter(Objects::nonNull).collect(Collectors.toList()))); } public Projects(List versions) { @@ -62,36 +61,31 @@ public class Projects extends HashSet { }); Projects newProjects = new Projects(foundProjectsToSkip); foundProjectsToBump.forEach(projectVersion -> newProjects - .add(new ProjectVersion(projectVersion.projectName, - projectVersion.postReleaseSnapshotVersion()))); + .add(new ProjectVersion(projectVersion.projectName, projectVersion.postReleaseSnapshotVersion()))); newProjects.addAll(foundProjectsToSkip); return newProjects; } - private static IllegalStateException exception(Projects projects, - String projectName) { - return new IllegalStateException("Project with name [" + projectName - + "] is not present in the list of projects [" + projects.asList() - + "] . " + additionalErrorMessage(projectName)); + private static IllegalStateException exception(Projects projects, String projectName) { + return new IllegalStateException( + "Project with name [" + projectName + "] is not present in the list of projects [" + projects.asList() + + "] . " + additionalErrorMessage(projectName)); } private static String additionalErrorMessage(String projectName) { - return "Either put it in the BOM or set it via the [--releaser.fixed-versions[" - + projectName + "]=1.0.0.RELEASE] property"; + return "Either put it in the BOM or set it via the [--releaser.fixed-versions[" + projectName + + "]=1.0.0.RELEASE] property"; } public ProjectVersion releaseTrain(ReleaserProperties properties) { return stream() - .filter(version -> version.projectName - .equals(properties.getMetaRelease().getReleaseTrainProjectName()) - || properties.getMetaRelease().getReleaseTrainDependencyNames() - .contains(version.projectName)) + .filter(version -> version.projectName.equals(properties.getMetaRelease().getReleaseTrainProjectName()) + || properties.getMetaRelease().getReleaseTrainDependencyNames().contains(version.projectName)) .findFirst() - .orElseThrow(() -> new IllegalStateException("Projects " + this - + " don't contain any of the following release train names [" - + properties.getMetaRelease().getReleaseTrainProjectName() - + "] or " - + properties.getMetaRelease().getReleaseTrainDependencyNames())); + .orElseThrow(() -> new IllegalStateException( + "Projects " + this + " don't contain any of the following release train names [" + + properties.getMetaRelease().getReleaseTrainProjectName() + "] or " + + properties.getMetaRelease().getReleaseTrainDependencyNames())); } @Override @@ -110,8 +104,7 @@ public class Projects extends HashSet { public Projects postReleaseSnapshotVersion(List projectsToSkip) { Projects projects = this.stream().filter(v -> projectsToSkip(projectsToSkip, v)) .collect(Collectors.toCollection(Projects::new)); - Projects bumped = this.stream().map( - v -> new ProjectVersion(v.projectName, v.postReleaseSnapshotVersion())) + Projects bumped = this.stream().map(v -> new ProjectVersion(v.projectName, v.postReleaseSnapshotVersion())) .collect(Collectors.toCollection(Projects::new)); Projects merged = new Projects(projects); merged.addAll(bumped); @@ -129,26 +122,21 @@ public class Projects extends HashSet { public ProjectVersion forFile(File projectRoot) { final ProjectVersion thisProject = new ProjectVersion(projectRoot); - return this.stream() - .filter(projectVersion -> projectVersion.projectName - .equals(thisProject.projectName)) + return this.stream().filter(projectVersion -> projectVersion.projectName.equals(thisProject.projectName)) .findFirst().orElseThrow(() -> exception(this, thisProject.projectName)); } public ProjectVersion forName(String projectName) { - return this.stream() - .filter(projectVersion -> projectVersion.projectName.equals(projectName)) - .findFirst().orElseThrow(() -> exception(this, projectName)); + return this.stream().filter(projectVersion -> projectVersion.projectName.equals(projectName)).findFirst() + .orElseThrow(() -> exception(this, projectName)); } public boolean containsProject(String projectName) { - return this.stream().anyMatch( - projectVersion -> projectVersion.projectName.equals(projectName)); + return this.stream().anyMatch(projectVersion -> projectVersion.projectName.equals(projectName)); } public List forNameStartingWith(String projectName) { - return this.stream().filter( - projectVersion -> projectVersion.projectName.startsWith(projectName)) + return this.stream().filter(projectVersion -> projectVersion.projectName.startsWith(projectName)) .collect(Collectors.toList()); } @@ -162,14 +150,13 @@ public class Projects extends HashSet { } public Set asProjects() { - return this.stream().map(projectVersion -> new Project(projectVersion.projectName, - projectVersion.version)).collect(Collectors.toSet()); + return this.stream().map(projectVersion -> new Project(projectVersion.projectName, projectVersion.version)) + .collect(Collectors.toSet()); } @Override public String toString() { - return stream().map(v -> "[" + v.projectName + "=>" + v.version + "]") - .collect(Collectors.joining("\n")); + return stream().map(v -> "[" + v.projectName + "=>" + v.version + "]").collect(Collectors.joining("\n")); } } diff --git a/releaser-core/src/main/java/releaser/internal/sagan/Project.java b/releaser-core/src/main/java/releaser/internal/sagan/Project.java index 3450b51a..17aa6087 100644 --- a/releaser-core/src/main/java/releaser/internal/sagan/Project.java +++ b/releaser-core/src/main/java/releaser/internal/sagan/Project.java @@ -16,64 +16,73 @@ package releaser.internal.sagan; -import java.util.ArrayList; import java.util.List; import com.fasterxml.jackson.annotation.JsonInclude; +import org.springframework.core.style.ToStringCreator; + /** * @author Marcin Grzejszczak */ @JsonInclude(JsonInclude.Include.NON_NULL) public class Project { - public String id; + private String name; - public String name; + private String slug; - public String repoUrl; + private String repositoryUrl; - public String siteUrl; + private String status; - public String category; + public List releases; - public String stackOverflowTags; + public String getName() { + return name; + } - public List projectReleases = new ArrayList<>(); + public void setName(String name) { + this.name = name; + } - public Object projectSamples = new Object(); + public String getSlug() { + return slug; + } - public Object nonMostCurrentReleases = new ArrayList<>(); + public void setSlug(String slug) { + this.slug = slug; + } - public List stackOverflowTagList = new ArrayList<>(); + public String getRepositoryUrl() { + return repositoryUrl; + } - public Object mostCurrentRelease = new MostCurrentRelease(); + public void setRepositoryUrl(String repositoryUrl) { + this.repositoryUrl = repositoryUrl; + } - public Boolean aggregator; + public String getStatus() { + return status; + } - public String rawBootConfig; + public void setStatus(String status) { + this.status = status; + } - public String rawOverview; + public List getReleases() { + return this.releases; + } - public int displayOrder = Integer.MAX_VALUE; - - public boolean topLevelProject = true; + public void setReleases(List releases) { + this.releases = releases; + } @Override public String toString() { - return "Project{" + "id='" + this.id + '\'' + ", name='" + this.name + '\'' - + ", repoUrl='" + this.repoUrl + '\'' + ", siteUrl='" + this.siteUrl - + '\'' + ", category='" + this.category + '\'' + ", stackOverflowTags='" - + this.stackOverflowTags + '\'' + ", projectReleases=" - + this.projectReleases + ", stackOverflowTagList=" - + this.stackOverflowTagList + ", aggregator=" + this.aggregator - + ", rawBootConfig='" + this.rawBootConfig + '\'' + ", rawOverview='" - + this.rawOverview + '\'' + '}'; - } - - static class MostCurrentRelease { - - public boolean present; + return new ToStringCreator(this).append("name", name).append("slug", slug) + .append("repositoryUrl", repositoryUrl).append("status", status).append("releases", releases) + .toString(); } diff --git a/releaser-core/src/main/java/releaser/internal/sagan/Release.java b/releaser-core/src/main/java/releaser/internal/sagan/Release.java index 873e6369..6dd1caa4 100644 --- a/releaser-core/src/main/java/releaser/internal/sagan/Release.java +++ b/releaser-core/src/main/java/releaser/internal/sagan/Release.java @@ -18,46 +18,69 @@ package releaser.internal.sagan; import com.fasterxml.jackson.annotation.JsonInclude; +import org.springframework.core.style.ToStringCreator; + /** * @author Marcin Grzejszczak */ @JsonInclude(JsonInclude.Include.NON_NULL) public class Release { - public String releaseStatus = ""; + private String version; - public String refDocUrl = ""; + private String status; - public String apiDocUrl = ""; + private boolean current; - public String groupId = ""; + private String referenceDocUrl; - public String artifactId = ""; + private String apiDocUrl; - public Repository repository; + public String getVersion() { + return version; + } - public String version = ""; + public void setVersion(String version) { + this.version = version; + } - public boolean current; + public String getStatus() { + return status; + } - public boolean generalAvailability; + public void setStatus(String status) { + this.status = status; + } - public boolean preRelease; + public boolean isCurrent() { + return current; + } - public String versionDisplayName = ""; + public void setCurrent(boolean current) { + this.current = current; + } - public boolean snapshot; + public String getReferenceDocUrl() { + return referenceDocUrl; + } + + public void setReferenceDocUrl(String referenceDocUrl) { + this.referenceDocUrl = referenceDocUrl; + } + + public String getApiDocUrl() { + return apiDocUrl; + } + + public void setApiDocUrl(String apiDocUrl) { + this.apiDocUrl = apiDocUrl; + } @Override public String toString() { - return "Release{" + "releaseStatus='" + this.releaseStatus + '\'' - + ", refDocUrl='" + this.refDocUrl + '\'' + ", apiDocUrl='" - + this.apiDocUrl + '\'' + ", groupId='" + this.groupId + '\'' - + ", artifactId='" + this.artifactId + '\'' + ", repository=" - + this.repository + ", version='" + this.version + '\'' + ", current=" - + this.current + ", generalAvailability=" + this.generalAvailability - + ", preRelease=" + this.preRelease + ", versionDisplayName='" - + this.versionDisplayName + '\'' + ", snapshot=" + this.snapshot + '}'; + return new ToStringCreator(this).append("version", version).append("status", status).append("current", current) + .append("referenceDocUrl", referenceDocUrl).append("apiDocUrl", apiDocUrl).toString(); + } } diff --git a/releaser-core/src/main/java/releaser/internal/sagan/ReleaseUpdate.java b/releaser-core/src/main/java/releaser/internal/sagan/ReleaseInput.java similarity index 52% rename from releaser-core/src/main/java/releaser/internal/sagan/ReleaseUpdate.java rename to releaser-core/src/main/java/releaser/internal/sagan/ReleaseInput.java index dcadbc63..359957b1 100644 --- a/releaser-core/src/main/java/releaser/internal/sagan/ReleaseUpdate.java +++ b/releaser-core/src/main/java/releaser/internal/sagan/ReleaseInput.java @@ -18,35 +18,49 @@ package releaser.internal.sagan; import com.fasterxml.jackson.annotation.JsonInclude; +import org.springframework.core.style.ToStringCreator; + /** * @author Marcin Grzejszczak */ @JsonInclude(JsonInclude.Include.NON_NULL) -public class ReleaseUpdate { +public class ReleaseInput { - public String groupId = ""; + private String version = ""; - public String artifactId = ""; + private String referenceDocUrl = ""; - public String version = ""; + private String apiDocUrl = ""; - public String releaseStatus = ""; + public String getVersion() { + return this.version; + } - public String refDocUrl = ""; + public void setVersion(String version) { + this.version = version; + } - public String apiDocUrl = ""; + public String getReferenceDocUrl() { + return this.referenceDocUrl; + } - public Boolean current; + public void setReferenceDocUrl(String referenceDocUrl) { + this.referenceDocUrl = referenceDocUrl; + } - public Repository repository; + public String getApiDocUrl() { + return this.apiDocUrl; + } + + public void setApiDocUrl(String apiDocUrl) { + this.apiDocUrl = apiDocUrl; + } @Override public String toString() { - return "ReleaseUpdate{" + "groupId='" + this.groupId + '\'' + ", artifactId='" - + this.artifactId + '\'' + ", version='" + this.version + '\'' - + ", releaseStatus='" + this.releaseStatus + '\'' + ", refDocUrl='" - + this.refDocUrl + '\'' + ", apiDocUrl='" + this.apiDocUrl + '\'' - + ", repository=" + this.repository + '}'; + return new ToStringCreator(this).append("version", version).append("referenceDocUrl", referenceDocUrl) + .append("apiDocUrl", apiDocUrl).toString(); + } } diff --git a/releaser-core/src/main/java/releaser/internal/sagan/Repository.java b/releaser-core/src/main/java/releaser/internal/sagan/Repository.java index b29c0e42..a3548d85 100644 --- a/releaser-core/src/main/java/releaser/internal/sagan/Repository.java +++ b/releaser-core/src/main/java/releaser/internal/sagan/Repository.java @@ -34,9 +34,8 @@ public class Repository { @Override public String toString() { - return "Repository{" + "id='" + this.id + '\'' + ", name='" + this.name + '\'' - + ", url='" + this.url + '\'' + ", snapshotsEnabled=" - + this.snapshotsEnabled + '}'; + return "Repository{" + "id='" + this.id + '\'' + ", name='" + this.name + '\'' + ", url='" + this.url + '\'' + + ", snapshotsEnabled=" + this.snapshotsEnabled + '}'; } } diff --git a/releaser-core/src/main/java/releaser/internal/sagan/RestTemplateSaganClient.java b/releaser-core/src/main/java/releaser/internal/sagan/RestTemplateSaganClient.java index bb5826dd..d90068d4 100644 --- a/releaser-core/src/main/java/releaser/internal/sagan/RestTemplateSaganClient.java +++ b/releaser-core/src/main/java/releaser/internal/sagan/RestTemplateSaganClient.java @@ -17,6 +17,7 @@ package releaser.internal.sagan; import java.net.URI; +import java.util.Collections; import java.util.List; import org.slf4j.Logger; @@ -36,8 +37,7 @@ import org.springframework.web.client.RestTemplate; */ class RestTemplateSaganClient implements SaganClient { - private static final Logger log = LoggerFactory - .getLogger(RestTemplateSaganClient.class); + private static final Logger log = LoggerFactory.getLogger(RestTemplateSaganClient.class); private final RestTemplate restTemplate; @@ -50,56 +50,91 @@ class RestTemplateSaganClient implements SaganClient { @Override public Project getProject(String projectName) { - return this.restTemplate.getForObject( - this.baseUrl + "/project_metadata/{projectName}", Project.class, - projectName); - } + HttpHeaders headers = new HttpHeaders(); + headers.put("Accept", Collections.singletonList("application/hal+json")); + Project project = this.restTemplate.exchange(this.baseUrl + "/api/projects/{projectName}", HttpMethod.GET, + new HttpEntity<>(headers), Project.class, projectName).getBody(); + if (project == null) { + return null; + } - @Override - public Release getRelease(String projectName, String releaseVersion) { - return this.restTemplate.getForObject( - this.baseUrl - + "/project_metadata/{projectName}/releases/{releaseVersion}", - Release.class, projectName, releaseVersion); - } - - @Override - public Release deleteRelease(String projectName, String releaseVersion) { - ResponseEntity entity = this.restTemplate.exchange( - this.baseUrl - + "/project_metadata/{projectName}/releases/{releaseVersion}", - HttpMethod.DELETE, new HttpEntity<>(""), Release.class, projectName, - releaseVersion); - Release release = entity.getBody(); - log.info("Response from Sagan\n\n[{}] \n with body [{}]", entity, release); - return release; - } - - @Override - public Project updateRelease(String projectName, List releaseUpdates) { - RequestEntity> request = RequestEntity - .put(URI.create( - this.baseUrl + "/project_metadata/" + projectName + "/releases")) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) - .body(releaseUpdates); - ResponseEntity entity = this.restTemplate.exchange(request, - Project.class); - Project project = entity.getBody(); - log.info("Response from Sagan\n\n[{}] \n with body [{}]", entity, project); + EmbeddedProjectReleases body = this.restTemplate.exchange(this.baseUrl + "/api/projects/{projectName}/releases", + HttpMethod.GET, new HttpEntity<>(headers), EmbeddedProjectReleases.class, projectName).getBody(); + project.setReleases(body._embedded.releases); return project; } + @Override + public Release getRelease(String projectName, String releaseVersion) { + HttpHeaders headers = new HttpHeaders(); + headers.put("Accept", Collections.singletonList("application/hal+json")); + return this.restTemplate.exchange(this.baseUrl + "/api/projects/{projectName}/releases/{releaseVersion}", + HttpMethod.GET, new HttpEntity<>(headers), Release.class, projectName, releaseVersion).getBody(); + } + + @Override + public boolean deleteRelease(String projectName, String releaseVersion) { + ResponseEntity entity = this.restTemplate.exchange( + this.baseUrl + "/api/projects/{projectName}/releases/{releaseVersion}", HttpMethod.DELETE, + new HttpEntity<>(""), Release.class, projectName, releaseVersion); + boolean deleted = entity.getStatusCode().is2xxSuccessful(); + log.info("Response from Sagan\n\n[{}] \n with status [{}]", entity, entity.getStatusCode()); + return deleted; + } + + @Override + public boolean addRelease(String projectName, ReleaseInput releaseInput) { + RequestEntity request = RequestEntity + .post(URI.create(this.baseUrl + "/api/projects/" + projectName + "/releases")) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE).body(releaseInput); + ResponseEntity entity = this.restTemplate.exchange(request, Project.class); + boolean added = entity.getStatusCode().is2xxSuccessful(); + log.info("Response from Sagan\n\n[{}]", entity); + return added; + } + @Override public Project patchProject(Project project) { - RequestEntity request = RequestEntity - .patch(URI.create(this.baseUrl + "/project_metadata/" + project.id)) - .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) - .body(project); - ResponseEntity entity = this.restTemplate.exchange(request, - Project.class); - Project updatedProject = entity.getBody(); - log.info("Response from Sagan\n\n[{}] \n with body [{}]", entity, updatedProject); - return updatedProject; + // RequestEntity request = RequestEntity + // .patch(URI.create(this.baseUrl + "/project_metadata/" + project.getSlug())) + // .header(HttpHeaders.CONTENT_TYPE, + // MediaType.APPLICATION_JSON_UTF8_VALUE).body(project); + // ResponseEntity entity = this.restTemplate.exchange(request, + // Project.class); + // Project updatedProject = entity.getBody(); + // log.info("Response from Sagan\n\n[{}] \n with body [{}]", entity, + // updatedProject); + // return updatedProject; + // FIXME: no api yet https://github.com/spring-io/sagan/issues/1052 + return null; + } + + private static class EmbeddedProjectReleases { + + private ProjectReleases _embedded; + + public ProjectReleases get_embedded() { + return this._embedded; + } + + public void set_embedded(ProjectReleases _embedded) { + this._embedded = _embedded; + } + + } + + private static class ProjectReleases { + + private List releases; + + public List getReleases() { + return this.releases; + } + + public void setReleases(List releases) { + this.releases = releases; + } + } } diff --git a/releaser-core/src/main/java/releaser/internal/sagan/SaganClient.java b/releaser-core/src/main/java/releaser/internal/sagan/SaganClient.java index a1a94186..79a7fa3a 100644 --- a/releaser-core/src/main/java/releaser/internal/sagan/SaganClient.java +++ b/releaser-core/src/main/java/releaser/internal/sagan/SaganClient.java @@ -16,8 +16,6 @@ package releaser.internal.sagan; -import java.util.List; - /** * @author Marcin Grzejszczak */ @@ -27,9 +25,9 @@ public interface SaganClient { Release getRelease(String projectName, String releaseVersion); - Release deleteRelease(String projectName, String releaseVersion); + boolean deleteRelease(String projectName, String releaseVersion); - Project updateRelease(String projectName, List releaseUpdate); + boolean addRelease(String projectName, ReleaseInput releaseInput); Project patchProject(Project project); diff --git a/releaser-core/src/main/java/releaser/internal/sagan/SaganUpdater.java b/releaser-core/src/main/java/releaser/internal/sagan/SaganUpdater.java index a3a8b7c7..7f525d85 100644 --- a/releaser-core/src/main/java/releaser/internal/sagan/SaganUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/sagan/SaganUpdater.java @@ -23,7 +23,6 @@ import java.util.Comparator; import java.util.Optional; import java.util.stream.Collectors; -import edu.emory.mathcs.backport.java.util.Collections; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import releaser.internal.ReleaserProperties; @@ -50,37 +49,34 @@ public class SaganUpdater { this.releaserProperties = releaserProperties; } - public ExecutionResult updateSagan(File projectFile, String branch, - ProjectVersion originalVersion, ProjectVersion currentVersion, - Projects projects) { + public ExecutionResult updateSagan(File projectFile, String branch, ProjectVersion originalVersion, + ProjectVersion currentVersion, Projects projects) { if (!this.releaserProperties.getSagan().isUpdateSagan()) { log.info("Will not update sagan, since the switch to do so " + "is off. Set [releaser.sagan.update-sagan] to [true] to change that"); return ExecutionResult.skipped(); } - ReleaseUpdate update = releaseUpdate(branch, originalVersion, currentVersion, - projects); - Exception updateReleaseException = updateSaganForNonSnapshot(branch, - originalVersion, currentVersion, projects); + ReleaseInput update = releaseUpdate(branch, originalVersion, currentVersion, projects); + Exception updateReleaseException = updateSaganForNonSnapshot(branch, originalVersion, currentVersion, projects); if (updateReleaseException == null) { log.info("Updating Sagan releases with \n\n{}", update); try { - Project project = this.saganClient.updateRelease( - currentVersion.projectName, Collections.singletonList(update)); - Optional projectVersion = latestVersion(currentVersion, - project); - log.info("Found the following latest project version [{}]", - projectVersion); + boolean added = this.saganClient.addRelease(currentVersion.projectName, update); + if (!added) { + return ExecutionResult.unstable( + new Exception("Unable to add release for project " + currentVersion.toPrettyString())); + } + Project project = saganClient.getProject(currentVersion.projectName); + Optional projectVersion = latestVersion(currentVersion, project); + log.info("Found the following latest project version [{}]", projectVersion); boolean present = projectVersion.isPresent(); - if (present - && currentVersionNewerOrEqual(currentVersion, projectVersion)) { + if (present && currentVersionNewerOrEqual(currentVersion, projectVersion)) { updateDocumentationIfNecessary(projectFile, project); } else { log.info(present - ? "Latest version [" + projectVersion.get() + "] present and " - + "the current version [" + currentVersion - + "] is older than that one. " + "Will do nothing." + ? "Latest version [" + projectVersion.get() + "] present and " + "the current version [" + + currentVersion + "] is older than that one. " + "Will do nothing." : "No latest version found. Will do nothing."); return ExecutionResult.skipped(); } @@ -91,37 +87,35 @@ public class SaganUpdater { } } return updateReleaseException == null ? ExecutionResult.success() - : ExecutionResult.unstable( - new IllegalStateException(updateReleaseException.getMessage())); + : ExecutionResult.unstable(new IllegalStateException(updateReleaseException.getMessage())); } private void updateDocumentationIfNecessary(File projectFile, Project project) { boolean shouldUpdate = false; File docsModule = docsModule(projectFile); - File indexDoc = new File(docsModule, - this.releaserProperties.getSagan().getIndexSectionFileName()); - File bootDoc = new File(docsModule, - this.releaserProperties.getSagan().getBootSectionFileName()); + File indexDoc = new File(docsModule, this.releaserProperties.getSagan().getIndexSectionFileName()); + File bootDoc = new File(docsModule, this.releaserProperties.getSagan().getBootSectionFileName()); if (indexDoc.exists()) { log.debug("Index adoc file exists"); String fileText = fileToText(indexDoc); - if (StringUtils.hasText(fileText) && !fileText.equals(project.rawOverview)) { - log.info( - "Index adoc content differs from the previously stored, will update it"); - project.rawOverview = fileText; - shouldUpdate = true; - } + // if (StringUtils.hasText(fileText) && !fileText.equals(project.rawOverview)) + // { + // log.info("Index adoc content differs from the previously stored, will + // update it"); + // project.rawOverview = fileText; + // shouldUpdate = true; + // } } if (bootDoc.exists()) { log.debug("Boot adoc file exists"); String fileText = fileToText(bootDoc); - if (StringUtils.hasText(fileText) - && !fileText.equals(project.rawBootConfig)) { - log.info( - "Boot adoc content differs from the previously stored, will update it"); - project.rawBootConfig = fileText; - shouldUpdate = true; - } + // if (StringUtils.hasText(fileText) && + // !fileText.equals(project.rawBootConfig)) { + // log.info("Boot adoc content differs from the previously stored, will update + // it"); + // project.rawBootConfig = fileText; + // shouldUpdate = true; + // } } if (shouldUpdate) { this.saganClient.patchProject(project); @@ -133,8 +127,7 @@ public class SaganUpdater { } File docsModule(File projectFile) { - return new File(projectFile, - this.releaserProperties.getSagan().getDocsAdocsFile()); + return new File(projectFile, this.releaserProperties.getSagan().getDocsAdocsFile()); } private String fileToText(File file) { @@ -146,49 +139,40 @@ public class SaganUpdater { } } - private Optional latestVersion(ProjectVersion currentVersion, - Project project) { + private Optional latestVersion(ProjectVersion currentVersion, Project project) { if (project == null) { return Optional.empty(); } - return project.projectReleases.stream().filter(release -> release.current) - .map(release -> new ProjectVersion(currentVersion.projectName, - release.version)) + return project.getReleases().stream().filter(Release::isCurrent) + .map(release -> new ProjectVersion(currentVersion.projectName, release.getVersion())) .max(Comparator.comparing(o -> o.version)); } - private boolean currentVersionNewerOrEqual(ProjectVersion currentVersion, - Optional projectVersion) { + private boolean currentVersionNewerOrEqual(ProjectVersion currentVersion, Optional projectVersion) { return currentVersion.compareTo(projectVersion.get()) >= 0; } - private Exception updateSaganForNonSnapshot(String branch, - ProjectVersion originalVersion, ProjectVersion version, Projects projects) { + private Exception updateSaganForNonSnapshot(String branch, ProjectVersion originalVersion, ProjectVersion version, + Projects projects) { Exception updateReleaseException = null; if (!version.isSnapshot()) { - log.info( - "Version is non snapshot [{}]. Will remove all older versions and mark this as current", - version); + log.info("Version is non snapshot [{}]. Will remove all older versions and mark this as current", version); Project project = this.saganClient.getProject(version.projectName); if (project != null) { removeAllSameMinorVersions(version, project); } - String snapshot = toSnapshot(version.version); + String snapshot = toSnapshot(version); removeVersionFromSagan(version, snapshot); if (version.isRelease() || version.isServiceRelease()) { try { - String bumpedSnapshot = toSnapshot(version.bumpedVersion()); - ReleaseUpdate snapshotUpdate = releaseUpdate(branch, originalVersion, - new ProjectVersion(version.projectName, bumpedSnapshot), - projects); - log.info("Updating Sagan with bumped snapshot \n\n[{}]", - snapshotUpdate); - this.saganClient.updateRelease(version.projectName, - Collections.singletonList(snapshotUpdate)); + String bumpedSnapshot = bumpedSnapshot(version); + ReleaseInput snapshotUpdate = releaseUpdate(branch, originalVersion, + new ProjectVersion(version.projectName, bumpedSnapshot), projects); + log.info("Updating Sagan with bumped snapshot \n\n[{}]", snapshotUpdate); + this.saganClient.addRelease(version.projectName, snapshotUpdate); } catch (Exception e) { - log.warn("Failed to update [" + version.projectName + "/" + snapshot - + "] from Sagan", e); + log.warn("Failed to update [" + version.projectName + "/" + snapshot + "] from Sagan", e); updateReleaseException = e; } } @@ -197,75 +181,61 @@ public class SaganUpdater { } private void removeAllSameMinorVersions(ProjectVersion version, Project project) { - project.projectReleases.stream() - .filter(release -> version.isSameMinor(release.version)) - .collect(Collectors.toList()) - .forEach(release -> removeVersionFromSagan(version, release.version)); + project.getReleases().stream().filter(release -> version.isSameMinor(release.getVersion())) + .collect(Collectors.toList()).forEach(release -> removeVersionFromSagan(version, release.getVersion())); } private void removeVersionFromSagan(ProjectVersion version, String snapshot) { log.info("Removing [{}/{}] from Sagan", version.projectName, snapshot); try { - this.saganClient.deleteRelease(version.projectName, snapshot); + boolean deleted = this.saganClient.deleteRelease(version.projectName, snapshot); + if (!deleted) { + log.warn("Failed to remove [" + version.projectName + "/" + snapshot + "] from Sagan"); + } } catch (Exception e) { - log.warn("Failed to remove [" + version.projectName + "/" + snapshot - + "] from Sagan", e); + log.warn("Failed to remove [" + version.projectName + "/" + snapshot + "] from Sagan", e); } } - private ReleaseUpdate releaseUpdate(String branch, ProjectVersion originalVersion, - ProjectVersion version, Projects projects) { - ReleaseUpdate update = new ReleaseUpdate(); - update.groupId = originalVersion.groupId(); - update.artifactId = version.projectName; - update.version = version.version; - update.releaseStatus = version(version); - update.apiDocUrl = referenceUrl(branch, version, projects); - update.refDocUrl = update.apiDocUrl; - update.current = true; + private ReleaseInput releaseUpdate(String branch, ProjectVersion originalVersion, ProjectVersion version, + Projects projects) { + ReleaseInput update = new ReleaseInput(); + update.setVersion(version.version); + update.setReferenceDocUrl(referenceUrl(branch, version, projects)); + update.setApiDocUrl(null); return update; } - private String toSnapshot(String version) { + private String bumpedSnapshot(ProjectVersion projectVersion) { + String bumpedVersion = projectVersion.bumpedVersion(); + return toSnapshot(new ProjectVersion("", bumpedVersion)); + } + + private String toSnapshot(ProjectVersion projectVersion) { + String version = projectVersion.version; if (version.contains("RELEASE")) { return version.replace("RELEASE", "BUILD-SNAPSHOT"); } else if (version.matches(".*SR[0-9]+")) { return version.substring(0, version.lastIndexOf(".")) + ".BUILD-SNAPSHOT"; } - return version; - } - - private String version(ProjectVersion version) { - if (version.isSnapshot()) { - return "SNAPSHOT"; - } - else if (version.isMilestone() || version.isRc()) { - return "PRERELEASE"; - } - else if (version.isRelease() || version.isServiceRelease()) { - return "GENERAL_AVAILABILITY"; - } - return ""; + return projectVersion.toSnapshotVersion(); } private String releaseTrainVersion(Projects projects) { - String releaseTrainProjectName = this.releaserProperties.getMetaRelease() - .getReleaseTrainProjectName(); - return projects.containsProject(releaseTrainProjectName) - ? projects.forName(releaseTrainProjectName).version : ""; + String releaseTrainProjectName = this.releaserProperties.getMetaRelease().getReleaseTrainProjectName(); + return projects.containsProject(releaseTrainProjectName) ? projects.forName(releaseTrainProjectName).version + : ""; } - private String referenceUrl(String branch, ProjectVersion version, - Projects projects) { + private String referenceUrl(String branch, ProjectVersion version, Projects projects) { String releaseTrainVersion = releaseTrainVersion(projects); // up till Greenwich we have a different URL for docs // if there's no release train, will assume that 2.2.x is the version that has the // new docs boolean hasReleaseTrainVersion = StringUtils.hasText(releaseTrainVersion); - boolean newDocs = hasReleaseTrainVersion - ? releaseTrainVersion.toLowerCase().charAt(0) > 'g' + boolean newDocs = hasReleaseTrainVersion ? releaseTrainVersion.toLowerCase().charAt(0) > 'g' : version.version.compareTo("2.2") > 0; if (newDocs) { return newReferenceUrl(branch, version); @@ -274,30 +244,17 @@ public class SaganUpdater { } private String newReferenceUrl(String branch, ProjectVersion version) { - if (!version.isSnapshot()) { - // static/sleuth/{version}/ - return "https://cloud.spring.io/spring-cloud-static/" + version.projectName - + "/{version}/reference/html/"; - } - if (branch.toLowerCase().contains("main")) { - // sleuth/ - return "https://cloud.spring.io/" + version.projectName + "/reference/html/"; - } - // sleuth/1.1.x/ - return "https://cloud.spring.io/" + version.projectName + "/" + branch - + "/reference/html/"; + return "https://docs.spring.io/" + version.projectName + "/docs/{version}/reference/html/"; } private String oldReferenceUrl(String branch, ProjectVersion version) { if (!version.isSnapshot()) { // static/sleuth/{version}/ - return "https://cloud.spring.io/spring-cloud-static/" + version.projectName - + "/{version}/"; + return "https://cloud.spring.io/spring-cloud-static/" + version.projectName + "/{version}/"; } if (branch.toLowerCase().contains("main")) { // sleuth/ - return "https://cloud.spring.io/" + version.projectName + "/" - + version.projectName + ".html"; + return "https://cloud.spring.io/" + version.projectName + "/" + version.projectName + ".html"; } // sleuth/1.1.x/ return "https://cloud.spring.io/" + version.projectName + "/" + branch + "/"; diff --git a/releaser-core/src/main/java/releaser/internal/tech/BuildUnstableException.java b/releaser-core/src/main/java/releaser/internal/tech/BuildUnstableException.java index 858115b0..1e5275da 100644 --- a/releaser-core/src/main/java/releaser/internal/tech/BuildUnstableException.java +++ b/releaser-core/src/main/java/releaser/internal/tech/BuildUnstableException.java @@ -46,8 +46,7 @@ public class BuildUnstableException extends RuntimeException implements Serializ */ public static final String EXIT_CODE = "BUILD_UNSTABLE"; - private static final Logger log = LoggerFactory - .getLogger(BuildUnstableException.class); + private static final Logger log = LoggerFactory.getLogger(BuildUnstableException.class); /** * List of exceptions causing this instability. @@ -61,8 +60,7 @@ public class BuildUnstableException extends RuntimeException implements Serializ } public BuildUnstableException(String message, List throwables) { - this(throwables.stream().map(BuildUnstableException::breakReferenceChain) - .collect(Collectors.toList())); + this(throwables.stream().map(BuildUnstableException::breakReferenceChain).collect(Collectors.toList())); log.warn("\n\n" + DESCRIPTION + message + " with causes " + throwables); } @@ -72,8 +70,7 @@ public class BuildUnstableException extends RuntimeException implements Serializ private static Throwable breakReferenceChain(Throwable cause) { if (cause instanceof HttpServerErrorException) { - return new RuntimeException( - "[Breaking self reference chain] " + cause.toString()); + return new RuntimeException("[Breaking self reference chain] " + cause.toString()); } return cause; } diff --git a/releaser-core/src/main/java/releaser/internal/tech/ExecutionResult.java b/releaser-core/src/main/java/releaser/internal/tech/ExecutionResult.java index 889f0f04..c9b5171d 100644 --- a/releaser-core/src/main/java/releaser/internal/tech/ExecutionResult.java +++ b/releaser-core/src/main/java/releaser/internal/tech/ExecutionResult.java @@ -65,23 +65,20 @@ public class ExecutionResult implements Serializable { } public static ExecutionResult failure(List throwables) { - return new ExecutionResult(throwables.stream() - .map(ExecutionResult::breakReferenceChain).collect(Collectors.toList())); + return new ExecutionResult( + throwables.stream().map(ExecutionResult::breakReferenceChain).collect(Collectors.toList())); } private static Exception breakReferenceChain(Exception cause) { - if (cause instanceof HttpServerErrorException - || cause instanceof HttpClientErrorException) { + if (cause instanceof HttpServerErrorException || cause instanceof HttpClientErrorException) { System.out.println("Breaking the reference chain. . . i think"); - return new RuntimeException( - "[Breaking self reference chain] " + cause.toString()); + return new RuntimeException("[Breaking self reference chain] " + cause.toString()); } return cause; } public static ExecutionResult unstable(Exception ex) { - return new ExecutionResult(ex instanceof BuildUnstableException ? ex - : new BuildUnstableException(ex)); + return new ExecutionResult(ex instanceof BuildUnstableException ? ex : new BuildUnstableException(ex)); } public static ExecutionResult skipped() { @@ -110,18 +107,17 @@ public class ExecutionResult implements Serializable { } public boolean isUnstable() { - return !this.exceptions.isEmpty() && this.exceptions.stream() - .allMatch(t -> t instanceof BuildUnstableException); + return !this.exceptions.isEmpty() + && this.exceptions.stream().allMatch(t -> t instanceof BuildUnstableException); } public String toStringResult() { - return isUnstable() ? "UNSTABLE" - : isFailure() ? "FAILURE" : isSkipped() ? "SKIPPED" : "SUCCESS"; + return isUnstable() ? "UNSTABLE" : isFailure() ? "FAILURE" : isSkipped() ? "SKIPPED" : "SUCCESS"; } public boolean isFailure() { - return !this.exceptions.isEmpty() && this.exceptions.stream() - .anyMatch(t -> !(t instanceof BuildUnstableException)); + return !this.exceptions.isEmpty() + && this.exceptions.stream().anyMatch(t -> !(t instanceof BuildUnstableException)); } public boolean isSuccess() { @@ -148,8 +144,7 @@ public class ExecutionResult implements Serializable { this.skipped = skipped; } - private static final class MergedThrowable extends RuntimeException - implements Serializable { + private static final class MergedThrowable extends RuntimeException implements Serializable { private MergedThrowable(List throwables) { super("Failed due to the following exceptions " + throwables); @@ -157,8 +152,7 @@ public class ExecutionResult implements Serializable { } - private static final class MergedUnstableThrowable extends BuildUnstableException - implements Serializable { + private static final class MergedUnstableThrowable extends BuildUnstableException implements Serializable { private MergedUnstableThrowable(List throwables) { super("Unstable due to the following exceptions " + throwables); diff --git a/releaser-core/src/main/java/releaser/internal/tech/HandlebarsHelper.java b/releaser-core/src/main/java/releaser/internal/tech/HandlebarsHelper.java index 2724e7c8..830f83f9 100644 --- a/releaser-core/src/main/java/releaser/internal/tech/HandlebarsHelper.java +++ b/releaser-core/src/main/java/releaser/internal/tech/HandlebarsHelper.java @@ -34,8 +34,7 @@ public final class HandlebarsHelper { public static Template template(String templateSubFolder, String templateName) { try { - Handlebars handlebars = new Handlebars( - new ClassPathTemplateLoader("/templates/" + templateSubFolder)); + Handlebars handlebars = new Handlebars(new ClassPathTemplateLoader("/templates/" + templateSubFolder)); handlebars.registerHelper("replace", StringHelpers.replace); handlebars.registerHelper("capitalizeFirst", StringHelpers.capitalizeFirst); return handlebars.compile(templateName); diff --git a/releaser-core/src/main/java/releaser/internal/tech/PomReader.java b/releaser-core/src/main/java/releaser/internal/tech/PomReader.java index 51aa3a3f..5125a88a 100644 --- a/releaser-core/src/main/java/releaser/internal/tech/PomReader.java +++ b/releaser-core/src/main/java/releaser/internal/tech/PomReader.java @@ -60,11 +60,9 @@ public final class PomReader { } catch (XmlPullParserException | IOException e) { if (file.isFile() && fileText.length() == 0) { - throw new IllegalStateException( - "File [" + pom.getAbsolutePath() + "] is empty", e); + throw new IllegalStateException("File [" + pom.getAbsolutePath() + "] is empty", e); } - throw new IllegalStateException( - "Failed to read file: " + pom.getAbsolutePath(), e); + throw new IllegalStateException("Failed to read file: " + pom.getAbsolutePath(), e); } } diff --git a/releaser-core/src/main/java/releaser/internal/tech/TemporaryFileStorage.java b/releaser-core/src/main/java/releaser/internal/tech/TemporaryFileStorage.java index 77684ffe..2dea9380 100644 --- a/releaser-core/src/main/java/releaser/internal/tech/TemporaryFileStorage.java +++ b/releaser-core/src/main/java/releaser/internal/tech/TemporaryFileStorage.java @@ -65,8 +65,7 @@ public final class TemporaryFileStorage { if (file.isDirectory()) { Files.walkFileTree(file.toPath(), new SimpleFileVisitor() { @Override - public FileVisitResult visitFile(Path file, - BasicFileAttributes attrs) throws IOException { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (log.isTraceEnabled()) { log.trace("Removing file [" + file + "]"); } @@ -75,8 +74,7 @@ public final class TemporaryFileStorage { } @Override - public FileVisitResult postVisitDirectory(Path dir, - IOException exc) throws IOException { + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { if (log.isTraceEnabled()) { log.trace("Removing dir [" + dir + "]"); } @@ -110,9 +108,8 @@ public final class TemporaryFileStorage { return tempDir; } } - throw new IllegalStateException("Failed to create directory within " - + TEMP_DIR_ATTEMPTS + " attempts (tried " + baseName + "0 to " + baseName - + (TEMP_DIR_ATTEMPTS - 1) + ")"); + throw new IllegalStateException("Failed to create directory within " + TEMP_DIR_ATTEMPTS + " attempts (tried " + + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ")"); } } diff --git a/releaser-core/src/main/java/releaser/internal/template/BlogTemplateGenerator.java b/releaser-core/src/main/java/releaser/internal/template/BlogTemplateGenerator.java index 0aab0245..9b90d1e4 100644 --- a/releaser-core/src/main/java/releaser/internal/template/BlogTemplateGenerator.java +++ b/releaser-core/src/main/java/releaser/internal/template/BlogTemplateGenerator.java @@ -34,8 +34,7 @@ import releaser.internal.project.Projects; */ class BlogTemplateGenerator { - private static final Logger log = LoggerFactory - .getLogger(BlogTemplateGenerator.class); + private static final Logger log = LoggerFactory.getLogger(BlogTemplateGenerator.class); private static final Pattern RC_PATTERN = Pattern.compile("(.*)(RC)([0-9]+)"); @@ -53,8 +52,8 @@ class BlogTemplateGenerator { private final NotesGenerator notesGenerator; - BlogTemplateGenerator(Template template, String releaseVersion, File blogOutput, - Projects projects, ProjectGitHubHandler handler) { + BlogTemplateGenerator(Template template, String releaseVersion, File blogOutput, Projects projects, + ProjectGitHubHandler handler) { this.template = template; this.releaseVersion = releaseVersion; this.blogOutput = blogOutput; @@ -75,24 +74,21 @@ class BlogTemplateGenerator { boolean release = !SR_PATTERN.matcher(this.releaseVersion).matches() && !RC_PATTERN.matcher(this.releaseVersion).matches() && !MILESTONE_PATTERN.matcher(this.releaseVersion).matches(); - boolean nonRelease = !(release - || SR_PATTERN.matcher(this.releaseVersion).matches()); + boolean nonRelease = !(release || SR_PATTERN.matcher(this.releaseVersion).matches()); String availability = availability(release); String releaseName = parsedReleaseName(this.releaseVersion, release); String releaseLink = link(nonRelease); - Map map = ImmutableMap.builder() - .put("availability", availability).put("releaseName", releaseName) - .put("releaseLink", releaseLink) + Map map = ImmutableMap.builder().put("availability", availability) + .put("releaseName", releaseName).put("releaseLink", releaseLink) .put("releaseVersion", this.releaseVersion) - .put("projects", this.notesGenerator.fromProjects(this.projects)) - .put("nonRelease", nonRelease).build(); + .put("projects", this.notesGenerator.fromProjects(this.projects)).put("nonRelease", nonRelease) + .build(); String blog = this.template.apply(map); Files.write(this.blogOutput.toPath(), blog.getBytes()); return this.blogOutput; } catch (Exception e) { - throw new IllegalStateException( - "Exception occurred while trying to create a blog entry", e); + throw new IllegalStateException("Exception occurred while trying to create a blog entry", e); } } @@ -127,8 +123,7 @@ class BlogTemplateGenerator { } if (log.isWarnEnabled()) { log.warn("Unrecognized release [{}] . " - + "Hopefully, you know what you're doing. Will treat it as milestone", - this.releaseVersion); + + "Hopefully, you know what you're doing. Will treat it as milestone", this.releaseVersion); } return milestone(milestone); } @@ -147,8 +142,7 @@ class BlogTemplateGenerator { return "[Spring Milestone](https://repo.spring.io/milestone/) repository"; } return "[Maven Central](https://repo1.maven.org/maven2/" - + "org/springframework/cloud/spring-cloud-dependencies/" - + this.releaseVersion + "/)"; + + "org/springframework/cloud/spring-cloud-dependencies/" + this.releaseVersion + "/)"; } } diff --git a/releaser-core/src/main/java/releaser/internal/template/EmailTemplateGenerator.java b/releaser-core/src/main/java/releaser/internal/template/EmailTemplateGenerator.java index 68992751..dea50335 100644 --- a/releaser-core/src/main/java/releaser/internal/template/EmailTemplateGenerator.java +++ b/releaser-core/src/main/java/releaser/internal/template/EmailTemplateGenerator.java @@ -28,8 +28,7 @@ import org.slf4j.LoggerFactory; */ class EmailTemplateGenerator { - private static final Logger log = LoggerFactory - .getLogger(EmailTemplateGenerator.class); + private static final Logger log = LoggerFactory.getLogger(EmailTemplateGenerator.class); private final Template template; @@ -50,8 +49,7 @@ class EmailTemplateGenerator { return this.emailOutput; } catch (Exception e) { - throw new IllegalStateException( - "Exception occurred while trying to generate an email template", e); + throw new IllegalStateException("Exception occurred while trying to generate an email template", e); } } diff --git a/releaser-core/src/main/java/releaser/internal/template/NotesGenerator.java b/releaser-core/src/main/java/releaser/internal/template/NotesGenerator.java index c5de83a3..010d4db7 100644 --- a/releaser-core/src/main/java/releaser/internal/template/NotesGenerator.java +++ b/releaser-core/src/main/java/releaser/internal/template/NotesGenerator.java @@ -37,13 +37,12 @@ class NotesGenerator { } Set fromProjects(Projects projects) { - return projects.stream().filter(projectVersion -> !projectVersion.projectName - .toLowerCase().contains("boot")).map(projectVersion -> { + return projects.stream().filter(projectVersion -> !projectVersion.projectName.toLowerCase().contains("boot")) + .map(projectVersion -> { String name = projectVersion.projectName; String version = projectVersion.version; String closedMilestoneUrl = this.handler.milestoneUrl(projectVersion); - String convertedName = Arrays.stream(name.split("-")) - .map(StringUtils::capitalize) + String convertedName = Arrays.stream(name.split("-")).map(StringUtils::capitalize) .collect(Collectors.joining(" ")); return new Notes(convertedName, version, closedMilestoneUrl); }).collect(Collectors.toSet()); @@ -90,8 +89,7 @@ class Notes { if (this.name != null ? !this.name.equals(notes.name) : notes.name != null) { return false; } - return this.version != null ? this.version.equals(notes.version) - : notes.version == null; + return this.version != null ? this.version.equals(notes.version) : notes.version == null; } @Override diff --git a/releaser-core/src/main/java/releaser/internal/template/ReleaseNotesTemplateGenerator.java b/releaser-core/src/main/java/releaser/internal/template/ReleaseNotesTemplateGenerator.java index f89acc01..4ef245cd 100644 --- a/releaser-core/src/main/java/releaser/internal/template/ReleaseNotesTemplateGenerator.java +++ b/releaser-core/src/main/java/releaser/internal/template/ReleaseNotesTemplateGenerator.java @@ -43,8 +43,8 @@ class ReleaseNotesTemplateGenerator { private final NotesGenerator notesGenerator; - ReleaseNotesTemplateGenerator(Template template, String releaseVersion, - File blogOutput, Projects projects, ProjectGitHubHandler handler) { + ReleaseNotesTemplateGenerator(Template template, String releaseVersion, File blogOutput, Projects projects, + ProjectGitHubHandler handler) { this.template = template; this.releaseVersion = releaseVersion; this.blogOutput = blogOutput; @@ -57,15 +57,13 @@ class ReleaseNotesTemplateGenerator { Map map = ImmutableMap.builder() .put("date", LocalDate.now().format(DateTimeFormatter.ISO_DATE)) .put("releaseVersion", this.releaseVersion) - .put("projects", this.notesGenerator.fromProjects(this.projects)) - .build(); + .put("projects", this.notesGenerator.fromProjects(this.projects)).build(); String blog = this.template.apply(map); Files.write(this.blogOutput.toPath(), blog.getBytes()); return this.blogOutput; } catch (IOException e) { - throw new IllegalStateException( - "Exception occurred while trying to generate release notes", e); + throw new IllegalStateException("Exception occurred while trying to generate release notes", e); } } diff --git a/releaser-core/src/main/java/releaser/internal/template/TemplateGenerator.java b/releaser-core/src/main/java/releaser/internal/template/TemplateGenerator.java index 13b0c38e..18df1e66 100644 --- a/releaser-core/src/main/java/releaser/internal/template/TemplateGenerator.java +++ b/releaser-core/src/main/java/releaser/internal/template/TemplateGenerator.java @@ -59,8 +59,7 @@ public class TemplateGenerator { this.releaseNotesOutput = new File("target/notes.md"); } - TemplateGenerator(ReleaserProperties props, File output, - ProjectGitHubHandler handler) { + TemplateGenerator(ReleaserProperties props, File output, ProjectGitHubHandler handler) { this.props = props; this.emailOutput = output; this.blogOutput = output; @@ -97,8 +96,7 @@ public class TemplateGenerator { File blogOutput = file(this.blogOutput); String releaseVersion = parsedVersion(projects); Template template = template(BLOG_TEMPLATE); - return new BlogTemplateGenerator(template, releaseVersion, blogOutput, projects, - this.handler).blog(); + return new BlogTemplateGenerator(template, releaseVersion, blogOutput, projects, this.handler).blog(); } public File tweet(Projects projects) { @@ -112,8 +110,8 @@ public class TemplateGenerator { File output = file(this.releaseNotesOutput); String releaseVersion = parsedVersion(projects); Template template = template(RELEASE_NOTES_TEMPLATE); - return new ReleaseNotesTemplateGenerator(template, releaseVersion, output, - projects, this.handler).releaseNotes(); + return new ReleaseNotesTemplateGenerator(template, releaseVersion, output, projects, this.handler) + .releaseNotes(); } private String parsedVersion(Projects projects) { @@ -128,8 +126,7 @@ public class TemplateGenerator { } private Template template(String template) { - return HandlebarsHelper.template(this.props.getTemplate().getTemplateFolder(), - template); + return HandlebarsHelper.template(this.props.getTemplate().getTemplateFolder(), template); } } diff --git a/releaser-core/src/main/java/releaser/internal/template/TwitterTemplateGenerator.java b/releaser-core/src/main/java/releaser/internal/template/TwitterTemplateGenerator.java index 47cc6765..44f26090 100644 --- a/releaser-core/src/main/java/releaser/internal/template/TwitterTemplateGenerator.java +++ b/releaser-core/src/main/java/releaser/internal/template/TwitterTemplateGenerator.java @@ -28,8 +28,7 @@ import org.slf4j.LoggerFactory; */ class TwitterTemplateGenerator { - private static final Logger log = LoggerFactory - .getLogger(TwitterTemplateGenerator.class); + private static final Logger log = LoggerFactory.getLogger(TwitterTemplateGenerator.class); private final Template template; @@ -50,8 +49,7 @@ class TwitterTemplateGenerator { return this.output; } catch (Exception e) { - throw new IllegalStateException( - "Exception occurred while trying to generate a twitter template", e); + throw new IllegalStateException("Exception occurred while trying to generate a twitter template", e); } } diff --git a/releaser-core/src/main/java/releaser/internal/versions/VersionsFetcher.java b/releaser-core/src/main/java/releaser/internal/versions/VersionsFetcher.java index af923d6a..76f4a081 100644 --- a/releaser-core/src/main/java/releaser/internal/versions/VersionsFetcher.java +++ b/releaser-core/src/main/java/releaser/internal/versions/VersionsFetcher.java @@ -60,8 +60,7 @@ public class VersionsFetcher implements Closeable { private final ReleaserProperties properties; - public VersionsFetcher(ReleaserProperties properties, - ProjectPomUpdater projectPomUpdater) { + public VersionsFetcher(ReleaserProperties properties, ProjectPomUpdater projectPomUpdater) { this.properties = properties; this.projectPomUpdater = projectPomUpdater; this.toPropertiesConverter = new ToPropertiesConverter(new RawGithubRetriever()); @@ -75,8 +74,7 @@ public class VersionsFetcher implements Closeable { public boolean isLatestGa(ProjectVersion version) { if (!version.isReleaseOrServiceRelease()) { if (log.isDebugEnabled()) { - log.debug("Version [" + version.toString() - + "] is non GA, will not fetch any versions."); + log.debug("Version [" + version.toString() + "] is non GA, will not fetch any versions."); } return false; } @@ -86,55 +84,44 @@ public class VersionsFetcher implements Closeable { return false; } String latestVersionsUrl = this.properties.getVersions().getAllVersionsFileUrl(); - InitializrProperties initializrProperties = this.toPropertiesConverter - .toProperties(latestVersionsUrl); + InitializrProperties initializrProperties = this.toPropertiesConverter.toProperties(latestVersionsUrl); if (initializrProperties == null) { return false; } ProjectVersion bomVersion = latestBomVersion(); if (bomVersion == null) { - log.info("No BOM mapping with name [{}] found", - this.properties.getVersions().getBomName()); + log.info("No BOM mapping with name [{}] found", this.properties.getVersions().getBomName()); return false; } Projects projectVersions = null; try { - projectVersions = this.projectPomUpdater.retrieveVersionsFromReleaseTrainBom( - "v" + bomVersion.toString(), false); + projectVersions = this.projectPomUpdater.retrieveVersionsFromReleaseTrainBom("v" + bomVersion.toString(), + false); } catch (Exception ex) { - log.error( - "Failed to check the project versions. Will return that the project is not GA", - ex); + log.error("Failed to check the project versions. Will return that the project is not GA", ex); return false; } boolean containsProject = projectVersions.containsProject(version.projectName); if (containsProject) { return bomVersion.compareTo(projectVersions.forName(version.projectName)) > 0; } - log.info("The project [" + version.projectName - + "] is not present in the BOM with projects [" + projectVersions.stream() - .map(v -> v.projectName).collect(Collectors.joining(", ")) - + "]"); + log.info("The project [" + version.projectName + "] is not present in the BOM with projects [" + + projectVersions.stream().map(v -> v.projectName).collect(Collectors.joining(", ")) + "]"); return false; } private ProjectVersion latestBomVersion() { String latestVersionsUrl = this.properties.getVersions().getAllVersionsFileUrl(); - InitializrProperties initializrProperties = this.toPropertiesConverter - .toProperties(latestVersionsUrl); + InitializrProperties initializrProperties = this.toPropertiesConverter.toProperties(latestVersionsUrl); if (initializrProperties == null) { return null; } ProjectVersion springCloudVersion = initializrProperties.getEnv().getBoms() - .getOrDefault( - this.properties.getVersions().getBomName(), new BillOfMaterials()) - .getMappings().stream() - .map(mapping -> new ProjectVersion( - this.properties.getVersions().getBomName(), mapping.getVersion())) - .filter(ProjectVersion::isReleaseOrServiceRelease) - .max(ProjectVersion::compareTo).orElse(new ProjectVersion( - this.properties.getVersions().getBomName(), "")); + .getOrDefault(this.properties.getVersions().getBomName(), new BillOfMaterials()).getMappings().stream() + .map(mapping -> new ProjectVersion(this.properties.getVersions().getBomName(), mapping.getVersion())) + .filter(ProjectVersion::isReleaseOrServiceRelease).max(ProjectVersion::compareTo) + .orElse(new ProjectVersion(this.properties.getVersions().getBomName(), "")); log.info("Latest BOM version is [{}]", springCloudVersion.version); return springCloudVersion; } @@ -154,14 +141,13 @@ class RawGithubRetriever { try { URL url = new URL(stringUrl); URLConnection con = url.openConnection(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader( - con.getInputStream(), StandardCharsets.UTF_8))) { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) { return reader.lines().collect(Collectors.joining("\n")); } } catch (IOException e) { - LOG.warn("Exception occurred while trying to fetch the URL [" + stringUrl - + "] contents"); + LOG.warn("Exception occurred while trying to fetch the URL [" + stringUrl + "] contents"); return null; } } @@ -185,16 +171,12 @@ class ToPropertiesConverter implements Closeable { return null; } YamlPropertiesFactoryBean yamlProcessor = new YamlPropertiesFactoryBean(); - yamlProcessor.setResources(new InputStreamResource(new ByteArrayInputStream( - retrievedFile.getBytes(StandardCharsets.UTF_8)))); + yamlProcessor.setResources( + new InputStreamResource(new ByteArrayInputStream(retrievedFile.getBytes(StandardCharsets.UTF_8)))); Properties properties = yamlProcessor.getObject(); - return new Binder( - new MapConfigurationPropertySource(properties.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().toString(), - e -> e.getValue().toString())))) - .bind("initializr", - InitializrProperties.class) - .get(); + return new Binder(new MapConfigurationPropertySource(properties.entrySet().stream() + .collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString())))) + .bind("initializr", InitializrProperties.class).get(); }); } diff --git a/releaser-core/src/test/java/releaser/SpringCloudReleaserProperties.java b/releaser-core/src/test/java/releaser/SpringCloudReleaserProperties.java index 23c72ec1..32548dde 100644 --- a/releaser-core/src/test/java/releaser/SpringCloudReleaserProperties.java +++ b/releaser-core/src/test/java/releaser/SpringCloudReleaserProperties.java @@ -32,17 +32,13 @@ public class SpringCloudReleaserProperties { public static ReleaserProperties get() { try { - File releaserConfig = new File(SpringCloudReleaserProperties.class - .getResource("/application.yml").toURI()); + File releaserConfig = new File(SpringCloudReleaserProperties.class.getResource("/application.yml").toURI()); YamlPropertiesFactoryBean yamlProcessor = new YamlPropertiesFactoryBean(); yamlProcessor.setResources(new FileSystemResource(releaserConfig)); Properties properties = yamlProcessor.getObject(); - ReleaserProperties releaserProperties = new Binder( - new MapConfigurationPropertySource(properties.entrySet().stream() - .collect(Collectors.toMap(e -> e.getKey().toString(), - e -> e.getValue().toString())))) - .bind("releaser", ReleaserProperties.class) - .get(); + ReleaserProperties releaserProperties = new Binder(new MapConfigurationPropertySource(properties.entrySet() + .stream().collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString())))) + .bind("releaser", ReleaserProperties.class).get(); return releaserProperties; } catch (URISyntaxException e) { diff --git a/releaser-core/src/test/java/releaser/internal/PomUpdateAcceptanceTests.java b/releaser-core/src/test/java/releaser/internal/PomUpdateAcceptanceTests.java index 7dc93b36..1b006fb7 100644 --- a/releaser-core/src/test/java/releaser/internal/PomUpdateAcceptanceTests.java +++ b/releaser-core/src/test/java/releaser/internal/PomUpdateAcceptanceTests.java @@ -62,25 +62,20 @@ public class PomUpdateAcceptanceTests { ReleaserProperties releaserProperties = releaserProperties(); releaserProperties.getFixedVersions().put("checkstyle", "100.0.0.RELEASE"); ProjectPomUpdater projectPomUpdater = new ProjectPomUpdater(releaserProperties, - Collections - .singletonList(MavenBomParserAccessor.maven(releaserProperties))); + Collections.singletonList(MavenBomParserAccessor.maven(releaserProperties))); Projects projects = projectPomUpdater.retrieveVersionsFromReleaseTrainBom(); File project = new File(this.temporaryFolder, "/spring-cloud-sleuth"); - projectPomUpdater.updateProjectFromReleaseTrain(project, projects, - projects.forFile(project), true); + projectPomUpdater.updateProjectFromReleaseTrain(project, projects, projects.forFile(project), true); then(this.temporaryFolder).exists(); Model rootPom = PomReader.readPom(tmpFile("/spring-cloud-sleuth/pom.xml")); - Model depsPom = PomReader.readPom( - tmpFile("/spring-cloud-sleuth/spring-cloud-sleuth-dependencies/pom.xml")); - Model corePom = PomReader.readPom( - tmpFile("/spring-cloud-sleuth/spring-cloud-sleuth-core/pom.xml")); + Model depsPom = PomReader.readPom(tmpFile("/spring-cloud-sleuth/spring-cloud-sleuth-dependencies/pom.xml")); + Model corePom = PomReader.readPom(tmpFile("/spring-cloud-sleuth/spring-cloud-sleuth-core/pom.xml")); Model zipkinStreamPom = PomReader.readPom(tmpFile( "/spring-cloud-sleuth/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/pom.xml")); then(rootPom.getVersion()).isEqualTo("1.2.0.BUILD-SNAPSHOT"); - then(rootPom.getProperties()) - .containsEntry("spring-cloud-commons.version", "1.2.0.BUILD-SNAPSHOT") + then(rootPom.getProperties()).containsEntry("spring-cloud-commons.version", "1.2.0.BUILD-SNAPSHOT") .containsEntry("spring-cloud-stream.version", "Chelsea.BUILD-SNAPSHOT") .containsEntry("spring-cloud-netflix.version", "1.3.0.BUILD-SNAPSHOT") .containsEntry("checkstyle.version", "100.0.0.RELEASE"); @@ -95,23 +90,20 @@ public class PomUpdateAcceptanceTests { throws Exception { ReleaserProperties releaserProperties = branchReleaserProperties(); ProjectPomUpdater projectPomUpdater = new ProjectPomUpdater(releaserProperties, - Collections - .singletonList(MavenBomParserAccessor.maven(releaserProperties))); + Collections.singletonList(MavenBomParserAccessor.maven(releaserProperties))); Projects projects = projectPomUpdater.retrieveVersionsFromReleaseTrainBom(); projects.add(new ProjectVersion("spring-cloud-sleuth-samples", "0.0.5.RELEASE")); File project = new File(this.temporaryFolder, "/spring-cloud-sleuth-with-unmatched-property/spring-cloud-sleuth-samples"); addBuildSnapshotToChildPom(project); - projectPomUpdater.updateProjectFromReleaseTrain(project, projects, - projects.forFile(project), true); + projectPomUpdater.updateProjectFromReleaseTrain(project, projects, projects.forFile(project), true); } private void addBuildSnapshotToChildPom(File project) throws IOException { File childPom = new File(project, "pom.xml"); String text = new String(Files.readAllBytes(childPom.toPath())); - Files.write(childPom.toPath(), - text.replaceAll("1.19.2", "1.19.2.BUILD-SNAPSHOT").getBytes()); + Files.write(childPom.toPath(), text.replaceAll("1.19.2", "1.19.2.BUILD-SNAPSHOT").getBytes()); } @Test @@ -119,15 +111,13 @@ public class PomUpdateAcceptanceTests { throws Exception { ReleaserProperties releaserProperties = branchReleaserProperties(); ProjectPomUpdater projectPomUpdater = new ProjectPomUpdater(releaserProperties, - Collections - .singletonList(MavenBomParserAccessor.maven(releaserProperties))); + Collections.singletonList(MavenBomParserAccessor.maven(releaserProperties))); Projects projects = projectPomUpdater.retrieveVersionsFromReleaseTrainBom(); - File project = new File(this.temporaryFolder, - "/spring-cloud-sleuth-with-unmatched-property"); + File project = new File(this.temporaryFolder, "/spring-cloud-sleuth-with-unmatched-property"); BDDAssertions - .thenThrownBy(() -> projectPomUpdater.updateProjectFromReleaseTrain( - project, projects, projects.forFile(project), true)) + .thenThrownBy(() -> projectPomUpdater.updateProjectFromReleaseTrain(project, projects, + projects.forFile(project), true)) .hasMessageContaining("0.3.1.BUILD-SNAPSHOT"); } @@ -136,18 +126,15 @@ public class PomUpdateAcceptanceTests { throws Exception { ReleaserProperties releaserProperties = branchReleaserProperties(); ProjectPomUpdater projectPomUpdater = new ProjectPomUpdater(releaserProperties, - Collections - .singletonList(MavenBomParserAccessor.maven(releaserProperties))); + Collections.singletonList(MavenBomParserAccessor.maven(releaserProperties))); Projects projects = projectPomUpdater.retrieveVersionsFromReleaseTrainBom(); - projects.removeIf(projectVersion -> projectVersion.projectName - .contains("spring-cloud-build")); + projects.removeIf(projectVersion -> projectVersion.projectName.contains("spring-cloud-build")); projects.add(new ProjectVersion("spring-cloud-build", "1.4.2.RELEASE")); - File project = new File(this.temporaryFolder, - "/spring-cloud-sleuth-with-milestone-dep"); + File project = new File(this.temporaryFolder, "/spring-cloud-sleuth-with-milestone-dep"); BDDAssertions - .thenThrownBy(() -> projectPomUpdater.updateProjectFromReleaseTrain( - project, projects, projects.forFile(project), true)) + .thenThrownBy(() -> projectPomUpdater.updateProjectFromReleaseTrain(project, projects, + projects.forFile(project), true)) .hasMessageContaining("1.19.2-M2"); } @@ -156,15 +143,13 @@ public class PomUpdateAcceptanceTests { throws Exception { ReleaserProperties releaserProperties = branchReleaserProperties(); ProjectPomUpdater projectPomUpdater = new ProjectPomUpdater(releaserProperties, - Collections - .singletonList(MavenBomParserAccessor.maven(releaserProperties))); + Collections.singletonList(MavenBomParserAccessor.maven(releaserProperties))); Projects projects = projects(projectPomUpdater); - File project = new File(this.temporaryFolder, - "/spring-cloud-sleuth-with-milestone-dep"); + File project = new File(this.temporaryFolder, "/spring-cloud-sleuth-with-milestone-dep"); BDDAssertions - .thenThrownBy(() -> projectPomUpdater.updateProjectFromReleaseTrain( - project, projects, projects.forFile(project), true)) + .thenThrownBy(() -> projectPomUpdater.updateProjectFromReleaseTrain(project, projects, + projects.forFile(project), true)) .hasMessageContaining("1.19.2-M2"); } @@ -173,35 +158,26 @@ public class PomUpdateAcceptanceTests { throws Exception { ReleaserProperties releaserProperties = branchReleaserProperties(); ProjectPomUpdater projectPomUpdater = new ProjectPomUpdater(releaserProperties, - Collections - .singletonList(MavenBomParserAccessor.maven(releaserProperties))); + Collections.singletonList(MavenBomParserAccessor.maven(releaserProperties))); Projects projects = projects(projectPomUpdater); - File project = new File(this.temporaryFolder, - "/spring-cloud-sleuth-with-ignored-line"); + File project = new File(this.temporaryFolder, "/spring-cloud-sleuth-with-ignored-line"); - projectPomUpdater.updateProjectFromReleaseTrain(project, projects, - projects.forFile(project), true); + projectPomUpdater.updateProjectFromReleaseTrain(project, projects, projects.forFile(project), true); } private Projects projects(ProjectPomUpdater projectPomUpdater) { Projects projects = projectPomUpdater.retrieveVersionsFromReleaseTrainBom(); - projects.removeIf( - projectVersion -> projectVersion.projectName.equals("spring-cloud")); + projects.removeIf(projectVersion -> projectVersion.projectName.equals("spring-cloud")); projects.add(new ProjectVersion("spring-cloud", "Camden.RC1")); - projects.removeIf(projectVersion -> projectVersion.projectName - .equals("spring-cloud-dependencies")); + projects.removeIf(projectVersion -> projectVersion.projectName.equals("spring-cloud-dependencies")); projects.add(new ProjectVersion("spring-cloud-dependencies", "Camden.RC1")); - projects.removeIf(projectVersion -> projectVersion.projectName - .equals("spring-cloud-starter")); + projects.removeIf(projectVersion -> projectVersion.projectName.equals("spring-cloud-starter")); projects.add(new ProjectVersion("spring-cloud-starter", "Camden.RC1")); - projects.removeIf(projectVersion -> projectVersion.projectName - .equals("spring-cloud-starter-build")); + projects.removeIf(projectVersion -> projectVersion.projectName.equals("spring-cloud-starter-build")); projects.add(new ProjectVersion("spring-cloud-starter-build", "Camden.RC1")); - projects.removeIf(projectVersion -> projectVersion.projectName - .equals("spring-cloud-release")); + projects.removeIf(projectVersion -> projectVersion.projectName.equals("spring-cloud-release")); projects.add(new ProjectVersion("spring-cloud-release", "Camden.RC1")); - projects.removeIf(projectVersion -> projectVersion.projectName - .contains("spring-cloud-build")); + projects.removeIf(projectVersion -> projectVersion.projectName.contains("spring-cloud-build")); projects.add(new ProjectVersion("spring-cloud-build", "1.4.2.RELEASE")); return projects; } @@ -211,26 +187,21 @@ public class PomUpdateAcceptanceTests { throws Exception { ReleaserProperties releaserProperties = branchReleaserProperties(); ProjectPomUpdater projectPomUpdater = new ProjectPomUpdater(releaserProperties, - Collections - .singletonList(MavenBomParserAccessor.maven(releaserProperties))); + Collections.singletonList(MavenBomParserAccessor.maven(releaserProperties))); Projects projects = projectPomUpdater.retrieveVersionsFromReleaseTrainBom(); - projects.removeIf(projectVersion -> projectVersion.projectName - .contains("spring-cloud-build")); + projects.removeIf(projectVersion -> projectVersion.projectName.contains("spring-cloud-build")); projects.add(new ProjectVersion("spring-cloud-build", "1.4.2.BUILD-SNAPSHOT")); File project = new File(this.temporaryFolder, "/spring-cloud-sleuth"); - BDDAssertions - .thenThrownBy(() -> projectPomUpdater.updateProjectFromReleaseTrain( - project, projects, projects.forFile(project), true)) - .hasMessageContaining("BUILD-SNAPSHOT"); + BDDAssertions.thenThrownBy(() -> projectPomUpdater.updateProjectFromReleaseTrain(project, projects, + projects.forFile(project), true)).hasMessageContaining("BUILD-SNAPSHOT"); } @Test public void should_not_update_a_project_that_is_not_on_the_list() throws Exception { ReleaserProperties releaserProperties = releaserProperties(); ProjectPomUpdater projectPomUpdater = new ProjectPomUpdater(releaserProperties, - Collections - .singletonList(MavenBomParserAccessor.maven(releaserProperties))); + Collections.singletonList(MavenBomParserAccessor.maven(releaserProperties))); File beforeProcessing = pom("/projects/project/"); Projects projects = projectPomUpdater.retrieveVersionsFromReleaseTrainBom(); File project = tmpFile("/project/"); @@ -245,8 +216,7 @@ public class PomUpdateAcceptanceTests { private ReleaserProperties releaserProperties() throws URISyntaxException { ReleaserProperties releaserProperties = SpringCloudReleaserProperties.get(); - releaserProperties.getGit().setReleaseTrainBomUrl( - file("/projects/spring-cloud-release/").toURI().toString()); + releaserProperties.getGit().setReleaseTrainBomUrl(file("/projects/spring-cloud-release/").toURI().toString()); return releaserProperties; } @@ -265,10 +235,7 @@ public class PomUpdateAcceptanceTests { } private File pom(String relativePath) throws URISyntaxException { - return new File( - new File( - PomUpdateAcceptanceTests.class.getResource(relativePath).toURI()), - "pom.xml"); + return new File(new File(PomUpdateAcceptanceTests.class.getResource(relativePath).toURI()), "pom.xml"); } private String asString(File file) throws IOException { diff --git a/releaser-core/src/test/java/releaser/internal/ReleaserPropertiesTests.java b/releaser-core/src/test/java/releaser/internal/ReleaserPropertiesTests.java index d4be96f0..e81bd1cd 100644 --- a/releaser-core/src/test/java/releaser/internal/ReleaserPropertiesTests.java +++ b/releaser-core/src/test/java/releaser/internal/ReleaserPropertiesTests.java @@ -72,13 +72,10 @@ public class ReleaserPropertiesTests { BDDAssertions.then(properties.getWorkingDir()).isEqualTo("foo"); BDDAssertions.then(properties.getFixedVersions()).isEqualTo(map()); BDDAssertions.then(properties.getMaven().getBuildCommand()).isEqualTo("foo2"); - BDDAssertions.then(properties.getGradle().getIgnoredGradleRegex()) - .isEqualTo(Arrays.asList("foo3", "foo4")); - BDDAssertions.then(properties.getMetaRelease().getProjectsToSkip()) - .isEqualTo(Arrays.asList("foo5", "foo6")); + BDDAssertions.then(properties.getGradle().getIgnoredGradleRegex()).isEqualTo(Arrays.asList("foo3", "foo4")); + BDDAssertions.then(properties.getMetaRelease().getProjectsToSkip()).isEqualTo(Arrays.asList("foo5", "foo6")); BDDAssertions.then(properties.getGit().getPassword()).isEqualTo("foo7"); - BDDAssertions.then(properties.getPom().getIgnoredPomRegex()) - .isEqualTo(Arrays.asList("foo8", "foo9")); + BDDAssertions.then(properties.getPom().getIgnoredPomRegex()).isEqualTo(Arrays.asList("foo8", "foo9")); BDDAssertions.then(properties.getSagan().getBaseUrl()).isEqualTo("foo10"); } diff --git a/releaser-core/src/test/java/releaser/internal/ReleaserTests.java b/releaser-core/src/test/java/releaser/internal/ReleaserTests.java index 79a0220d..0c9a53cb 100644 --- a/releaser-core/src/test/java/releaser/internal/ReleaserTests.java +++ b/releaser-core/src/test/java/releaser/internal/ReleaserTests.java @@ -42,7 +42,7 @@ import releaser.internal.project.Projects; import releaser.internal.sagan.SaganUpdater; import releaser.internal.template.TemplateGenerator; -import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.boot.test.system.OutputCaptureRule; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.then; @@ -55,7 +55,7 @@ import static org.mockito.Mockito.never; public class ReleaserTests { @Rule - public OutputCapture outputCapture = new OutputCapture(); + public OutputCaptureRule outputCapture = new OutputCaptureRule(); @Mock ProjectPomUpdater projectPomUpdater; @@ -93,9 +93,8 @@ public class ReleaserTests { } Releaser releaser(Supplier originalVersionSupplier) { - return new Releaser(SpringCloudReleaserProperties.get(), this.projectPomUpdater, - this.projectCommandExecutor, this.projectGitHandler, - this.projectGitHubHandler, this.templateGenerator, this.gradleUpdater, + return new Releaser(SpringCloudReleaserProperties.get(), this.projectPomUpdater, this.projectCommandExecutor, + this.projectGitHandler, this.projectGitHubHandler, this.templateGenerator, this.gradleUpdater, this.saganUpdater, this.documentationUpdater, this.postReleaseActions) { @Override ProjectVersion originalVersion(File project) { @@ -105,71 +104,60 @@ public class ReleaserTests { } Releaser releaser() { - return new Releaser(new ReleaserProperties(), this.projectPomUpdater, - this.projectCommandExecutor, this.projectGitHandler, - this.projectGitHubHandler, this.templateGenerator, this.gradleUpdater, + return new Releaser(new ReleaserProperties(), this.projectPomUpdater, this.projectCommandExecutor, + this.projectGitHandler, this.projectGitHubHandler, this.templateGenerator, this.gradleUpdater, this.saganUpdater, this.documentationUpdater, this.postReleaseActions); } @Test public void should_not_bump_versions_for_original_release_project() { - releaser(() -> new ProjectVersion("original", "1.0.0.RELEASE")) - .rollbackReleaseVersion(this.pom, - new Projects(new ProjectVersion("changed", "1.0.0.RELEASE")), - new ProjectVersion("changed", "1.0.0.RELEASE")); + releaser(() -> new ProjectVersion("original", "1.0.0.RELEASE")).rollbackReleaseVersion(this.pom, + new Projects(new ProjectVersion("changed", "1.0.0.RELEASE")), + new ProjectVersion("changed", "1.0.0.RELEASE")); - BDDAssertions.then(this.outputCapture.toString()).contains( - "Successfully reverted the commit and came back to snapshot versions"); - then(this.projectGitHandler).should(never()) - .commitAfterBumpingVersions(any(File.class), any(ProjectVersion.class)); + BDDAssertions.then(this.outputCapture.toString()) + .contains("Successfully reverted the commit and came back to snapshot versions"); + then(this.projectGitHandler).should(never()).commitAfterBumpingVersions(any(File.class), + any(ProjectVersion.class)); } @Test public void should_not_bump_versions_for_original_snapshot_project_and_current_snapshot() { - releaser(() -> new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")) - .rollbackReleaseVersion(this.pom, - new Projects( - new ProjectVersion("changed", "1.0.0.BUILD-SNAPSHOT")), - new ProjectVersion("changed", "1.0.0.BUILD-SNAPSHOT")); + releaser(() -> new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")).rollbackReleaseVersion(this.pom, + new Projects(new ProjectVersion("changed", "1.0.0.BUILD-SNAPSHOT")), + new ProjectVersion("changed", "1.0.0.BUILD-SNAPSHOT")); - BDDAssertions.then(this.outputCapture.toString()) - .contains("Won't rollback a snapshot version"); - then(this.projectGitHandler).should(never()) - .commitAfterBumpingVersions(any(File.class), any(ProjectVersion.class)); + BDDAssertions.then(this.outputCapture.toString()).contains("Won't rollback a snapshot version"); + then(this.projectGitHandler).should(never()).commitAfterBumpingVersions(any(File.class), + any(ProjectVersion.class)); } @Test public void should_bump_versions_for_original_snapshot_project() { ProjectVersion scReleaseVersion = new ProjectVersion("changed", "1.0.0.RELEASE"); - releaser(() -> new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")) - .rollbackReleaseVersion(this.pom, new Projects( - new ProjectVersion("changed", "1.0.0.RELEASE"), + releaser(() -> new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")).rollbackReleaseVersion(this.pom, + new Projects(new ProjectVersion("changed", "1.0.0.RELEASE"), new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE"), new ProjectVersion("spring-boot-starter", "3.0.0.RELEASE")), - scReleaseVersion); + scReleaseVersion); - BDDAssertions.then(this.outputCapture.toString()) - .contains("Project was successfully updated") + BDDAssertions.then(this.outputCapture.toString()).contains("Project was successfully updated") .contains("Successfully reverted the commit and bumped snapshot versions") - .contains("spring-boot-starter=>3.0.0.RELEASE") - .contains("spring-cloud-build=>2.0.1.SNAPSHOT") + .contains("spring-boot-starter=>3.0.0.RELEASE").contains("spring-cloud-build=>2.0.1.SNAPSHOT") .contains("changed=>1.0.1.SNAPSHOT"); } @Test public void should_not_generate_email_for_snapshot_version() { - releaser().createEmail(new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT"), - projects()); + releaser().createEmail(new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT"), projects()); then(this.templateGenerator).should(never()).email(any(Projects.class)); } @Test public void should_generate_email_for_release_version() { - BDDMockito.given(this.templateGenerator.email(projects())) - .willReturn(new File(".")); - releaser().createEmail(new ProjectVersion("original", "1.0.0.RELEASE"), - projects()); + BDDMockito.given(this.templateGenerator.email(projects())).willReturn(new File(".")); + releaser().createEmail(new ProjectVersion("original", "1.0.0.RELEASE"), projects()); then(this.templateGenerator).should().email(any(Projects.class)); } @@ -178,20 +166,17 @@ public class ReleaserTests { public void should_not_close_milestone_for_snapshots() { releaser().closeMilestone(new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")); - then(this.projectGitHubHandler).should(never()) - .closeMilestone(any(ProjectVersion.class)); + then(this.projectGitHubHandler).should(never()).closeMilestone(any(ProjectVersion.class)); } @Test public void should_not_rollback_for_snapshots() { - releaser(() -> new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")) - .rollbackReleaseVersion(null, - new Projects( - new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")), - new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")); + releaser(() -> new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")).rollbackReleaseVersion(null, + new Projects(new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")), + new ProjectVersion("original", "1.0.0.BUILD-SNAPSHOT")); - then(this.projectGitHandler).should(never()) - .revertChangesIfApplicable(any(File.class), any(ProjectVersion.class)); + then(this.projectGitHandler).should(never()).revertChangesIfApplicable(any(File.class), + any(ProjectVersion.class)); } Projects projects() { diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/GradleBomParserTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/GradleBomParserTests.java index f0e0940f..c2de2d3d 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/GradleBomParserTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/GradleBomParserTests.java @@ -30,8 +30,7 @@ class GradleBomParserTests { @Test void should_read_versions_from_bom_from_properties() { - GradleBomParser parser = new GradleBomParser(new ReleaserProperties(), - new ArrayList<>()) { + GradleBomParser parser = new GradleBomParser(new ReleaserProperties(), new ArrayList<>()) { @Override public boolean isApplicable(File clonedBom) { return true; @@ -52,8 +51,7 @@ class GradleBomParserTests { VersionsFromBom versionsFromBom = parser.versionsFromBom(new File(".")); - BDDAssertions.then(versionsFromBom.versionForProject("spring-cloud-contract")) - .isEqualTo("1.0.0.RELEASE"); + BDDAssertions.then(versionsFromBom.versionForProject("spring-cloud-contract")).isEqualTo("1.0.0.RELEASE"); } @Test @@ -62,8 +60,7 @@ class GradleBomParserTests { gradleSubstitution.put("verifierVersion", "spring-cloud-contract"); ReleaserProperties releaserProperties = new ReleaserProperties(); releaserProperties.getGradle().setGradlePropsSubstitution(gradleSubstitution); - GradleBomParser parser = new GradleBomParser(releaserProperties, - new ArrayList<>()) { + GradleBomParser parser = new GradleBomParser(releaserProperties, new ArrayList<>()) { @Override public boolean isApplicable(File clonedBom) { return true; @@ -84,22 +81,19 @@ class GradleBomParserTests { VersionsFromBom versionsFromBom = parser.versionsFromBom(new File(".")); - BDDAssertions.then(versionsFromBom.versionForProject("spring-cloud-contract")) - .isEqualTo("1.0.0.RELEASE"); + BDDAssertions.then(versionsFromBom.versionForProject("spring-cloud-contract")).isEqualTo("1.0.0.RELEASE"); } @Test void should_be_not_applicable_when_no_build_gradle_is_present() { - GradleBomParser parser = new GradleBomParser(new ReleaserProperties(), - new ArrayList<>()); + GradleBomParser parser = new GradleBomParser(new ReleaserProperties(), new ArrayList<>()); BDDAssertions.then(parser.isApplicable(new File("."))).isFalse(); } @Test void should_be_applicable_when_build_gradle_is_present() { - GradleBomParser parser = new GradleBomParser(new ReleaserProperties(), - new ArrayList<>()) { + GradleBomParser parser = new GradleBomParser(new ReleaserProperties(), new ArrayList<>()) { @Override File file(File clonedBom, String child) { return clonedBom; @@ -111,8 +105,7 @@ class GradleBomParserTests { @Test void should_return_empty_version_when_no_gradle_properties_is_present() { - GradleBomParser parser = new GradleBomParser(new ReleaserProperties(), - new ArrayList<>()); + GradleBomParser parser = new GradleBomParser(new ReleaserProperties(), new ArrayList<>()); VersionsFromBom versionsFromBom = parser.versionsFromBom(new File(".")); diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/MavenBomParserTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/MavenBomParserTests.java index f6b067a5..b5fdfad5 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/MavenBomParserTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/MavenBomParserTests.java @@ -51,8 +51,7 @@ public class MavenBomParserTests { BomParser parser = new MavenBomParser(this.properties, Collections.emptyList()); thenThrownBy(() -> parser.versionsFromBom(this.springCloudReleaseProject)) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Pom is not present"); + .isInstanceOf(IllegalStateException.class).hasMessageContaining("Pom is not present"); } @Test @@ -69,8 +68,7 @@ public class MavenBomParserTests { public void should_throw_exception_when_cloud_pom_is_missing() { BomParser parser = new MavenBomParser(this.properties, Collections.emptyList()); - thenThrownBy(() -> parser.versionsFromBom(new File("."))) - .isInstanceOf(IllegalStateException.class) + thenThrownBy(() -> parser.versionsFromBom(new File("."))).isInstanceOf(IllegalStateException.class) .hasMessageContaining("Pom is not present"); } @@ -81,8 +79,7 @@ public class MavenBomParserTests { BomParser parser = new MavenBomParser(this.properties, Collections.emptyList()); thenThrownBy(() -> parser.versionsFromBom(this.springCloudReleaseProject)) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Pom is not present"); + .isInstanceOf(IllegalStateException.class).hasMessageContaining("Pom is not present"); } } diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/PomReaderTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/PomReaderTests.java index f128bb90..d756319c 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/PomReaderTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/PomReaderTests.java @@ -46,12 +46,10 @@ public class PomReaderTests { @Before public void setup() throws URISyntaxException { - URI scRelease = GitRepoTests.class.getResource("/projects/spring-cloud-release") - .toURI(); + URI scRelease = GitRepoTests.class.getResource("/projects/spring-cloud-release").toURI(); this.springCloudReleaseProject = new File(scRelease); this.springCloudReleaseProjectPom = new File(scRelease.getPath(), "pom.xml"); - this.empty = new File( - GitRepoTests.class.getResource("/projects/project/empty.xml").toURI()); + this.empty = new File(GitRepoTests.class.getResource("/projects/project/empty.xml").toURI()); this.licenseFile = new File(scRelease.getPath(), "LICENSE.txt"); } @@ -78,16 +76,14 @@ public class PomReaderTests { @Test public void should_throw_exception_when_file_is_invalid() { - thenThrownBy(() -> PomReader.readPom(this.licenseFile)) - .hasMessageStartingWith("Failed to read file: ") + thenThrownBy(() -> PomReader.readPom(this.licenseFile)).hasMessageStartingWith("Failed to read file: ") .hasCauseInstanceOf(XmlPullParserException.class); } @Test public void should_throw_exception_when_file_is_empty() { thenThrownBy(() -> PomReader.readPom(this.empty)).hasMessageStartingWith("File [") - .hasMessageContaining("] is empty") - .hasCauseInstanceOf(EOFException.class); + .hasMessageContaining("] is empty").hasCauseInstanceOf(EOFException.class); } } diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/PomUpdaterTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/PomUpdaterTests.java index 0dae4341..247d9e3d 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/PomUpdaterTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/PomUpdaterTests.java @@ -64,51 +64,40 @@ public class PomUpdaterTests { } @Test - public void should_not_update_pom_when_project_is_not_on_the_versions_list() - throws Exception { + public void should_not_update_pom_when_project_is_not_on_the_versions_list() throws Exception { File springCloudReleasePom = file("/projects/spring-cloud-release"); - BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudReleasePom, - this.versionsFromBom)).isFalse(); - } - - @Test - public void should_not_update_pom_when_project_with_parent_suffix_is_not_on_the_versions_list() - throws Exception { - File springCloud = pom("/projects/project", "pom_with_parent_suffix.xml"); - - BDDAssertions.then( - this.pomUpdater.shouldProjectBeUpdated(springCloud, this.versionsFromBom)) + BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudReleasePom, this.versionsFromBom)) .isFalse(); } @Test - public void should_update_pom_for_project_with_suffix_when_project_is_on_the_versions_list() - throws Exception { - File springCloud = pom("/projects/project", - "pom_matching_with_parent_suffix.xml"); + public void should_not_update_pom_when_project_with_parent_suffix_is_not_on_the_versions_list() throws Exception { + File springCloud = pom("/projects/project", "pom_with_parent_suffix.xml"); - BDDAssertions.then( - this.pomUpdater.shouldProjectBeUpdated(springCloud, this.versionsFromBom)) - .isTrue(); + BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloud, this.versionsFromBom)).isFalse(); } @Test - public void should_update_pom_when_project_is_not_on_the_versions_list() - throws Exception { + public void should_update_pom_for_project_with_suffix_when_project_is_on_the_versions_list() throws Exception { + File springCloud = pom("/projects/project", "pom_matching_with_parent_suffix.xml"); + + BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloud, this.versionsFromBom)).isTrue(); + } + + @Test + public void should_update_pom_when_project_is_not_on_the_versions_list() throws Exception { File springCloudSleuthPom = file("/projects/spring-cloud-sleuth"); - BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudSleuthPom, - this.versionsFromBom)).isTrue(); + BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudSleuthPom, this.versionsFromBom)).isTrue(); } @Test - public void should_not_update_pom_when_project_is_on_the_versions_list_but_there_is_no_pom() - throws Exception { + public void should_not_update_pom_when_project_is_on_the_versions_list_but_there_is_no_pom() throws Exception { File springCloudSleuthPom = file("/projects/spring-cloud-sleuth/empty-folder"); - BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudSleuthPom, - this.versionsFromBom)).isFalse(); + BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudSleuthPom, this.versionsFromBom)) + .isFalse(); } @Test @@ -116,110 +105,85 @@ public class PomUpdaterTests { File originalPom = pom("/projects/project"); File pomInTemp = tmpFile("/project/pom.xml"); ModelWrapper rootPom = model("foo"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isEqualTo(asString(originalPom)); } @Test - public void should_update_the_pom_if_only_artifact_id_is_matched_in_the_root_pom() - throws Exception { + public void should_update_the_pom_if_only_artifact_id_is_matched_in_the_root_pom() throws Exception { File originalPom = pom("/projects/project", "pom_matching_artifact.xml"); File pomInTemp = tmpFile("/project/pom_matching_artifact.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); } @Test - public void should_update_the_pom_if_parent_is_matched_via_sc_build() - throws Exception { + public void should_update_the_pom_if_parent_is_matched_via_sc_build() throws Exception { File originalPom = pom("/projects/project", "pom_matching_parent_v2.xml"); File pomInTemp = tmpFile("/project/pom_matching_parent_v2.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(originalPom)).isNotEqualTo(asString(storedPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("0.0.2"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("0.0.2"); } @Test - public void should_update_the_pom_if_parent_is_matched_via_sc_dependencies_parent() - throws Exception { + public void should_update_the_pom_if_parent_is_matched_via_sc_dependencies_parent() throws Exception { File originalPom = pom("/projects/project", "pom_matching_parent.xml"); File pomInTemp = tmpFile("/project/pom_matching_parent.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("0.0.2"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("0.0.2"); } @Test - public void should_not_update_child_pom_when_project_is_not_on_the_versions_list() - throws Exception { + public void should_not_update_child_pom_when_project_is_not_on_the_versions_list() throws Exception { File springCloudReleasePom = file("/projects/spring-cloud-release"); - BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudReleasePom, - this.versionsFromBom)).isFalse(); + BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudReleasePom, this.versionsFromBom)) + .isFalse(); } @Test - public void should_update_child_pom_when_project_is_not_on_the_versions_list() - throws Exception { + public void should_update_child_pom_when_project_is_not_on_the_versions_list() throws Exception { File springCloudSleuthPom = file("/projects/spring-cloud-sleuth"); - BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudSleuthPom, - this.versionsFromBom)).isTrue(); + BDDAssertions.then(this.pomUpdater.shouldProjectBeUpdated(springCloudSleuthPom, this.versionsFromBom)).isTrue(); } @Test - public void should_update_the_child_pom_if_parent_is_matched_via_sc_build() - throws Exception { - File originalPom = pom("/projects/project/children", - "pom_matching_parent_v2.xml"); + public void should_update_the_child_pom_if_parent_is_matched_via_sc_build() throws Exception { + File originalPom = pom("/projects/project/children", "pom_matching_parent_v2.xml"); File pomInTemp = tmpFile("/project/children/pom_matching_parent_v2.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); // the rest is the same BDDAssertions.then(overriddenPomModel.getProperties()) .containsEntry("spring-cloud-foo.version", "1.3.1.BUILD-SNAPSHOT") @@ -227,26 +191,20 @@ public class PomUpdaterTests { } @Test - public void should_update_the_parent_from_properties_even_if_group_ids_dont_match() - throws Exception { - File originalPom = pom("/projects/project/children", - "pom_different_group_boot_parent.xml"); + public void should_update_the_parent_from_properties_even_if_group_ids_dont_match() throws Exception { + File originalPom = pom("/projects/project/children", "pom_different_group_boot_parent.xml"); File pomInTemp = tmpFile("/project/children/pom_different_group_boot_parent.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth", "org.springframework.cloud"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("1.5.8.RELEASE"); - BDDAssertions.then(overriddenPomModel.getProperties()) - .containsEntry("spring-cloud-sleuth.version", "0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("1.5.8.RELEASE"); + BDDAssertions.then(overriddenPomModel.getProperties()).containsEntry("spring-cloud-sleuth.version", + "0.0.3.BUILD-SNAPSHOT"); } @Test @@ -255,137 +213,104 @@ public class PomUpdaterTests { File originalPom = pom("/projects/project/children", "pom_different_group.xml"); File pomInTemp = tmpFile("/project/children/pom_different_group.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth", "org.springframework.cloud"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("1.2.2.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("1.5.8.RELEASE"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("1.2.2.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("1.5.8.RELEASE"); // the rest is the same - BDDAssertions.then(overriddenPomModel.getProperties()) - .containsEntry("spring-cloud-sleuth.version", "0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getProperties()).containsEntry("spring-cloud-sleuth.version", + "0.0.3.BUILD-SNAPSHOT"); } @Test public void should_update_everything_when_group_ids_dont_match_and_there_is_skip_deployment_property() throws Exception { - File originalPom = pom("/projects/project/children", - "pom_different_group_skip_deployment_prop.xml"); - File pomInTemp = tmpFile( - "/project/children/pom_different_group_skip_deployment_prop.xml"); + File originalPom = pom("/projects/project/children", "pom_different_group_skip_deployment_prop.xml"); + File pomInTemp = tmpFile("/project/children/pom_different_group_skip_deployment_prop.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth", "org.springframework.cloud"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("1.2.2.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("1.5.8.RELEASE"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("1.2.2.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("1.5.8.RELEASE"); // the rest is the same - BDDAssertions.then(overriddenPomModel.getProperties()) - .containsEntry("spring-cloud-sleuth.version", "0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getProperties()).containsEntry("spring-cloud-sleuth.version", + "0.0.3.BUILD-SNAPSHOT"); } @Test public void should_update_everything_when_group_ids_dont_match_and_there_is_skip_in_deployment_plugin() throws Exception { - File originalPom = pom("/projects/project/children", - "pom_different_group_skip_deployment_plugin.xml"); - File pomInTemp = tmpFile( - "/project/children/pom_different_group_skip_deployment_plugin.xml"); + File originalPom = pom("/projects/project/children", "pom_different_group_skip_deployment_plugin.xml"); + File pomInTemp = tmpFile("/project/children/pom_different_group_skip_deployment_plugin.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth", "org.springframework.cloud"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("1.2.2.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("1.5.8.RELEASE"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("1.2.2.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("1.5.8.RELEASE"); // the rest is the same - BDDAssertions.then(overriddenPomModel.getProperties()) - .containsEntry("spring-cloud-sleuth.version", "0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getProperties()).containsEntry("spring-cloud-sleuth.version", + "0.0.3.BUILD-SNAPSHOT"); } @Test public void should_update_everything_when_group_ids_dont_match_and_there_is_skip_in_deployment_plugin_management() throws Exception { - File originalPom = pom("/projects/project/children", - "pom_different_group_skip_deployment_plugin_mngmnt.xml"); - File pomInTemp = tmpFile( - "/project/children/pom_different_group_skip_deployment_plugin_mngmnt.xml"); + File originalPom = pom("/projects/project/children", "pom_different_group_skip_deployment_plugin_mngmnt.xml"); + File pomInTemp = tmpFile("/project/children/pom_different_group_skip_deployment_plugin_mngmnt.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth", "org.springframework.cloud"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("1.2.2.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("1.5.8.RELEASE"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("1.2.2.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("1.5.8.RELEASE"); // the rest is the same - BDDAssertions.then(overriddenPomModel.getProperties()) - .containsEntry("spring-cloud-sleuth.version", "0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getProperties()).containsEntry("spring-cloud-sleuth.version", + "0.0.3.BUILD-SNAPSHOT"); } @Test - public void should_update_boot_parent_even_if_the_project_group_doesnt_match() - throws Exception { - File originalPom = pom("/projects/project/children", - "pom_case_from_contract.xml"); + public void should_update_boot_parent_even_if_the_project_group_doesnt_match() throws Exception { + File originalPom = pom("/projects/project/children", "pom_case_from_contract.xml"); File pomInTemp = tmpFile("/project/children/pom_case_from_contract.xml"); - ModelWrapper rootPom = model("spring-cloud-contract", - "org.springframework.cloud"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper rootPom = model("spring-cloud-contract", "org.springframework.cloud"); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("0.0.2.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("0.0.2.BUILD-SNAPSHOT"); } @Test - public void should_update_the_child_pom_if_parent_is_matched_via_sc_dependencies_parent() - throws Exception { + public void should_update_the_child_pom_if_parent_is_matched_via_sc_dependencies_parent() throws Exception { File originalPom = pom("/projects/project/children", "pom_matching_parent.xml"); File pomInTemp = tmpFile("/project/children/pom_matching_parent.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); // the rest is the same BDDAssertions.then(overriddenPomModel.getProperties()) .containsEntry("spring-cloud-foo.version", "1.3.1.BUILD-SNAPSHOT") @@ -394,38 +319,30 @@ public class PomUpdaterTests { @Test public void should_update_the_child_pom_if_properties_are_matched() throws Exception { - File originalPom = pom("/projects/project/children", - "pom_matching_properties.xml"); + File originalPom = pom("/projects/project/children", "pom_matching_properties.xml"); File pomInTemp = tmpFile("/project/children/pom_matching_properties.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("0.0.3.BUILD-SNAPSHOT"); BDDAssertions.then(overriddenPomModel.getProperties()) .containsEntry("spring-cloud-sleuth.version", "0.0.3.BUILD-SNAPSHOT") .containsEntry("spring-cloud-vault.version", "0.0.4.BUILD-SNAPSHOT"); } @Test - public void should_override_a_pom_when_there_was_a_change_in_the_model() - throws Exception { - File beforeProcessing = pom("/projects/project/children", - "pom_matching_properties.xml"); + public void should_override_a_pom_when_there_was_a_change_in_the_model() throws Exception { + File beforeProcessing = pom("/projects/project/children", "pom_matching_properties.xml"); File afterProcessing = tmpFile("/project/children/pom_matching_properties.xml"); - ModelWrapper model = this.pomUpdater.updateModel(model("spring-cloud-sleuth"), - afterProcessing, this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(model("spring-cloud-sleuth"), afterProcessing, + this.versionsFromBom); - File processedPom = this.pomUpdater.overwritePomIfDirty(model, - VersionsFromBom.EMPTY_VERSION, afterProcessing); + File processedPom = this.pomUpdater.overwritePomIfDirty(model, VersionsFromBom.EMPTY_VERSION, afterProcessing); String processedPomText = asString(processedPom); String beforeProcessingText = asString(beforeProcessing); @@ -433,51 +350,39 @@ public class PomUpdaterTests { } @Test - public void should_not_override_a_pom_when_there_was_no_change_in_the_model() - throws Exception { + public void should_not_override_a_pom_when_there_was_no_change_in_the_model() throws Exception { File beforeProcessing = pom("/projects/project/"); File afterProcessing = tmpFile("/project/pom.xml"); - ModelWrapper model = this.pomUpdater.updateModel(model("foo"), afterProcessing, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(model("foo"), afterProcessing, this.versionsFromBom); - File processedPom = this.pomUpdater.overwritePomIfDirty(model, - VersionsFromBom.EMPTY_VERSION, afterProcessing); + File processedPom = this.pomUpdater.overwritePomIfDirty(model, VersionsFromBom.EMPTY_VERSION, afterProcessing); BDDAssertions.then(asString(processedPom)).isEqualTo(asString(beforeProcessing)); } @Test - public void should_update_the_model_when_root_project_has_parent_suffix() - throws Exception { + public void should_update_the_model_when_root_project_has_parent_suffix() throws Exception { File originalPom = pom("/projects/spring-cloud-contract"); File pomInTemp = tmpFile("/spring-cloud-contract/pom.xml"); ModelWrapper rootPom = model("spring-cloud-contract-parent"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isNotEqualTo(asString(originalPom)); Model overriddenPomModel = PomReader.readPom(storedPom); - BDDAssertions.then(overriddenPomModel.getVersion()) - .isEqualTo("0.0.2.BUILD-SNAPSHOT"); - BDDAssertions.then(overriddenPomModel.getParent().getVersion()) - .isEqualTo("0.0.2"); + BDDAssertions.then(overriddenPomModel.getVersion()).isEqualTo("0.0.2.BUILD-SNAPSHOT"); + BDDAssertions.then(overriddenPomModel.getParent().getVersion()).isEqualTo("0.0.2"); } @Test - public void should_not_update_the_model_when_project_uses_same_version_for_artifact() - throws Exception { - File originalPom = pom("/projects/project/", - "pom_matching_artifact_same_version.xml"); + public void should_not_update_the_model_when_project_uses_same_version_for_artifact() throws Exception { + File originalPom = pom("/projects/project/", "pom_matching_artifact_same_version.xml"); File pomInTemp = tmpFile("/project/pom_matching_artifact_same_version.xml"); ModelWrapper rootPom = model("spring-cloud-sleuth"); - ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, - this.versionsFromBom); + ModelWrapper model = this.pomUpdater.updateModel(rootPom, pomInTemp, this.versionsFromBom); - File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, - pomInTemp); + File storedPom = this.pomUpdater.overwritePomIfDirty(model, this.versionsFromBom, pomInTemp); BDDAssertions.then(asString(storedPom)).isEqualTo(asString(originalPom)); } @@ -518,8 +423,7 @@ public class PomUpdaterTests { } private File pom(String relativePath, String pomName) throws URISyntaxException { - return new File(new File(GitRepoTests.class.getResource(relativePath).toURI()), - pomName); + return new File(new File(GitRepoTests.class.getResource(relativePath).toURI()), pomName); } private String asString(File file) throws IOException { diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectPomUpdaterTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectPomUpdaterTests.java index b0ee3925..dd6bca53 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectPomUpdaterTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectPomUpdaterTests.java @@ -36,13 +36,12 @@ public class ProjectPomUpdaterTests { public void should_skip_any_steps_if_there_is_no_pom_xml() { ReleaserProperties properties = SpringCloudReleaserProperties.get(); ProjectGitHandler handler = BDDMockito.mock(ProjectGitHandler.class); - ProjectPomUpdater updater = new ProjectPomUpdater(properties, - Collections.emptyList()); + ProjectPomUpdater updater = new ProjectPomUpdater(properties, Collections.emptyList()); updater.updateProjectFromReleaseTrain(new File("target"), new Projects(), new ProjectVersion("foo", "1.0.0.RELEASE"), false); - BDDMockito.then(handler).shouldHaveZeroInteractions(); + BDDMockito.then(handler).shouldHaveNoInteractions(); } } diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectVersionTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectVersionTests.java index 92fd5f28..f4e2cb1e 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectVersionTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectVersionTests.java @@ -42,10 +42,8 @@ public class ProjectVersionTests { @Before public void setup() throws URISyntaxException { - URI scRelease = GitRepoTests.class.getResource("/projects/spring-cloud-release") - .toURI(); - URI scContract = GitRepoTests.class.getResource("/projects/spring-cloud-contract") - .toURI(); + URI scRelease = GitRepoTests.class.getResource("/projects/spring-cloud-release").toURI(); + URI scContract = GitRepoTests.class.getResource("/projects/spring-cloud-contract").toURI(); this.springCloudReleaseProject = new File(scRelease.getPath(), "pom.xml"); this.springCloudContract = new File(scContract.getPath(), "pom.xml"); } @@ -60,8 +58,7 @@ public class ProjectVersionTests { @Test public void should_build_version_from_file() { - ProjectVersion projectVersion = new ProjectVersion( - this.springCloudReleaseProject); + ProjectVersion projectVersion = new ProjectVersion(this.springCloudReleaseProject); then(projectVersion.version).isEqualTo("Dalston.BUILD-SNAPSHOT"); then(projectVersion.projectName).isEqualTo("spring-cloud-starter-build"); @@ -86,8 +83,8 @@ public class ProjectVersionTests { public void should_throw_exception_if_version_is_not_long_enough() { String version = "1"; - thenThrownBy(() -> projectVersion(version).bumpedVersion()) - .isInstanceOf(IllegalStateException.class).hasMessageContaining( + thenThrownBy(() -> projectVersion(version).bumpedVersion()).isInstanceOf(IllegalStateException.class) + .hasMessageContaining( "Version [1] is invalid. Should be of format [1.2.3.A] / [1.2.3-A] or [A.B] / [A-B]"); } @@ -143,8 +140,8 @@ public class ProjectVersionTests { public void should_throw_exception_when_trying_to_get_major_from_invalid_version() { String version = "1"; - thenThrownBy(() -> projectVersion(version).major()) - .isInstanceOf(IllegalStateException.class).hasMessageContaining( + thenThrownBy(() -> projectVersion(version).major()).isInstanceOf(IllegalStateException.class) + .hasMessageContaining( "Version [1] is invalid. Should be of format [1.2.3.A] / [1.2.3-A] or [A.B] / [A-B]"); } @@ -163,88 +160,70 @@ public class ProjectVersionTests { @Test public void should_not_bump_version_by_patch_version_when_non_ga_or_sr() { - then(projectVersion("1.0.1-SNAPSHOT").postReleaseSnapshotVersion()) - .isEqualTo("1.0.1-SNAPSHOT"); - then(projectVersion("1.0.1-M1").postReleaseSnapshotVersion()) - .isEqualTo("1.0.1-SNAPSHOT"); - then(projectVersion("1.0.1-RC1").postReleaseSnapshotVersion()) - .isEqualTo("1.0.1-SNAPSHOT"); - then(projectVersion("Finchley-SR1").postReleaseSnapshotVersion()) - .isEqualTo("Finchley-SNAPSHOT"); + then(projectVersion("1.0.1-SNAPSHOT").postReleaseSnapshotVersion()).isEqualTo("1.0.1-SNAPSHOT"); + then(projectVersion("1.0.1-M1").postReleaseSnapshotVersion()).isEqualTo("1.0.1-SNAPSHOT"); + then(projectVersion("1.0.1-RC1").postReleaseSnapshotVersion()).isEqualTo("1.0.1-SNAPSHOT"); + then(projectVersion("Finchley-SR1").postReleaseSnapshotVersion()).isEqualTo("Finchley-SNAPSHOT"); } @Test public void should_not_bump_version_by_patch_version_when_non_ga_or_sr_with_hyphen() { - then(projectVersion("1.0.1-SNAPSHOT").postReleaseSnapshotVersion()) - .isEqualTo("1.0.1-SNAPSHOT"); - then(projectVersion("1.0.1-M1").postReleaseSnapshotVersion()) - .isEqualTo("1.0.1-SNAPSHOT"); - then(projectVersion("1.0.1-RC1").postReleaseSnapshotVersion()) - .isEqualTo("1.0.1-SNAPSHOT"); - then(projectVersion("Finchley-SR1").postReleaseSnapshotVersion()) - .isEqualTo("Finchley-SNAPSHOT"); + then(projectVersion("1.0.1-SNAPSHOT").postReleaseSnapshotVersion()).isEqualTo("1.0.1-SNAPSHOT"); + then(projectVersion("1.0.1-M1").postReleaseSnapshotVersion()).isEqualTo("1.0.1-SNAPSHOT"); + then(projectVersion("1.0.1-RC1").postReleaseSnapshotVersion()).isEqualTo("1.0.1-SNAPSHOT"); + then(projectVersion("Finchley-SR1").postReleaseSnapshotVersion()).isEqualTo("Finchley-SNAPSHOT"); } @Test public void should_bump_version_by_patch_version_when_bumping_snapshots_for_ga() { - then(projectVersion("1.0.1-RELEASE").postReleaseSnapshotVersion()) - .isEqualTo("1.0.2-SNAPSHOT"); + then(projectVersion("1.0.1-RELEASE").postReleaseSnapshotVersion()).isEqualTo("1.0.2-SNAPSHOT"); } @Test public void should_return_the_previous_version_for_release_train_version_when_bumping_snapshots() { String version = "Edgware-SNAPSHOT"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("Edgware-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("Edgware-SNAPSHOT"); } @Test public void should_return_the_previous_version_for_hyphen_release_train_version_when_bumping_snapshots() { String version = "Edgware-SNAPSHOT"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("Edgware-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("Edgware-SNAPSHOT"); } @Test public void should_bump_version_by_patch_version_when_bumping_releases() { String version = "1.0.1-RELEASE"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("1.0.2-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("1.0.2-SNAPSHOT"); } @Test public void should_bump_version_by_patch_version_when_bumping_releases_with_hyphen() { String version = "1.0.1-RELEASE"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("1.0.2-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("1.0.2-SNAPSHOT"); version = "3.1.0"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("3.1.1-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("3.1.1-SNAPSHOT"); version = "3.0.0"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("3.0.1-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("3.0.1-SNAPSHOT"); version = "2.0.0"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("2.0.1-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("2.0.1-SNAPSHOT"); version = "3.0.1"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("3.0.2-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("3.0.2-SNAPSHOT"); } @Test public void should_return_the_previous_version_for_release_train_version_when_bumping_releases() { String version = "Edgware-RELEASE"; - then(projectVersion(version).postReleaseSnapshotVersion()) - .isEqualTo("Edgware-SNAPSHOT"); + then(projectVersion(version).postReleaseSnapshotVersion()).isEqualTo("Edgware-SNAPSHOT"); } @Test @@ -407,8 +386,7 @@ public class ProjectVersionTests { String thisVersion = "1.3.2-SR3"; String thatVersion = "1.3.1-SR3"; - then(projectVersion(thisVersion).compareTo(projectVersion(thatVersion))) - .isPositive(); + then(projectVersion(thisVersion).compareTo(projectVersion(thatVersion))).isPositive(); } @Test @@ -416,117 +394,72 @@ public class ProjectVersionTests { String thisVersion = "1.3.0-RC3"; String thatVersion = "1.3.1-RC3"; - then(projectVersion(thisVersion).compareTo(projectVersion(thatVersion))) - .isNegative(); + then(projectVersion(thisVersion).compareTo(projectVersion(thatVersion))).isNegative(); } @Test public void should_compare_builds_in_terms_of_maturity_for_projects() { String thisVersion = "1.3.2.RELEASE"; - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.1-SNAPSHOT"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.1-M1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.1-RC1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.1.RELEASE"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.3.RELEASE"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.3-SNAPSHOT"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.3-M1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.3-RC1"))) - .isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.1-SNAPSHOT"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.1-M1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.1-RC1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.1.RELEASE"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.3.RELEASE"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.3-SNAPSHOT"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.3-M1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.3.3-RC1"))).isTrue(); } @Test public void should_compare_builds_in_terms_of_maturity_for_trains() { String thisVersion = "Hoxton-SR1"; - then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-SNAPSHOT"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-M1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-RC1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton.RELEASE"))) - .isTrue(); - then(projectVersion(thisVersion) - .isMoreMature(projectVersion("Iexample-SNAPSHOT"))).isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-M1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-RC1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample.RELEASE"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-SR1"))) - .isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-SNAPSHOT"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-M1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-RC1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton.RELEASE"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-SNAPSHOT"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-M1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-RC1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample.RELEASE"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-SR1"))).isFalse(); thisVersion = "Hoxton-SNAPSHOT"; - then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-SNAPSHOT"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-M1"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-RC1"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton.RELEASE"))) - .isFalse(); - then(projectVersion(thisVersion) - .isMoreMature(projectVersion("Iexample-SNAPSHOT"))).isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-M1"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-RC1"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample.RELEASE"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-SR1"))) - .isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-SNAPSHOT"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-M1"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton-RC1"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Hoxton.RELEASE"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-SNAPSHOT"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-M1"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-RC1"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample.RELEASE"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("Iexample-SR1"))).isFalse(); thisVersion = "1.0.1.RELEASE"; - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-SNAPSHOT"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-M1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-RC1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1.RELEASE"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-SNAPSHOT"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-M1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-RC1"))) - .isTrue(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2.RELEASE"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-SR1"))) - .isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-SNAPSHOT"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-M1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-RC1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1.RELEASE"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-SNAPSHOT"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-M1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-RC1"))).isTrue(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2.RELEASE"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-SR1"))).isFalse(); thisVersion = "1.0.1-SNAPSHOT"; - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-SNAPSHOT"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-M1"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-RC1"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1.RELEASE"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-SNAPSHOT"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-M1"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-RC1"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2.RELEASE"))) - .isFalse(); - then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-SR1"))) - .isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-SNAPSHOT"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-M1"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1-RC1"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.1.RELEASE"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-SNAPSHOT"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-M1"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-RC1"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2.RELEASE"))).isFalse(); + then(projectVersion(thisVersion).isMoreMature(projectVersion("1.0.2-SR1"))).isFalse(); } @Test @@ -711,31 +644,26 @@ public class ProjectVersionTests { @Test public void should_return_snapshot_unacceptable_patterns_for_a_milestone_or_rc_version() { - List milestonePatterns = projectVersion("1.0.0-M1") - .unacceptableVersionPatterns(); + List milestonePatterns = projectVersion("1.0.0-M1").unacceptableVersionPatterns(); then(milestonePatterns).isNotEmpty(); then(milestonePatterns.get(0).pattern()).contains("SNAPSHOT"); - List rcPatterns = projectVersion("1.0.0-RC1") - .unacceptableVersionPatterns(); + List rcPatterns = projectVersion("1.0.0-RC1").unacceptableVersionPatterns(); then(rcPatterns).isNotEmpty(); then(rcPatterns.get(0).pattern()).contains("SNAPSHOT"); - List milestonePatternsWithDash = projectVersion("1.0.0-M1") - .unacceptableVersionPatterns(); + List milestonePatternsWithDash = projectVersion("1.0.0-M1").unacceptableVersionPatterns(); then(milestonePatternsWithDash).isNotEmpty(); then(milestonePatternsWithDash.get(0).pattern()).contains("SNAPSHOT"); - List rcPatternsWithDash = projectVersion("1.0.0-RC1") - .unacceptableVersionPatterns(); + List rcPatternsWithDash = projectVersion("1.0.0-RC1").unacceptableVersionPatterns(); then(rcPatternsWithDash).isNotEmpty(); then(rcPatternsWithDash.get(0).pattern()).contains("SNAPSHOT"); } @Test public void should_return_snapshot_milestone_rc_unacceptable_patterns_for_a_ga_or_sr_version() { - List gaPatterns = projectVersion("1.0.0.RELEASE") - .unacceptableVersionPatterns(); + List gaPatterns = projectVersion("1.0.0.RELEASE").unacceptableVersionPatterns(); thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(gaPatterns); gaPatterns = projectVersion("1.0.0").unacceptableVersionPatterns(); @@ -744,24 +672,19 @@ public class ProjectVersionTests { gaPatterns = projectVersion("1.0.0-RELEASE").unacceptableVersionPatterns(); thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(gaPatterns); - List srPatterns = projectVersion("1.0.0-SR1") - .unacceptableVersionPatterns(); + List srPatterns = projectVersion("1.0.0-SR1").unacceptableVersionPatterns(); thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(srPatterns); - List srPatternsWithDash = projectVersion("1.0.0-SR1") - .unacceptableVersionPatterns(); + List srPatternsWithDash = projectVersion("1.0.0-SR1").unacceptableVersionPatterns(); thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(srPatternsWithDash); - List unknownTypeOfVersion = projectVersion("1.0.0.SOMETHING") - .unacceptableVersionPatterns(); - thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent( - unknownTypeOfVersion); + List unknownTypeOfVersion = projectVersion("1.0.0.SOMETHING").unacceptableVersionPatterns(); + thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(unknownTypeOfVersion); } @Test public void should_return_v100RELEASE_when_tag_name_is_requested() { - then(projectVersion("1.0.0.RELEASE").releaseTagName()) - .isEqualTo("v1.0.0.RELEASE"); + then(projectVersion("1.0.0.RELEASE").releaseTagName()).isEqualTo("v1.0.0.RELEASE"); } @Test @@ -771,93 +694,77 @@ public class ProjectVersionTests { @Test public void should_return_decremented_patch_when_patch_above_zero() { - then(projectVersion("1.2.3.RELEASE").computePreviousPatchTag("v", "RELEASE")) - .contains("v1.2.2.RELEASE"); + then(projectVersion("1.2.3.RELEASE").computePreviousPatchTag("v", "RELEASE")).contains("v1.2.2.RELEASE"); } @Test public void should_use_current_suffix_if_no_forced_suffix() { - then(projectVersion("1.2.3.WHATEVER").computePreviousPatchTag("v", "")) - .contains("v1.2.2.WHATEVER"); + then(projectVersion("1.2.3.WHATEVER").computePreviousPatchTag("v", "")).contains("v1.2.2.WHATEVER"); } @Test public void should_replace_suffix() { - then(projectVersion("1.2.3.WHATEVER").computePreviousPatchTag("v", "RELEASE")) - .contains("v1.2.2.RELEASE"); + then(projectVersion("1.2.3.WHATEVER").computePreviousPatchTag("v", "RELEASE")).contains("v1.2.2.RELEASE"); } @Test public void should_return_empty_when_patch_at_zero() { - then(projectVersion("1.2.0.WHATEVER").computePreviousPatchTag("v", "RELEASE")) - .isEmpty(); + then(projectVersion("1.2.0.WHATEVER").computePreviousPatchTag("v", "RELEASE")).isEmpty(); } @Test public void should_return_minor_pattern_when_minor_above_zero() { - then(projectVersion("1.2.0.WHATEVER") - .computePreviousMinorTagPattern("v", "RELEASE").get().pattern()) - .isEqualTo("\\Qv1.1.\\E\\d+\\Q.RELEASE\\E"); + then(projectVersion("1.2.0.WHATEVER").computePreviousMinorTagPattern("v", "RELEASE").get().pattern()) + .isEqualTo("\\Qv1.1.\\E\\d+\\Q.RELEASE\\E"); } @Test public void should_compute_minor_pattern_with_current_suffix_if_no_forced_suffix() { - then(projectVersion("1.2.0.WHATEVER").computePreviousMinorTagPattern("v", "") - .get().pattern()).isEqualTo("\\Qv1.1.\\E\\d+\\Q.WHATEVER\\E"); + then(projectVersion("1.2.0.WHATEVER").computePreviousMinorTagPattern("v", "").get().pattern()) + .isEqualTo("\\Qv1.1.\\E\\d+\\Q.WHATEVER\\E"); } @Test public void should_return_empty_minor_pattern_when_minor_zero() { - then(projectVersion("1.0.0.WHATEVER").computePreviousMinorTagPattern("v", - "RELEASE")).isEmpty(); + then(projectVersion("1.0.0.WHATEVER").computePreviousMinorTagPattern("v", "RELEASE")).isEmpty(); } @Test public void should_return_major_pattern_when_major_above_zero() { - then(projectVersion("1.0.0.WHATEVER") - .computePreviousMajorTagPattern("v", "RELEASE").pattern()) - .isEqualTo("\\Qv0.\\E\\d+\\Q.\\E\\d+\\Q.RELEASE\\E"); + then(projectVersion("1.0.0.WHATEVER").computePreviousMajorTagPattern("v", "RELEASE").pattern()) + .isEqualTo("\\Qv0.\\E\\d+\\Q.\\E\\d+\\Q.RELEASE\\E"); } @Test public void should_compute_major_pattern_with_current_suffix_if_no_forced_suffix() { - then(projectVersion("1.0.0.WHATEVER").computePreviousMajorTagPattern("v", "") - .pattern()).isEqualTo("\\Qv0.\\E\\d+\\Q.\\E\\d+\\Q.WHATEVER\\E"); + then(projectVersion("1.0.0.WHATEVER").computePreviousMajorTagPattern("v", "").pattern()) + .isEqualTo("\\Qv0.\\E\\d+\\Q.\\E\\d+\\Q.WHATEVER\\E"); } @Test public void should_throw_major_pattern_when_major_zero() { assertThatIllegalArgumentException() - .isThrownBy(() -> projectVersion("0.0.1.WHATEVER") - .computePreviousMajorTagPattern("v", "RELEASE")); + .isThrownBy(() -> projectVersion("0.0.1.WHATEVER").computePreviousMajorTagPattern("v", "RELEASE")); } - private void thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent( - List unknownTypeOfVersion) { + private void thenPatternsForSnapshotMilestoneAndReleaseCandidateArePresent(List unknownTypeOfVersion) { then(unknownTypeOfVersion).isNotEmpty(); then(unknownTypeOfVersion.get(0).pattern()).contains("SNAPSHOT"); then(unknownTypeOfVersion.get(1).pattern()).contains("M[0-9]"); then(unknownTypeOfVersion.get(2).pattern()).contains("RC"); - then(unknownTypeOfVersion.get(0).matcher("SomeName-SNAPSHOT").lookingAt()) - .isTrue(); - then(unknownTypeOfVersion.get(0).matcher("SomeName.BUILD-SNAPSHOT").lookingAt()) - .isTrue(); - then(unknownTypeOfVersion.get(0) - .matcher("\t\t1.19.2-SNAPSHOT\n").lookingAt()) - .isTrue(); + then(unknownTypeOfVersion.get(0).matcher("SomeName-SNAPSHOT").lookingAt()).isTrue(); + then(unknownTypeOfVersion.get(0).matcher("SomeName.BUILD-SNAPSHOT").lookingAt()).isTrue(); + then(unknownTypeOfVersion.get(0).matcher("\t\t1.19.2-SNAPSHOT\n").lookingAt()).isTrue(); then(unknownTypeOfVersion.get(1).matcher("SomeName-M3").lookingAt()).isTrue(); then(unknownTypeOfVersion.get(1).matcher("SomeName.M3").lookingAt()).isTrue(); - then(unknownTypeOfVersion.get(1) - .matcher("\t\t1.19.2-M2\n").lookingAt()) - .isTrue(); + then(unknownTypeOfVersion.get(1).matcher("\t\t1.19.2-M2\n").lookingAt()) + .isTrue(); then(unknownTypeOfVersion.get(2).matcher("SomeName-RC3").lookingAt()).isTrue(); then(unknownTypeOfVersion.get(2).matcher("SomeName.RC3").lookingAt()).isTrue(); - then(unknownTypeOfVersion.get(2) - .matcher("1.19.2-RC1").lookingAt()) - .isTrue(); + then(unknownTypeOfVersion.get(2).matcher("1.19.2-RC1").lookingAt()).isTrue(); } private ProjectVersion projectVersion(String version) { diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectsTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectsTests.java index 0b2441fd..31ce41be 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectsTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/ProjectsTests.java @@ -71,8 +71,7 @@ public class ProjectsTests { projectVersions.add(new ProjectVersion("spring-boot-starter-build", "1.0.0")); Projects projects = new Projects(projectVersions); - then(projects.forNameStartingWith("spring-boot").get(0).version) - .isEqualTo("1.0.0"); + then(projects.forNameStartingWith("spring-boot").get(0).version).isEqualTo("1.0.0"); } @Test @@ -82,25 +81,18 @@ public class ProjectsTests { projectVersions.add(build); ProjectVersion boot = new ProjectVersion("spring-boot-starter", "2.0.0-RELEASE"); projectVersions.add(boot); - ProjectVersion bootDeps = new ProjectVersion("spring-boot-dependencies", - "2.0.0.RELEASE"); + ProjectVersion bootDeps = new ProjectVersion("spring-boot-dependencies", "2.0.0.RELEASE"); projectVersions.add(bootDeps); - ProjectVersion original = new ProjectVersion("spring-cloud-starter-foo", - "3.0.0.BUILD-SNAPSHOT"); + ProjectVersion original = new ProjectVersion("spring-cloud-starter-foo", "3.0.0.BUILD-SNAPSHOT"); projectVersions.add(original); Projects projects = new Projects(projectVersions); - Projects forRollback = Projects.forRollback(SpringCloudReleaserProperties.get(), - projects); + Projects forRollback = Projects.forRollback(SpringCloudReleaserProperties.get(), projects); - then(forRollback.forName("spring-cloud-build").version) - .isEqualTo("1.0.1-SNAPSHOT"); - then(forRollback.forName("spring-boot-starter").version) - .isEqualTo("2.0.0-RELEASE"); - then(forRollback.forName("spring-boot-dependencies").version) - .isEqualTo("2.0.0.RELEASE"); - then(forRollback.forName("spring-cloud-starter-foo").version) - .isEqualTo("3.0.0.BUILD-SNAPSHOT"); + then(forRollback.forName("spring-cloud-build").version).isEqualTo("1.0.1-SNAPSHOT"); + then(forRollback.forName("spring-boot-starter").version).isEqualTo("2.0.0-RELEASE"); + then(forRollback.forName("spring-boot-dependencies").version).isEqualTo("2.0.0.RELEASE"); + then(forRollback.forName("spring-cloud-starter-foo").version).isEqualTo("3.0.0.BUILD-SNAPSHOT"); } @Test @@ -149,8 +141,7 @@ public class ProjectsTests { @Test public void should_return_projects_with_bumped_versions() { Set projectVersions = new HashSet<>(); - projectVersions - .add(new ProjectVersion("spring-boot-dependencies", "2.0.0.RELEASE")); + projectVersions.add(new ProjectVersion("spring-boot-dependencies", "2.0.0.RELEASE")); projectVersions.add(new ProjectVersion("spring-boot-starter", "2.0.0.RELEASE")); projectVersions.add(new ProjectVersion("foo", "1.0.0.RELEASE")); projectVersions.add(new ProjectVersion("bar", "1.0.1.M1")); @@ -160,11 +151,9 @@ public class ProjectsTests { projectVersions.add(new ProjectVersion("foo4", "Finchley.SR4")); Projects projects = new Projects(projectVersions); - Projects bumped = projects - .postReleaseSnapshotVersion(Collections.singletonList("spring-boot")); + Projects bumped = projects.postReleaseSnapshotVersion(Collections.singletonList("spring-boot")); - then(bumped.forName("spring-boot-dependencies").version) - .isEqualTo("2.0.0.RELEASE"); + then(bumped.forName("spring-boot-dependencies").version).isEqualTo("2.0.0.RELEASE"); then(bumped.forName("spring-boot-starter").version).isEqualTo("2.0.0.RELEASE"); then(bumped.forName("foo").version).isEqualTo("1.0.1.SNAPSHOT"); then(bumped.forName("bar").version).isEqualTo("1.0.1.SNAPSHOT"); @@ -180,9 +169,8 @@ public class ProjectsTests { projectVersions.add(new ProjectVersion("foo", "1.0.0")); Projects projects = new Projects(projectVersions); - thenThrownBy(() -> projects.forFile(this.springCloudReleasePom)) - .isInstanceOf(IllegalStateException.class).hasMessageContaining( - "Project with name [spring-cloud-starter-build] is not present"); + thenThrownBy(() -> projects.forFile(this.springCloudReleasePom)).isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Project with name [spring-cloud-starter-build] is not present"); } @Test @@ -191,9 +179,8 @@ public class ProjectsTests { projectVersions.add(new ProjectVersion("foo", "1.0.0")); Projects projects = new Projects(projectVersions); - thenThrownBy(() -> projects.forName("spring-cloud-starter-build")) - .isInstanceOf(IllegalStateException.class).hasMessageContaining( - "Project with name [spring-cloud-starter-build] is not present"); + thenThrownBy(() -> projects.forName("spring-cloud-starter-build")).isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Project with name [spring-cloud-starter-build] is not present"); } @Test @@ -224,9 +211,8 @@ public class ProjectsTests { projectVersions.add(new ProjectVersion("foo", "1.0.0")); Projects projects = new Projects(projectVersions); - thenThrownBy(() -> projects.releaseTrain(properties)) - .isInstanceOf(IllegalStateException.class).hasMessageContaining( - "don't contain any of the following release train names"); + thenThrownBy(() -> projects.releaseTrain(properties)).isInstanceOf(IllegalStateException.class) + .hasMessageContaining("don't contain any of the following release train names"); } private File file(String relativePath) { diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/PropertyStorerTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/PropertyStorerTests.java index 66385b55..6940e05e 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/PropertyStorerTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/PropertyStorerTests.java @@ -51,8 +51,7 @@ public class PropertyStorerTests { } private String containsWarnMsgAboutEmptyVersion() { - return BDDMockito - .argThat(argument -> argument.contains("is empty. Will not set it")); + return BDDMockito.argThat(argument -> argument.contains("is empty. Will not set it")); } } diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/PropertyVersionChangerTests.java b/releaser-core/src/test/java/releaser/internal/buildsystem/PropertyVersionChangerTests.java index 7937e35c..3407358a 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/PropertyVersionChangerTests.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/PropertyVersionChangerTests.java @@ -44,49 +44,44 @@ public class PropertyVersionChangerTests { @Test public void should_set_version_when_project_matches_property_name() throws Exception { - PropertyVersionChanger changer = new PropertyVersionChanger(model(), versions(), - null, null, this.propertyStorer); + PropertyVersionChanger changer = new PropertyVersionChanger(model(), versions(), null, null, + this.propertyStorer); changer.apply(null); - then(this.propertyStorer).should().setPropertyVersionIfApplicable( - project("spring-cloud-sleuth", "1.2.0.BUILD-SNAPSHOT")); + then(this.propertyStorer).should() + .setPropertyVersionIfApplicable(project("spring-cloud-sleuth", "1.2.0.BUILD-SNAPSHOT")); } @Test - public void should_not_set_version_when_project_doesnt_match_property_name() - throws Exception { - PropertyVersionChanger changer = new PropertyVersionChanger(nonMatchingModel(), - versions(), null, null, this.propertyStorer); + public void should_not_set_version_when_project_doesnt_match_property_name() throws Exception { + PropertyVersionChanger changer = new PropertyVersionChanger(nonMatchingModel(), versions(), null, null, + this.propertyStorer); changer.apply(null); - then(this.propertyStorer).should(never()) - .setPropertyVersionIfApplicable(any(Project.class)); + then(this.propertyStorer).should(never()).setPropertyVersionIfApplicable(any(Project.class)); } @Test - public void should_not_set_version_when_project_matches_property_name_and_versions_are_the_same() - throws Exception { - PropertyVersionChanger changer = new PropertyVersionChanger(modelWithSameValues(), - versions(), null, null, this.propertyStorer); + public void should_not_set_version_when_project_matches_property_name_and_versions_are_the_same() throws Exception { + PropertyVersionChanger changer = new PropertyVersionChanger(modelWithSameValues(), versions(), null, null, + this.propertyStorer); changer.apply(null); - then(this.propertyStorer).should(never()) - .setPropertyVersionIfApplicable(any(Project.class)); + then(this.propertyStorer).should(never()).setPropertyVersionIfApplicable(any(Project.class)); } VersionsFromBom versions() { - return new VersionsFromBomBuilder().releaserProperties(new ReleaserProperties()) - .projects(allProjects()).retrieveFromBom(); + return new VersionsFromBomBuilder().releaserProperties(new ReleaserProperties()).projects(allProjects()) + .retrieveFromBom(); } @SuppressWarnings("unchecked") private Set allProjects() { - return new HashSet<>(Arrays.asList( - new Project[] { project("spring-cloud-aws", "1.2.0.BUILD-SNAPSHOT"), - project("spring-cloud-sleuth", "1.2.0.BUILD-SNAPSHOT") })); + return new HashSet<>(Arrays.asList(new Project[] { project("spring-cloud-aws", "1.2.0.BUILD-SNAPSHOT"), + project("spring-cloud-sleuth", "1.2.0.BUILD-SNAPSHOT") })); } Project project(String name, String value) { diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/TestUtils.java b/releaser-core/src/test/java/releaser/internal/buildsystem/TestUtils.java index 7636bd2e..46ba7b1f 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/TestUtils.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/TestUtils.java @@ -36,8 +36,7 @@ public final class TestUtils { prepareLocalRepo("target/test-classes/projects/", "spring-cloud-static"); } - private static void prepareLocalRepo(String buildDir, String repoPath) - throws IOException { + private static void prepareLocalRepo(String buildDir, String repoPath) throws IOException { File dotGit = new File(buildDir + repoPath + "/.git"); File git = new File(buildDir + repoPath + "/git"); if (git.exists()) { diff --git a/releaser-core/src/test/java/releaser/internal/buildsystem/VersionChangeAssertions.java b/releaser-core/src/test/java/releaser/internal/buildsystem/VersionChangeAssertions.java index b2541243..602b9dc1 100644 --- a/releaser-core/src/test/java/releaser/internal/buildsystem/VersionChangeAssertions.java +++ b/releaser-core/src/test/java/releaser/internal/buildsystem/VersionChangeAssertions.java @@ -54,12 +54,10 @@ class VersionChangeAssert extends AbstractAssert rows = Row.fromProjects(projects, true); @@ -50,8 +49,7 @@ public class RowTests { @Test public void should_convert_projects_to_rows_for_current_ga() { - Projects projects = new Projects( - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"), + Projects projects = new Projects(new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"), new ProjectVersion("sc-release", "2.0.1.RELEASE")); List rows = Row.fromProjects(projects, false); diff --git a/releaser-core/src/test/java/releaser/internal/docs/SpringCloudGhPagesParserTests.java b/releaser-core/src/test/java/releaser/internal/docs/SpringCloudGhPagesParserTests.java index 201580ee..d75e84b6 100644 --- a/releaser-core/src/test/java/releaser/internal/docs/SpringCloudGhPagesParserTests.java +++ b/releaser-core/src/test/java/releaser/internal/docs/SpringCloudGhPagesParserTests.java @@ -23,7 +23,7 @@ import org.assertj.core.api.BDDAssertions; import org.junit.Rule; import org.junit.Test; -import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.boot.test.system.OutputCaptureRule; /** * @author Marcin Grzejszczak @@ -31,74 +31,51 @@ import org.springframework.boot.test.rule.OutputCapture; public class SpringCloudGhPagesParserTests { @Rule - public OutputCapture capture = new OutputCapture(); + public OutputCaptureRule capture = new OutputCaptureRule(); - File rawHtml = new File(SpringCloudGhPagesParserTests.class - .getResource("/raw/spring-cloud-gh-pages-index.html").toURI()); + File rawHtml = new File( + SpringCloudGhPagesParserTests.class.getResource("/raw/spring-cloud-gh-pages-index.html").toURI()); - File wrongHtml = new File(SpringCloudGhPagesParserTests.class - .getResource("/raw/some-file.html").toURI()); + File wrongHtml = new File(SpringCloudGhPagesParserTests.class.getResource("/raw/some-file.html").toURI()); public SpringCloudGhPagesParserTests() throws URISyntaxException { } @Test public void should_parse_the_components_table() { - ReleaseTrainContents contents = new ReleaseTrainContentsParser() - .parseProjectPage(this.rawHtml); + ReleaseTrainContents contents = new ReleaseTrainContentsParser().parseProjectPage(this.rawHtml); BDDAssertions.then(contents).isNotNull(); - BDDAssertions.then(contents.title).isEqualTo( - new Title("Edgware.SR5", "Finchley.SR1", "Finchley.BUILD-SNAPSHOT")); + BDDAssertions.then(contents.title) + .isEqualTo(new Title("Edgware.SR5", "Finchley.SR1", "Finchley.BUILD-SNAPSHOT")); BDDAssertions.then(contents.rows).contains( - new Row("spring-cloud-aws", "1.2.3.RELEASE", "2.0.0.RELEASE", - "2.0.1.BUILD-SNAPSHOT"), - new Row("spring-cloud-bus", "1.3.3.RELEASE", "2.0.0.RELEASE", - "2.0.1.BUILD-SNAPSHOT"), - new Row("spring-cloud-cli", "1.4.1.RELEASE", "2.0.0.RELEASE", - "2.0.1.BUILD-SNAPSHOT"), - new Row("spring-cloud-commons", "1.3.5.RELEASE", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-contract", "1.2.6.RELEASE", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-config", "1.4.5.RELEASE", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-netflix", "1.4.6.RELEASE", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-security", "1.2.3.RELEASE", "2.0.0.RELEASE", - "2.0.1.BUILD-SNAPSHOT"), - new Row("spring-cloud-cloudfoundry", "1.1.2.RELEASE", "2.0.0.RELEASE", - "2.0.1.BUILD-SNAPSHOT"), - new Row("spring-cloud-consul", "1.3.5.RELEASE", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-sleuth", "1.3.5.RELEASE", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-stream", "Ditmars.SR4", "Elmhurst.SR1", - "Elmhurst.BUILD-SNAPSHOT"), - new Row("spring-cloud-zookeeper", "1.2.2.RELEASE", "2.0.0.RELEASE", - "2.0.1.BUILD-SNAPSHOT"), - new Row("spring-boot", "1.5.16.RELEASE", "2.0.4.RELEASE", - "2.0.4.BUILD-SNAPSHOT"), - new Row("spring-cloud-task", "1.2.3.RELEASE", "2.0.0.RELEASE", - "2.0.1.BUILD-SNAPSHOT"), - new Row("spring-cloud-vault", "1.1.2.RELEASE", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-gateway", "1.0.2.RELEASE", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-openfeign", "", "2.0.1.RELEASE", - "2.0.2.BUILD-SNAPSHOT"), - new Row("spring-cloud-function", "1.0.1.RELEASE", "1.0.0.RELEASE", - "1.0.1.BUILD-SNAPSHOT")); + new Row("spring-cloud-aws", "1.2.3.RELEASE", "2.0.0.RELEASE", "2.0.1.BUILD-SNAPSHOT"), + new Row("spring-cloud-bus", "1.3.3.RELEASE", "2.0.0.RELEASE", "2.0.1.BUILD-SNAPSHOT"), + new Row("spring-cloud-cli", "1.4.1.RELEASE", "2.0.0.RELEASE", "2.0.1.BUILD-SNAPSHOT"), + new Row("spring-cloud-commons", "1.3.5.RELEASE", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-contract", "1.2.6.RELEASE", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-config", "1.4.5.RELEASE", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-netflix", "1.4.6.RELEASE", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-security", "1.2.3.RELEASE", "2.0.0.RELEASE", "2.0.1.BUILD-SNAPSHOT"), + new Row("spring-cloud-cloudfoundry", "1.1.2.RELEASE", "2.0.0.RELEASE", "2.0.1.BUILD-SNAPSHOT"), + new Row("spring-cloud-consul", "1.3.5.RELEASE", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-sleuth", "1.3.5.RELEASE", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-stream", "Ditmars.SR4", "Elmhurst.SR1", "Elmhurst.BUILD-SNAPSHOT"), + new Row("spring-cloud-zookeeper", "1.2.2.RELEASE", "2.0.0.RELEASE", "2.0.1.BUILD-SNAPSHOT"), + new Row("spring-boot", "1.5.16.RELEASE", "2.0.4.RELEASE", "2.0.4.BUILD-SNAPSHOT"), + new Row("spring-cloud-task", "1.2.3.RELEASE", "2.0.0.RELEASE", "2.0.1.BUILD-SNAPSHOT"), + new Row("spring-cloud-vault", "1.1.2.RELEASE", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-gateway", "1.0.2.RELEASE", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-openfeign", "", "2.0.1.RELEASE", "2.0.2.BUILD-SNAPSHOT"), + new Row("spring-cloud-function", "1.0.1.RELEASE", "1.0.0.RELEASE", "1.0.1.BUILD-SNAPSHOT")); } @Test public void should_not_parse_the_components_table_when_markers_are_not_found() { - ReleaseTrainContents contents = new ReleaseTrainContentsParser() - .parseProjectPage(this.wrongHtml); + ReleaseTrainContents contents = new ReleaseTrainContentsParser().parseProjectPage(this.wrongHtml); BDDAssertions.then(contents).isNull(); - BDDAssertions.then(this.capture.toString()) - .contains("The page is missing the components table markers"); + BDDAssertions.then(this.capture.toString()).contains("The page is missing the components table markers"); } } diff --git a/releaser-core/src/test/java/releaser/internal/git/GitRepoTests.java b/releaser-core/src/test/java/releaser/internal/git/GitRepoTests.java index b8ca995c..0ca11af4 100644 --- a/releaser-core/src/test/java/releaser/internal/git/GitRepoTests.java +++ b/releaser-core/src/test/java/releaser/internal/git/GitRepoTests.java @@ -74,8 +74,8 @@ public class GitRepoTests { @Test public void should_throw_exception_when_there_is_no_repo() { - thenThrownBy(() -> this.gitRepo.cloneProject( - new URIish(GitRepoTests.class.getResource("/projects/").toURI().toURL()))) + thenThrownBy(() -> this.gitRepo + .cloneProject(new URIish(GitRepoTests.class.getResource("/projects/").toURI().toURL()))) .isInstanceOf(IllegalStateException.class) .hasMessageContaining("Exception occurred while cloning repo"); } @@ -97,8 +97,7 @@ public class GitRepoTests { File pom = new File(new File(this.tmpFolder, uri.getHumanishName()), "pom.xml"); then(pom).exists(); - then(Files.lines(pom.toPath()) - .anyMatch(s -> s.contains("Camden.SR3"))).isTrue(); + then(Files.lines(pom.toPath()).anyMatch(s -> s.contains("Camden.SR3"))).isTrue(); } @Test @@ -109,9 +108,7 @@ public class GitRepoTests { File pom = new File(new File(this.tmpFolder, uri.getHumanishName()), "pom.xml"); then(pom).exists(); - then(Files.lines(pom.toPath()) - .anyMatch(s -> s.contains("Camden.BUILD-SNAPSHOT"))) - .isTrue(); + then(Files.lines(pom.toPath()).anyMatch(s -> s.contains("Camden.BUILD-SNAPSHOT"))).isTrue(); } @Test @@ -131,8 +128,7 @@ public class GitRepoTests { } @Test - public void should_throw_an_exception_when_checking_out_nonexisting_branch() - throws IOException { + public void should_throw_an_exception_when_checking_out_nonexisting_branch() throws IOException { File project = new GitRepo(this.tmpFolder) .cloneProject(new URIish(this.springCloudReleaseProject.toURI().toURL())); try { @@ -190,14 +186,12 @@ public class GitRepoTests { private void tagIsPresent(Git git, String tag) throws GitAPIException { List refs = git.tagList().call(); System.out.println("All tags" + refs); - then(refs.stream().anyMatch(ref -> ref.getName().startsWith("refs/tags/" + tag))) - .isTrue(); + then(refs.stream().anyMatch(ref -> ref.getName().startsWith("refs/tags/" + tag))).isTrue(); } @Test public void should_push_changes_to_master_branch() throws Exception { - File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), - this.springCloudReleaseProject); + File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), this.springCloudReleaseProject); File project = new GitRepo(this.tmpFolder) .cloneProject(new URIish(this.springCloudReleaseProject.toURI().toURL())); GitTestUtils.setOriginOnProjectToTmp(origin, project); @@ -214,8 +208,7 @@ public class GitRepoTests { @Test public void should_push_changes_to_current_branch() throws Exception { - File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), - this.springCloudReleaseProject); + File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), this.springCloudReleaseProject); File project = new GitRepo(this.tmpFolder) .cloneProject(new URIish(this.springCloudReleaseProject.toURI().toURL())); GitTestUtils.setOriginOnProjectToTmp(origin, project); @@ -232,8 +225,7 @@ public class GitRepoTests { @Test public void should_return_the_branch_name() throws Exception { - File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), - this.springCloudReleaseProject); + File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), this.springCloudReleaseProject); File project = new GitRepo(this.tmpFolder) .cloneProject(new URIish(this.springCloudReleaseProject.toURI().toURL())); GitTestUtils.setOriginOnProjectToTmp(origin, project); @@ -246,8 +238,7 @@ public class GitRepoTests { @Test public void should_push_a_tag_to_new_branch_in_origin() throws Exception { - File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), - this.springCloudReleaseProject); + File origin = GitTestUtils.clonedProject(this.tmp.newFolder(), this.springCloudReleaseProject); File project = new GitRepo(this.tmpFolder) .cloneProject(new URIish(this.springCloudReleaseProject.toURI().toURL())); GitTestUtils.setOriginOnProjectToTmp(origin, project); @@ -297,8 +288,7 @@ public class GitRepoTests { } @Test - public void should_not_revert_changes_when_commit_message_is_not_related_to_updating_snapshots() - throws Exception { + public void should_not_revert_changes_when_commit_message_is_not_related_to_updating_snapshots() throws Exception { File project = new GitRepo(this.tmpFolder) .cloneProject(new URIish(this.springCloudReleaseProject.toURI().toURL())); diff --git a/releaser-core/src/test/java/releaser/internal/git/GitTestUtils.java b/releaser-core/src/test/java/releaser/internal/git/GitTestUtils.java index 6d2cc492..1a8d508e 100644 --- a/releaser-core/src/test/java/releaser/internal/git/GitTestUtils.java +++ b/releaser-core/src/test/java/releaser/internal/git/GitTestUtils.java @@ -53,8 +53,7 @@ public final class GitTestUtils { return new GitRepo.JGitFactory().open(project); } - public static File clonedProject(File baseDir, File projectToClone) - throws IOException { + public static File clonedProject(File baseDir, File projectToClone) throws IOException { GitRepo projectRepo = new GitRepo(baseDir); return projectRepo.cloneProject(new URIish(projectToClone.toURI().toURL())); } diff --git a/releaser-core/src/test/java/releaser/internal/git/ProjectGitHandlerTests.java b/releaser-core/src/test/java/releaser/internal/git/ProjectGitHandlerTests.java index 437d72e8..3f609b94 100644 --- a/releaser-core/src/test/java/releaser/internal/git/ProjectGitHandlerTests.java +++ b/releaser-core/src/test/java/releaser/internal/git/ProjectGitHandlerTests.java @@ -60,8 +60,7 @@ public class ProjectGitHandlerTests { @Test public void should_only_commit_without_pushing_changes_when_version_is_snapshot() { - this.updater.commitAndTagIfApplicable(this.file, - projectVersion("1.0.0.BUILD-SNAPSHOT")); + this.updater.commitAndTagIfApplicable(this.file, projectVersion("1.0.0.BUILD-SNAPSHOT")); then(this.gitRepo).should().commit(eq("Bumping versions")); then(this.gitRepo).should(never()).tag(anyString()); @@ -78,19 +77,16 @@ public class ProjectGitHandlerTests { @Test public void should_commit_when_snapshot_version_is_present_with_post_release_msg() { - ProjectVersion bumped = new ProjectVersion("name", - projectVersion("1.0.0.BUILD-SNAPSHOT").bumpedVersion()); + ProjectVersion bumped = new ProjectVersion("name", projectVersion("1.0.0.BUILD-SNAPSHOT").bumpedVersion()); this.updater.commitAfterBumpingVersions(this.file, bumped); - then(this.gitRepo).should() - .commit(eq("Bumping versions to 1.0.1.BUILD-SNAPSHOT after release")); + then(this.gitRepo).should().commit(eq("Bumping versions to 1.0.1.BUILD-SNAPSHOT after release")); then(this.gitRepo).should(never()).tag(anyString()); } @Test public void should_not_commit_when_non_snapshot_version_is_present() { - this.updater.commitAfterBumpingVersions(this.file, - projectVersion("1.0.0.RELEASE")); + this.updater.commitAfterBumpingVersions(this.file, projectVersion("1.0.0.RELEASE")); then(this.gitRepo).should(never()).commit(eq("Bumping versions after release")); then(this.gitRepo).should(never()).tag(anyString()); @@ -98,16 +94,14 @@ public class ProjectGitHandlerTests { @Test public void should_not_revert_changes_for_snapshots() { - this.updater.revertChangesIfApplicable(this.file, - projectVersion("1.0.0.BUILD-SNAPSHOT")); + this.updater.revertChangesIfApplicable(this.file, projectVersion("1.0.0.BUILD-SNAPSHOT")); then(this.gitRepo).should(never()).revert(anyString()); } @Test public void should_revert_changes_when_version_is_not_snapshot() { - this.updater.revertChangesIfApplicable(this.file, - projectVersion("1.0.0.RELEASE")); + this.updater.revertChangesIfApplicable(this.file, projectVersion("1.0.0.RELEASE")); then(this.gitRepo).should().revert(eq("Going back to snapshots")); } @@ -128,11 +122,8 @@ public class ProjectGitHandlerTests { @Test public void should_throw_exception_when_no_fixed_version_passed_for_the_project() { - BDDAssertions - .thenThrownBy( - () -> this.updater.cloneProjectFromOrg("spring-cloud-sleuth")) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("You haven't provided a version"); + BDDAssertions.thenThrownBy(() -> this.updater.cloneProjectFromOrg("spring-cloud-sleuth")) + .isInstanceOf(IllegalStateException.class).hasMessageContaining("You haven't provided a version"); } @Test @@ -181,8 +172,7 @@ public class ProjectGitHandlerTests { @Test public void should_check_out_a_branch_if_it_exists_when_cloning_from_org_and_its_a_release_train_version_with_at_least_one_dash() { - this.properties.getFixedVersions().put("spring-cloud-release", - "Finchley-BUILD-SNAPSHOT"); + this.properties.getFixedVersions().put("spring-cloud-release", "Finchley-BUILD-SNAPSHOT"); given(this.gitRepo.hasBranch(anyString())).willReturn(false); given(this.gitRepo.hasBranch("Finchley")).willReturn(true); @@ -209,8 +199,7 @@ public class ProjectGitHandlerTests { given(this.gitRepo.hasBranch(anyString())).willReturn(true); given(this.gitRepo.hasBranch("2.3.x")).willReturn(false); - this.updater.cloneAndGuessBranch(new File(".").getAbsolutePath(), - "2.3.4.RELEASE"); + this.updater.cloneAndGuessBranch(new File(".").getAbsolutePath(), "2.3.4.RELEASE"); then(this.gitRepo).should(never()).checkout("2.3.x"); } @@ -220,8 +209,7 @@ public class ProjectGitHandlerTests { given(this.gitRepo.hasBranch(anyString())).willReturn(false); given(this.gitRepo.hasBranch("2.3.x")).willReturn(true); - this.updater.cloneAndGuessBranch(new File(".").getAbsolutePath(), - "2.3.4.RELEASE"); + this.updater.cloneAndGuessBranch(new File(".").getAbsolutePath(), "2.3.4.RELEASE"); then(this.gitRepo).should().checkout("2.3.x"); } @@ -241,8 +229,7 @@ public class ProjectGitHandlerTests { given(this.gitRepo.hasBranch(anyString())).willReturn(false); given(this.gitRepo.hasBranch("Finchley")).willReturn(true); - this.updater.cloneAndGuessBranch(new File(".").getAbsolutePath(), "2.0.0.RELEASE", - "Finchley.SR6"); + this.updater.cloneAndGuessBranch(new File(".").getAbsolutePath(), "2.0.0.RELEASE", "Finchley.SR6"); then(this.gitRepo).should(never()).checkout("2.0.0"); then(this.gitRepo).should().checkout("Finchley"); diff --git a/releaser-core/src/test/java/releaser/internal/github/GithubIssuesTests.java b/releaser-core/src/test/java/releaser/internal/github/GithubIssuesTests.java index b7965226..73e622de 100644 --- a/releaser-core/src/test/java/releaser/internal/github/GithubIssuesTests.java +++ b/releaser-core/src/test/java/releaser/internal/github/GithubIssuesTests.java @@ -31,7 +31,7 @@ import org.mockito.BDDMockito; import releaser.internal.project.ProjectVersion; import releaser.internal.project.Projects; -import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.boot.test.system.OutputCaptureRule; /** * @author Marcin Grzejszczak @@ -42,7 +42,7 @@ public class GithubIssuesTests { public TemporaryFolder folder = new TemporaryFolder(); @Rule - public OutputCapture capture = new OutputCapture(); + public OutputCaptureRule capture = new OutputCaptureRule(); MkGithub github; @@ -73,7 +73,7 @@ public class GithubIssuesTests { new ProjectVersion("spring-cloud-build", "2.0.0.BUILD-SNAPSHOT")), new ProjectVersion("sc-release", "Edgware.BUILD-SNAPSHOT")); - BDDMockito.then(github).shouldHaveZeroInteractions(); + BDDMockito.then(github).shouldHaveNoInteractions(); } @Test @@ -82,17 +82,15 @@ public class GithubIssuesTests { GithubIssues issues = new GithubIssues(Collections.emptyList()); issues.fileIssueInSpringGuides( - new Projects(new ProjectVersion("foo", "1.0.0.RELEASE"), - new ProjectVersion("bar", "2.0.0.RELEASE"), + new Projects(new ProjectVersion("foo", "1.0.0.RELEASE"), new ProjectVersion("bar", "2.0.0.RELEASE"), new ProjectVersion("baz", "3.0.0.RELEASE")), new ProjectVersion("sc-release", "Edgware.RELEASE")); - BDDMockito.then(github).shouldHaveZeroInteractions(); + BDDMockito.then(github).shouldHaveNoInteractions(); } @Test - public void should_not_do_anything_for_non_release_train_version_when_updating_startspringio() - throws IOException { + public void should_not_do_anything_for_non_release_train_version_when_updating_startspringio() throws IOException { setupStartSpringIo(); Github github = BDDMockito.mock(Github.class); GithubIssues issues = new GithubIssues(Collections.emptyList()); @@ -102,28 +100,25 @@ public class GithubIssuesTests { new ProjectVersion("spring-cloud-build", "2.0.0.RELEASE")), new ProjectVersion("sc-release", "Edgware.BUILD-SNAPSHOT")); - BDDMockito.then(github).shouldHaveZeroInteractions(); + BDDMockito.then(github).shouldHaveNoInteractions(); } @Test - public void should_not_do_anything_if_not_applicable_when_updating_startspringio() - throws IOException { + public void should_not_do_anything_if_not_applicable_when_updating_startspringio() throws IOException { setupStartSpringIo(); Github github = BDDMockito.mock(Github.class); GithubIssues issues = new GithubIssues(Collections.emptyList()); issues.fileIssueInStartSpringIo( - new Projects(new ProjectVersion("foo", "1.0.0.RELEASE"), - new ProjectVersion("bar", "2.0.0.RELEASE"), + new Projects(new ProjectVersion("foo", "1.0.0.RELEASE"), new ProjectVersion("bar", "2.0.0.RELEASE"), new ProjectVersion("baz", "3.0.0.RELEASE")), new ProjectVersion("sc-release", "Edgware.RELEASE")); - BDDMockito.then(github).shouldHaveZeroInteractions(); + BDDMockito.then(github).shouldHaveNoInteractions(); } private Repo createGettingStartedGuides(MkGithub github) throws IOException { - return github.repos() - .create(new Repos.RepoCreate("getting-started-guides", false)); + return github.repos().create(new Repos.RepoCreate("getting-started-guides", false)); } private Repo createStartSpringIo(MkGithub github) throws IOException { diff --git a/releaser-core/src/test/java/releaser/internal/github/GithubMilestonesTests.java b/releaser-core/src/test/java/releaser/internal/github/GithubMilestonesTests.java index 8f6c8044..0971966e 100644 --- a/releaser-core/src/test/java/releaser/internal/github/GithubMilestonesTests.java +++ b/releaser-core/src/test/java/releaser/internal/github/GithubMilestonesTests.java @@ -30,7 +30,7 @@ import org.junit.rules.TemporaryFolder; import releaser.internal.ReleaserProperties; import releaser.internal.project.ProjectVersion; -import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.boot.test.system.OutputCaptureRule; import static org.assertj.core.api.BDDAssertions.then; import static org.assertj.core.api.BDDAssertions.thenThrownBy; @@ -44,7 +44,7 @@ public class GithubMilestonesTests { public TemporaryFolder folder = new TemporaryFolder(); @Rule - public OutputCapture capture = new OutputCapture(); + public OutputCaptureRule capture = new OutputCaptureRule(); MkGithub github; @@ -102,8 +102,7 @@ public class GithubMilestonesTests { } @Test - public void should_not_close_milestone_when_the_milestone_contains_numeric_version_only() - throws IOException { + public void should_not_close_milestone_when_the_milestone_contains_numeric_version_only() throws IOException { GithubMilestones milestones = new GithubMilestones(this.github, withToken()) { @Override String org() { @@ -137,16 +136,14 @@ public class GithubMilestonesTests { @Override URL foundMilestoneUrl(Milestone.Smart milestone) throws IOException { - return new URL( - "https://api.github.com/repos/spring-cloud/spring-cloud-sleuth/milestones/33"); + return new URL("https://api.github.com/repos/spring-cloud/spring-cloud-sleuth/milestones/33"); } }; this.repo.milestones().create("0.2.0.RELEASE"); String url = milestones.milestoneUrl(gaSleuthProject()); - then(url).isEqualTo( - "https://github.com/spring-cloud/spring-cloud-sleuth/milestone/33?closed=1"); + then(url).isEqualTo("https://github.com/spring-cloud/spring-cloud-sleuth/milestone/33?closed=1"); } @Test @@ -157,8 +154,7 @@ public class GithubMilestonesTests { String url = milestones.milestoneUrl(gaSleuthProject()); - then(url).isEqualTo( - "https://github.com/spring-cloud/spring-cloud-sleuth/milestone/33?closed=1"); + then(url).isEqualTo("https://github.com/spring-cloud/spring-cloud-sleuth/milestone/33?closed=1"); } @Test @@ -186,8 +182,7 @@ public class GithubMilestonesTests { } @Test - public void should_return_null_if_no_matching_milestone_was_found_within_threshold() - throws IOException { + public void should_return_null_if_no_matching_milestone_was_found_within_threshold() throws IOException { GithubMilestones milestones = new GithubMilestones(this.github, withThreshold()) { @Override String org() { @@ -203,8 +198,7 @@ public class GithubMilestonesTests { milestones.closeMilestone(gaSleuthProject()); - then(this.capture.toString()).contains( - "No matching milestones were found within the provided threshold [0]"); + then(this.capture.toString()).contains("No matching milestones were found within the provided threshold [0]"); } private ProjectVersion nonGaSleuthProject() { @@ -212,8 +206,7 @@ public class GithubMilestonesTests { } @Test - public void should_throw_exception_when_there_is_no_matching_milestone() - throws IOException { + public void should_throw_exception_when_there_is_no_matching_milestone() throws IOException { GithubMilestones milestones = new GithubMilestones(this.github, withToken()) { @Override String org() { @@ -232,8 +225,7 @@ public class GithubMilestonesTests { } @Test - public void should_print_that_no_milestones_were_found_when_io_problems_occurred() - throws IOException { + public void should_print_that_no_milestones_were_found_when_io_problems_occurred() throws IOException { GithubMilestones milestones = new GithubMilestones(this.github, withToken()) { @Override String org() { @@ -260,8 +252,7 @@ public class GithubMilestonesTests { public void should_throw_exception_when_no_token_was_passed() { GithubMilestones milestones = new GithubMilestones(new ReleaserProperties()); - thenThrownBy(() -> milestones.closeMilestone(nonGaSleuthProject())) - .isInstanceOf(IllegalArgumentException.class) + thenThrownBy(() -> milestones.closeMilestone(nonGaSleuthProject())).isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("You must set the value of the OAuth token"); } diff --git a/releaser-core/src/test/java/releaser/internal/gradle/GradleUpdaterTests.java b/releaser-core/src/test/java/releaser/internal/gradle/GradleUpdaterTests.java index 503590a4..fc90e485 100644 --- a/releaser-core/src/test/java/releaser/internal/gradle/GradleUpdaterTests.java +++ b/releaser-core/src/test/java/releaser/internal/gradle/GradleUpdaterTests.java @@ -64,16 +64,14 @@ public class GradleUpdaterTests { } }; properties.getGradle().setGradlePropsSubstitution(props); - Projects projects = new Projects( - new ProjectVersion("spring-cloud-contract", "1.0.0"), + Projects projects = new Projects(new ProjectVersion("spring-cloud-contract", "1.0.0"), new ProjectVersion("spring-cloud-sleuth", "2.0.0")); - new GradleUpdater().updateProjectFromReleaseTrain(properties, projectRoot, - projects, new ProjectVersion("spring-cloud-contract", "1.0.0"), true); + new GradleUpdater().updateProjectFromReleaseTrain(properties, projectRoot, projects, + new ProjectVersion("spring-cloud-contract", "1.0.0"), true); then(asString(tmpFile("gradleproject/gradle.properties"))).contains("foo=1.0.0"); - then(asString(tmpFile("gradleproject/child/gradle.properties"))) - .contains("bar=2.0.0"); + then(asString(tmpFile("gradleproject/child/gradle.properties"))).contains("bar=2.0.0"); } @Test @@ -87,15 +85,12 @@ public class GradleUpdaterTests { } }; properties.getGradle().setGradlePropsSubstitution(props); - Projects projects = new Projects( - new ProjectVersion("spring-cloud-contract", "1.0.0.BUILD-SNAPSHOT"), + Projects projects = new Projects(new ProjectVersion("spring-cloud-contract", "1.0.0.BUILD-SNAPSHOT"), new ProjectVersion("spring-cloud-sleuth", "2.0.0")); - thenThrownBy(() -> new GradleUpdater().updateProjectFromReleaseTrain(properties, - projectRoot, projects, + thenThrownBy(() -> new GradleUpdater().updateProjectFromReleaseTrain(properties, projectRoot, projects, new ProjectVersion("spring-cloud-contract", "1.0.0.RELEASE"), true)) - .hasMessageContaining( - "(BUILD-)?SNAPSHOT.*$] pattern in line number [1]"); + .hasMessageContaining("(BUILD-)?SNAPSHOT.*$] pattern in line number [1]"); } private File file(String relativePath) throws URISyntaxException { diff --git a/releaser-core/src/test/java/releaser/internal/postrelease/PostReleaseActionsTests.java b/releaser-core/src/test/java/releaser/internal/postrelease/PostReleaseActionsTests.java index 5374f995..d9b428ff 100644 --- a/releaser-core/src/test/java/releaser/internal/postrelease/PostReleaseActionsTests.java +++ b/releaser-core/src/test/java/releaser/internal/postrelease/PostReleaseActionsTests.java @@ -124,27 +124,25 @@ public class PostReleaseActionsTests { @Test public void should_do_nothing_when_is_not_meta_release_and_update_test_is_called() { this.properties.getMetaRelease().setEnabled(false); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater); actions.runUpdatedTests(currentGa()); BDDAssertions.then(this.cloned).isNull(); - BDDMockito.then(this.gradleUpdater).shouldHaveZeroInteractions(); + BDDMockito.then(this.gradleUpdater).shouldHaveNoInteractions(); } @Test public void should_do_nothing_when_the_switch_for_sample_check_is_off_and_update_test_is_called() { this.properties.getGit().setRunUpdatedSamples(false); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater); actions.runUpdatedTests(currentGa()); BDDAssertions.then(this.cloned).isNull(); - BDDMockito.then(this.gradleUpdater).shouldHaveZeroInteractions(); + BDDMockito.then(this.gradleUpdater).shouldHaveNoInteractions(); } @Test @@ -153,12 +151,11 @@ public class PostReleaseActionsTests { properties.getMetaRelease().setEnabled(true); properties.getGit().setRunUpdatedSamples(true); properties.getGit().setUpdateAllTestSamples(true); - properties.getGit().setTestSamplesProjectUrl( - tmpFile("spring-cloud-core-tests/").getAbsolutePath() + "/"); + properties.getGit().setTestSamplesProjectUrl(tmpFile("spring-cloud-core-tests/").getAbsolutePath() + "/"); properties.getMaven().setBuildCommand("touch build.log"); PostReleaseActions actions = new PostReleaseActions(projectGitHandler(properties), - projectPomUpdater(properties), this.gradleUpdater, commandExecutor, - properties, fetcher(properties), releaserPropertiesUpdater) { + projectPomUpdater(properties), this.gradleUpdater, commandExecutor, properties, fetcher(properties), + releaserPropertiesUpdater) { @Override ReleaserProperties projectProps(File file) { return properties; @@ -177,17 +174,15 @@ public class PostReleaseActionsTests { private void thenGradleUpdaterWasCalled() { BDDMockito.then(this.gradleUpdater).should().updateProjectFromReleaseTrain( - BDDMockito.any(ReleaserProperties.class), BDDMockito.any(File.class), - BDDMockito.any(Projects.class), BDDMockito.any(ProjectVersion.class), - BDDMockito.eq(false)); + BDDMockito.any(ReleaserProperties.class), BDDMockito.any(File.class), BDDMockito.any(Projects.class), + BDDMockito.any(ProjectVersion.class), BDDMockito.eq(false)); } @Test public void should_do_nothing_when_is_not_meta_release_and_release_train_docs_generation_is_called() { this.properties.getMetaRelease().setEnabled(false); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater); actions.generateReleaseTrainDocumentation(currentGa()); @@ -197,9 +192,8 @@ public class PostReleaseActionsTests { @Test public void should_do_nothing_when_the_switch_for_sample_check_is_off_and_release_train_docs_generation_is_called() { this.properties.getGit().setUpdateReleaseTrainDocs(false); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater); actions.generateReleaseTrainDocumentation(currentGa()); @@ -210,12 +204,10 @@ public class PostReleaseActionsTests { @Test public void should_update_project_and_run_tests_and_release_train_docs_generation_is_called() { this.properties.getMetaRelease().setEnabled(true); - this.properties.getGit().setReleaseTrainDocsUrl( - tmpFile("spring-cloud-core-tests/").getAbsolutePath() + "/"); + this.properties.getGit().setReleaseTrainDocsUrl(tmpFile("spring-cloud-core-tests/").getAbsolutePath() + "/"); this.properties.getMaven().setGenerateReleaseTrainDocsCommand("./test.sh"); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater); actions.generateReleaseTrainDocumentation(currentGa()); @@ -230,43 +222,38 @@ public class PostReleaseActionsTests { @Test public void should_do_nothing_when_is_not_meta_release_and_test_samples_update_is_called() { this.properties.getMetaRelease().setEnabled(false); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater); actions.updateAllTestSamples(currentGa()); BDDAssertions.then(this.cloned).isNull(); - BDDMockito.then(this.gradleUpdater).shouldHaveZeroInteractions(); + BDDMockito.then(this.gradleUpdater).shouldHaveNoInteractions(); } @Test public void should_do_nothing_when_the_switch_for_test_samples_update_check_is_off_and_update_is_called() { this.properties.getGit().setUpdateReleaseTrainDocs(false); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater); actions.updateAllTestSamples(currentGa()); BDDAssertions.then(this.cloned).isNull(); - BDDMockito.then(this.gradleUpdater).shouldHaveZeroInteractions(); + BDDMockito.then(this.gradleUpdater).shouldHaveNoInteractions(); } @Test - public void should_update_test_sample_projects_when_test_samples_update_is_called() - throws Exception { + public void should_update_test_sample_projects_when_test_samples_update_is_called() throws Exception { ReleaserProperties properties = SpringCloudReleaserProperties.get(); properties.getMetaRelease().setEnabled(true); properties.getGit().setUpdateAllTestSamples(true); properties.getGit().getAllTestSampleUrls().clear(); properties.getGit().getAllTestSampleUrls().put("spring-cloud-sleuth", - Collections.singletonList( - tmpFile("spring-cloud-core-tests/").getAbsolutePath() + "/")); + Collections.singletonList(tmpFile("spring-cloud-core-tests/").getAbsolutePath() + "/")); AtomicReference postReleaseProjects = new AtomicReference<>(); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, properties, - versionsFetcher, releaserPropertiesUpdater) { + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, properties, versionsFetcher, releaserPropertiesUpdater) { @Override Projects getPostReleaseProjects(Projects projects) { postReleaseProjects.set(super.getPostReleaseProjects(projects)); @@ -280,37 +267,31 @@ public class PostReleaseActionsTests { .filter(s -> s.getKey().contains("spring-cloud-core-tests")).findFirst() .orElseThrow(() -> new IllegalStateException("Not found")); File clonedFile = entry.getValue().get(0); - Model pomWithCloud = PomReader - .readPom(new File(clonedFile, "zuul-proxy-eureka/pom.xml")); + Model pomWithCloud = PomReader.readPom(new File(clonedFile, "zuul-proxy-eureka/pom.xml")); Git git = GitTestUtils.openGitProject(clonedFile); - BDDAssertions - .then(pomWithCloud.getProperties().getProperty("spring-cloud.version")) + BDDAssertions.then(pomWithCloud.getProperties().getProperty("spring-cloud.version")) .isEqualTo("Finchley.SNAPSHOT"); - BDDAssertions.then(pomWithCloud.getParent().getVersion()) - .isEqualTo("2.0.4.RELEASE"); + BDDAssertions.then(pomWithCloud.getParent().getVersion()).isEqualTo("2.0.4.RELEASE"); Iterator iterator = git.log().call().iterator(); RevCommit commit = iterator.next(); BDDAssertions.then(commit.getShortMessage()).isEqualTo( "Updated versions after [Finchley.SR1] release train and [2.0.1.RELEASE] [spring-cloud-sleuth] project release"); thenGradleUpdaterWasCalled(); - BDDAssertions.then( - postReleaseProjects.get().forName("spring-boot-dependencies").version) + BDDAssertions.then(postReleaseProjects.get().forName("spring-boot-dependencies").version) .isEqualTo("2.0.4.RELEASE"); } @Test - public void should_assume_that_project_version_is_snapshot_when_no_pom_is_present() - throws Exception { + public void should_assume_that_project_version_is_snapshot_when_no_pom_is_present() throws Exception { ReleaserProperties properties = SpringCloudReleaserProperties.get(); properties.getMetaRelease().setEnabled(true); properties.getGit().setUpdateAllTestSamples(true); properties.getGit().getAllTestSampleUrls().clear(); - properties.getGit().getAllTestSampleUrls().put("spring-cloud-sleuth", Collections - .singletonList(tmpFile("spring-cloud-static/").getAbsolutePath() + "/")); + properties.getGit().getAllTestSampleUrls().put("spring-cloud-sleuth", + Collections.singletonList(tmpFile("spring-cloud-static/").getAbsolutePath() + "/")); AtomicReference postReleaseProjects = new AtomicReference<>(); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, properties, - versionsFetcher, releaserPropertiesUpdater) { + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, properties, versionsFetcher, releaserPropertiesUpdater) { @Override Projects getPostReleaseProjects(Projects projects) { postReleaseProjects.set(super.getPostReleaseProjects(projects)); @@ -320,8 +301,7 @@ public class PostReleaseActionsTests { actions.updateAllTestSamples(currentGa()); - this.clonedTestProjects.entrySet().stream() - .filter(s -> s.getKey().contains("spring-cloud-static")).findFirst() + this.clonedTestProjects.entrySet().stream().filter(s -> s.getKey().contains("spring-cloud-static")).findFirst() .orElseThrow(() -> new IllegalStateException("Not found")); } @@ -329,14 +309,13 @@ public class PostReleaseActionsTests { public void should_do_nothing_when_guides_are_turned_off() { this.properties.getGit().setUpdateSpringGuides(false); VersionsFetcher versionsFetcher = BDDMockito.mock(VersionsFetcher.class); - PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, - this.updater, this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater); + PostReleaseActions actions = new PostReleaseActions(this.projectGitHandler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater); actions.deployGuides(Collections.emptyList()); BDDAssertions.then(this.cloned).isNull(); - BDDMockito.then(versionsFetcher).shouldHaveZeroInteractions(); + BDDMockito.then(versionsFetcher).shouldHaveNoInteractions(); } @Test @@ -348,33 +327,29 @@ public class PostReleaseActionsTests { BDDMockito.given(versionsFetcher.isLatestGa(BDDMockito.any())).willReturn(true); AtomicReference projectBuilderStub = new AtomicReference<>(); ProjectGitHandler handler = BDDMockito.mock(ProjectGitHandler.class); - ProjectCommandExecutor projectCommandExecutor = BDDMockito - .mock(ProjectCommandExecutor.class); - PostReleaseActions actions = new PostReleaseActions(handler, this.updater, - this.gradleUpdater, this.commandExecutor, this.properties, - versionsFetcher, releaserPropertiesUpdater) { + ProjectCommandExecutor projectCommandExecutor = BDDMockito.mock(ProjectCommandExecutor.class); + PostReleaseActions actions = new PostReleaseActions(handler, this.updater, this.gradleUpdater, + this.commandExecutor, this.properties, versionsFetcher, releaserPropertiesUpdater) { @Override ProjectCommandExecutor projectBuilder(ProcessedProject processedProject) { projectBuilderStub.set(projectCommandExecutor); return projectCommandExecutor; } }; - ProjectVersion projectVersion = new ProjectVersion( - new File(projects, "spring-cloud-release")); + ProjectVersion projectVersion = new ProjectVersion(new File(projects, "spring-cloud-release")); - actions.deployGuides(Collections.singletonList( - new ProcessedProject(this.properties, projectVersion, projectVersion))); + actions.deployGuides( + Collections.singletonList(new ProcessedProject(this.properties, projectVersion, projectVersion))); Awaitility.await().untilAsserted(() -> { BDDAssertions.then(projectBuilderStub.get()).isNotNull(); - BDDMockito.then(projectBuilderStub.get()).should() - .deployGuides(this.properties, projectVersion, projectVersion); + BDDMockito.then(projectBuilderStub.get()).should().deployGuides(this.properties, projectVersion, + projectVersion); }); } private String sleuthParentPomVersion() { - return PomReader.readPom(new File(this.cloned, "sleuth/pom.xml")).getParent() - .getVersion(); + return PomReader.readPom(new File(this.cloned, "sleuth/pom.xml")).getParent().getVersion(); } Projects currentGa() { diff --git a/releaser-core/src/test/java/releaser/internal/project/ProjectCommandExecutorTests.java b/releaser-core/src/test/java/releaser/internal/project/ProjectCommandExecutorTests.java index 028d0d1f..9fa216e3 100644 --- a/releaser-core/src/test/java/releaser/internal/project/ProjectCommandExecutorTests.java +++ b/releaser-core/src/test/java/releaser/internal/project/ProjectCommandExecutorTests.java @@ -36,7 +36,7 @@ import releaser.internal.PomUpdateAcceptanceTests; import releaser.internal.ReleaserProperties; import releaser.internal.buildsystem.TestUtils; -import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.boot.test.system.OutputCaptureRule; import org.springframework.util.FileSystemUtils; import static org.assertj.core.api.BDDAssertions.then; @@ -51,7 +51,7 @@ public class ProjectCommandExecutorTests { public TemporaryFolder tmp = new TemporaryFolder(); @Rule - public OutputCapture outputCapture = new OutputCapture(); + public OutputCaptureRule outputCapture = new OutputCaptureRule(); File temporaryFolder; @@ -80,32 +80,26 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("resolved.log"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("resolved.log"); } @Test - public void should_successfully_execute_a_command_when_path_is_provided_explicitly() - throws Exception { + public void should_successfully_execute_a_command_when_path_is_provided_explicitly() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setBuildCommand("ls -al"); properties.setWorkingDir(new File("/foo/bar").getAbsolutePath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"), + builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"), tmpFile("/builder/resolved").getPath()); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("resolved.log"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("resolved.log"); } @Test - public void should_successfully_execute_a_build_command_for_milestone_version() - throws Exception { + public void should_successfully_execute_a_build_command_for_milestone_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setBuildCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); @@ -117,8 +111,7 @@ public class ProjectCommandExecutorTests { } @Test - public void should_successfully_execute_a_build_command_for_rc_version() - throws Exception { + public void should_successfully_execute_a_build_command_for_rc_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setBuildCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); @@ -126,13 +119,11 @@ public class ProjectCommandExecutorTests { builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.RC1")); - then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo") - .doesNotContain("-Pguides"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo").doesNotContain("-Pguides"); } @Test - public void should_successfully_execute_a_build_command_for_release_version() - throws Exception { + public void should_successfully_execute_a_build_command_for_release_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setBuildCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); @@ -144,8 +135,7 @@ public class ProjectCommandExecutorTests { } @Test - public void should_successfully_execute_a_build_command_for_sr_version() - throws Exception { + public void should_successfully_execute_a_build_command_for_sr_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setBuildCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); @@ -157,19 +147,16 @@ public class ProjectCommandExecutorTests { } @Test - public void should_successfully_execute_a_command_when_system_props_placeholder_is_present() - throws Exception { + public void should_successfully_execute_a_command_when_system_props_placeholder_is_present() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setBuildCommand("echo {{systemProps}}"); properties.getBash().setSystemProperties("-Dhello=world -Dfoo=bar"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("-Dhello=world -Dfoo=bar"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("-Dhello=world -Dfoo=bar"); } @Test @@ -180,8 +167,7 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo"); } @@ -195,11 +181,9 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("hello=world foo=bar"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("hello=world foo=bar"); } @Test @@ -211,11 +195,9 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("-Dhello=world -Dfoo=bar bar"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("-Dhello=world -Dfoo=bar bar"); } @Test @@ -227,11 +209,9 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("bar -Dhello=world -Dfoo=bar"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("bar -Dhello=world -Dfoo=bar"); } @Test @@ -241,9 +221,8 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/unresolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - thenThrownBy(() -> builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"))).hasMessageContaining( - "contains a tag that wasn't resolved properly"); + thenThrownBy(() -> builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"))) + .hasStackTraceContaining("contains a tag that wasn't resolved properly"); } @Test @@ -254,9 +233,8 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/unresolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - thenThrownBy(() -> builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"))).hasMessageContaining( - "Process waiting time of [0] minutes exceeded"); + thenThrownBy(() -> builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"))) + .hasStackTraceContaining("Process waiting time of [0] minutes exceeded"); } @Test @@ -266,16 +244,13 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.deploy(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("resolved.log"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("resolved.log"); } @Test - public void should_successfully_execute_a_deploy_command_for_milestone_version() - throws Exception { + public void should_successfully_execute_a_deploy_command_for_milestone_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setDeployCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); @@ -283,90 +258,76 @@ public class ProjectCommandExecutorTests { builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.M1")); - then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo") - .doesNotContain("-Pguides"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo").doesNotContain("-Pguides"); } @Test - public void should_successfully_execute_a_deploy_command_for_milestone_version_for_maven() - throws Exception { + public void should_successfully_execute_a_deploy_command_for_milestone_version_for_maven() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getMaven().setDeployCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); - new ReleaserProcessExecutor(properties.getWorkingDir()) - .runCommand(new String[] { "touch", "pom.xml" }, 1); + new ReleaserProcessExecutor(properties.getWorkingDir()).runCommand(new String[] { "touch", "pom.xml" }, 1); ProjectCommandExecutor builder = projectBuilder(properties); builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.M1")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("foo -Pmilestone").doesNotContain("-Pguides"); - } - - @Test - public void should_successfully_execute_a_deploy_command_for_rc_version() - throws Exception { - ReleaserProperties properties = new ReleaserProperties(); - properties.getBash().setDeployCommand("echo foo"); - properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); - ProjectCommandExecutor builder = projectBuilder(properties); - - builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.RC1")); - - then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo") + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo -Pmilestone") .doesNotContain("-Pguides"); } @Test - public void should_successfully_execute_a_deploy_command_for_rc_version_for_maven() - throws Exception { - ReleaserProperties properties = new ReleaserProperties(); - properties.getMaven().setDeployCommand("echo foo"); - properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); - new ReleaserProcessExecutor(properties.getWorkingDir()) - .runCommand(new String[] { "touch", "pom.xml" }, 1); - ProjectCommandExecutor builder = projectBuilder(properties); - - builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.RC1")); - - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("foo -Pmilestone").doesNotContain("-Pguides"); - } - - @Test - public void should_successfully_execute_a_deploy_command_for_release_version() - throws Exception { + public void should_successfully_execute_a_deploy_command_for_rc_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setDeployCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.deploy(properties, original(), - new ProjectVersion("foo", "1.0.0.RELEASE")); + builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.RC1")); + + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo").doesNotContain("-Pguides"); + } + + @Test + public void should_successfully_execute_a_deploy_command_for_rc_version_for_maven() throws Exception { + ReleaserProperties properties = new ReleaserProperties(); + properties.getMaven().setDeployCommand("echo foo"); + properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); + new ReleaserProcessExecutor(properties.getWorkingDir()).runCommand(new String[] { "touch", "pom.xml" }, 1); + ProjectCommandExecutor builder = projectBuilder(properties); + + builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.RC1")); + + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo -Pmilestone") + .doesNotContain("-Pguides"); + } + + @Test + public void should_successfully_execute_a_deploy_command_for_release_version() throws Exception { + ReleaserProperties properties = new ReleaserProperties(); + properties.getBash().setDeployCommand("echo foo"); + properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); + ProjectCommandExecutor builder = projectBuilder(properties); + + builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.RELEASE")); then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo"); } @Test - public void should_successfully_execute_a_deploy_command_for_release_version_for_maven() - throws Exception { + public void should_successfully_execute_a_deploy_command_for_release_version_for_maven() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getMaven().setDeployCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); - new ReleaserProcessExecutor(properties.getWorkingDir()) - .runCommand(new String[] { "touch", "pom.xml" }, 1); + new ReleaserProcessExecutor(properties.getWorkingDir()).runCommand(new String[] { "touch", "pom.xml" }, 1); ProjectCommandExecutor builder = projectBuilder(properties); - builder.deploy(properties, original(), - new ProjectVersion("foo", "1.0.0.RELEASE")); + builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.RELEASE")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("foo -Pcentral"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("foo -Pcentral"); } @Test - public void should_successfully_execute_a_deploy_command_for_sr_version() - throws Exception { + public void should_successfully_execute_a_deploy_command_for_sr_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setDeployCommand("echo foo"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); @@ -378,19 +339,16 @@ public class ProjectCommandExecutorTests { } @Test - public void should_successfully_execute_a_deploy_command_with_sys_props_placeholder() - throws Exception { + public void should_successfully_execute_a_deploy_command_with_sys_props_placeholder() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setDeployCommand("echo \"{{systemProps}}\""); properties.getBash().setSystemProperties("-Dhello=hello-world"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.deploy(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("-Dhello=hello-world"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("-Dhello=hello-world"); } @Test @@ -402,11 +360,9 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - builder.deploy(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); + builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("-Dhello=hello-world"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("-Dhello=hello-world"); } @Test @@ -417,16 +373,14 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/unresolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - thenThrownBy(() -> builder.deploy(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"))).hasMessageContaining( - "Process waiting time of [0] minutes exceeded"); + thenThrownBy(() -> builder.deploy(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"))) + .hasMessageContaining("Process waiting time of [0] minutes exceeded"); } @Test public void should_successfully_execute_a_publish_docs_command() throws Exception { ReleaserProperties properties = new ReleaserProperties(); - properties.getBash().setPublishDocsCommand( - "ls -al && echo {{version}} {{oldVersion}} {{nextVersion}}"); + properties.getBash().setPublishDocsCommand("ls -al && echo {{version}} {{oldVersion}} {{nextVersion}}"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); TestReleaserProcessExecutor executor = testExecutor(properties.getWorkingDir()); ProjectCommandExecutor builder = new ProjectCommandExecutor() { @@ -436,8 +390,7 @@ public class ProjectCommandExecutorTests { } }; - builder.publishDocs(properties, original(), - new ProjectVersion("foo", "1.0.0.RELEASE")); + builder.publishDocs(properties, original(), new ProjectVersion("foo", "1.0.0.RELEASE")); then(asString(tmpFile("/builder/resolved/resolved.log"))) .contains("1.0.0.RELEASE 0.100.0.BUILD-SNAPSHOT 1.0.1.RELEASE"); @@ -445,11 +398,9 @@ public class ProjectCommandExecutorTests { } @Test - public void should_successfully_execute_a_publish_docs_command_with_sys_props_placeholder() - throws Exception { + public void should_successfully_execute_a_publish_docs_command_with_sys_props_placeholder() throws Exception { ReleaserProperties properties = new ReleaserProperties(); - properties.getBash().setPublishDocsCommand( - "echo {{systemProps}} 1 && echo {{systemProps}} 2"); + properties.getBash().setPublishDocsCommand("echo {{systemProps}} 1 && echo {{systemProps}} 2"); properties.getBash().setSystemProperties("-Dhello=world -Dfoo=bar"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); TestReleaserProcessExecutor executor = testExecutor(properties.getWorkingDir()); @@ -460,8 +411,7 @@ public class ProjectCommandExecutorTests { } }; - builder.publishDocs(properties, original(), - new ProjectVersion("foo", "Finchley.RELEASE")); + builder.publishDocs(properties, original(), new ProjectVersion("foo", "Finchley.RELEASE")); String s = asString(tmpFile("/builder/resolved/resolved.log")); System.out.println("====> " + s); @@ -470,8 +420,7 @@ public class ProjectCommandExecutorTests { } @Test - public void should_successfully_execute_a_publish_docs_command_and_substitute_the_version() - throws Exception { + public void should_successfully_execute_a_publish_docs_command_and_substitute_the_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setPublishDocsCommand("echo '{{version}}'"); properties.setWorkingDir(tmpFile("/builder/resolved").getPath()); @@ -483,16 +432,13 @@ public class ProjectCommandExecutorTests { } }; - builder.publishDocs(properties, original(), - new ProjectVersion("foo", "1.1.0.RELEASE")); + builder.publishDocs(properties, original(), new ProjectVersion("foo", "1.1.0.RELEASE")); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("1.1.0.RELEASE"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("1.1.0.RELEASE"); } @Test - public void should_successfully_execute_an_update_docs_command_and_substitute_the_version() - throws Exception { + public void should_successfully_execute_an_update_docs_command_and_substitute_the_version() throws Exception { ReleaserProperties properties = new ReleaserProperties(); properties.getBash().setGenerateReleaseTrainDocsCommand("echo '{{version}}'"); File resolved = tmpFile("/builder/resolved"); @@ -505,11 +451,9 @@ public class ProjectCommandExecutorTests { } }; - builder.generateReleaseTrainDocs(properties, "1.1.0.RELEASE", - resolved.getAbsolutePath()); + builder.generateReleaseTrainDocs(properties, "1.1.0.RELEASE", resolved.getAbsolutePath()); - then(asString(tmpFile("/builder/resolved/resolved.log"))) - .contains("1.1.0.RELEASE"); + then(asString(tmpFile("/builder/resolved/resolved.log"))).contains("1.1.0.RELEASE"); } @Test @@ -520,9 +464,8 @@ public class ProjectCommandExecutorTests { properties.setWorkingDir(tmpFile("/builder/unresolved").getPath()); ProjectCommandExecutor builder = projectBuilder(properties); - thenThrownBy(() -> builder.publishDocs(properties, original(), - new ProjectVersion("foo", "1.0.0.RELEASE"))).hasMessageContaining( - "Process waiting time of [0] minutes exceeded"); + thenThrownBy(() -> builder.publishDocs(properties, original(), new ProjectVersion("foo", "1.0.0.RELEASE"))) + .hasMessageContaining("Process waiting time of [0] minutes exceeded"); } @Test @@ -543,9 +486,8 @@ public class ProjectCommandExecutorTests { } }; - thenThrownBy(() -> builder.build(properties, original(), - new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"))).hasMessageContaining( - "The process has exited with exit code [1]"); + thenThrownBy(() -> builder.build(properties, original(), new ProjectVersion("foo", "1.0.0.BUILD-SNAPSHOT"))) + .hasStackTraceContaining("The process has exited with exit code [1]"); } private TestReleaserProcessExecutor testExecutor(String workingDir) { @@ -579,14 +521,12 @@ public class ProjectCommandExecutorTests { @Override ProcessExecutor processExecutor(String[] commands, String workingDir) { this.counter++; - final ProcessExecutor processExecutor = super.processExecutor(commands, - workingDir); + final ProcessExecutor processExecutor = super.processExecutor(commands, workingDir); File tempFile = tmpFile("/builder/resolved/resolved.log"); try { tempFile.createNewFile(); - OutputStream fos = new BufferedOutputStream( - new FileOutputStream(tempFile)); + OutputStream fos = new BufferedOutputStream(new FileOutputStream(tempFile)); return processExecutor // use redirectOutputAlsoTo to avoid overriding all output diff --git a/releaser-core/src/test/java/releaser/internal/sagan/RestTemplateSaganClientTests.java b/releaser-core/src/test/java/releaser/internal/sagan/RestTemplateSaganClientTests.java index 002b6bf5..53c7e237 100644 --- a/releaser-core/src/test/java/releaser/internal/sagan/RestTemplateSaganClientTests.java +++ b/releaser-core/src/test/java/releaser/internal/sagan/RestTemplateSaganClientTests.java @@ -17,8 +17,6 @@ package releaser.internal.sagan; import java.io.IOException; -import java.util.Arrays; -import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.Before; @@ -44,7 +42,7 @@ import static org.assertj.core.api.BDDAssertions.then; */ @RunWith(SpringRunner.class) @SpringBootTest(classes = RestTemplateSaganClientTests.Config.class) -@AutoConfigureStubRunner(ids = "sagan:sagan-site") +@AutoConfigureStubRunner(ids = "io.spring.sagan:sagan-site") public class RestTemplateSaganClientTests { @Value("${stubrunner.runningstubs.sagan-site.port}") @@ -64,139 +62,53 @@ public class RestTemplateSaganClientTests { } @Test - @Ignore("2 stubs point to the same endpoint") public void should_get_a_project() { - Project project = this.client.getProject("spring-framework"); + Project project = this.client.getProject("spring-boot"); - then(project.id).isEqualTo("spring-framework"); - then(project.name).isEqualTo("Spring Framework"); - then(project.repoUrl) - .isEqualTo("https://github.com/spring-projects/spring-framework"); - then(project.siteUrl).isEqualTo("https://projects.spring.io/spring-framework"); - then(project.category).isEqualTo("active"); - then(project.stackOverflowTags).isNotBlank(); - then(project.stackOverflowTagList).isNotEmpty(); - then(project.aggregator).isFalse(); - then(project.projectReleases).isNotEmpty(); - Release release = project.projectReleases.get(0); - then(release.releaseStatus).isEqualTo("PRERELEASE"); - then(release.refDocUrl).isEqualTo( - "http://docs.spring.io/spring/docs/5.0.0.RC4/spring-framework-reference/"); - then(release.apiDocUrl) - .isEqualTo("http://docs.spring.io/spring/docs/5.0.0.RC4/javadoc-api/"); - then(release.groupId).isEqualTo("org.springframework"); - then(release.artifactId).isEqualTo("spring-context"); - then(release.repository.id).isEqualTo("spring-milestones"); - then(release.repository.name).isEqualTo("Spring Milestones"); - then(release.repository.url).isEqualTo("https://repo.spring.io/libs-milestone"); - then(release.repository.snapshotsEnabled).isFalse(); - then(release.version).isEqualTo("5.0.0.RC4"); - then(release.current).isFalse(); - then(release.generalAvailability).isFalse(); - then(release.preRelease).isTrue(); - then(release.versionDisplayName).isEqualTo("5.0.0 RC4"); - then(release.snapshot).isFalse(); + then(project.getSlug()).isEqualTo("spring-boot"); + then(project.getName()).isEqualTo("Spring Boot"); + then(project.getRepositoryUrl()).isEqualTo("https://github.com/spring-projects/spring-boot"); + then(project.getStatus()).isEqualTo("ACTIVE"); + then(project.getReleases()).isNotEmpty(); + Release release = project.getReleases().get(0); + then(release.getStatus()).isEqualTo("PRERELEASE"); + then(release.getReferenceDocUrl()) + .isEqualTo("https://docs.spring.io/spring-boot/docs/2.4.0-M1/reference/html/"); + then(release.getApiDocUrl()).isEqualTo("https://docs.spring.io/spring-boot/docs/2.4.0-M1/api/"); + then(release.getVersion()).isEqualTo("2.4.0-M1"); } @Test public void should_get_a_release() { - Release release = this.client.getRelease("spring-framework", "5.0.0.RC4"); + Release release = this.client.getRelease("spring-boot", "2.3.0.RELEASE"); - then(release.releaseStatus).isEqualTo("PRERELEASE"); - then(release.refDocUrl).isEqualTo( - "http://docs.spring.io/spring/docs/{version}/spring-framework-reference/"); - then(release.apiDocUrl) - .isEqualTo("http://docs.spring.io/spring/docs/{version}/javadoc-api/"); - then(release.groupId).isEqualTo("org.springframework"); - then(release.artifactId).isEqualTo("spring-context"); - then(release.repository.id).isEqualTo("spring-milestones"); - then(release.repository.name).isEqualTo("Spring Milestones"); - then(release.repository.url).isEqualTo("https://repo.spring.io/libs-milestone"); - then(release.repository.snapshotsEnabled).isFalse(); - then(release.version).isEqualTo("5.0.0.RC4"); - then(release.current).isFalse(); - then(release.generalAvailability).isFalse(); - then(release.preRelease).isTrue(); - then(release.versionDisplayName).isEqualTo("5.0.0 RC4"); - then(release.snapshot).isFalse(); + then(release.getStatus()).isEqualTo("GENERAL_AVAILABILITY"); + then(release.getReferenceDocUrl()).isEqualTo("https://docs.spring.io/spring-boot/docs/current/reference/html/"); + then(release.getApiDocUrl()).isEqualTo("https://docs.spring.io/spring-boot/docs/current/api/"); + then(release.getVersion()).isEqualTo("2.3.0.RELEASE"); } @Test public void should_delete_a_release() { - Release release = this.client.deleteRelease("spring-framework", "5.0.0.RC4"); + boolean deleted = this.client.deleteRelease("spring-boot", "2.3.0.RELEASE"); - then(release).isNotNull(); - then(release.releaseStatus).isEqualTo("PRERELEASE"); + then(deleted).isTrue(); } @Test public void should_update_a_release() { - Repository snapshots = snapshots(); - Repository milestone = milestone(); - ReleaseUpdate firstRelease = new ReleaseUpdate(); - firstRelease.groupId = "org.springframework"; - firstRelease.artifactId = "spring-context"; - firstRelease.version = "1.2.8.RELEASE"; - firstRelease.releaseStatus = "PRERELEASE"; - firstRelease.refDocUrl = "http://docs.spring.io/spring/docs/{version}/spring-framework-reference/"; - firstRelease.apiDocUrl = "http://docs.spring.io/spring/docs/{version}/javadoc-api/"; - firstRelease.repository = milestone; + ReleaseInput releaseInput = new ReleaseInput(); + releaseInput.setVersion("2.2.0.RELEASE"); + releaseInput.setReferenceDocUrl("https://docs.spring.io/spring-boot/docs/{version}/reference/html/"); + releaseInput.setApiDocUrl("https://docs.spring.io/spring-boot/docs/{version}/api/"); - ReleaseUpdate secondRelease = new ReleaseUpdate(); - secondRelease.groupId = "org.springframework"; - secondRelease.artifactId = "spring-context"; - secondRelease.version = "5.0.0.BUILD-SNAPSHOT"; - secondRelease.releaseStatus = "SNAPSHOT"; - secondRelease.refDocUrl = "http://docs.spring.io/spring/docs/{version}/spring-framework-reference/"; - secondRelease.apiDocUrl = "http://docs.spring.io/spring/docs/{version}/javadoc-api/"; - secondRelease.repository = snapshots; - - ReleaseUpdate thirdRelease = new ReleaseUpdate(); - thirdRelease.groupId = "org.springframework"; - thirdRelease.artifactId = "spring-context"; - thirdRelease.version = "4.3.12.BUILD-SNAPSHOT"; - thirdRelease.releaseStatus = "SNAPSHOT"; - thirdRelease.refDocUrl = "http://docs.spring.io/spring/docs/{version}/spring-framework-reference/htmlsingle/"; - thirdRelease.apiDocUrl = "http://docs.spring.io/spring/docs/{version}/javadoc-api/"; - thirdRelease.repository = snapshots; - - ReleaseUpdate fourthRelease = new ReleaseUpdate(); - fourthRelease.groupId = "org.springframework"; - fourthRelease.artifactId = "spring-context"; - fourthRelease.version = "4.3.11.RELEASE"; - fourthRelease.releaseStatus = "GENERAL_AVAILABILITY"; - fourthRelease.current = true; - fourthRelease.refDocUrl = "http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/"; - fourthRelease.apiDocUrl = "http://docs.spring.io/spring/docs/current/javadoc-api/"; - - ReleaseUpdate fithRelease = new ReleaseUpdate(); - fithRelease.groupId = "org.springframework"; - fithRelease.artifactId = "spring-context"; - fithRelease.version = "4.2.9.RELEASE"; - fithRelease.releaseStatus = "GENERAL_AVAILABILITY"; - fithRelease.refDocUrl = "http://docs.spring.io/spring/docs/{version}/spring-framework-reference/htmlsingle/"; - fithRelease.apiDocUrl = "http://docs.spring.io/spring/docs/{version}/javadoc-api/"; - - ReleaseUpdate sithRelease = new ReleaseUpdate(); - sithRelease.groupId = "org.springframework"; - sithRelease.artifactId = "spring-context"; - sithRelease.version = "3.2.18.RELEASE"; - sithRelease.releaseStatus = "GENERAL_AVAILABILITY"; - sithRelease.refDocUrl = "http://docs.spring.io/spring/docs/{version}/spring-framework-reference/htmlsingle/"; - sithRelease.apiDocUrl = "http://docs.spring.io/spring/docs/{version}/javadoc-api/"; - - List updates = Arrays.asList(firstRelease, secondRelease, - thirdRelease, fourthRelease, fithRelease, sithRelease); - - Project project = this.client.updateRelease("spring-framework", updates); - - then(project.id).isEqualTo("spring-framework"); - then(project.name).isEqualTo("Spring Framework"); - then(project.projectReleases).hasSize(7); + boolean added = this.client.addRelease("spring-boot", releaseInput); + then(added).isTrue(); } @Test + @Ignore("no api yet https://github.com/spring-io/sagan/issues/1052") public void should_patch_a_project() throws IOException { String projectJson = "{\n \"id\" : \"spring-framework\",\n " + "\"rawBootConfig\" : \"rawBootConfig\",\n \"rawOverview\" : \"rawOverview\",\n " @@ -207,10 +119,10 @@ public class RestTemplateSaganClientTests { Project patchedProject = this.client.patchProject(project); - then(patchedProject.id).isEqualTo("spring-framework"); - then(patchedProject.name).isEqualTo("Spring Framework"); - then(patchedProject.rawBootConfig).isEqualTo("rawBootConfig"); - then(patchedProject.rawOverview).isEqualTo("rawOverview"); + // then(patchedProject.id).isEqualTo("spring-framework"); + // then(patchedProject.name).isEqualTo("Spring Framework"); + // then(patchedProject.rawBootConfig).isEqualTo("rawBootConfig"); + // then(patchedProject.rawOverview).isEqualTo("rawOverview"); } private Repository milestone() { @@ -237,8 +149,7 @@ public class RestTemplateSaganClientTests { } private RestTemplate restTemplate(ReleaserProperties properties) { - return new RestTemplateBuilder() - .basicAuthentication(properties.getGit().getOauthToken(), "").build(); + return new RestTemplateBuilder().basicAuthentication(properties.getGit().getOauthToken(), "").build(); } @Configuration diff --git a/releaser-core/src/test/java/releaser/internal/sagan/SaganUpdaterOldDocsTest.java b/releaser-core/src/test/java/releaser/internal/sagan/SaganUpdaterOldDocsTest.java deleted file mode 100644 index 193c40c6..00000000 --- a/releaser-core/src/test/java/releaser/internal/sagan/SaganUpdaterOldDocsTest.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * 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 releaser.internal.sagan; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentMatcher; -import org.mockito.BDDMockito; -import org.mockito.Mockito; -import releaser.internal.ReleaserProperties; -import releaser.internal.project.ProjectVersion; -import releaser.internal.project.Projects; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.never; - -/** - * @author Marcin Grzejszczak - */ -public class SaganUpdaterOldDocsTest { - - SaganClient saganClient = Mockito.mock(SaganClient.class); - - ReleaserProperties properties = new ReleaserProperties(); - - SaganUpdater saganUpdater; - - Projects projects = new Projects(); - - @Before - public void setup() { - Project project = new Project(); - project.projectReleases.addAll(Arrays.asList(release("1.0.0.RC1"), - release("1.1.0.BUILD-SNAPSHOT"), release("2.0.0.M4"))); - BDDMockito.given(this.saganClient.getProject(anyString())).willReturn(project); - this.properties.getSagan().setUpdateSagan(true); - this.saganUpdater = new SaganUpdater(this.saganClient, this.properties); - } - - private Release release(String version) { - Release release = new Release(); - release.version = version; - release.current = true; - return release; - } - - @Test - public void should_not_update_sagan_when_switch_is_off() { - this.properties.getSagan().setUpdateSagan(false); - - this.saganUpdater.updateSagan(new File("."), "master", version("2.2.0.M1"), - version("2.2.0.M1"), projects); - - then(this.saganClient).shouldHaveZeroInteractions(); - } - - @Test - public void should_update_sagan_releases_for_milestone() { - this.saganUpdater.updateSagan(new File("."), "master", version("1.0.0.M1"), - version("1.0.0.M1"), projects); - - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("1.0.0.M1", - "https://cloud.spring.io/spring-cloud-static/foo/{version}/", - "PRERELEASE"))); - } - - @Test - public void should_update_sagan_releases_for_rc() { - this.saganUpdater.updateSagan(new File("."), "master", version("1.0.0.RC1"), - version("1.0.0.RC1"), projects); - - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("1.0.0.RC1", - "https://cloud.spring.io/spring-cloud-static/foo/{version}/", - "PRERELEASE"))); - } - - @Test - public void should_not_update_docs_for_sagan_when_current_version_older() { - given(this.saganClient.updateRelease(BDDMockito.anyString(), - BDDMockito.anyList())).willReturn(a2_0_0_ReleaseProject()); - - this.saganUpdater.updateSagan(new File("."), "master", version("1.0.0.RC1"), - version("1.0.0.RC1"), projects); - - then(this.saganClient).should(BDDMockito.never()) - .patchProject(BDDMockito.any(Project.class)); - - } - - private Project a2_0_0_ReleaseProject() { - Project project = new Project(); - Release release = new Release(); - release.version = "2.0.0.RELEASE"; - release.current = true; - project.projectReleases = Collections.singletonList(release); - return project; - } - - @Test - public void should_not_update_docs_for_sagan_when_files_exist_but_content_does_not_differ() - throws IOException { - Project project = a2_0_0_ReleaseProject(); - project.rawOverview = "new overview"; - project.rawBootConfig = "new boot"; - given(this.saganClient.updateRelease(BDDMockito.anyString(), - BDDMockito.anyList())).willReturn(project); - - Path tmp = Files.createTempDirectory("releaser-test"); - createFile(tmp, "sagan-index.adoc", "new overview"); - createFile(tmp, "sagan-boot.adoc", "new boot"); - SaganUpdater saganUpdater = new SaganUpdater(this.saganClient, this.properties) { - @Override - File docsModule(File projectFile) { - return tmp.toFile(); - } - }; - - saganUpdater.updateSagan(new File("."), "master", version("3.0.0.RC1"), - version("3.0.0.RC1"), projects); - - then(this.saganClient).should(BDDMockito.never()) - .patchProject(BDDMockito.any(Project.class)); - } - - @Test - public void should_update_docs_for_sagan_when_current_version_newer_and_only_overview_adoc_exists() - throws IOException { - given(this.saganClient.updateRelease(BDDMockito.anyString(), - BDDMockito.anyList())).willReturn(a2_0_0_ReleaseProject()); - - Path tmp = Files.createTempDirectory("releaser-test"); - createFile(tmp, "sagan-index.adoc", "new text"); - SaganUpdater saganUpdater = new SaganUpdater(this.saganClient, this.properties) { - @Override - File docsModule(File projectFile) { - return tmp.toFile(); - } - }; - - saganUpdater.updateSagan(new File("."), "master", version("3.0.0.RC1"), - version("3.0.0.RC1"), projects); - - then(this.saganClient).should().patchProject( - BDDMockito.argThat(argument -> "new text".equals(argument.rawOverview))); - } - - @Test - public void should_update_docs_for_sagan_when_current_version_newer_and_only_boot_adoc_exists() - throws IOException { - given(this.saganClient.updateRelease(BDDMockito.anyString(), - BDDMockito.anyList())).willReturn(a2_0_0_ReleaseProject()); - - Path tmp = Files.createTempDirectory("releaser-test"); - createFile(tmp, "sagan-boot.adoc", "new text"); - SaganUpdater saganUpdater = new SaganUpdater(this.saganClient, this.properties) { - @Override - File docsModule(File projectFile) { - return tmp.toFile(); - } - }; - - saganUpdater.updateSagan(new File("."), "master", version("3.0.0.RC1"), - version("3.0.0.RC1"), projects); - - then(this.saganClient).should().patchProject(BDDMockito - .argThat(argument -> "new text".equals(argument.rawBootConfig))); - } - - private void createFile(Path tmp, String filename, String text) throws IOException { - File overviewAdoc = new File(tmp.toString(), filename); - overviewAdoc.createNewFile(); - Files.write(overviewAdoc.toPath(), text.getBytes()); - } - - private ProjectVersion version(String version) { - return new ProjectVersion("foo", version); - } - - @Test - public void should_update_sagan_from_main() { - ProjectVersion projectVersion = version("1.0.0.BUILD-SNAPSHOT"); - - this.saganUpdater.updateSagan(new File("."), "main", projectVersion, - projectVersion, projects); - - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("1.0.0.BUILD-SNAPSHOT", - "https://cloud.spring.io/foo/foo.html", "SNAPSHOT"))); - } - - @Test - public void should_update_sagan_from_release_version() { - ProjectVersion projectVersion = version("1.0.0.RELEASE"); - - this.saganUpdater.updateSagan(new File("."), "main", projectVersion, - projectVersion, projects); - - then(this.saganClient).should().deleteRelease("foo", "1.0.0.RC1"); - then(this.saganClient).should().deleteRelease("foo", "1.0.0.BUILD-SNAPSHOT"); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("1.0.0.RELEASE", - "https://cloud.spring.io/spring-cloud-static/foo/{version}/", - "GENERAL_AVAILABILITY"))); - then(this.saganClient).should().deleteRelease("foo", "1.0.0.BUILD-SNAPSHOT"); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("1.0.1.BUILD-SNAPSHOT", - "https://cloud.spring.io/foo/foo.html", "SNAPSHOT"))); - } - - @Test - public void should_update_sagan_from_non_main() { - ProjectVersion projectVersion = version("1.1.0.BUILD-SNAPSHOT"); - - this.saganUpdater.updateSagan(new File("."), "1.1.x", projectVersion, - projectVersion, projects); - - then(this.saganClient).should(never()).deleteRelease(anyString(), anyString()); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("1.1.0.BUILD-SNAPSHOT", - "https://cloud.spring.io/foo/1.1.x/", "SNAPSHOT"))); - } - - private ArgumentMatcher> withReleaseUpdate(final String version, - final String refDocUrl, final String releaseStatus) { - return argument -> { - ReleaseUpdate item = argument.get(0); - return "foo".equals(item.artifactId) - && releaseStatus.equals(item.releaseStatus) - && version.equals(item.version) && refDocUrl.equals(item.apiDocUrl) - && refDocUrl.equals(item.refDocUrl) && item.current; - }; - } - -} diff --git a/releaser-core/src/test/java/releaser/internal/sagan/SaganUpdaterTest.java b/releaser-core/src/test/java/releaser/internal/sagan/SaganUpdaterTest.java index 806a31ab..46109807 100644 --- a/releaser-core/src/test/java/releaser/internal/sagan/SaganUpdaterTest.java +++ b/releaser-core/src/test/java/releaser/internal/sagan/SaganUpdaterTest.java @@ -20,22 +20,25 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.List; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentMatcher; -import org.mockito.BDDMockito; -import org.mockito.Mockito; import releaser.internal.ReleaserProperties; import releaser.internal.project.ProjectVersion; import releaser.internal.project.Projects; +import releaser.internal.tech.ExecutionResult; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; /** @@ -43,7 +46,7 @@ import static org.mockito.Mockito.never; */ public class SaganUpdaterTest { - SaganClient saganClient = Mockito.mock(SaganClient.class); + SaganClient saganClient = mock(SaganClient.class); ReleaserProperties properties = new ReleaserProperties(); @@ -51,20 +54,20 @@ public class SaganUpdaterTest { Projects projects = new Projects(); + private Project project; + @Before public void setup() { - Project project = new Project(); - project.projectReleases.addAll(Arrays.asList(release("2.2.0.RC1"), - release("2.3.0.BUILD-SNAPSHOT"), release("2.2.0.M4"))); - BDDMockito.given(this.saganClient.getProject(anyString())).willReturn(project); + project = new Project(); + project.setReleases(Arrays.asList(release("2.2.0-RC1"), release("2.3.0-SNAPSHOT"), release("2.2.0-M4"))); this.properties.getSagan().setUpdateSagan(true); this.saganUpdater = new SaganUpdater(this.saganClient, this.properties); } private Release release(String version) { Release release = new Release(); - release.version = version; - release.current = true; + release.setVersion(version); + // release.setCurrent(true); return release; } @@ -72,64 +75,59 @@ public class SaganUpdaterTest { public void should_not_update_sagan_when_switch_is_off() { this.properties.getSagan().setUpdateSagan(false); - this.saganUpdater.updateSagan(new File("."), "master", version("2.2.0.M1"), - version("2.2.0.M1"), projects); + ExecutionResult result = this.saganUpdater.updateSagan(new File("."), "main", version("2.2.0-M1"), + version("2.2.0-M1"), projects); + assertThat(result.isSkipped()).isTrue(); - then(this.saganClient).shouldHaveZeroInteractions(); + then(this.saganClient).shouldHaveNoInteractions(); } @Test public void should_update_sagan_releases_for_milestone() { - this.saganUpdater.updateSagan(new File("."), "master", version("2.2.0.M1"), - version("2.2.0.M1"), projects); + given(this.saganClient.addRelease(eq("foo"), any())).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("2.2.0-M1")); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("2.2.0.M1", - "https://cloud.spring.io/spring-cloud-static/foo/{version}/reference/html/", - "PRERELEASE"))); + ExecutionResult result = this.saganUpdater.updateSagan(new File("."), "main", version("2.2.0-M1"), + version("2.2.0-M1"), projects); + assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); + + then(this.saganClient).should().addRelease(eq("foo"), + argThat(withReleaseUpdate("2.2.0-M1", "https://docs.spring.io/foo/docs/{version}/reference/html/"))); } @Test public void should_update_sagan_releases_for_rc() { - this.saganUpdater.updateSagan(new File("."), "master", version("2.2.0.RC1"), - version("2.2.0.RC1"), projects); + given(this.saganClient.addRelease(anyString(), any())).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("2.2.0-RC1")); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("2.2.0.RC1", - "https://cloud.spring.io/spring-cloud-static/foo/{version}/reference/html/", - "PRERELEASE"))); + ExecutionResult result = this.saganUpdater.updateSagan(new File("."), "main", version("2.2.0-RC1"), + version("2.2.0-RC1"), projects); + assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); + + then(this.saganClient).should().addRelease(eq("foo"), + argThat(withReleaseUpdate("2.2.0-RC1", "https://docs.spring.io/foo/docs/{version}/reference/html/"))); } @Test public void should_not_update_docs_for_sagan_when_current_version_older() { - given(this.saganClient.updateRelease(BDDMockito.anyString(), - BDDMockito.anyList())).willReturn(a2_0_0_ReleaseProject()); + given(this.saganClient.addRelease(anyString(), any())).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("2.2.0-RC1")); - this.saganUpdater.updateSagan(new File("."), "master", version("2.2.0.RC1"), - version("2.2.0.RC1"), projects); + ExecutionResult result = this.saganUpdater.updateSagan(new File("."), "main", version("2.2.0-RC1"), + version("2.2.0-RC1"), projects); + assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); - then(this.saganClient).should(BDDMockito.never()) - .patchProject(BDDMockito.any(Project.class)); + then(this.saganClient).should(never()).patchProject(any(Project.class)); } - private Project a2_0_0_ReleaseProject() { - Project project = new Project(); - Release release = new Release(); - release.version = "2.0.0.RELEASE"; - release.current = true; - project.projectReleases = Collections.singletonList(release); - return project; - } - @Test - public void should_not_update_docs_for_sagan_when_files_exist_but_content_does_not_differ() - throws IOException { - Project project = a2_0_0_ReleaseProject(); - project.rawOverview = "new overview"; - project.rawBootConfig = "new boot"; - given(this.saganClient.updateRelease(BDDMockito.anyString(), - BDDMockito.anyList())).willReturn(project); + public void should_not_update_docs_for_sagan_when_files_exist_but_content_does_not_differ() throws IOException { + given(this.saganClient.addRelease(anyString(), any())).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("3.0.0-RC1")); Path tmp = Files.createTempDirectory("releaser-test"); createFile(tmp, "sagan-index.adoc", "new overview"); @@ -141,18 +139,19 @@ public class SaganUpdaterTest { } }; - saganUpdater.updateSagan(new File("."), "master", version("3.0.0.RC1"), - version("3.0.0.RC1"), projects); + ExecutionResult result = saganUpdater.updateSagan(new File("."), "main", version("3.0.0-RC1"), + version("3.0.0-RC1"), projects); + assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); - then(this.saganClient).should(BDDMockito.never()) - .patchProject(BDDMockito.any(Project.class)); + then(this.saganClient).should(never()).patchProject(any(Project.class)); } @Test public void should_update_docs_for_sagan_when_current_version_newer_and_only_overview_adoc_exists() throws IOException { - given(this.saganClient.updateRelease(BDDMockito.anyString(), - BDDMockito.anyList())).willReturn(a2_0_0_ReleaseProject()); + given(this.saganClient.addRelease(anyString(), any())).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("3.0.0-RC1")); Path tmp = Files.createTempDirectory("releaser-test"); createFile(tmp, "sagan-index.adoc", "new text"); @@ -163,18 +162,19 @@ public class SaganUpdaterTest { } }; - saganUpdater.updateSagan(new File("."), "master", version("3.0.0.RC1"), - version("3.0.0.RC1"), projects); + ExecutionResult result = saganUpdater.updateSagan(new File("."), "main", version("3.0.0-RC1"), + version("3.0.0-RC1"), projects); + assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); - then(this.saganClient).should().patchProject( - BDDMockito.argThat(argument -> "new text".equals(argument.rawOverview))); + // FIXME: then(this.saganClient).should().patchProject(argThat(argument -> "new + // text".equals(argument.rawOverview))); } @Test - public void should_update_docs_for_sagan_when_current_version_newer_and_only_boot_adoc_exists() - throws IOException { - given(this.saganClient.updateRelease(BDDMockito.anyString(), - BDDMockito.anyList())).willReturn(a2_0_0_ReleaseProject()); + public void should_update_docs_for_sagan_when_current_version_newer_and_only_boot_adoc_exists() throws IOException { + given(this.saganClient.addRelease(anyString(), any())).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("3.0.0-RC1")); Path tmp = Files.createTempDirectory("releaser-test"); createFile(tmp, "sagan-boot.adoc", "new text"); @@ -185,11 +185,13 @@ public class SaganUpdaterTest { } }; - saganUpdater.updateSagan(new File("."), "master", version("3.0.0.RC1"), - version("3.0.0.RC1"), projects); + ExecutionResult result = saganUpdater.updateSagan(new File("."), "main", version("3.0.0-RC1"), + version("3.0.0-RC1"), projects); + assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); - then(this.saganClient).should().patchProject(BDDMockito - .argThat(argument -> "new text".equals(argument.rawBootConfig))); + // FIXME: then(this.saganClient).should().patchProject(argThat(argument -> "new + // text".equals(argument.rawBootConfig))); } private void createFile(Path tmp, String filename, String text) throws IOException { @@ -204,57 +206,80 @@ public class SaganUpdaterTest { @Test public void should_update_sagan_from_main() { - ProjectVersion projectVersion = version("2.2.0.BUILD-SNAPSHOT"); + ProjectVersion projectVersion = version("2.4.0-SNAPSHOT"); + given(this.saganClient.addRelease(anyString(), any())).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("2.4.0-SNAPSHOT")); - this.saganUpdater.updateSagan(new File("."), "main", projectVersion, - projectVersion, projects); + Project updated = new Project(); + updated.setReleases(new ArrayList<>(project.getReleases())); + updated.getReleases().add(release(projectVersion.version)); + given(this.saganClient.getProject(anyString())).willReturn(updated); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("2.2.0.BUILD-SNAPSHOT", - "https://cloud.spring.io/foo/reference/html/", "SNAPSHOT"))); + ExecutionResult result = this.saganUpdater.updateSagan(new File("."), "main", projectVersion, projectVersion, + projects); + // FIXME: assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); + + then(this.saganClient).should().addRelease(eq("foo"), argThat( + withReleaseUpdate("2.4.0-SNAPSHOT", "https://docs.spring.io/foo/docs/{version}/reference/html/"))); } @Test public void should_update_sagan_from_release_version() { - ProjectVersion projectVersion = version("2.2.0.RELEASE"); + ProjectVersion projectVersion = version("2.2.0"); + given(this.saganClient.addRelease(eq("foo"), any())).willReturn(true); + given(this.saganClient.deleteRelease("foo", "2.2.0-RC1")).willReturn(true); + given(this.saganClient.deleteRelease("foo", "2.2.0-SNAPSHOT")).willReturn(true); + given(this.saganClient.deleteRelease("foo", "2.2.0-M4")).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("2.2.0")); - this.saganUpdater.updateSagan(new File("."), "main", projectVersion, - projectVersion, projects); + ExecutionResult result = this.saganUpdater.updateSagan(new File("."), "main", projectVersion, projectVersion, + projects); + assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); - then(this.saganClient).should().deleteRelease("foo", "2.2.0.RC1"); - then(this.saganClient).should().deleteRelease("foo", "2.2.0.BUILD-SNAPSHOT"); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("2.2.0.RELEASE", - "https://cloud.spring.io/spring-cloud-static/foo/{version}/reference/html/", - "GENERAL_AVAILABILITY"))); - then(this.saganClient).should().deleteRelease("foo", "2.2.0.BUILD-SNAPSHOT"); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("2.2.1.BUILD-SNAPSHOT", - "https://cloud.spring.io/foo/reference/html/", "SNAPSHOT"))); + then(this.saganClient).should().deleteRelease("foo", "2.2.0-RC1"); + then(this.saganClient).should().deleteRelease("foo", "2.2.0-SNAPSHOT"); + then(this.saganClient).should().addRelease(eq("foo"), + argThat(withReleaseUpdate("2.2.0", "https://docs.spring.io/foo/docs/{version}/reference/html/"))); + then(this.saganClient).should().deleteRelease("foo", "2.2.0-SNAPSHOT"); + then(this.saganClient).should().addRelease(eq("foo"), argThat( + withReleaseUpdate("2.2.1-SNAPSHOT", "https://docs.spring.io/foo/docs/{version}/reference/html/"))); } @Test - public void should_update_sagan_from_non_master() { - ProjectVersion projectVersion = version("2.3.0.BUILD-SNAPSHOT"); + public void should_update_sagan_from_non_main() { + ProjectVersion projectVersion = version("2.3.0-SNAPSHOT"); + given(this.saganClient.addRelease(eq("foo"), any())).willReturn(true); + given(this.saganClient.getProject("foo")).willReturn(projectWithNewRelease("2.3.0-SNAPSHOT")); - this.saganUpdater.updateSagan(new File("."), "2.3.x", projectVersion, - projectVersion, projects); + ExecutionResult result = this.saganUpdater.updateSagan(new File("."), "2.3.x", projectVersion, projectVersion, + projects); + assertThat(result.isSkipped()).isFalse(); + assertThat(result.isSuccess()).isTrue(); then(this.saganClient).should(never()).deleteRelease(anyString(), anyString()); - then(this.saganClient).should().updateRelease(BDDMockito.eq("foo"), - BDDMockito.argThat(withReleaseUpdate("2.3.0.BUILD-SNAPSHOT", - "https://cloud.spring.io/foo/2.3.x/reference/html/", - "SNAPSHOT"))); + then(this.saganClient).should().addRelease(eq("foo"), argThat( + withReleaseUpdate("2.3.0-SNAPSHOT", "https://docs.spring.io/foo/docs/{version}/reference/html/"))); } - private ArgumentMatcher> withReleaseUpdate(final String version, - final String refDocUrl, final String releaseStatus) { + private Project projectWithNewRelease(String version) { + Project p = new Project(); + p.setName(project.getName()); + p.setSlug(project.getSlug()); + p.setRepositoryUrl(project.getRepositoryUrl()); + p.setReleases(new ArrayList<>(project.getReleases())); + Release release = release(version); + release.setCurrent(true); + p.getReleases().add(release); + return p; + } + + private ArgumentMatcher withReleaseUpdate(final String version, final String refDocUrl) { return argument -> { - ReleaseUpdate item = argument.get(0); - return "foo".equals(item.artifactId) - && releaseStatus.equals(item.releaseStatus) - && version.equals(item.version) && refDocUrl.equals(item.apiDocUrl) - && refDocUrl.equals(item.refDocUrl) && item.current; + ReleaseInput item = argument; + return version.equals(item.getVersion()) && item.getApiDocUrl() == null + && refDocUrl.equals(item.getReferenceDocUrl()); }; } diff --git a/releaser-core/src/test/java/releaser/internal/template/TemplateGeneratorTests.java b/releaser-core/src/test/java/releaser/internal/template/TemplateGeneratorTests.java index 761f76d0..fb97cfae 100644 --- a/releaser-core/src/test/java/releaser/internal/template/TemplateGeneratorTests.java +++ b/releaser-core/src/test/java/releaser/internal/template/TemplateGeneratorTests.java @@ -38,8 +38,7 @@ public class TemplateGeneratorTests { ReleaserProperties props = SpringCloudReleaserProperties.get(); - ProjectGitHubHandler handler = new ProjectGitHubHandler(this.props, - Collections.emptyList()) { + ProjectGitHubHandler handler = new ProjectGitHubHandler(this.props, Collections.emptyList()) { @Override public String milestoneUrl(ProjectVersion releaseVersion) { if (releaseVersion.projectName.equals("spring-cloud-foo")) { @@ -53,8 +52,7 @@ public class TemplateGeneratorTests { public void should_generate_email_from_template_for_tag_with_v_prefix() { this.props.getPom().setBranch("vDalston.RELEASE"); - File generatedMail = new TemplateGenerator(this.props, this.handler) - .email(new Projects()); + File generatedMail = new TemplateGenerator(this.props, this.handler).email(new Projects()); then(generatedMail).hasContent(expectedEmail()); } @@ -63,9 +61,8 @@ public class TemplateGeneratorTests { public void should_generate_email_from_template_when_output_folder_is_missing() { this.props.getPom().setBranch("vDalston.RELEASE"); - File generatedMail = new TemplateGenerator(this.props, - new File("target/foo/bar/baz/template.txt"), this.handler) - .email(new Projects()); + File generatedMail = new TemplateGenerator(this.props, new File("target/foo/bar/baz/template.txt"), + this.handler).email(new Projects()); then(generatedMail).hasContent(expectedEmail()); } @@ -74,8 +71,7 @@ public class TemplateGeneratorTests { public void should_generate_email_from_template_for_tag_without_v_prefix() { this.props.getPom().setBranch("Dalston.RELEASE"); - File generatedMail = new TemplateGenerator(this.props, this.handler) - .email(new Projects()); + File generatedMail = new TemplateGenerator(this.props, this.handler).email(new Projects()); then(generatedMail).hasContent(expectedEmail()); } @@ -84,8 +80,7 @@ public class TemplateGeneratorTests { public void should_generate_tweet_from_template_for_tag_with_v_prefix() { this.props.getPom().setBranch("vDalston.RELEASE"); - File generatedTweet = new TemplateGenerator(this.props, this.handler) - .tweet(new Projects()); + File generatedTweet = new TemplateGenerator(this.props, this.handler).tweet(new Projects()); then(generatedTweet).hasContent(expectedTweet()); } @@ -94,15 +89,13 @@ public class TemplateGeneratorTests { public void should_generate_tweet_from_template_for_tag_without_v_prefix() { this.props.getPom().setBranch("Dalston.RELEASE"); - File generatedTweet = new TemplateGenerator(this.props, this.handler) - .tweet(new Projects()); + File generatedTweet = new TemplateGenerator(this.props, this.handler).tweet(new Projects()); then(generatedTweet).hasContent(expectedTweet()); } @Test - public void should_generate_blog_from_template_for_tag_with_v_prefix_release() - throws IOException { + public void should_generate_blog_from_template_for_tag_with_v_prefix_release() throws IOException { this.props.getPom().setBranch("vDalston.RELEASE"); Projects projects = new Projects(new HashSet() { { @@ -112,23 +105,18 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("General Availability (RELEASE) of the [Spring Cloud Dalston]") - .contains("The release can be found in [Maven Central]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0.RELEASE | ([issues](https://foo.bar.com))") + then(content(generatedBlog)).contains("General Availability (RELEASE) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Maven Central]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0.RELEASE | ([issues](https://foo.bar.com))") .contains("| Spring Cloud Foo | 1.0.2.RELEASE |  ") - .contains("Dalston.RELEASE").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE'"); + .contains("Dalston.RELEASE") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE'"); } @Test - public void should_generate_blog_from_template_for_tag_without_v_prefix_release() - throws IOException { + public void should_generate_blog_from_template_for_tag_without_v_prefix_release() throws IOException { this.props.getPom().setBranch("Dalston.RELEASE"); Projects projects = new Projects(new HashSet() { { @@ -137,22 +125,17 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("General Availability (RELEASE) of the [Spring Cloud Dalston]") - .contains("The release can be found in [Maven Central]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0.RELEASE | ([issues](https://foo.bar.com))") - .contains("Dalston.RELEASE").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE'"); + then(content(generatedBlog)).contains("General Availability (RELEASE) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Maven Central]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0.RELEASE | ([issues](https://foo.bar.com))") + .contains("Dalston.RELEASE") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE'"); } @Test - public void should_generate_blog_from_template_for_tag_without_v_prefix_release_using_calver() - throws IOException { + public void should_generate_blog_from_template_for_tag_without_v_prefix_release_using_calver() throws IOException { this.props.getPom().setBranch("2020.0.5"); Projects projects = new Projects(new HashSet() { { @@ -161,22 +144,17 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("General Availability (RELEASE) of the [Spring Cloud 2020.0.5]") - .contains("The release can be found in [Maven Central]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0 | ([issues](https://foo.bar.com))") - .contains("2020.0.5").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2020.0.5'"); + then(content(generatedBlog)).contains("General Availability (RELEASE) of the [Spring Cloud 2020.0.5]") + .contains("The release can be found in [Maven Central]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0 | ([issues](https://foo.bar.com))") + .contains("2020.0.5") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2020.0.5'"); } @Test - public void should_generate_sr_blog_from_template_for_tag_with_v_prefix_release() - throws IOException { + public void should_generate_sr_blog_from_template_for_tag_with_v_prefix_release() throws IOException { this.props.getPom().setBranch("vDalston.SR1"); Projects projects = new Projects(new HashSet() { { @@ -185,22 +163,17 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("Service Release 1 (SR1) of the [Spring Cloud Dalston]") - .contains("The release can be found in [Maven Central]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0.RELEASE | ([issues](https://foo.bar.com))") - .contains("Dalston.SR1").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.SR1'"); + then(content(generatedBlog)).contains("Service Release 1 (SR1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Maven Central]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0.RELEASE | ([issues](https://foo.bar.com))") + .contains("Dalston.SR1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.SR1'"); } @Test - public void should_generate_sr_blog_from_template_for_tag_without_v_prefix_release() - throws IOException { + public void should_generate_sr_blog_from_template_for_tag_without_v_prefix_release() throws IOException { this.props.getPom().setBranch("Dalston.SR1"); Projects projects = new Projects(new HashSet() { { @@ -209,22 +182,17 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("Service Release 1 (SR1) of the [Spring Cloud Dalston]") - .contains("The release can be found in [Maven Central]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0.RELEASE | ([issues](https://foo.bar.com))") - .contains("Dalston.SR1").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.SR1'"); + then(content(generatedBlog)).contains("Service Release 1 (SR1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Maven Central]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0.RELEASE | ([issues](https://foo.bar.com))") + .contains("Dalston.SR1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.SR1'"); } @Test - public void should_generate_milestone_blog_from_template_for_tag_with_v_prefix_release() - throws IOException { + public void should_generate_milestone_blog_from_template_for_tag_with_v_prefix_release() throws IOException { this.props.getPom().setBranch("vDalston.M1"); Projects projects = new Projects(new HashSet() { { @@ -233,24 +201,18 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("Milestone 1 (M1) of the [Spring Cloud Dalston]") - .contains("The release can be found in [Spring Milestone]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0.M1 | ([issues](https://foo.bar.com))") - .contains("spring-milestones") - .contains("url 'https://repo.spring.io/milestone'") - .contains("Dalston.M1").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.M1'"); + then(content(generatedBlog)).contains("Milestone 1 (M1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Spring Milestone]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0.M1 | ([issues](https://foo.bar.com))") + .contains("spring-milestones").contains("url 'https://repo.spring.io/milestone'") + .contains("Dalston.M1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.M1'"); } @Test - public void should_generate_milestone_blog_from_template_for_tag_without_v_prefix_release() - throws IOException { + public void should_generate_milestone_blog_from_template_for_tag_without_v_prefix_release() throws IOException { this.props.getPom().setBranch("Dalston.M1"); Projects projects = new Projects(new HashSet() { { @@ -259,19 +221,14 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("Milestone 1 (M1) of the [Spring Cloud Dalston]") - .contains("The release can be found in [Spring Milestone]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0.M1 | ([issues](https://foo.bar.com))") - .contains("spring-milestones") - .contains("url 'https://repo.spring.io/milestone'") - .contains("Dalston.M1").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.M1'"); + then(content(generatedBlog)).contains("Milestone 1 (M1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Spring Milestone]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0.M1 | ([issues](https://foo.bar.com))") + .contains("spring-milestones").contains("url 'https://repo.spring.io/milestone'") + .contains("Dalston.M1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.M1'"); } @Test @@ -285,24 +242,18 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("Milestone 1 (M1) of the [Spring Cloud 2020.0.0]") - .contains("The release can be found in [Spring Milestone]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0-M1 | ([issues](https://foo.bar.com))") - .contains("spring-milestones") - .contains("url 'https://repo.spring.io/milestone'") - .contains("2020.0.0-M1").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2020.0.0-M1'"); + then(content(generatedBlog)).contains("Milestone 1 (M1) of the [Spring Cloud 2020.0.0]") + .contains("The release can be found in [Spring Milestone]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0-M1 | ([issues](https://foo.bar.com))") + .contains("spring-milestones").contains("url 'https://repo.spring.io/milestone'") + .contains("2020.0.0-M1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2020.0.0-M1'"); } @Test - public void should_generate_rc_blog_from_template_for_tag_with_v_prefix_release() - throws IOException { + public void should_generate_rc_blog_from_template_for_tag_with_v_prefix_release() throws IOException { this.props.getPom().setBranch("vDalston.RC1"); Projects projects = new Projects(new HashSet() { { @@ -311,24 +262,18 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("Release Candidate 1 (RC1) of the [Spring Cloud Dalston]") - .contains("The release can be found in [Spring Milestone]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0.RC1 | ([issues](https://foo.bar.com))") - .contains("spring-milestones") - .contains("url 'https://repo.spring.io/milestone'") - .contains("Dalston.RC1").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RC1'"); + then(content(generatedBlog)).contains("Release Candidate 1 (RC1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Spring Milestone]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0.RC1 | ([issues](https://foo.bar.com))") + .contains("spring-milestones").contains("url 'https://repo.spring.io/milestone'") + .contains("Dalston.RC1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RC1'"); } @Test - public void should_generate_rc_blog_from_template_for_tag_without_v_prefix_release() - throws IOException { + public void should_generate_rc_blog_from_template_for_tag_without_v_prefix_release() throws IOException { this.props.getPom().setBranch("Dalston.RC1"); Projects projects = new Projects(new HashSet() { { @@ -337,24 +282,18 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("Release Candidate 1 (RC1) of the [Spring Cloud Dalston]") - .contains("The release can be found in [Spring Milestone]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0.RC1 | ([issues](https://foo.bar.com))") - .contains("spring-milestones") - .contains("url 'https://repo.spring.io/milestone'") - .contains("Dalston.RC1").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RC1'"); + then(content(generatedBlog)).contains("Release Candidate 1 (RC1) of the [Spring Cloud Dalston]") + .contains("The release can be found in [Spring Milestone]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0.RC1 | ([issues](https://foo.bar.com))") + .contains("spring-milestones").contains("url 'https://repo.spring.io/milestone'") + .contains("Dalston.RC1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RC1'"); } @Test - public void should_generate_rc_blog_from_template_for_tag_without_v_prefix_release_calver() - throws IOException { + public void should_generate_rc_blog_from_template_for_tag_without_v_prefix_release_calver() throws IOException { this.props.getPom().setBranch("2020.0.0-RC1"); Projects projects = new Projects(new HashSet() { { @@ -363,26 +302,19 @@ public class TemplateGeneratorTests { } }); - File generatedBlog = new TemplateGenerator(this.props, this.handler) - .blog(projects); + File generatedBlog = new TemplateGenerator(this.props, this.handler).blog(projects); - then(content(generatedBlog)) - .contains("Release Candidate 1 (RC1) of the [Spring Cloud 2020.0.0]") - .contains("The release can be found in [Spring Milestone]") - .contains("### Spring Cloud Sleuth") - .contains( - "| Spring Cloud Sleuth | 1.0.0-RC1 | ([issues](https://foo.bar.com))") - .contains("spring-milestones") - .contains("url 'https://repo.spring.io/milestone'") - .contains("2020.0.0-RC1").contains( - "mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2020.0.0-RC1'"); + then(content(generatedBlog)).contains("Release Candidate 1 (RC1) of the [Spring Cloud 2020.0.0]") + .contains("The release can be found in [Spring Milestone]").contains("### Spring Cloud Sleuth") + .contains("| Spring Cloud Sleuth | 1.0.0-RC1 | ([issues](https://foo.bar.com))") + .contains("spring-milestones").contains("url 'https://repo.spring.io/milestone'") + .contains("2020.0.0-RC1") + .contains("mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2020.0.0-RC1'"); } @Test - public void should_generate_release_notes_template_when_url_exists() - throws IOException { - ProjectGitHubHandler handler = new ProjectGitHubHandler(this.props, - Collections.emptyList()) { + public void should_generate_release_notes_template_when_url_exists() throws IOException { + ProjectGitHubHandler handler = new ProjectGitHubHandler(this.props, Collections.emptyList()) { @Override public String milestoneUrl(ProjectVersion releaseVersion) { return "https://foo.bar.com?closed=1"; @@ -397,13 +329,11 @@ public class TemplateGeneratorTests { } }); - File generatedOutput = new TemplateGenerator(this.props, handler) - .releaseNotes(projects); + File generatedOutput = new TemplateGenerator(this.props, handler).releaseNotes(projects); - then(content(generatedOutput)).contains("# Dalston.RC1").contains( - "Spring Cloud Sleuth `1.0.0.RC1` ([issues](https://foo.bar.com?closed=1))") - .contains( - "Spring Cloud Consul `1.0.1.RC1` ([issues](https://foo.bar.com?closed=1))") + then(content(generatedOutput)).contains("# Dalston.RC1") + .contains("Spring Cloud Sleuth `1.0.0.RC1` ([issues](https://foo.bar.com?closed=1))") + .contains("Spring Cloud Consul `1.0.1.RC1` ([issues](https://foo.bar.com?closed=1))") .doesNotContain("Boot"); } @@ -412,8 +342,7 @@ public class TemplateGeneratorTests { } private String expectedEmail() { - return "Title:\n" + "Spring Cloud Dalston.RELEASE available\n\n" + "Content:\n" - + "All,\n" + "\n" + return "Title:\n" + "Spring Cloud Dalston.RELEASE available\n\n" + "Content:\n" + "All,\n" + "\n" + "On behalf of the team and the community, I'm excited to announce Spring Cloud Dalston RELEASE Train release.\n" + "\n" + "link to blog post\n" + "link to twitter\n\n" + "Cheers,\n"; } diff --git a/releaser-core/src/test/java/releaser/internal/versions/VersionsFromBomFetcherTests.java b/releaser-core/src/test/java/releaser/internal/versions/VersionsFromBomFetcherTests.java index d279bc44..d5be80bd 100644 --- a/releaser-core/src/test/java/releaser/internal/versions/VersionsFromBomFetcherTests.java +++ b/releaser-core/src/test/java/releaser/internal/versions/VersionsFromBomFetcherTests.java @@ -49,17 +49,13 @@ class VersionsFromBomFetcherTests { } @Test - void should_return_false_when_current_version_is_not_present_in_the_bom() - throws URISyntaxException { - ProjectVersion projectVersion = new ProjectVersion("spring-cloud-non-existant", - "1.0.0.RELEASE"); - URI initilizrUri = VersionsFromBomFetcherTests.class - .getResource("/raw/initializr.yml").toURI(); + void should_return_false_when_current_version_is_not_present_in_the_bom() throws URISyntaxException { + ProjectVersion projectVersion = new ProjectVersion("spring-cloud-non-existant", "1.0.0.RELEASE"); + URI initilizrUri = VersionsFromBomFetcherTests.class.getResource("/raw/initializr.yml").toURI(); ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setUpdateSpringGuides(true); properties.getVersions().setAllVersionsFileUrl(initilizrUri.toString()); - properties.getGit().setReleaseTrainBomUrl( - file("/projects/spring-cloud-release/").toURI().toString()); + properties.getGit().setReleaseTrainBomUrl(file("/projects/spring-cloud-release/").toURI().toString()); ProjectPomUpdater updater = new ProjectPomUpdater(properties, new ArrayList<>()); VersionsFetcher versionsFetcher = new VersionsFetcher(properties, updater); @@ -70,8 +66,7 @@ class VersionsFromBomFetcherTests { @Test void should_return_false_when_current_version_is_not_ga() { - ProjectVersion projectVersion = new ProjectVersion("spring-cloud-contract", - "1.0.0.BUILD-SNAPSHOT"); + ProjectVersion projectVersion = new ProjectVersion("spring-cloud-contract", "1.0.0.BUILD-SNAPSHOT"); ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setUpdateSpringGuides(true); ProjectPomUpdater updater = new ProjectPomUpdater(properties, new ArrayList<>()); @@ -84,15 +79,13 @@ class VersionsFromBomFetcherTests { @Test void should_return_false_when_exception_occurs_while_fetching_version_info() { - ProjectVersion projectVersion = new ProjectVersion("spring-cloud-contract", - "1.0.0.BUILD-SNAPSHOT"); + ProjectVersion projectVersion = new ProjectVersion("spring-cloud-contract", "1.0.0.BUILD-SNAPSHOT"); ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setUpdateSpringGuides(true); VersionsFetcher versionsFetcher = new VersionsFetcher(properties, new ProjectPomUpdater(properties, new ArrayList<>()) { @Override - public Projects retrieveVersionsFromReleaseTrainBom(String branch, - boolean updateFixedVersions) { + public Projects retrieveVersionsFromReleaseTrainBom(String branch, boolean updateFixedVersions) { throw new IllegalStateException("BOOM!"); } }); @@ -103,8 +96,7 @@ class VersionsFromBomFetcherTests { } private File localFile(String relativePath) throws URISyntaxException { - return new File( - VersionsFromBomFetcherTests.class.getResource(relativePath).toURI()); + return new File(VersionsFromBomFetcherTests.class.getResource(relativePath).toURI()); } private File file(String relativePath) { diff --git a/releaser-spring/pom.xml b/releaser-spring/pom.xml index e69f4558..5af6a319 100644 --- a/releaser-spring/pom.xml +++ b/releaser-spring/pom.xml @@ -59,6 +59,11 @@ spring-boot-starter-test test + + org.junit.vintage + junit-vintage-engine + test + diff --git a/releaser-spring/src/main/java/releaser/ReleaserCommandLineRunner.java b/releaser-spring/src/main/java/releaser/ReleaserCommandLineRunner.java index bb68dbc3..e1b6725a 100644 --- a/releaser-spring/src/main/java/releaser/ReleaserCommandLineRunner.java +++ b/releaser-spring/src/main/java/releaser/ReleaserCommandLineRunner.java @@ -32,8 +32,8 @@ public class ReleaserCommandLineRunner implements CommandLineRunner { private final Parser parser; - public ReleaserCommandLineRunner(SpringReleaser releaser, - ExecutionResultHandler executionResultHandler, Parser parser) { + public ReleaserCommandLineRunner(SpringReleaser releaser, ExecutionResultHandler executionResultHandler, + Parser parser) { this.releaser = releaser; this.executionResultHandler = executionResultHandler; this.parser = parser; diff --git a/releaser-spring/src/main/java/releaser/internal/buildsystem/BuildsystemConfiguration.java b/releaser-spring/src/main/java/releaser/internal/buildsystem/BuildsystemConfiguration.java index 247ba5d6..5cf26b30 100644 --- a/releaser-spring/src/main/java/releaser/internal/buildsystem/BuildsystemConfiguration.java +++ b/releaser-spring/src/main/java/releaser/internal/buildsystem/BuildsystemConfiguration.java @@ -36,8 +36,7 @@ class BuildsystemConfiguration { return new MavenBomParser(releaserProperties, customBomParsers(customBomParsers)); } - private List customBomParsers( - List customBomParsers) { + private List customBomParsers(List customBomParsers) { return customBomParsers == null ? new ArrayList<>() : customBomParsers; } @@ -45,14 +44,12 @@ class BuildsystemConfiguration { @ConditionalOnMissingBean BomParser gradleBomParser(ReleaserProperties releaserProperties, @Autowired(required = false) List customBomParsers) { - return new GradleBomParser(releaserProperties, - customBomParsers(customBomParsers)); + return new GradleBomParser(releaserProperties, customBomParsers(customBomParsers)); } @Bean @ConditionalOnMissingBean - ProjectPomUpdater pomUpdater(ReleaserProperties releaserProperties, - List bomParsers) { + ProjectPomUpdater pomUpdater(ReleaserProperties releaserProperties, List bomParsers) { return new ProjectPomUpdater(releaserProperties, bomParsers); } diff --git a/releaser-spring/src/main/java/releaser/internal/github/GithubConfiguration.java b/releaser-spring/src/main/java/releaser/internal/github/GithubConfiguration.java index 4160366e..a7ff9940 100644 --- a/releaser-spring/src/main/java/releaser/internal/github/GithubConfiguration.java +++ b/releaser-spring/src/main/java/releaser/internal/github/GithubConfiguration.java @@ -31,8 +31,7 @@ class GithubConfiguration { BeanPostProcessor cachingGithubBeanPostProcessor() { return new BeanPostProcessor() { @Override - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof RtGithub) { return new CachingGithub((Github) bean); } diff --git a/releaser-spring/src/main/java/releaser/internal/options/Options.java b/releaser-spring/src/main/java/releaser/internal/options/Options.java index 9837df92..b566b61a 100644 --- a/releaser-spring/src/main/java/releaser/internal/options/Options.java +++ b/releaser-spring/src/main/java/releaser/internal/options/Options.java @@ -60,14 +60,13 @@ public class Options implements Serializable { */ public String range = ""; - Options(Boolean metaRelease, Boolean fullRelease, Boolean interactive, Boolean dryRun, - List taskNames, String startFrom, String range) { + Options(Boolean metaRelease, Boolean fullRelease, Boolean interactive, Boolean dryRun, List taskNames, + String startFrom, String range) { this.metaRelease = metaRelease; this.fullRelease = fullRelease; this.interactive = interactive; this.dryRun = dryRun; - this.taskNames = taskNames.stream().map(this::removeQuotingChars) - .collect(Collectors.toList()); + this.taskNames = taskNames.stream().map(this::removeQuotingChars).collect(Collectors.toList()); this.startFrom = removeQuotingChars(startFrom); this.range = removeQuotingChars(range); } @@ -81,9 +80,8 @@ public class Options implements Serializable { @Override public String toString() { - return "Options{" + "metaRelease=" + this.metaRelease + ", fullRelease=" - + this.fullRelease + ", interactive=" + this.interactive + ", dryRun=" - + this.dryRun + ", taskNames=" + this.taskNames + ", startFrom='" + return "Options{" + "metaRelease=" + this.metaRelease + ", fullRelease=" + this.fullRelease + ", interactive=" + + this.interactive + ", dryRun=" + this.dryRun + ", taskNames=" + this.taskNames + ", startFrom='" + this.startFrom + '\'' + ", range='" + this.range + '\'' + '}'; } diff --git a/releaser-spring/src/main/java/releaser/internal/options/OptionsBuilder.java b/releaser-spring/src/main/java/releaser/internal/options/OptionsBuilder.java index e1924395..f416aaf1 100644 --- a/releaser-spring/src/main/java/releaser/internal/options/OptionsBuilder.java +++ b/releaser-spring/src/main/java/releaser/internal/options/OptionsBuilder.java @@ -71,8 +71,8 @@ public class OptionsBuilder { } public Options options() { - return new Options(this.metaRelease, this.fullRelease, this.interactive, - this.dryRun, this.taskNames, this.startFrom, this.range); + return new Options(this.metaRelease, this.fullRelease, this.interactive, this.dryRun, this.taskNames, + this.startFrom, this.range); } } diff --git a/releaser-spring/src/main/java/releaser/internal/sagan/SaganConfiguration.java b/releaser-spring/src/main/java/releaser/internal/sagan/SaganConfiguration.java index d7ed76c9..88d4d7a1 100644 --- a/releaser-spring/src/main/java/releaser/internal/sagan/SaganConfiguration.java +++ b/releaser-spring/src/main/java/releaser/internal/sagan/SaganConfiguration.java @@ -16,8 +16,6 @@ package releaser.internal.sagan; -import java.util.List; - import releaser.internal.ReleaserProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -44,8 +42,7 @@ class SaganConfiguration { @Bean @ConditionalOnMissingBean - @ConditionalOnProperty(value = "releaser.sagan.update-sagan", havingValue = "false", - matchIfMissing = true) + @ConditionalOnProperty(value = "releaser.sagan.update-sagan", havingValue = "false", matchIfMissing = true) SaganClient noOpSaganClient() { return new SaganClient() { @Override @@ -59,14 +56,13 @@ class SaganConfiguration { } @Override - public Release deleteRelease(String projectName, String releaseVersion) { - return null; + public boolean deleteRelease(String projectName, String releaseVersion) { + return false; } @Override - public Project updateRelease(String projectName, - List releaseUpdate) { - return null; + public boolean addRelease(String projectName, ReleaseInput releaseInput) { + return false; } @Override @@ -81,8 +77,7 @@ class SaganConfiguration { "In order to connect to Sagan you need to pass the Github OAuth token. " + "You can do it via the [--releaser.git.oauth-token=...] " + "command line argument or an env variable [export RELEASER_GIT_OAUTH_TOKEN=...]."); - return new RestTemplateBuilder() - .basicAuthentication(properties.getGit().getOauthToken(), "").build(); + return new RestTemplateBuilder().basicAuthentication(properties.getGit().getOauthToken(), "").build(); } } diff --git a/releaser-spring/src/main/java/releaser/internal/spring/Arguments.java b/releaser-spring/src/main/java/releaser/internal/spring/Arguments.java index f6875015..c5b4176e 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/Arguments.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/Arguments.java @@ -80,34 +80,29 @@ public final class Arguments implements Serializable { */ public final List processedProjects; - private Arguments(ProjectToRun thisProject, Projects projects, - ProjectVersion currentProjectFromBom) { + private Arguments(ProjectToRun thisProject, Projects projects, ProjectVersion currentProjectFromBom) { this.project = thisProject.thisProjectFolder; this.projects = projects; this.originalVersion = thisProject.originalVersion; - log.info("Creating Arguments for: " + thisProject.name() + "; Original version: " - + this.originalVersion); + log.info("Creating Arguments for: " + thisProject.name() + "; Original version: " + this.originalVersion); Assert.isTrue(this.originalVersion != null && this.originalVersion.version != null, "Original Version must not be null for project: " + thisProject.name()); this.versionFromBom = currentProjectFromBom; this.properties = thisProject.thisProjectReleaserProperties; this.options = thisProject.options; this.projectToRun = thisProject; - this.processedProjects = new LinkedList<>(Collections.singletonList( - new ProcessedProject(thisProject.thisProjectReleaserProperties, - this.versionFromBom, this.originalVersion))); + this.processedProjects = new LinkedList<>(Collections.singletonList(new ProcessedProject( + thisProject.thisProjectReleaserProperties, this.versionFromBom, this.originalVersion))); } // in this case the project will be the BOM - private Arguments(ProjectToRun thisProject, - List processedProjects) { + private Arguments(ProjectToRun thisProject, List processedProjects) { this.project = thisProject.thisProjectFolder; - this.projects = new Projects(processedProjects.stream() - .map(p -> p.newProjectVersion).collect(Collectors.toSet())); + this.projects = new Projects( + processedProjects.stream().map(p -> p.newProjectVersion).collect(Collectors.toSet())); this.originalVersion = thisProject.originalVersion; - log.info("Creating Arguments for: " + thisProject.name() + "; Original version: " - + this.originalVersion); + log.info("Creating Arguments for: " + thisProject.name() + "; Original version: " + this.originalVersion); Assert.isTrue(this.originalVersion != null && this.originalVersion.version != null, "Original Version must not be null for project: " + thisProject.name()); this.versionFromBom = thisProject.thisProjectVersionFromBom; @@ -118,41 +113,28 @@ public final class Arguments implements Serializable { } public static Arguments forProject(ProjectToRun thisProject) { - return new Arguments(thisProject, - thisProject.allProjectsFromBom.allProjectVersionsFromBom, + return new Arguments(thisProject, thisProject.allProjectsFromBom.allProjectVersionsFromBom, thisProject.allProjectsFromBom.currentProjectFromBom); } - public static Arguments forPostRelease(ReleaserProperties properties, - ProjectsToRun projectsToRun) { - List projects = projectsToRun.stream() - .map(ProjectToRun.ProjectToRunSupplier::get) + public static Arguments forPostRelease(ReleaserProperties properties, ProjectsToRun projectsToRun) { + List projects = projectsToRun.stream().map(ProjectToRun.ProjectToRunSupplier::get) .collect(Collectors.toCollection(LinkedList::new)); - List processedProjects = projectsToRunToProcessedProject( - projects); - ProjectToRun releaseTrainProject = projects.stream() - .filter(p -> isReleaseTrainProject(properties, p)).findFirst() - .orElseThrow( - () -> new IllegalStateException("Missing release train version")); + List processedProjects = projectsToRunToProcessedProject(projects); + ProjectToRun releaseTrainProject = projects.stream().filter(p -> isReleaseTrainProject(properties, p)) + .findFirst().orElseThrow(() -> new IllegalStateException("Missing release train version")); return new Arguments(releaseTrainProject, processedProjects); } - private static boolean isReleaseTrainProject(ReleaserProperties properties, - ProjectToRun p) { - return p.originalVersion.projectName - .equals(properties.getMetaRelease().getReleaseTrainProjectName()) - || properties.getMetaRelease().getReleaseTrainDependencyNames() - .contains(p.originalVersion.projectName) - || p.name() - .equals(properties.getMetaRelease().getReleaseTrainProjectName()); + private static boolean isReleaseTrainProject(ReleaserProperties properties, ProjectToRun p) { + return p.originalVersion.projectName.equals(properties.getMetaRelease().getReleaseTrainProjectName()) + || properties.getMetaRelease().getReleaseTrainDependencyNames().contains(p.originalVersion.projectName) + || p.name().equals(properties.getMetaRelease().getReleaseTrainProjectName()); } - private static List projectsToRunToProcessedProject( - List projects) { - return projects.stream() - .map(p -> new ProcessedProject(p.thisProjectReleaserProperties, - p.thisProjectVersionFromBom, p.originalVersion)) - .collect(Collectors.toCollection(LinkedList::new)); + private static List projectsToRunToProcessedProject(List projects) { + return projects.stream().map(p -> new ProcessedProject(p.thisProjectReleaserProperties, + p.thisProjectVersionFromBom, p.originalVersion)).collect(Collectors.toCollection(LinkedList::new)); } public ProjectVersion releaseTrain() { @@ -161,11 +143,9 @@ public final class Arguments implements Serializable { @Override public String toString() { - return "Arguments{" + "project=" + project + ", projects=" + projects - + ", originalVersion=" + originalVersion + ", versionFromBom=" - + versionFromBom + ", properties=" + properties + ", options=" + options - + ", projectToRun=" + projectToRun + ", processedProjects=" - + processedProjects + '}'; + return "Arguments{" + "project=" + project + ", projects=" + projects + ", originalVersion=" + originalVersion + + ", versionFromBom=" + versionFromBom + ", properties=" + properties + ", options=" + options + + ", projectToRun=" + projectToRun + ", processedProjects=" + processedProjects + '}'; } } diff --git a/releaser-spring/src/main/java/releaser/internal/spring/BatchConfiguration.java b/releaser-spring/src/main/java/releaser/internal/spring/BatchConfiguration.java index 65ec95d0..0bc61646 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/BatchConfiguration.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/BatchConfiguration.java @@ -62,8 +62,7 @@ class BatchConfiguration { @Bean @ConditionalOnMissingBean(ExecutionResultHandler.class) - SpringBatchExecutionResultHandler springBatchExecutionResultHandler( - BuildReportHandler buildReportHandler, + SpringBatchExecutionResultHandler springBatchExecutionResultHandler(BuildReportHandler buildReportHandler, ConfigurableApplicationContext context) { return new SpringBatchExecutionResultHandler(buildReportHandler, context); } @@ -77,15 +76,12 @@ class BatchConfiguration { @Bean @ConditionalOnMissingBean - FlowRunner flowRunner(StepBuilderFactory stepBuilderFactory, - JobBuilderFactory jobBuilderFactory, + FlowRunner flowRunner(StepBuilderFactory stepBuilderFactory, JobBuilderFactory jobBuilderFactory, ProjectsToRunFactory projectsToRunFactory, JobLauncher jobLauncher, - FlowRunnerTaskExecutorSupplier flowRunnerTaskExecutorSupplier, - ConfigurableApplicationContext context, ReleaserProperties releaserProperties, - BuildReportHandler reportHandler) { - return new SpringBatchFlowRunner(stepBuilderFactory, jobBuilderFactory, - projectsToRunFactory, jobLauncher, flowRunnerTaskExecutorSupplier, - context, releaserProperties, reportHandler); + FlowRunnerTaskExecutorSupplier flowRunnerTaskExecutorSupplier, ConfigurableApplicationContext context, + ReleaserProperties releaserProperties, BuildReportHandler reportHandler) { + return new SpringBatchFlowRunner(stepBuilderFactory, jobBuilderFactory, projectsToRunFactory, jobLauncher, + flowRunnerTaskExecutorSupplier, context, releaserProperties, reportHandler); } @Bean @@ -110,8 +106,7 @@ class BatchConfiguration { protected JobExplorer createJobExplorer() throws Exception { JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean(); jobExplorerFactoryBean.setDataSource(dataSource); - jobExplorerFactoryBean - .setSerializer(myJackson2ExecutionContextStringSerializer); + jobExplorerFactoryBean.setSerializer(myJackson2ExecutionContextStringSerializer); jobExplorerFactoryBean.afterPropertiesSet(); return jobExplorerFactoryBean.getObject(); } @@ -120,8 +115,7 @@ class BatchConfiguration { protected JobRepository createJobRepository() throws Exception { JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean(); jobRepositoryFactoryBean.setDataSource(dataSource); - jobRepositoryFactoryBean - .setSerializer(myJackson2ExecutionContextStringSerializer); + jobRepositoryFactoryBean.setSerializer(myJackson2ExecutionContextStringSerializer); jobRepositoryFactoryBean.setTransactionManager(transactionManager); jobRepositoryFactoryBean.afterPropertiesSet(); return jobRepositoryFactoryBean.getObject(); diff --git a/releaser-spring/src/main/java/releaser/internal/spring/DefaultSpringReleaser.java b/releaser-spring/src/main/java/releaser/internal/spring/DefaultSpringReleaser.java index 114e0417..34a9e283 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/DefaultSpringReleaser.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/DefaultSpringReleaser.java @@ -38,10 +38,8 @@ class DefaultSpringReleaser implements SpringReleaser { private final FlowRunner flowRunner; - DefaultSpringReleaser(ReleaserProperties properties, - OptionsAndPropertiesFactory optionsAndPropertiesFactory, - ProjectsToRunFactory projectsToRunFactory, - TasksToRunFactory tasksToRunFactory, FlowRunner flowRunner) { + DefaultSpringReleaser(ReleaserProperties properties, OptionsAndPropertiesFactory optionsAndPropertiesFactory, + ProjectsToRunFactory projectsToRunFactory, TasksToRunFactory tasksToRunFactory, FlowRunner flowRunner) { this.properties = properties; this.optionsAndPropertiesFactory = optionsAndPropertiesFactory; this.projectsToRunFactory = projectsToRunFactory; @@ -59,25 +57,22 @@ class DefaultSpringReleaser implements SpringReleaser { @Override public ExecutionResult release(Options options) { - OptionsAndProperties optionsAndProperties = prepareOptionsAndProperties(options, - this.properties); + OptionsAndProperties optionsAndProperties = prepareOptionsAndProperties(options, this.properties); // order matters! Tasks will mutate options and properties TasksToRun releaseTasksToRun = releaseTasksFromOptions(optionsAndProperties); ProjectsToRun projectsToRun = releaseProjects(optionsAndProperties); - ExecutionResult releaseTasksExecutionResult = runReleaseTasks( - optionsAndProperties, projectsToRun, releaseTasksToRun); + ExecutionResult releaseTasksExecutionResult = runReleaseTasks(optionsAndProperties, projectsToRun, + releaseTasksToRun); if (releaseTasksExecutionResult.isFailure()) { return releaseTasksExecutionResult; } - TasksToRun postReleaseTrainTasksToRun = postReleaseTrainTasksFromOptions( - optionsAndProperties); - ExecutionResult postReleaseTrainTasksExecutionResult = runPostReleaseTasks( - optionsAndProperties, postReleaseTrainTasksToRun); + TasksToRun postReleaseTrainTasksToRun = postReleaseTrainTasksFromOptions(optionsAndProperties); + ExecutionResult postReleaseTrainTasksExecutionResult = runPostReleaseTasks(optionsAndProperties, + postReleaseTrainTasksToRun); return releaseTasksExecutionResult.merge(postReleaseTrainTasksExecutionResult); } - private OptionsAndProperties prepareOptionsAndProperties(Options options, - ReleaserProperties properties) { + private OptionsAndProperties prepareOptionsAndProperties(Options options, ReleaserProperties properties) { return this.optionsAndPropertiesFactory.get(properties, options); } @@ -89,21 +84,20 @@ class DefaultSpringReleaser implements SpringReleaser { return this.tasksToRunFactory.release(options); } - private TasksToRun postReleaseTrainTasksFromOptions( - OptionsAndProperties optionsAndProperties) { + private TasksToRun postReleaseTrainTasksFromOptions(OptionsAndProperties optionsAndProperties) { return this.tasksToRunFactory.postRelease(optionsAndProperties.options); } - private ExecutionResult runReleaseTasks(OptionsAndProperties optionsAndProperties, - ProjectsToRun projectsToRun, TasksToRun tasksToRun) { - return this.flowRunner.runReleaseTasks(optionsAndProperties.options, - optionsAndProperties.properties, projectsToRun, tasksToRun); + private ExecutionResult runReleaseTasks(OptionsAndProperties optionsAndProperties, ProjectsToRun projectsToRun, + TasksToRun tasksToRun) { + return this.flowRunner.runReleaseTasks(optionsAndProperties.options, optionsAndProperties.properties, + projectsToRun, tasksToRun); } private ExecutionResult runPostReleaseTasks(OptionsAndProperties optionsAndProperties, TasksToRun postReleaseTasksToRun) { - return this.flowRunner.runPostReleaseTrainTasks(optionsAndProperties.options, - optionsAndProperties.properties, "postRelease", postReleaseTasksToRun); + return this.flowRunner.runPostReleaseTrainTasks(optionsAndProperties.options, optionsAndProperties.properties, + "postRelease", postReleaseTasksToRun); } } diff --git a/releaser-spring/src/main/java/releaser/internal/spring/ExecutionResultReport.java b/releaser-spring/src/main/java/releaser/internal/spring/ExecutionResultReport.java index ed07ef99..7330b3b3 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/ExecutionResultReport.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/ExecutionResultReport.java @@ -42,8 +42,7 @@ public class ExecutionResultReport { } public ExecutionResultReport(String projectName, String shortName, String description, - Class releaserTaskType, String state, - List exceptions) { + Class releaserTaskType, String state, List exceptions) { this.projectName = projectName; this.shortName = shortName; this.description = description; diff --git a/releaser-spring/src/main/java/releaser/internal/spring/FlowRunner.java b/releaser-spring/src/main/java/releaser/internal/spring/FlowRunner.java index 9f685ca9..ab3f9765 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/FlowRunner.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/FlowRunner.java @@ -33,8 +33,7 @@ public interface FlowRunner { * @param releaserTask - the task to run * @return the decision on what to do with the task */ - default Decision beforeTask(Options options, ReleaserProperties properties, - ReleaserTask releaserTask) { + default Decision beforeTask(Options options, ReleaserProperties properties, ReleaserTask releaserTask) { return Decision.CONTINUE; } @@ -45,8 +44,7 @@ public interface FlowRunner { * @param releaserTask - the task to run * @return the decision on what to do with the task */ - default Decision afterTask(Options options, ReleaserProperties properties, - ReleaserTask releaserTask) { + default Decision afterTask(Options options, ReleaserProperties properties, ReleaserTask releaserTask) { return Decision.CONTINUE; } @@ -58,8 +56,8 @@ public interface FlowRunner { * @param tasksToRun - set of release tasks to run for each project * @return the result of release execution */ - ExecutionResult runReleaseTasks(Options options, ReleaserProperties properties, - ProjectsToRun projectToRuns, TasksToRun tasksToRun); + ExecutionResult runReleaseTasks(Options options, ReleaserProperties properties, ProjectsToRun projectToRuns, + TasksToRun tasksToRun); /** * Runs the post release tasks. @@ -69,8 +67,7 @@ public interface FlowRunner { * @param tasksToRun - set of post release tasks to run for each project * @return the result of release execution */ - ExecutionResult runPostReleaseTrainTasks(Options options, - ReleaserProperties properties, String executingTaskName, + ExecutionResult runPostReleaseTrainTasks(Options options, ReleaserProperties properties, String executingTaskName, TasksToRun tasksToRun); /** diff --git a/releaser-spring/src/main/java/releaser/internal/spring/OptionsParser.java b/releaser-spring/src/main/java/releaser/internal/spring/OptionsParser.java index 50c09aaf..a30c8f1e 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/OptionsParser.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/OptionsParser.java @@ -51,8 +51,7 @@ class OptionsParser implements Parser { private final ConfigurableApplicationContext context; - OptionsParser(List allTasks, - List singleProjectReleaserTasks, + OptionsParser(List allTasks, List singleProjectReleaserTasks, ConfigurableApplicationContext context) { this.allTasks = allTasks; this.singleProjectReleaserTasks = singleProjectReleaserTasks; @@ -66,39 +65,32 @@ class OptionsParser implements Parser { log.info("Got following args <{}>", (Object[]) args); try { ArgumentAcceptingOptionSpec metaReleaseOpt = parser - .acceptsAll(Arrays.asList("x", "meta-release"), - "Do you want to do the meta release?") + .acceptsAll(Arrays.asList("x", "meta-release"), "Do you want to do the meta release?") .withRequiredArg().ofType(Boolean.class).defaultsTo(false); ArgumentAcceptingOptionSpec fullReleaseOpt = parser .acceptsAll(Arrays.asList("f", "full-release"), "Do you want to do the full release of a single project?") .withOptionalArg().ofType(Boolean.class).defaultsTo(false); - ArgumentAcceptingOptionSpec interactiveOpt = parser.acceptsAll( - Arrays.asList("i", "interactive"), - "Do you want to set the properties from the command line of a single project?") + ArgumentAcceptingOptionSpec interactiveOpt = parser + .acceptsAll(Arrays.asList("i", "interactive"), + "Do you want to set the properties from the command line of a single project?") .withRequiredArg().ofType(Boolean.class).defaultsTo(true); - ArgumentAcceptingOptionSpec dryRunOpt = parser.acceptsAll( - Arrays.asList("dr", "dry-run"), + ArgumentAcceptingOptionSpec dryRunOpt = parser.acceptsAll(Arrays.asList("dr", "dry-run"), "Do you want to do the release / meta release with build and install projects locally only?") .withRequiredArg().ofType(Boolean.class).defaultsTo(false); LinkedList singleProjectReleaseTasks = this.allTasks.stream() .filter(releaserTask -> releaserTask instanceof SingleProjectReleaserTask) .collect(Collectors.toCollection(LinkedList::new)); singleProjectReleaseTasks.forEach(task -> parser - .acceptsAll(Arrays.asList(task.shortName(), task.name()), - task.description()) - .withOptionalArg()); - ArgumentAcceptingOptionSpec startFromOpt = parser.acceptsAll( - Arrays.asList("a", "start-from"), - "Starts all release task starting " + .acceptsAll(Arrays.asList(task.shortName(), task.name()), task.description()).withOptionalArg()); + ArgumentAcceptingOptionSpec startFromOpt = parser + .acceptsAll(Arrays.asList("a", "start-from"), "Starts all release task starting " + "from the given task. Requires passing the task name (either one letter or the full name)") .withRequiredArg().ofType(String.class); ArgumentAcceptingOptionSpec taskNamesOpt = parser - .acceptsAll(Arrays.asList("tn", "task-names"), - "Starts all release task for the given task names") + .acceptsAll(Arrays.asList("tn", "task-names"), "Starts all release task for the given task names") .withRequiredArg().ofType(String.class).defaultsTo(""); - ArgumentAcceptingOptionSpec rangeOpt = parser.acceptsAll( - Arrays.asList("r", "range"), + ArgumentAcceptingOptionSpec rangeOpt = parser.acceptsAll(Arrays.asList("r", "range"), "Runs release tasks from the given range. Requires passing " + "the task names with a hyphen. The first task is inclusive, " + "the second inclusive. E.g. 's-m' would mean running 'snapshot', " @@ -115,32 +107,25 @@ class OptionsParser implements Parser { Boolean interactive = options.valueOf(interactiveOpt); Boolean dryRun = options.valueOf(dryRunOpt); Boolean fullRelease = options.has(fullReleaseOpt); - List providedTaskNames = StringUtils.hasText(options - .valueOf(taskNamesOpt)) ? Arrays.asList( - removeQuotingChars(options.valueOf(taskNamesOpt)).split(",")) - : new ArrayList<>(); - providedTaskNames = providedTaskNames.stream().map(this::removeQuotingChars) - .collect(Collectors.toList()); + List providedTaskNames = StringUtils.hasText(options.valueOf(taskNamesOpt)) + ? Arrays.asList(removeQuotingChars(options.valueOf(taskNamesOpt)).split(",")) : new ArrayList<>(); + providedTaskNames = providedTaskNames.stream().map(this::removeQuotingChars).collect(Collectors.toList()); log.info("Passed tasks {} from command line", providedTaskNames); - List allTaskNames = singleProjectReleaseTasks.stream() - .map(ReleaserTask::name).collect(Collectors.toList()); - List tasksFromOptions = singleProjectReleaseTasks.stream().filter( - task -> options.has(task.name()) || options.has(task.shortName())) - .map(ReleaserTask::name).collect(Collectors.toList()); + List allTaskNames = singleProjectReleaseTasks.stream().map(ReleaserTask::name) + .collect(Collectors.toList()); + List tasksFromOptions = singleProjectReleaseTasks.stream() + .filter(task -> options.has(task.name()) || options.has(task.shortName())).map(ReleaserTask::name) + .collect(Collectors.toList()); if (providedTaskNames.isEmpty()) { - providedTaskNames.addAll(tasksFromOptions.isEmpty() && !metaRelease - ? allTaskNames : tasksFromOptions); + providedTaskNames.addAll(tasksFromOptions.isEmpty() && !metaRelease ? allTaskNames : tasksFromOptions); } - List taskNames = filterProvidedTaskNames(providedTaskNames, - allTaskNames, metaRelease); + List taskNames = filterProvidedTaskNames(providedTaskNames, allTaskNames, metaRelease); String startFrom = options.valueOf(startFromOpt); String range = options.valueOf(rangeOpt); - Options buildOptions = new OptionsBuilder().metaRelease(metaRelease) - .fullRelease(fullRelease).interactive(interactive).dryRun(dryRun) - .taskNames(taskNames).startFrom(startFrom).range(range).options(); - log.info( - "\n\nWill use the following options to process the project\n\n{}\n\n", - buildOptions); + Options buildOptions = new OptionsBuilder().metaRelease(metaRelease).fullRelease(fullRelease) + .interactive(interactive).dryRun(dryRun).taskNames(taskNames).startFrom(startFrom).range(range) + .options(); + log.info("\n\nWill use the following options to process the project\n\n{}\n\n", buildOptions); return buildOptions; } catch (Exception e) { @@ -149,8 +134,8 @@ class OptionsParser implements Parser { } } - List filterProvidedTaskNames(List providedTaskNames, - List allTaskNames, boolean metaRelease) { + List filterProvidedTaskNames(List providedTaskNames, List allTaskNames, + boolean metaRelease) { if (metaRelease) { return providedTaskNames; } @@ -170,8 +155,7 @@ class OptionsParser implements Parser { System.err.println(e.getMessage()); e.printStackTrace(); System.err.println(intro()); - System.err.println( - "java -jar releaser-spring-1.0.0.BUILD-SNAPSHOT.jar [options...] "); + System.err.println("java -jar releaser-spring-1.0.0.BUILD-SNAPSHOT.jar [options...] "); try { parser.printHelpOn(System.err); } @@ -194,15 +178,13 @@ class OptionsParser implements Parser { private String intro() { return "\nHere you can find the list of tasks in order for a single project\n\n[" - + this.singleProjectReleaserTasks.stream().map(ReleaserTask::name) - .collect(Collectors.joining(",")) + + this.singleProjectReleaserTasks.stream().map(ReleaserTask::name).collect(Collectors.joining(",")) + "]\n\n"; } private String examples() { - return "\nExamples of usage:\n\n" + "Run 'build' & 'commit' & 'deploy'\n" - + "java -jar jar.jar -b -c -d\n\n" + "Start from 'push'\n" - + "java -jar releaser.jar -a push\n\n" + "Range 'docs' -> 'push'\n" + return "\nExamples of usage:\n\n" + "Run 'build' & 'commit' & 'deploy'\n" + "java -jar jar.jar -b -c -d\n\n" + + "Start from 'push'\n" + "java -jar releaser.jar -a push\n\n" + "Range 'docs' -> 'push'\n" + "java -jar releaser.jar -r o-p\n\n" + "\n\n"; } diff --git a/releaser-spring/src/main/java/releaser/internal/spring/ProjectToRun.java b/releaser-spring/src/main/java/releaser/internal/spring/ProjectToRun.java index 2e29ca16..02c2f216 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/ProjectToRun.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/ProjectToRun.java @@ -64,8 +64,7 @@ public class ProjectToRun implements Serializable { */ public final Options options; - public ProjectToRun(File thisProjectFolder, ProjectsFromBom allProjectsFromBom, - ProjectVersion originalVersion, + public ProjectToRun(File thisProjectFolder, ProjectsFromBom allProjectsFromBom, ProjectVersion originalVersion, ReleaserProperties thisProjectReleaserProperties, Options options) { this.thisProjectFolder = thisProjectFolder; this.allProjectsFromBom = allProjectsFromBom; @@ -100,8 +99,7 @@ public class ProjectToRun implements Serializable { * Supplier of a project to run. Since retrieval of a project may require cloning it, * we will cache the cloned location instead of cloning it each time. */ - public static class ProjectToRunSupplier - implements Supplier, Closeable { + public static class ProjectToRunSupplier implements Supplier, Closeable { private static final Map CACHE = new ConcurrentHashMap<>(); diff --git a/releaser-spring/src/main/java/releaser/internal/spring/ProjectsFromBom.java b/releaser-spring/src/main/java/releaser/internal/spring/ProjectsFromBom.java index 55d0035c..8d3466e6 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/ProjectsFromBom.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/ProjectsFromBom.java @@ -34,8 +34,7 @@ public class ProjectsFromBom { */ public final ProjectVersion currentProjectFromBom; - public ProjectsFromBom(Projects allProjectVersionsFromBom, - ProjectVersion currentProjectFromBom) { + public ProjectsFromBom(Projects allProjectVersionsFromBom, ProjectVersion currentProjectFromBom) { this.allProjectVersionsFromBom = allProjectVersionsFromBom; this.currentProjectFromBom = currentProjectFromBom; } diff --git a/releaser-spring/src/main/java/releaser/internal/spring/ProjectsToRunFactory.java b/releaser-spring/src/main/java/releaser/internal/spring/ProjectsToRunFactory.java index 920f45a5..7e962b9a 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/ProjectsToRunFactory.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/ProjectsToRunFactory.java @@ -62,19 +62,15 @@ class ProjectsToRunFactory implements Closeable { Options options = optionsAndProperties.options; ReleaserProperties properties = optionsAndProperties.properties; if (!options.metaRelease) { - log.info( - "Single project release picked. Will release only the current project"); + log.info("Single project release picked. Will release only the current project"); File projectFolder = projectFolder(properties); ProjectVersion version = new ProjectVersion(projectFolder); - ProjectsFromBom projectsFromBom = this.versionsToBumpFactory - .withProject(projectFolder); - return new ProjectsToRun( - new ProjectToRun.ProjectToRunSupplier(version.projectName, () -> { - ReleaserProperties changedProps = updatePropertiesIfCustomConfigPresent( - properties.copy(), projectFolder); - return new ProjectToRun(projectFolder, projectsFromBom, version, - changedProps, options); - })); + ProjectsFromBom projectsFromBom = this.versionsToBumpFactory.withProject(projectFolder); + return new ProjectsToRun(new ProjectToRun.ProjectToRunSupplier(version.projectName, () -> { + ReleaserProperties changedProps = updatePropertiesIfCustomConfigPresent(properties.copy(), + projectFolder); + return new ProjectToRun(projectFolder, projectsFromBom, version, changedProps, options); + })); } log.info("Meta release picked"); return metaReleaseProjectsToRun(options, properties); @@ -101,48 +97,39 @@ class ProjectsToRunFactory implements Closeable { return new File(workingDir); } - private ProjectsToRun metaReleaseProjectsToRun(Options options, - ReleaserProperties originalProps) { - return metaProjectsToRun(options, originalProps, - metaReleaseProjects(options, originalProps)); + private ProjectsToRun metaReleaseProjectsToRun(Options options, ReleaserProperties originalProps) { + return metaProjectsToRun(options, originalProps, metaReleaseProjects(options, originalProps)); } - private ProjectsToRun metaReleasePostReleaseProjectsToRun(Options options, - ReleaserProperties originalProps) { - return metaProjectsToRun(options, originalProps, - allButSkippedProjects(originalProps)); + private ProjectsToRun metaReleasePostReleaseProjectsToRun(Options options, ReleaserProperties originalProps) { + return metaProjectsToRun(options, originalProps, allButSkippedProjects(originalProps)); } - private ProjectsToRun metaProjectsToRun(Options options, - ReleaserProperties originalProps, List projectNames) { - return projectNames.stream() - .map(project -> projectSupplier(options, originalProps, project)) + private ProjectsToRun metaProjectsToRun(Options options, ReleaserProperties originalProps, + List projectNames) { + return projectNames.stream().map(project -> projectSupplier(options, originalProps, project)) .collect(Collectors.toCollection(ProjectsToRun::new)); } - private ProjectToRun.ProjectToRunSupplier projectSupplier(Options options, - ReleaserProperties originalProps, String project) { + private ProjectToRun.ProjectToRunSupplier projectSupplier(Options options, ReleaserProperties originalProps, + String project) { return new ProjectToRun.ProjectToRunSupplier(project, () -> { File clonedProjectFromOrg = this.releaser.clonedProjectFromOrg(project); - ReleaserProperties properties = updatePropertiesIfCustomConfigPresent( - originalProps.copy(), clonedProjectFromOrg); - log.info("Successfully cloned the project [{}] to [{}]", project, + ReleaserProperties properties = updatePropertiesIfCustomConfigPresent(originalProps.copy(), clonedProjectFromOrg); + log.info("Successfully cloned the project [{}] to [{}]", project, clonedProjectFromOrg); ProjectVersion originalVersion = new ProjectVersion(clonedProjectFromOrg); - ProjectsFromBom projectsFromBom = this.versionsToBumpFactory - .withProject(clonedProjectFromOrg); - return new ProjectToRun(clonedProjectFromOrg, projectsFromBom, - originalVersion, properties, options); + ProjectsFromBom projectsFromBom = this.versionsToBumpFactory.withProject(clonedProjectFromOrg); + return new ProjectToRun(clonedProjectFromOrg, projectsFromBom, originalVersion, properties, options); }); } - private ReleaserProperties updatePropertiesIfCustomConfigPresent( - ReleaserProperties copy, File clonedProjectFromOrg) { + private ReleaserProperties updatePropertiesIfCustomConfigPresent(ReleaserProperties copy, + File clonedProjectFromOrg) { return this.updater.updateProperties(copy, clonedProjectFromOrg); } - private List metaReleaseProjects(Options options, - ReleaserProperties properties) { + private List metaReleaseProjects(Options options, ReleaserProperties properties) { List filteredProjects = allButSkippedProjects(properties); if (StringUtils.hasText(options.startFrom)) { filteredProjects = filterStartFrom(options, filteredProjects); @@ -150,15 +137,13 @@ class ProjectsToRunFactory implements Closeable { else if (!options.taskNames.isEmpty()) { filteredProjects = filterTaskNames(options, filteredProjects); } - log.info("\n\n\nFor meta-release, will release the projects {}\n\n\n", - filteredProjects); + log.info("\n\n\nFor meta-release, will release the projects {}\n\n\n", filteredProjects); return filteredProjects; } private List allButSkippedProjects(ReleaserProperties properties) { List projects = new ArrayList<>(properties.getFixedVersions().keySet()); - log.info("List of projects that should not be cloned {}", - properties.getMetaRelease().getProjectsToSkip()); + log.info("List of projects that should not be cloned {}", properties.getMetaRelease().getProjectsToSkip()); List filteredProjects = filterProjectsToSkip(projects, properties); log.info("List of all projects to clone before filtering {}", filteredProjects); return filteredProjects; @@ -168,11 +153,8 @@ class ProjectsToRunFactory implements Closeable { return new ArrayList<>(properties.getFixedVersions().keySet()); } - private List filterProjectsToSkip(List projects, - ReleaserProperties properties) { - return projects - .stream().filter(project -> !properties.getMetaRelease() - .getProjectsToSkip().contains(project)) + private List filterProjectsToSkip(List projects, ReleaserProperties properties) { + return projects.stream().filter(project -> !properties.getMetaRelease().getProjectsToSkip().contains(project)) .collect(Collectors.toList()); } @@ -180,22 +162,19 @@ class ProjectsToRunFactory implements Closeable { log.info("Start from option provided [{}]", options.startFrom); int projectIndex = filteredProjects.indexOf(options.startFrom); if (projectIndex < 0) { - throw new IllegalStateException( - "Project [" + options.startFrom + "] not found"); + throw new IllegalStateException("Project [" + options.startFrom + "] not found"); } if (log.isDebugEnabled()) { log.debug("Index of project [{}] is [{}]", options.startFrom, projectIndex); } - filteredProjects = filteredProjects.subList(projectIndex, - filteredProjects.size()); + filteredProjects = filteredProjects.subList(projectIndex, filteredProjects.size()); options.startFrom = ""; return filteredProjects; } private List filterTaskNames(Options options, List filteredProjects) { log.info("Task names provided {}", options.taskNames); - filteredProjects = filteredProjects.stream() - .filter(project -> options.taskNames.contains(project)) + filteredProjects = filteredProjects.stream().filter(project -> options.taskNames.contains(project)) .collect(Collectors.toList()); options.taskNames = new ArrayList<>(); return filteredProjects; diff --git a/releaser-spring/src/main/java/releaser/internal/spring/ReleaserConfiguration.java b/releaser-spring/src/main/java/releaser/internal/spring/ReleaserConfiguration.java index d93aee81..dd1b20a9 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/ReleaserConfiguration.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/ReleaserConfiguration.java @@ -59,15 +59,14 @@ class ReleaserConfiguration { @Bean @ConditionalOnMissingBean - VersionsToBumpFactory versionsToBumpFactory(Releaser releaser, - ReleaserProperties properties) { + VersionsToBumpFactory versionsToBumpFactory(Releaser releaser, ReleaserProperties properties) { return new VersionsToBumpFactory(releaser, properties); } @Bean @ConditionalOnMissingBean - ProjectsToRunFactory projectsToRunFactory(VersionsToBumpFactory versionsToBumpFactory, - Releaser releaser, ReleaserPropertiesUpdater updater) { + ProjectsToRunFactory projectsToRunFactory(VersionsToBumpFactory versionsToBumpFactory, Releaser releaser, + ReleaserPropertiesUpdater updater) { return new ProjectsToRunFactory(versionsToBumpFactory, releaser, updater); } @@ -80,11 +79,10 @@ class ReleaserConfiguration { @Bean @ConditionalOnMissingBean SpringReleaser springReleaser(OptionsAndPropertiesFactory optionsAndPropertiesFactory, - ProjectsToRunFactory projectsToRunFactory, - TasksToRunFactory tasksToRunFactory, FlowRunner flowRunner, + ProjectsToRunFactory projectsToRunFactory, TasksToRunFactory tasksToRunFactory, FlowRunner flowRunner, ReleaserProperties properties) { - return new DefaultSpringReleaser(properties, optionsAndPropertiesFactory, - projectsToRunFactory, tasksToRunFactory, flowRunner); + return new DefaultSpringReleaser(properties, optionsAndPropertiesFactory, projectsToRunFactory, + tasksToRunFactory, flowRunner); } @Bean @@ -95,8 +93,7 @@ class ReleaserConfiguration { @Bean @ConditionalOnMissingBean - VersionsFetcher versionsFetcher(ProjectPomUpdater updater, - ReleaserProperties properties) { + VersionsFetcher versionsFetcher(ProjectPomUpdater updater, ReleaserProperties properties) { return new VersionsFetcher(properties, updater); } @@ -108,8 +105,7 @@ class ReleaserConfiguration { @Bean @ConditionalOnMissingBean - ProjectGitHubHandler projectGitHubHandler( - @Autowired(required = false) List customGithubIssues, + ProjectGitHubHandler projectGitHubHandler(@Autowired(required = false) List customGithubIssues, ReleaserProperties properties) { return new ProjectGitHubHandler(properties, customGithubIssues != null ? customGithubIssues : new ArrayList<>()); @@ -117,8 +113,7 @@ class ReleaserConfiguration { @Bean @ConditionalOnMissingBean - TemplateGenerator templateGenerator(ProjectGitHubHandler handler, - ReleaserProperties properties) { + TemplateGenerator templateGenerator(ProjectGitHubHandler handler, ReleaserProperties properties) { return new TemplateGenerator(properties, handler); } @@ -130,47 +125,39 @@ class ReleaserConfiguration { @Bean @ConditionalOnMissingBean - SaganUpdater saganUpdater(SaganClient saganClient, - ReleaserProperties releaserProperties) { + SaganUpdater saganUpdater(SaganClient saganClient, ReleaserProperties releaserProperties) { return new SaganUpdater(saganClient, releaserProperties); } @Bean @ConditionalOnMissingBean - PostReleaseActions postReleaseActions(ProjectGitHandler handler, - ProjectPomUpdater pomUpdater, GradleUpdater gradleUpdater, - ProjectCommandExecutor projectCommandExecutor, + PostReleaseActions postReleaseActions(ProjectGitHandler handler, ProjectPomUpdater pomUpdater, + GradleUpdater gradleUpdater, ProjectCommandExecutor projectCommandExecutor, ReleaserProperties releaserProperties, VersionsFetcher versionsFetcher, ReleaserPropertiesUpdater releaserPropertiesUpdater) { - return new PostReleaseActions(handler, pomUpdater, gradleUpdater, - projectCommandExecutor, releaserProperties, versionsFetcher, - releaserPropertiesUpdater); + return new PostReleaseActions(handler, pomUpdater, gradleUpdater, projectCommandExecutor, releaserProperties, + versionsFetcher, releaserPropertiesUpdater); } @Bean @ConditionalOnMissingBean - DocumentationUpdater documentationUpdater(ProjectGitHandler projectGitHandler, - ReleaserProperties properties, TemplateGenerator templateGenerator, - @Autowired( - required = false) List customProjectDocumentationUpdaters) { + DocumentationUpdater documentationUpdater(ProjectGitHandler projectGitHandler, ReleaserProperties properties, + TemplateGenerator templateGenerator, + @Autowired(required = false) List customProjectDocumentationUpdaters) { return new DocumentationUpdater(projectGitHandler, properties, templateGenerator, - customProjectDocumentationUpdaters != null - ? customProjectDocumentationUpdaters : new ArrayList<>()); + customProjectDocumentationUpdaters != null ? customProjectDocumentationUpdaters : new ArrayList<>()); } @Bean @ConditionalOnMissingBean - Releaser releaser(ProjectPomUpdater projectPomUpdater, - ProjectCommandExecutor projectCommandExecutor, - ProjectGitHandler projectGitHandler, - ProjectGitHubHandler projectGitHubHandler, - TemplateGenerator templateGenerator, GradleUpdater gradleUpdater, - SaganUpdater saganUpdater, DocumentationUpdater documentationUpdater, - PostReleaseActions postReleaseActions, + Releaser releaser(ProjectPomUpdater projectPomUpdater, ProjectCommandExecutor projectCommandExecutor, + ProjectGitHandler projectGitHandler, ProjectGitHubHandler projectGitHubHandler, + TemplateGenerator templateGenerator, GradleUpdater gradleUpdater, SaganUpdater saganUpdater, + DocumentationUpdater documentationUpdater, PostReleaseActions postReleaseActions, ReleaserProperties releaserProperties) { - return new Releaser(releaserProperties, projectPomUpdater, projectCommandExecutor, - projectGitHandler, projectGitHubHandler, templateGenerator, gradleUpdater, - saganUpdater, documentationUpdater, postReleaseActions); + return new Releaser(releaserProperties, projectPomUpdater, projectCommandExecutor, projectGitHandler, + projectGitHubHandler, templateGenerator, gradleUpdater, saganUpdater, documentationUpdater, + postReleaseActions); } @Bean @@ -181,8 +168,7 @@ class ReleaserConfiguration { @Bean @ConditionalOnMissingBean - Parser optionsParser(List allTasks, - List singleProjectReleaserTasks, + Parser optionsParser(List allTasks, List singleProjectReleaserTasks, ConfigurableApplicationContext context) { return new OptionsParser(allTasks, singleProjectReleaserTasks, context); } diff --git a/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchBuildReportHandler.java b/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchBuildReportHandler.java index 1b2d4b5f..105776c8 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchBuildReportHandler.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchBuildReportHandler.java @@ -39,8 +39,7 @@ import org.springframework.util.StringUtils; class SpringBatchBuildReportHandler implements BuildReportHandler { - private static final Logger log = LoggerFactory - .getLogger(SpringBatchExecutionResultHandler.class); + private static final Logger log = LoggerFactory.getLogger(SpringBatchExecutionResultHandler.class); private final JobExplorer jobExplorer; @@ -52,34 +51,27 @@ class SpringBatchBuildReportHandler implements BuildReportHandler { public void reportBuildSummary() { List jobNames = this.jobExplorer.getJobNames(); List sortedJobExecutions = jobNames.stream() - .flatMap(name -> this.jobExplorer.findJobInstancesByJobName(name, 0, 100) - .stream()) - .flatMap(instance -> this.jobExplorer.getJobExecutions(instance).stream()) - .filter(j -> !j.isRunning()) - .sorted(Comparator.comparing(JobExecution::getCreateTime)) - .collect(Collectors.toList()); - List stepContexts = sortedJobExecutions.stream() - .flatMap(j -> j.getStepExecutions().stream()) + .flatMap(name -> this.jobExplorer.findJobInstancesByJobName(name, 0, 100).stream()) + .flatMap(instance -> this.jobExplorer.getJobExecutions(instance).stream()).filter(j -> !j.isRunning()) + .sorted(Comparator.comparing(JobExecution::getCreateTime)).collect(Collectors.toList()); + List stepContexts = sortedJobExecutions.stream().flatMap(j -> j.getStepExecutions().stream()) .collect(Collectors.toCollection(LinkedList::new)); printTable(buildTable(stepContexts)); } private List buildTable(List stepContexts) { return stepContexts.stream().map(step -> { - String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") - .format(step.getStartTime()); - long millis = ChronoUnit.MILLIS.between(step.getStartTime().toInstant(), - step.getEndTime().toInstant()); + String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(step.getStartTime()); + long millis = ChronoUnit.MILLIS.between(step.getStartTime().toInstant(), step.getEndTime().toInstant()); ExecutionContext context = step.getExecutionContext(); ExecutionResultReport entity = (ExecutionResultReport) context.get("entity"); if (entity == null) { return null; } - String projectName = TrainPostReleaseReleaserTask.class - .isAssignableFrom(entity.getReleaserTaskType()) ? "postRelease" - : entity.getProjectName(); - return new Table(date, time(millis), projectName, entity.getShortName(), - entity.getDescription(), entity.getState(), entity.getExceptions()); + String projectName = TrainPostReleaseReleaserTask.class.isAssignableFrom(entity.getReleaserTaskType()) + ? "postRelease" : entity.getProjectName(); + return new Table(date, time(millis), projectName, entity.getShortName(), entity.getDescription(), + entity.getState(), entity.getExceptions()); }).filter(Objects::nonNull).collect(Collectors.toCollection(LinkedList::new)); } @@ -96,23 +88,20 @@ class SpringBatchBuildReportHandler implements BuildReportHandler { } private void printTable(List
table) { - String string = "\n\n***** BUILD REPORT *****\n\n" - + FlipTableConverters.fromIterable(table, Table.class) + String string = "\n\n***** BUILD REPORT *****\n\n" + FlipTableConverters.fromIterable(table, Table.class) + "\n\n***** BUILD REPORT *****\n\n"; - List
brokenTasks = table.stream() - .filter(table1 -> StringUtils.hasText(table1.thrownException)) + List
brokenTasks = table.stream().filter(table1 -> StringUtils.hasText(table1.thrownException)) .collect(Collectors.toList()); if (!brokenTasks.isEmpty()) { - String brokenBuilds = "\n\n[BUILD UNSTABLE] The following release tasks are failing!\n\n" - + brokenTasks.stream().map(table1 -> String.format( + String brokenBuilds = "\n\n[BUILD UNSTABLE] The following release tasks are failing!\n\n" + brokenTasks + .stream() + .map(table1 -> String.format( "***** Project / Task : <%s/%s> ***** \nTask Description <%s>\nException Stacktrace \n\n%s", - table1.projectName, table1.taskCaption, - table1.taskDescription, - table1.exceptions + "\n" + table1.exceptions.stream() - .map(Throwable::getStackTrace).flatMap(Arrays::stream) - .map(StackTraceElement::toString) - .collect(Collectors.joining("\n")))) - .collect(Collectors.joining("\n\n")); + table1.projectName, table1.taskCaption, table1.taskDescription, + table1.exceptions + "\n" + + table1.exceptions.stream().map(Throwable::getStackTrace).flatMap(Arrays::stream) + .map(StackTraceElement::toString).collect(Collectors.joining("\n")))) + .collect(Collectors.joining("\n\n")); log.warn(string + brokenBuilds); } else { @@ -138,9 +127,8 @@ class SpringBatchBuildReportHandler implements BuildReportHandler { List exceptions; - Table(String creationTime, String executionTime, String projectName, - String taskCaption, String taskDescription, String taskState, - List exceptions) { + Table(String creationTime, String executionTime, String projectName, String taskCaption, String taskDescription, + String taskState, List exceptions) { this.creationTime = creationTime; this.executionTime = executionTime; this.projectName = projectName; diff --git a/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchExecutionResultHandler.java b/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchExecutionResultHandler.java index 270b6d02..429ec11c 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchExecutionResultHandler.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchExecutionResultHandler.java @@ -29,15 +29,13 @@ import org.springframework.context.ConfigurableApplicationContext; class SpringBatchExecutionResultHandler implements ExecutionResultHandler { - private static final Logger log = LoggerFactory - .getLogger(SpringBatchExecutionResultHandler.class); + private static final Logger log = LoggerFactory.getLogger(SpringBatchExecutionResultHandler.class); private final ConfigurableApplicationContext context; private final BuildReportHandler buildReportHandler; - SpringBatchExecutionResultHandler(BuildReportHandler buildReportHandler, - ConfigurableApplicationContext context) { + SpringBatchExecutionResultHandler(BuildReportHandler buildReportHandler, ConfigurableApplicationContext context) { this.buildReportHandler = buildReportHandler; this.context = context; } @@ -53,8 +51,7 @@ class SpringBatchExecutionResultHandler implements ExecutionResultHandler { return; } else if (executionResult.isUnstable()) { - log.warn( - "The release went fine, however at least one unstable post release task was found", + log.warn("The release went fine, however at least one unstable post release task was found", executionResult.foundExceptions()); handleUnstableException(); } @@ -77,12 +74,11 @@ class SpringBatchExecutionResultHandler implements ExecutionResultHandler { buildStatus.createNewFile(); String text = "[BUILD UNSTABLE] The release happened successfully, but there were post release issues"; Files.write(buildStatus.toPath(), text.getBytes()); - log.info( - "\n\n\n ___ _ _ ___ _ ___ _ _ _ _ ___ _____ _ ___ _ ___ \n" - + " | _ ) | | |_ _| | | \\ | | | | \\| / __|_ _/_\\ | _ ) | | __|\n" - + " | _ \\ |_| || || |__| |) | | |_| | .` \\__ \\ | |/ _ \\| _ \\ |__| _| \n" - + " |___/\\___/|___|____|___/ \\___/|_|\\_|___/ |_/_/ \\_\\___/____|___|\n" - + " "); + log.info("\n\n\n ___ _ _ ___ _ ___ _ _ _ _ ___ _____ _ ___ _ ___ \n" + + " | _ ) | | |_ _| | | \\ | | | | \\| / __|_ _/_\\ | _ ) | | __|\n" + + " | _ \\ |_| || || |__| |) | | |_| | .` \\__ \\ | |/ _ \\| _ \\ |__| _| \n" + + " |___/\\___/|___|____|___/ \\___/|_|\\_|___/ |_/_/ \\_\\___/____|___|\n" + + " "); } catch (IOException e) { throw new IllegalStateException( @@ -101,12 +97,11 @@ class SpringBatchExecutionResultHandler implements ExecutionResultHandler { buildStatus.createNewFile(); String text = "[BUILD STABLE] All the release steps have been successfully executed!"; Files.write(buildStatus.toPath(), text.getBytes()); - log.info( - "\n\n\n ___ _ _ ___ _ ___ ___ _ _ ___ ___ ___ ___ ___ ___ _ _ _ \n" - + " | _ ) | | |_ _| | | \\ / __| | | |/ __/ __| __/ __/ __| __| | | | | \n" - + " | _ \\ |_| || || |__| |) | \\__ \\ |_| | (_| (__| _|\\__ \\__ \\ _|| |_| | |__ \n" - + " |___/\\___/|___|____|___/ |___/\\___/ \\___\\___|___|___/___/_| \\___/|____|\n" - + " "); + log.info("\n\n\n ___ _ _ ___ _ ___ ___ _ _ ___ ___ ___ ___ ___ ___ _ _ _ \n" + + " | _ ) | | |_ _| | | \\ / __| | | |/ __/ __| __/ __/ __| __| | | | | \n" + + " | _ \\ |_| || || |__| |) | \\__ \\ |_| | (_| (__| _|\\__ \\__ \\ _|| |_| | |__ \n" + + " |___/\\___/|___|____|___/ |___/\\___/ \\___\\___|___|___/___/_| \\___/|____|\n" + + " "); } catch (IOException e) { log.info("Failed to store the file but the build was stable"); @@ -131,8 +126,7 @@ class SpringBatchExecutionResultHandler implements ExecutionResultHandler { + " "); } catch (IOException e) { - throw new IllegalStateException( - "[BUILD FAILED] Couldn't create a file to show that the build is unstable"); + throw new IllegalStateException("[BUILD FAILED] Couldn't create a file to show that the build is unstable"); } } diff --git a/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchFlowRunner.java b/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchFlowRunner.java index 1c56c370..72503b7c 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchFlowRunner.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/SpringBatchFlowRunner.java @@ -67,8 +67,7 @@ import org.springframework.core.task.TaskExecutor; class SpringBatchFlowRunner implements FlowRunner, Closeable { - private static final Logger log = LoggerFactory - .getLogger(SpringBatchFlowRunner.class); + private static final Logger log = LoggerFactory.getLogger(SpringBatchFlowRunner.class); private static final String MSG = "\nPress 'q' to quit, 's' to skip, any key to continue\n\n"; @@ -90,12 +89,10 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { private final ReleaserProperties releaserProperties; - SpringBatchFlowRunner(StepBuilderFactory stepBuilderFactory, - JobBuilderFactory jobBuilderFactory, + SpringBatchFlowRunner(StepBuilderFactory stepBuilderFactory, JobBuilderFactory jobBuilderFactory, ProjectsToRunFactory projectsToRunFactory, JobLauncher jobLauncher, - FlowRunnerTaskExecutorSupplier flowRunnerTaskExecutorSupplier, - ConfigurableApplicationContext context, ReleaserProperties releaserProperties, - BuildReportHandler reportHandler) { + FlowRunnerTaskExecutorSupplier flowRunnerTaskExecutorSupplier, ConfigurableApplicationContext context, + ReleaserProperties releaserProperties, BuildReportHandler reportHandler) { this.stepBuilderFactory = stepBuilderFactory; this.jobBuilderFactory = jobBuilderFactory; this.projectsToRunFactory = projectsToRunFactory; @@ -103,58 +100,48 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { this.flowRunnerTaskExecutorSupplier = flowRunnerTaskExecutorSupplier; this.stepSkipper = new ConsoleInputStepSkipper(context, reportHandler); this.releaserProperties = releaserProperties; - this.executorService = Executors.newFixedThreadPool( - this.releaserProperties.getMetaRelease().getReleaseGroupThreadCount()); + this.executorService = Executors + .newFixedThreadPool(this.releaserProperties.getMetaRelease().getReleaseGroupThreadCount()); } @Override - public Decision beforeTask(Options options, ReleaserProperties properties, - ReleaserTask releaserTask) { + public Decision beforeTask(Options options, ReleaserProperties properties, ReleaserTask releaserTask) { return decide(options, releaserTask); } - private Step createStep(ReleaserTask releaserTask, - NamedArgumentsSupplier argsSupplier) { - return this.stepBuilderFactory - .get(argsSupplier.projectName + "_" + releaserTask.name()) + private Step createStep(ReleaserTask releaserTask, NamedArgumentsSupplier argsSupplier) { + return this.stepBuilderFactory.get(argsSupplier.projectName + "_" + releaserTask.name()) .tasklet((contribution, chunkContext) -> { Arguments args = argsSupplier.get(); - FlowRunner.Decision decision = beforeTask(args.options, - args.properties, releaserTask); + FlowRunner.Decision decision = beforeTask(args.options, args.properties, releaserTask); if (decision == FlowRunner.Decision.CONTINUE) { ExecutionResult result = runTask(releaserTask, args); - contribution.getStepExecution().getExecutionContext() - .put("result", result); - List errors = (List) contribution - .getStepExecution().getExecutionContext().get("errors"); + contribution.getStepExecution().getExecutionContext().put("result", result); + List errors = (List) contribution.getStepExecution().getExecutionContext() + .get("errors"); RuntimeException exception = result.foundExceptions(); errors = addExceptionToErrors(errors, exception); String status = result.toStringResult(); - ExecutionResultReport entity = buildEntity(releaserTask, args, - status, errors); - contribution.getStepExecution().getExecutionContext() - .put("entity", entity); + ExecutionResultReport entity = buildEntity(releaserTask, args, status, errors); + contribution.getStepExecution().getExecutionContext().put("entity", entity); if (result.isFailureOrUnstable()) { log.warn("The execution of [{}] failed [{}] / unstable [{}]", - entity.getReleaserTaskType().getSimpleName(), - result.isFailure(), result.isUnstable()); - contribution.getStepExecution().getExecutionContext() - .put("errors", errors); + entity.getReleaserTaskType().getSimpleName(), result.isFailure(), + result.isUnstable()); + contribution.getStepExecution().getExecutionContext().put("errors", errors); } } else { - ExecutionResultReport entity = buildEntity(releaserTask, args, - "SKIPPED", Collections.emptyList()); - contribution.getStepExecution().getExecutionContext() - .put("entity", entity); + ExecutionResultReport entity = buildEntity(releaserTask, args, "SKIPPED", + Collections.emptyList()); + contribution.getStepExecution().getExecutionContext().put("entity", entity); log.info("Skipping step [{}]", releaserTask.name()); } return RepeatStatus.FINISHED; }).listener(releaserListener(argsSupplier, releaserTask)).build(); } - private List addExceptionToErrors(List errors, - RuntimeException exception) { + private List addExceptionToErrors(List errors, RuntimeException exception) { if (errors == null) { errors = new LinkedList<>(); } @@ -164,14 +151,13 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { return errors; } - private ExecutionResultReport buildEntity(ReleaserTask releaserTask, Arguments args, - String state, List errors) { + private ExecutionResultReport buildEntity(ReleaserTask releaserTask, Arguments args, String state, + List errors) { String projectName = args.project.getName(); String shortName = releaserTask.getClass().getSimpleName(); String description = releaserTask.description(); Class releaseType = releaserTask.getClass(); - return new ExecutionResultReport(projectName, shortName, description, releaseType, - state, errors); + return new ExecutionResultReport(projectName, shortName, description, releaseType, state, errors); } private ExecutionResult runTask(ReleaserTask releaserTask, Arguments args) { @@ -197,25 +183,21 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { } } - private StepExecutionListener releaserListener(NamedArgumentsSupplier argsSupplier, - ReleaserTask releaserTask) { + private StepExecutionListener releaserListener(NamedArgumentsSupplier argsSupplier, ReleaserTask releaserTask) { return new StepExecutionListenerSupport() { @Override public ExitStatus afterStep(StepExecution stepExecution) { Arguments args = argsSupplier.get(); - FlowRunner.Decision decision = afterTask(args.options, args.properties, - releaserTask); + FlowRunner.Decision decision = afterTask(args.options, args.properties, releaserTask); if (decision == FlowRunner.Decision.ABORT) { return ExitStatus.FAILED; } - ExecutionResult result = (ExecutionResult) stepExecution - .getExecutionContext().get("result"); + ExecutionResult result = (ExecutionResult) stepExecution.getExecutionContext().get("result"); if (result == null || result.isSuccess()) { return stepExecution.getExitStatus(); } else if (result.isUnstable()) { - return ExitStatus.COMPLETED - .addExitDescription(BuildUnstableException.DESCRIPTION); + return ExitStatus.COMPLETED.addExitDescription(BuildUnstableException.DESCRIPTION); } else if (result.isFailure()) { return ExitStatus.FAILED; @@ -226,8 +208,8 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { } @Override - public ExecutionResult runReleaseTasks(Options options, ReleaserProperties properties, - ProjectsToRun projectsToRun, TasksToRun tasksToRun) { + public ExecutionResult runReleaseTasks(Options options, ReleaserProperties properties, ProjectsToRun projectsToRun, + TasksToRun tasksToRun) { if (properties.isPostReleaseTasksOnly() && options.metaRelease) { log.info("Only post release tasks will be executed for the meta release"); return ExecutionResult.skipped(); @@ -237,8 +219,7 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { if (groups.hasGroups()) { log.info("Found the following release groups {}", releaseGroups); } - List flows = releaseGroups.stream() - .map(group -> buildFlowForGroup(tasksToRun, group)) + List flows = releaseGroups.stream().map(group -> buildFlowForGroup(tasksToRun, group)) .collect(Collectors.toCollection(LinkedList::new)); Iterator flowsIterator = flows.iterator(); if (!flowsIterator.hasNext()) { @@ -252,16 +233,14 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { return runJob(buildJobForFlows(flowsIterator)); } - private ExecutionResult runComposites(List flows, - ProjectsToReleaseGroups groups) { + private ExecutionResult runComposites(List flows, ProjectsToReleaseGroups groups) { if (groups.hasGroups()) { // will run in parallel List results = new LinkedList<>(); for (StuffToRun flow : flows) { log.info("Releasing group [{}]", flow.releaseGroup); ExecutionResult executionResult = runInParallel(flow); - log.info("Group [{}] execution result is [{}]", flow.releaseGroup, - executionResult); + log.info("Group [{}] execution result is [{}]", flow.releaseGroup, executionResult); if (executionResult.isFailure()) { // stop running any additional flows when an release task exception // was found @@ -292,8 +271,7 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { log.info("Scheduling a build for project [{}]", s.projectName()); List> futures = new LinkedList<>(); futures.add(this.executorService.submit(() -> { - log.info("Running a composite task [{}] in parallel", - releaserTask.name()); + log.info("Running a composite task [{}] in parallel", releaserTask.name()); return releaserTask.apply(Arguments.forProject(s.get())); })); boolean atLeastOneFailure = false; @@ -305,8 +283,7 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { } } if (atLeastOneFailure) { - log.warn( - "At least one project failed within the group, will NOT continue with subsequent groups"); + log.warn("At least one project failed within the group, will NOT continue with subsequent groups"); break; } } @@ -317,8 +294,7 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { ExecutionResult result = ExecutionResult.success(); for (StuffToRun stuffToRun : stuffToRunList) { for (ProjectToRun.ProjectToRunSupplier s : stuffToRun.releaseGroup.projectsToRun) { - result = result - .merge(stuffToRun.task.apply(Arguments.forProject(s.get()))); + result = result.merge(stuffToRun.task.apply(Arguments.forProject(s.get()))); if (result.isFailure()) { return result; } @@ -328,8 +304,7 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { } private Job buildJobForFlows(Iterator flowsIterator) { - JobBuilder release = this.jobBuilderFactory - .get("release_" + System.currentTimeMillis()); + JobBuilder release = this.jobBuilderFactory.get("release_" + System.currentTimeMillis()); StuffToRun stuffToRun = flowsIterator.next(); Flow first = stuffToRun.flow; JobFlowBuilder start = release.start(first); @@ -344,21 +319,18 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { private StuffToRun buildFlowForGroup(TasksToRun tasksToRun, ReleaseGroup group) { FlowBuilder flowBuilder = new FlowBuilder<>( - group.flowName() + (group.shouldRunInParallel() ? "_Parallel" : "") + "_" - + System.currentTimeMillis()); + group.flowName() + (group.shouldRunInParallel() ? "_Parallel" : "") + "_" + System.currentTimeMillis()); Iterator iterator = group.iterator(); if (!iterator.hasNext() || tasksToRun.isEmpty()) { return new StuffToRun(group, flowBuilder.build()); } // only one project to run - run in sequence final ProjectToRun.ProjectToRunSupplier project = iterator.next(); - if (tasksToRun.size() == 1 - && tasksToRun.get(0) instanceof CompositeReleaserTask) { + if (tasksToRun.size() == 1 && tasksToRun.get(0) instanceof CompositeReleaserTask) { return new StuffToRun(group, (CompositeReleaserTask) tasksToRun.get(0)); } flowBuilder.start(toFlowOfTasks(tasksToRun, - new NamedArgumentsSupplier(project.projectName(), - () -> Arguments.forProject(project.get())), + new NamedArgumentsSupplier(project.projectName(), () -> Arguments.forProject(project.get())), flowBuilder(project.projectName()))); if (!iterator.hasNext()) { return new StuffToRun(group, flowBuilder.build()); @@ -370,8 +342,7 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { final ProjectToRun.ProjectToRunSupplier nextProject = iterator.next(); String projectName = project.projectName(); flows.add(toFlowOfTasks(tasksToRun, - new NamedArgumentsSupplier(project.projectName(), - () -> Arguments.forProject(nextProject.get())), + new NamedArgumentsSupplier(project.projectName(), () -> Arguments.forProject(nextProject.get())), flowBuilder(projectName))); } return new StuffToRun(group, split.add(flows.toArray(new Flow[0])).end()); @@ -382,10 +353,9 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { } @Override - public ExecutionResult runPostReleaseTrainTasks(Options options, - ReleaserProperties properties, String taskName, TasksToRun tasksToRun) { - ProjectsToRun projectsToRun = postReleaseTrainProjects( - new OptionsAndProperties(properties, options)); + public ExecutionResult runPostReleaseTrainTasks(Options options, ReleaserProperties properties, String taskName, + TasksToRun tasksToRun) { + ProjectsToRun projectsToRun = postReleaseTrainProjects(new OptionsAndProperties(properties, options)); Flow flow = postReleaseFlow(tasksToRun, properties, projectsToRun); String name = taskName + "_" + System.currentTimeMillis(); if (flow == null) { @@ -400,8 +370,7 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { return this.projectsToRunFactory.postReleaseTrain(options); } - private Flow toFlowOfTasks(TasksToRun tasksToRun, NamedArgumentsSupplier args, - FlowBuilder flowBuilder) { + private Flow toFlowOfTasks(TasksToRun tasksToRun, NamedArgumentsSupplier args, FlowBuilder flowBuilder) { Iterator iterator = tasksToRun.iterator(); ReleaserTask task = iterator.next(); flowBuilder.start(createStep(task, args)); @@ -415,10 +384,9 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { try { JobExecution execution = this.jobLauncher.run(job, new JobParameters()); if (!ExitStatus.COMPLETED.equals(execution.getExitStatus())) { - return ExecutionResult.failure(new IllegalStateException( - "Job failed to get executed successfully. Failed with exit code [" - + execution.getExitStatus().getExitCode() - + "] and description [" + return ExecutionResult.failure( + new IllegalStateException("Job failed to get executed successfully. Failed with exit code [" + + execution.getExitStatus().getExitCode() + "] and description [" + execution.getExitStatus().getExitDescription() + "]")); } List thrownExceptions = exceptionsThrownBySteps(execution); @@ -431,8 +399,8 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { @SuppressWarnings("unchecked") private List exceptionsThrownBySteps(JobExecution execution) { - return execution.getStepExecutions().stream() - .map(e -> e.getExecutionContext().get("errors") != null + return execution + .getStepExecutions().stream().map(e -> e.getExecutionContext().get("errors") != null ? (List) e.getExecutionContext().get("errors") : new LinkedList()) .reduce(new LinkedList(), (o, o2) -> { o.addAll(o2); @@ -440,16 +408,15 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { }); } - private Flow postReleaseFlow(TasksToRun tasksToRun, ReleaserProperties properties, - ProjectsToRun projectsToRun) { + private Flow postReleaseFlow(TasksToRun tasksToRun, ReleaserProperties properties, ProjectsToRun projectsToRun) { Iterator iterator = tasksToRun.iterator(); if (!iterator.hasNext()) { return null; } ReleaserTask task = iterator.next(); Flow flow = flow(properties, projectsToRun, task); - FlowBuilder flowBuilder = new FlowBuilder( - "parallelPostRelease_" + System.currentTimeMillis()).start(flow); + FlowBuilder flowBuilder = new FlowBuilder("parallelPostRelease_" + System.currentTimeMillis()) + .start(flow); if (!iterator.hasNext()) { return flowBuilder.build(); } @@ -468,11 +435,9 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { return taskExecutor; } - private Flow flow(ReleaserProperties properties, ProjectsToRun projectsToRun, - ReleaserTask task) { - return new FlowBuilder(task.name() + "Flow") - .start(createStep(task, new NamedArgumentsSupplier("postRelease", - () -> Arguments.forPostRelease(properties, projectsToRun)))) + private Flow flow(ReleaserProperties properties, ProjectsToRun projectsToRun, ReleaserTask task) { + return new FlowBuilder(task.name() + "Flow").start(createStep(task, + new NamedArgumentsSupplier("postRelease", () -> Arguments.forPostRelease(properties, projectsToRun)))) .build(); } @@ -487,10 +452,9 @@ class SpringBatchFlowRunner implements FlowRunner, Closeable { } private void printLog(boolean interactive, ReleaserTask task) { - String taskType = task instanceof PostReleaseReleaserTask ? "Post Release Task" - : "Release Task"; - log.info("\n\n\n=== {} [{}] ===\n\n{} {}\n\n", task.header(), taskType, - task.description(), interactive ? MSG : ""); + String taskType = task instanceof PostReleaseReleaserTask ? "Post Release Task" : "Release Task"; + log.info("\n\n\n=== {} [{}] ===\n\n{} {}\n\n", task.header(), taskType, task.description(), + interactive ? MSG : ""); } @Override @@ -539,8 +503,7 @@ class ConsoleInputStepSkipper { private final BuildReportHandler reportHandler; - ConsoleInputStepSkipper(ConfigurableApplicationContext context, - BuildReportHandler reportHandler) { + ConsoleInputStepSkipper(ConfigurableApplicationContext context, BuildReportHandler reportHandler) { this.context = context; this.reportHandler = reportHandler; } @@ -600,19 +563,16 @@ class ProjectsToReleaseGroups { } List toReleaseGroup(ProjectsToRun projectsToRun) { - ReleaseGroups releaseGroups = new ReleaseGroups( - this.releaserProperties.getMetaRelease().getReleaseGroups()); - return releaseGroup(releaseGroups, null, new LinkedList<>(), - projectsToRun.iterator()); + ReleaseGroups releaseGroups = new ReleaseGroups(this.releaserProperties.getMetaRelease().getReleaseGroups()); + return releaseGroup(releaseGroups, null, new LinkedList<>(), projectsToRun.iterator()); } boolean hasGroups() { return !this.releaserProperties.getMetaRelease().getReleaseGroups().isEmpty(); } - private List releaseGroup(ReleaseGroups releaseGroups, - ReleaseGroup currentGroup, List merged, - Iterator iterator) { + private List releaseGroup(ReleaseGroups releaseGroups, ReleaseGroup currentGroup, + List merged, Iterator iterator) { if (iterator.hasNext()) { // sleuth ProjectToRun.ProjectToRunSupplier supplier = iterator.next(); @@ -678,14 +638,12 @@ class ReleaseGroup { } private String projectName() { - return this.projectsToRun.isEmpty() ? "EMPTY" - : this.projectsToRun.get(0).projectName(); + return this.projectsToRun.isEmpty() ? "EMPTY" : this.projectsToRun.get(0).projectName(); } @Override public String toString() { - return "ReleaseGroup{" + "group=" - + (group.length > 0 ? Arrays.toString(group) : projectName()) + '}'; + return "ReleaseGroup{" + "group=" + (group.length > 0 ? Arrays.toString(group) : projectName()) + '}'; } } @@ -699,8 +657,7 @@ class ReleaseGroups { } String[] group(String name) { - String foundGroup = this.releaseGroups.stream().filter(s -> s.contains(name)) - .findFirst().orElse(null); + String foundGroup = this.releaseGroups.stream().filter(s -> s.contains(name)).findFirst().orElse(null); if (foundGroup == null) { return new String[0]; } diff --git a/releaser-spring/src/main/java/releaser/internal/spring/TasksToRunFactory.java b/releaser-spring/src/main/java/releaser/internal/spring/TasksToRunFactory.java index c2dc8a7c..a4e1be3e 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/TasksToRunFactory.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/TasksToRunFactory.java @@ -51,11 +51,9 @@ class TasksToRunFactory { TasksToRun release(OptionsAndProperties optionsAndProperties) { TasksToRun tasks = releaseTasks(optionsAndProperties); - tasks.forEach(t -> t.setup(optionsAndProperties.options, - optionsAndProperties.properties)); - log.info("Will run the following tasks {}", - tasks.stream().map(t -> t.getClass().getSimpleName()).collect(Collectors - .toCollection((Supplier>) LinkedList::new))); + tasks.forEach(t -> t.setup(optionsAndProperties.options, optionsAndProperties.properties)); + log.info("Will run the following tasks {}", tasks.stream().map(t -> t.getClass().getSimpleName()) + .collect(Collectors.toCollection((Supplier>) LinkedList::new))); return tasks; } @@ -67,8 +65,7 @@ class TasksToRunFactory { } if (options.metaRelease) { if (options.dryRun) { - return new TasksToRun( - this.context.getBean(MetaReleaseDryRunCompositeTask.class)); + return new TasksToRun(this.context.getBean(MetaReleaseDryRunCompositeTask.class)); } return new TasksToRun(this.context.getBean(MetaReleaseCompositeTask.class)); } @@ -79,8 +76,7 @@ class TasksToRunFactory { return new TasksToRun(this.context.getBean(ReleaseCompositeTask.class)); } // A single project release - List tasks = new LinkedList<>( - this.context.getBeansOfType(ReleaserTask.class).values()); + List tasks = new LinkedList<>(this.context.getBeansOfType(ReleaserTask.class).values()); tasks.sort(AnnotationAwareOrderComparator.INSTANCE); return tasksToRunForSingleProject(options, tasks); } @@ -95,8 +91,7 @@ class TasksToRunFactory { return new TasksToRun(tasks); } - private TasksToRun tasksToRunForSingleProject(Options options, - List tasks) { + private TasksToRun tasksToRunForSingleProject(Options options, List tasks) { if (StringUtils.hasText(options.startFrom)) { return startFrom(tasks, options); } @@ -151,8 +146,7 @@ class TasksToRunFactory { private TasksToRun startFrom(List tasks, Options options) { TasksToRun tasksToRun = new TasksToRun(); for (ReleaserTask task : tasks) { - if (options.startFrom.trim().equals(task.name()) - || options.startFrom.trim().equals(task.shortName())) { + if (options.startFrom.trim().equals(task.name()) || options.startFrom.trim().equals(task.shortName())) { tasksToRun.add(task); } } @@ -165,13 +159,11 @@ class TasksToRunFactory { for (int i = 0; i < allTasks.size(); i++) { msg.append(i).append(") ").append(allTasks.get(i).description()).append("\n"); } - msg.append("\n").append( - "You can pick a range of options by using the hyphen - e.g. '2-4' will execute jobs [2,3,4]\n"); - msg.append("You can execute all tasks starting from a job " - + "by using a hyphen and providing only one " + msg.append("\n") + .append("You can pick a range of options by using the hyphen - e.g. '2-4' will execute jobs [2,3,4]\n"); + msg.append("You can execute all tasks starting from a job " + "by using a hyphen and providing only one " + "number - e.g. '8-' will execute jobs [8,9,10]\n"); - msg.append("You can execute given tasks by providing a " - + "comma separated list of tasks - e.g. " + msg.append("You can execute given tasks by providing a " + "comma separated list of tasks - e.g. " + "'3,7,8' will execute jobs [3,7,8]\n"); msg.append("\n").append("You can press 'q' to quit\n\n"); return msg; diff --git a/releaser-spring/src/main/java/releaser/internal/spring/VersionsToBumpFactory.java b/releaser-spring/src/main/java/releaser/internal/spring/VersionsToBumpFactory.java index 6296cacb..49a76f65 100644 --- a/releaser-spring/src/main/java/releaser/internal/spring/VersionsToBumpFactory.java +++ b/releaser-spring/src/main/java/releaser/internal/spring/VersionsToBumpFactory.java @@ -34,8 +34,7 @@ import org.springframework.util.StringUtils; class VersionsToBumpFactory implements Closeable { - private static final Logger log = LoggerFactory - .getLogger(VersionsToBumpFactory.class); + private static final Logger log = LoggerFactory.getLogger(VersionsToBumpFactory.class); private static final Map CACHE = new ConcurrentHashMap<>(); @@ -51,10 +50,9 @@ class VersionsToBumpFactory implements Closeable { ProjectsFromBom withProject(File project) { return CACHE.computeIfAbsent(project, file -> { log.info("Fetch from git [{}], meta release [{}], project [{}]", - this.properties.getGit().isFetchVersionsFromGit(), - this.properties.getMetaRelease().isEnabled(), project); - if (this.properties.getGit().isFetchVersionsFromGit() - && !this.properties.getMetaRelease().isEnabled()) { + this.properties.getGit().isFetchVersionsFromGit(), this.properties.getMetaRelease().isEnabled(), + project); + if (this.properties.getGit().isFetchVersionsFromGit() && !this.properties.getMetaRelease().isEnabled()) { return fetchVersionsFromGitForSingleProject(project); } return fetchVersionsFromFixedProjects(project); @@ -65,14 +63,12 @@ class VersionsToBumpFactory implements Closeable { ProjectVersion originalVersion = new ProjectVersion(project); Projects fixedVersions = this.releaser.fixedVersions(); log.info("Got the following fixed versions [{}]", fixedVersions); - String fixedVersionForProject = fixedVersions - .containsProject(originalVersion.projectName) - ? fixedVersions.forName(originalVersion.projectName).version : ""; - log.info("Found fixed version for this project [{}] is [{}]", - originalVersion.projectName, fixedVersionForProject); + String fixedVersionForProject = fixedVersions.containsProject(originalVersion.projectName) + ? fixedVersions.forName(originalVersion.projectName).version : ""; + log.info("Found fixed version for this project [{}] is [{}]", originalVersion.projectName, + fixedVersionForProject); ProjectVersion versionFromBom = StringUtils.hasText(fixedVersionForProject) - ? new ProjectVersion(originalVersion.projectName, fixedVersionForProject) - : new ProjectVersion(project); + ? new ProjectVersion(originalVersion.projectName, fixedVersionForProject) : new ProjectVersion(project); log.info("Version from bom [{}]", versionFromBom); fixedVersions.add(versionFromBom); printSettingVersionFromFixedVersions(fixedVersions); @@ -82,43 +78,35 @@ class VersionsToBumpFactory implements Closeable { private ProjectsFromBom fetchVersionsFromGitForSingleProject(File project) { printVersionRetrieval(); Projects projectsToUpdate = this.releaser.retrieveVersionsFromBom(); - ProjectVersion versionFromBom = assertNoSnapshotsForANonSnapshotProject(project, - projectsToUpdate); + ProjectVersion versionFromBom = assertNoSnapshotsForANonSnapshotProject(project, projectsToUpdate); return cachedProjectsFromBom(versionFromBom, projectsToUpdate); } - private ProjectsFromBom cachedProjectsFromBom(ProjectVersion versionFromBom, - Projects projectsToUpdate) { + private ProjectsFromBom cachedProjectsFromBom(ProjectVersion versionFromBom, Projects projectsToUpdate) { return new ProjectsFromBom(projectsToUpdate, versionFromBom); } - ProjectVersion assertNoSnapshotsForANonSnapshotProject(File project, - Projects projectsToUpdate) { + ProjectVersion assertNoSnapshotsForANonSnapshotProject(File project, Projects projectsToUpdate) { ProjectVersion versionFromBom; versionFromBom = projectsToUpdate.forFile(project); assertNoSnapshotsForANonSnapshotProject(projectsToUpdate, versionFromBom); return versionFromBom; } - private void assertNoSnapshotsForANonSnapshotProject(Projects projects, - ProjectVersion versionFromBom) { + private void assertNoSnapshotsForANonSnapshotProject(Projects projects, ProjectVersion versionFromBom) { if (!versionFromBom.isSnapshot() && projects.containsSnapshots()) { - throw new IllegalStateException("You are trying to release a non snapshot " - + "version [" + versionFromBom + "] of the project [" - + versionFromBom.projectName + "] but " + throw new IllegalStateException("You are trying to release a non snapshot " + "version [" + versionFromBom + + "] of the project [" + versionFromBom.projectName + "] but " + "there is at least one SNAPSHOT library version in the Spring Cloud Release project"); } } private void printVersionRetrieval() { - log.info("\n\n\n=== RETRIEVING VERSIONS ===\n\nWill clone the BOM project" - + " to retrieve all versions"); + log.info("\n\n\n=== RETRIEVING VERSIONS ===\n\nWill clone the BOM project" + " to retrieve all versions"); } private void printSettingVersionFromFixedVersions(Projects projectsToUpdate) { - log.info( - "\n\n\n=== RETRIEVED VERSIONS ===\n\nWill use the fixed versions" - + " of projects\n\n{}", + log.info("\n\n\n=== RETRIEVED VERSIONS ===\n\nWill use the fixed versions" + " of projects\n\n{}", projectsToUpdate.stream().map(p -> p.projectName + " => " + p.version) .collect(Collectors.joining("\n"))); } diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/ProjectPostReleaseReleaserTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/ProjectPostReleaseReleaserTask.java index 20206044..b1e60348 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/ProjectPostReleaseReleaserTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/ProjectPostReleaseReleaserTask.java @@ -20,7 +20,6 @@ package releaser.internal.tasks; * Marker interface for a post release task for a single project. Example: update the * GitHub milestone for the project. */ -public interface ProjectPostReleaseReleaserTask - extends SingleProjectReleaserTask, PostReleaseReleaserTask { +public interface ProjectPostReleaseReleaserTask extends SingleProjectReleaserTask, PostReleaseReleaserTask { } diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/ReleaserTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/ReleaserTask.java index 826c750b..c9a3331c 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/ReleaserTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/ReleaserTask.java @@ -92,7 +92,6 @@ public interface ReleaserTask extends Ordered, Function values = new LinkedList<>(dryRunTasks.values()); values.sort(AnnotationAwareOrderComparator.INSTANCE); - log.info("For project [{}], found the following dry run tasks {}", - args.project.getName(), - values.stream().map(r -> r.getClass().getSimpleName()) - .collect(Collectors.toCollection(LinkedList::new))); - return flowRunner().runReleaseTasks(args.options, args.properties, - new ProjectsToRun(new ProjectToRun.ProjectToRunSupplier( - args.originalVersion.projectName, () -> args.projectToRun)), + log.info("For project [{}], found the following dry run tasks {}", args.project.getName(), values.stream() + .map(r -> r.getClass().getSimpleName()).collect(Collectors.toCollection(LinkedList::new))); + return flowRunner().runReleaseTasks(args.options, args.properties, new ProjectsToRun( + new ProjectToRun.ProjectToRunSupplier(args.originalVersion.projectName, () -> args.projectToRun)), new TasksToRun(values)); } diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/composite/MetaReleaseCompositeTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/composite/MetaReleaseCompositeTask.java index 89aeb60a..e945af15 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/composite/MetaReleaseCompositeTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/composite/MetaReleaseCompositeTask.java @@ -36,8 +36,7 @@ public class MetaReleaseCompositeTask implements CompositeReleaserTask { */ public static final int ORDER = -80; - private static final Logger log = LoggerFactory - .getLogger(MetaReleaseCompositeTask.class); + private static final Logger log = LoggerFactory.getLogger(MetaReleaseCompositeTask.class); private final ApplicationContext context; diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/composite/MetaReleaseDryRunCompositeTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/composite/MetaReleaseDryRunCompositeTask.java index 533697e6..35e4045e 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/composite/MetaReleaseDryRunCompositeTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/composite/MetaReleaseDryRunCompositeTask.java @@ -36,8 +36,7 @@ public class MetaReleaseDryRunCompositeTask implements CompositeReleaserTask { */ public static final int ORDER = -70; - private static final Logger log = LoggerFactory - .getLogger(MetaReleaseDryRunCompositeTask.class); + private static final Logger log = LoggerFactory.getLogger(MetaReleaseDryRunCompositeTask.class); private final ApplicationContext context; diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/composite/ReleaseCompositeTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/composite/ReleaseCompositeTask.java index 01b3b8dd..e40f8c6a 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/composite/ReleaseCompositeTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/composite/ReleaseCompositeTask.java @@ -82,23 +82,18 @@ public class ReleaseCompositeTask implements CompositeReleaserTask { @Override public ExecutionResult runTask(Arguments args) { - Map releaseTasks = this.context - .getBeansOfType(ReleaseReleaserTask.class); + Map releaseTasks = this.context.getBeansOfType(ReleaseReleaserTask.class); Map projectPostReleaseTasks = this.context .getBeansOfType(ProjectPostReleaseReleaserTask.class); - Collection allReleaseTasks = new LinkedList<>( - releaseTasks.values()); + Collection allReleaseTasks = new LinkedList<>(releaseTasks.values()); allReleaseTasks.addAll(projectPostReleaseTasks.values()); List values = new LinkedList<>(allReleaseTasks); values.sort(AnnotationAwareOrderComparator.INSTANCE); - log.info( - "For project [{}], found the following release and project post release tasks {}", - args.project.getName(), - values.stream().map(r -> r.getClass().getSimpleName()) + log.info("For project [{}], found the following release and project post release tasks {}", + args.project.getName(), values.stream().map(r -> r.getClass().getSimpleName()) .collect(Collectors.toCollection(LinkedList::new))); - return flowRunner().runReleaseTasks(args.options, args.properties, - new ProjectsToRun(new ProjectToRun.ProjectToRunSupplier( - args.originalVersion.projectName, () -> args.projectToRun)), + return flowRunner().runReleaseTasks(args.options, args.properties, new ProjectsToRun( + new ProjectToRun.ProjectToRunSupplier(args.originalVersion.projectName, () -> args.projectToRun)), new TasksToRun(values)); } diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/composite/ReleaseVerboseCompositeTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/composite/ReleaseVerboseCompositeTask.java index 49986272..8cc8f843 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/composite/ReleaseVerboseCompositeTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/composite/ReleaseVerboseCompositeTask.java @@ -33,8 +33,7 @@ public class ReleaseVerboseCompositeTask implements CompositeReleaserTask { */ public static final int ORDER = -90; - private static final Logger log = LoggerFactory - .getLogger(ReleaseVerboseCompositeTask.class); + private static final Logger log = LoggerFactory.getLogger(ReleaseVerboseCompositeTask.class); private final ApplicationContext context; diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/composite/TrainPostReleaseCompositeTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/composite/TrainPostReleaseCompositeTask.java index 4769cbe9..510e896b 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/composite/TrainPostReleaseCompositeTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/composite/TrainPostReleaseCompositeTask.java @@ -46,8 +46,7 @@ public class TrainPostReleaseCompositeTask implements CompositeReleaserTask { */ public static final int ORDER = -50; - private static final Logger log = LoggerFactory - .getLogger(TrainPostReleaseCompositeTask.class); + private static final Logger log = LoggerFactory.getLogger(TrainPostReleaseCompositeTask.class); private final ApplicationContext context; @@ -81,12 +80,11 @@ public class TrainPostReleaseCompositeTask implements CompositeReleaserTask { public ExecutionResult runTask(Arguments args) { Map trainPostReleaseReleaserTasks = this.context .getBeansOfType(TrainPostReleaseReleaserTask.class); - List values = new LinkedList<>( - trainPostReleaseReleaserTasks.values()); + List values = new LinkedList<>(trainPostReleaseReleaserTasks.values()); values.sort(AnnotationAwareOrderComparator.INSTANCE); log.info("Found the following post release tasks {}", values); - return flowRunner().runPostReleaseTrainTasks(args.options, args.properties, - this.name(), new TasksToRun(values)); + return flowRunner().runPostReleaseTrainTasks(args.options, args.properties, this.name(), + new TasksToRun(values)); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CloseMilestonesProjectPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CloseMilestonesProjectPostReleaseTask.java index fcabdfca..904f772e 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CloseMilestonesProjectPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CloseMilestonesProjectPostReleaseTask.java @@ -21,8 +21,7 @@ import releaser.internal.spring.Arguments; import releaser.internal.tasks.ProjectPostReleaseReleaserTask; import releaser.internal.tech.ExecutionResult; -public class CloseMilestonesProjectPostReleaseTask - implements ProjectPostReleaseReleaserTask { +public class CloseMilestonesProjectPostReleaseTask implements ProjectPostReleaseReleaserTask { /** * Order of this task. The higher value, the lower order. diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CreateTemplatesTrainPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CreateTemplatesTrainPostReleaseTask.java index 10b4de09..b1d6759d 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CreateTemplatesTrainPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/CreateTemplatesTrainPostReleaseTask.java @@ -59,8 +59,7 @@ public class CreateTemplatesTrainPostReleaseTask implements TrainPostReleaseRele return this.releaser.createEmail(args.versionFromBom, args.projects) .merge(this.releaser.createBlog(args.versionFromBom, args.projects)) .merge(this.releaser.createTweet(args.versionFromBom, args.projects)) - .merge(this.releaser.createReleaseNotes(args.versionFromBom, - args.projects)); + .merge(this.releaser.createReleaseNotes(args.versionFromBom, args.projects)); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/PostReleaseTasksConfiguration.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/PostReleaseTasksConfiguration.java index 67739ce2..ce824c13 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/PostReleaseTasksConfiguration.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/PostReleaseTasksConfiguration.java @@ -26,8 +26,7 @@ import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnDefaultFlowEnabled -@ConditionalOnProperty(value = "releaser.skip-post-release-tasks", havingValue = "false", - matchIfMissing = true) +@ConditionalOnProperty(value = "releaser.skip-post-release-tasks", havingValue = "false", matchIfMissing = true) class PostReleaseTasksConfiguration { @Bean @@ -40,24 +39,21 @@ class PostReleaseTasksConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnProperty("releaser.template.enabled") - CreateTemplatesTrainPostReleaseTask createTemplatesTrainPostReleaseTask( - Releaser releaser) { + CreateTemplatesTrainPostReleaseTask createTemplatesTrainPostReleaseTask(Releaser releaser) { return new CreateTemplatesTrainPostReleaseTask(releaser); } @Bean @ConditionalOnMissingBean @ConditionalOnProperty("releaser.git.run-updated-samples") - RunUpdatedSamplesTrainPostReleaseTask runUpdatedSamplesTrainPostReleaseTask( - Releaser releaser) { + RunUpdatedSamplesTrainPostReleaseTask runUpdatedSamplesTrainPostReleaseTask(Releaser releaser) { return new RunUpdatedSamplesTrainPostReleaseTask(releaser); } @Bean @ConditionalOnMissingBean @ConditionalOnProperty("releaser.git.update-all-test-samples") - UpdateAllTestSamplesTrainPostReleaseTask updateAllTestSamplesTrainPostReleaseTask( - Releaser releaser) { + UpdateAllTestSamplesTrainPostReleaseTask updateAllTestSamplesTrainPostReleaseTask(Releaser releaser) { return new UpdateAllTestSamplesTrainPostReleaseTask(releaser); } @@ -71,32 +67,28 @@ class PostReleaseTasksConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnProperty("releaser.git.update-release-train-docs") - UpdateReleaseTrainDocsTrainPostReleaseTask updateReleaseTrainDocsTrainPostReleaseTask( - Releaser releaser) { + UpdateReleaseTrainDocsTrainPostReleaseTask updateReleaseTrainDocsTrainPostReleaseTask(Releaser releaser) { return new UpdateReleaseTrainDocsTrainPostReleaseTask(releaser); } @Bean @ConditionalOnMissingBean @ConditionalOnProperty("releaser.git.update-release-train-wiki") - UpdateReleaseTrainWikiTrainPostReleaseTask updateReleaseTrainWikiTrainPostReleaseTask( - Releaser releaser) { + UpdateReleaseTrainWikiTrainPostReleaseTask updateReleaseTrainWikiTrainPostReleaseTask(Releaser releaser) { return new UpdateReleaseTrainWikiTrainPostReleaseTask(releaser); } @Bean @ConditionalOnMissingBean @ConditionalOnProperty("releaser.sagan.update-sagan") - UpdateSaganProjectPostReleaseTask updateSaganProjectPostReleaseTask( - Releaser releaser) { + UpdateSaganProjectPostReleaseTask updateSaganProjectPostReleaseTask(Releaser releaser) { return new UpdateSaganProjectPostReleaseTask(releaser); } @Bean @ConditionalOnMissingBean @ConditionalOnProperty("releaser.sagan.update-start-spring-io") - UpdateStartSpringIoTrainPostReleaseTask updateStartSpringIoTrainPostReleaseTask( - Releaser releaser) { + UpdateStartSpringIoTrainPostReleaseTask updateStartSpringIoTrainPostReleaseTask(Releaser releaser) { return new UpdateStartSpringIoTrainPostReleaseTask(releaser); } diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/RunUpdatedSamplesTrainPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/RunUpdatedSamplesTrainPostReleaseTask.java index 5e2c0080..9fb1e02d 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/RunUpdatedSamplesTrainPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/RunUpdatedSamplesTrainPostReleaseTask.java @@ -21,8 +21,7 @@ import releaser.internal.spring.Arguments; import releaser.internal.tasks.TrainPostReleaseReleaserTask; import releaser.internal.tech.ExecutionResult; -public class RunUpdatedSamplesTrainPostReleaseTask - implements TrainPostReleaseReleaserTask { +public class RunUpdatedSamplesTrainPostReleaseTask implements TrainPostReleaseReleaserTask { /** * Order of this task. The higher value, the lower order. diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateAllTestSamplesTrainPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateAllTestSamplesTrainPostReleaseTask.java index d280dde3..10e431b8 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateAllTestSamplesTrainPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateAllTestSamplesTrainPostReleaseTask.java @@ -21,8 +21,7 @@ import releaser.internal.spring.Arguments; import releaser.internal.tasks.TrainPostReleaseReleaserTask; import releaser.internal.tech.ExecutionResult; -public class UpdateAllTestSamplesTrainPostReleaseTask - implements TrainPostReleaseReleaserTask { +public class UpdateAllTestSamplesTrainPostReleaseTask implements TrainPostReleaseReleaserTask { /** * Order of this task. The higher value, the lower order. diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateGuidesTrainPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateGuidesTrainPostReleaseTask.java index b9c451bc..14d9e3f7 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateGuidesTrainPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateGuidesTrainPostReleaseTask.java @@ -56,8 +56,7 @@ public class UpdateGuidesTrainPostReleaseTask implements TrainPostReleaseRelease @Override public ExecutionResult runTask(Arguments args) { - return this.releaser.updateSpringGuides(args.versionFromBom, args.projects, - args.processedProjects); + return this.releaser.updateSpringGuides(args.versionFromBom, args.projects, args.processedProjects); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateReleaseTrainDocsTrainPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateReleaseTrainDocsTrainPostReleaseTask.java index dfa75c3d..5b979b61 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateReleaseTrainDocsTrainPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateReleaseTrainDocsTrainPostReleaseTask.java @@ -21,8 +21,7 @@ import releaser.internal.spring.Arguments; import releaser.internal.tasks.TrainPostReleaseReleaserTask; import releaser.internal.tech.ExecutionResult; -public class UpdateReleaseTrainDocsTrainPostReleaseTask - implements TrainPostReleaseReleaserTask { +public class UpdateReleaseTrainDocsTrainPostReleaseTask implements TrainPostReleaseReleaserTask { /** * Order of this task. The higher value, the lower order. diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateReleaseTrainWikiTrainPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateReleaseTrainWikiTrainPostReleaseTask.java index d4ffaca3..df8a6957 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateReleaseTrainWikiTrainPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateReleaseTrainWikiTrainPostReleaseTask.java @@ -21,8 +21,7 @@ import releaser.internal.spring.Arguments; import releaser.internal.tasks.TrainPostReleaseReleaserTask; import releaser.internal.tech.ExecutionResult; -public class UpdateReleaseTrainWikiTrainPostReleaseTask - implements TrainPostReleaseReleaserTask { +public class UpdateReleaseTrainWikiTrainPostReleaseTask implements TrainPostReleaseReleaserTask { /** * Order of this task. The higher value, the lower order. diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateSaganProjectPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateSaganProjectPostReleaseTask.java index b0e2c8f0..b11d5a83 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateSaganProjectPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateSaganProjectPostReleaseTask.java @@ -56,8 +56,7 @@ public class UpdateSaganProjectPostReleaseTask implements ProjectPostReleaseRele @Override public ExecutionResult runTask(Arguments args) { - return this.releaser.updateSagan(args.project, args.versionFromBom, - args.projects); + return this.releaser.updateSagan(args.project, args.versionFromBom, args.projects); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateStartSpringIoTrainPostReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateStartSpringIoTrainPostReleaseTask.java index 08269344..ad055a8f 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateStartSpringIoTrainPostReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/postrelease/UpdateStartSpringIoTrainPostReleaseTask.java @@ -21,8 +21,7 @@ import releaser.internal.spring.Arguments; import releaser.internal.tasks.TrainPostReleaseReleaserTask; import releaser.internal.tech.ExecutionResult; -public class UpdateStartSpringIoTrainPostReleaseTask - implements TrainPostReleaseReleaserTask { +public class UpdateStartSpringIoTrainPostReleaseTask implements TrainPostReleaseReleaserTask { /** * Order of this task. The higher value, the lower order. diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/release/BuildProjectReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/release/BuildProjectReleaseTask.java index 3b48840a..719276f8 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/release/BuildProjectReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/release/BuildProjectReleaseTask.java @@ -25,8 +25,7 @@ import releaser.internal.tech.ExecutionResult; public class BuildProjectReleaseTask implements DryRunReleaseReleaserTask { - private static final Logger log = LoggerFactory - .getLogger(BuildProjectReleaseTask.class); + private static final Logger log = LoggerFactory.getLogger(BuildProjectReleaseTask.class); /** * Order of this task. The higher value, the lower order. @@ -62,8 +61,7 @@ public class BuildProjectReleaseTask implements DryRunReleaseReleaserTask { @Override public ExecutionResult runTask(Arguments args) { log.info("Arguments for this release task: " + args); - return this.releaser.buildProject(args.properties, args.originalVersion, - args.versionFromBom); + return this.releaser.buildProject(args.properties, args.originalVersion, args.versionFromBom); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/release/BumpBackToSnapshotReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/release/BumpBackToSnapshotReleaseTask.java index c9e67ffe..0e28de30 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/release/BumpBackToSnapshotReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/release/BumpBackToSnapshotReleaseTask.java @@ -56,8 +56,7 @@ public class BumpBackToSnapshotReleaseTask implements ReleaseReleaserTask { @Override public ExecutionResult runTask(Arguments args) { - return this.releaser.rollbackReleaseVersion(args.project, args.projects, - args.versionFromBom); + return this.releaser.rollbackReleaseVersion(args.project, args.projects, args.versionFromBom); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/release/DeployArtifactsReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/release/DeployArtifactsReleaseTask.java index b3fb47da..db2958d0 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/release/DeployArtifactsReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/release/DeployArtifactsReleaseTask.java @@ -56,8 +56,7 @@ public class DeployArtifactsReleaseTask implements ReleaseReleaserTask { @Override public ExecutionResult runTask(Arguments args) { - return this.releaser.deploy(args.properties, args.originalVersion, - args.versionFromBom); + return this.releaser.deploy(args.properties, args.originalVersion, args.versionFromBom); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/release/PublishDocsReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/release/PublishDocsReleaseTask.java index 16014c56..76e8b872 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/release/PublishDocsReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/release/PublishDocsReleaseTask.java @@ -56,8 +56,7 @@ public class PublishDocsReleaseTask implements ReleaseReleaserTask { @Override public ExecutionResult runTask(Arguments args) { - return this.releaser.publishDocs(args.properties, args.originalVersion, - args.versionFromBom); + return this.releaser.publishDocs(args.properties, args.originalVersion, args.versionFromBom); } @Override diff --git a/releaser-spring/src/main/java/releaser/internal/tasks/release/UpdatingPomsReleaseTask.java b/releaser-spring/src/main/java/releaser/internal/tasks/release/UpdatingPomsReleaseTask.java index 978c18d0..00158c01 100644 --- a/releaser-spring/src/main/java/releaser/internal/tasks/release/UpdatingPomsReleaseTask.java +++ b/releaser-spring/src/main/java/releaser/internal/tasks/release/UpdatingPomsReleaseTask.java @@ -56,8 +56,7 @@ public class UpdatingPomsReleaseTask implements DryRunReleaseReleaserTask { @Override public ExecutionResult runTask(Arguments args) { - return this.releaser.updateProjectFromBom(args.project, args.projects, - args.versionFromBom); + return this.releaser.updateProjectFromBom(args.project, args.projects, args.versionFromBom); } @Override diff --git a/releaser-spring/src/test/java/releaser/internal/buildsystem/TestUtils.java b/releaser-spring/src/test/java/releaser/internal/buildsystem/TestUtils.java index 1996a573..e1a66c5f 100644 --- a/releaser-spring/src/test/java/releaser/internal/buildsystem/TestUtils.java +++ b/releaser-spring/src/test/java/releaser/internal/buildsystem/TestUtils.java @@ -31,15 +31,13 @@ public final class TestUtils { prepareLocalRepo("target/test-classes/projects/", "spring-cloud"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-wiki"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-release"); - prepareLocalRepo("target/test-classes/projects/", - "spring-cloud-release-with-snapshot"); + prepareLocalRepo("target/test-classes/projects/", "spring-cloud-release-with-snapshot"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-consul"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-build"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-static-angel"); } - private static void prepareLocalRepo(String buildDir, String repoPath) - throws IOException { + private static void prepareLocalRepo(String buildDir, String repoPath) throws IOException { File dotGit = new File(buildDir + repoPath + "/.git"); File git = new File(buildDir + repoPath + "/git"); if (git.exists()) { diff --git a/releaser-spring/src/test/java/releaser/internal/docs/TestDocumentationUpdater.java b/releaser-spring/src/test/java/releaser/internal/docs/TestDocumentationUpdater.java index 2b9927ae..7afa4e0e 100644 --- a/releaser-spring/src/test/java/releaser/internal/docs/TestDocumentationUpdater.java +++ b/releaser-spring/src/test/java/releaser/internal/docs/TestDocumentationUpdater.java @@ -25,11 +25,9 @@ import releaser.internal.git.ProjectGitHandler; */ public class TestDocumentationUpdater extends DocumentationUpdater { - public TestDocumentationUpdater(ReleaserProperties properties, - CustomProjectDocumentationUpdater updater, ProjectGitHandler handler, - TestReleaseContentsUpdater testRelease) { - super(new ProjectDocumentationUpdater(properties, handler, - Collections.singletonList(updater)), testRelease); + public TestDocumentationUpdater(ReleaserProperties properties, CustomProjectDocumentationUpdater updater, + ProjectGitHandler handler, TestReleaseContentsUpdater testRelease) { + super(new ProjectDocumentationUpdater(properties, handler, Collections.singletonList(updater)), testRelease); } } diff --git a/releaser-spring/src/test/java/releaser/internal/docs/TestReleaseContentsUpdater.java b/releaser-spring/src/test/java/releaser/internal/docs/TestReleaseContentsUpdater.java index b54ddf77..2c084df5 100644 --- a/releaser-spring/src/test/java/releaser/internal/docs/TestReleaseContentsUpdater.java +++ b/releaser-spring/src/test/java/releaser/internal/docs/TestReleaseContentsUpdater.java @@ -25,8 +25,8 @@ import releaser.internal.template.TemplateGenerator; */ public class TestReleaseContentsUpdater extends ReleaseTrainContentsUpdater { - public TestReleaseContentsUpdater(ReleaserProperties properties, - ProjectGitHandler handler, TemplateGenerator templateGenerator) { + public TestReleaseContentsUpdater(ReleaserProperties properties, ProjectGitHandler handler, + TemplateGenerator templateGenerator) { super(properties, handler, templateGenerator); } diff --git a/releaser-spring/src/test/java/releaser/internal/git/GitTestUtils.java b/releaser-spring/src/test/java/releaser/internal/git/GitTestUtils.java index 6d2cc492..1a8d508e 100644 --- a/releaser-spring/src/test/java/releaser/internal/git/GitTestUtils.java +++ b/releaser-spring/src/test/java/releaser/internal/git/GitTestUtils.java @@ -53,8 +53,7 @@ public final class GitTestUtils { return new GitRepo.JGitFactory().open(project); } - public static File clonedProject(File baseDir, File projectToClone) - throws IOException { + public static File clonedProject(File baseDir, File projectToClone) throws IOException { GitRepo projectRepo = new GitRepo(baseDir); return projectRepo.cloneProject(new URIish(projectToClone.toURI().toURL())); } diff --git a/releaser-spring/src/test/java/releaser/internal/spring/ProjectsToReleaseGroupsTests.java b/releaser-spring/src/test/java/releaser/internal/spring/ProjectsToReleaseGroupsTests.java index 718f7fb0..fcca159f 100644 --- a/releaser-spring/src/test/java/releaser/internal/spring/ProjectsToReleaseGroupsTests.java +++ b/releaser-spring/src/test/java/releaser/internal/spring/ProjectsToReleaseGroupsTests.java @@ -33,8 +33,7 @@ class ProjectsToReleaseGroupsTests { properties.getMetaRelease().setReleaseGroups(Arrays.asList("c,d", "e,f,g")); ProjectsToRun projectsToRun = projectsToRun(); - List groups = new ProjectsToReleaseGroups(properties) - .toReleaseGroup(projectsToRun); + List groups = new ProjectsToReleaseGroups(properties).toReleaseGroup(projectsToRun); BDDAssertions.then(groups).hasSize(5); BDDAssertions.then(projectNames(0, groups)).containsExactly("a"); @@ -45,8 +44,7 @@ class ProjectsToReleaseGroupsTests { } private List projectNames(int index, List groups) { - return groups.get(index).projectsToRun.stream() - .map(ProjectToRun.ProjectToRunSupplier::projectName) + return groups.get(index).projectsToRun.stream().map(ProjectToRun.ProjectToRunSupplier::projectName) .collect(Collectors.toCollection(LinkedList::new)); } diff --git a/releaser-spring/src/test/java/releaser/internal/spring/ReleaserPropertiesUpdaterTests.java b/releaser-spring/src/test/java/releaser/internal/spring/ReleaserPropertiesUpdaterTests.java index 1ef0bc52..1d0f1588 100644 --- a/releaser-spring/src/test/java/releaser/internal/spring/ReleaserPropertiesUpdaterTests.java +++ b/releaser-spring/src/test/java/releaser/internal/spring/ReleaserPropertiesUpdaterTests.java @@ -32,8 +32,8 @@ public class ReleaserPropertiesUpdaterTests { File relaserUpdater; public ReleaserPropertiesUpdaterTests() throws URISyntaxException { - this.relaserUpdater = new File(ReleaserPropertiesUpdaterTests.class - .getResource("/projects/releaser-updater/").toURI()); + this.relaserUpdater = new File( + ReleaserPropertiesUpdaterTests.class.getResource("/projects/releaser-updater/").toURI()); } @Test @@ -41,8 +41,7 @@ public class ReleaserPropertiesUpdaterTests { ReleaserProperties original = originalReleaserProperties(); ReleaserPropertiesUpdater updater = new ReleaserPropertiesUpdater(); - ReleaserProperties props = updater.updateProperties(original, - this.relaserUpdater); + ReleaserProperties props = updater.updateProperties(original, this.relaserUpdater); BDDAssertions.then(props.getMaven().getBuildCommand()).isEqualTo("maven_build"); BDDAssertions.then(props.getGradle().getBuildCommand()).isEqualTo("gradle_build"); diff --git a/releaser-spring/src/test/java/releaser/internal/spring/SpringBatchFlowRunnerTests.java b/releaser-spring/src/test/java/releaser/internal/spring/SpringBatchFlowRunnerTests.java index 99ecd885..45604f26 100644 --- a/releaser-spring/src/test/java/releaser/internal/spring/SpringBatchFlowRunnerTests.java +++ b/releaser-spring/src/test/java/releaser/internal/spring/SpringBatchFlowRunnerTests.java @@ -48,52 +48,42 @@ class SpringBatchFlowRunnerTests { ReleaserProperties releaserProperties = new ReleaserProperties(); @Test - void should_not_fail_the_release_when_project_post_release_task_fails( - @Autowired SpringBatchFlowRunner runner) { + void should_not_fail_the_release_when_project_post_release_task_fails(@Autowired SpringBatchFlowRunner runner) { Options options = new OptionsBuilder().interactive(false).options(); ProjectsToRun projectsToRun = projectsToRun(options, releaserProperties); TasksToRun tasks = new TasksToRun(new MyProjectPostReleaseTask()); - ExecutionResult executionResult = runner.runReleaseTasks(options, - releaserProperties, projectsToRun, tasks); + ExecutionResult executionResult = runner.runReleaseTasks(options, releaserProperties, projectsToRun, tasks); BDDAssertions.then(executionResult.isUnstable()).isTrue(); } @Test - void should_execute_post_train_tasks_when_such_property_is_set( - @Autowired SpringBatchFlowRunner runner, + void should_execute_post_train_tasks_when_such_property_is_set(@Autowired SpringBatchFlowRunner runner, @Autowired ProjectsToRunFactory factory) { - Options options = new OptionsBuilder().interactive(false).metaRelease(true) - .options(); + Options options = new OptionsBuilder().interactive(false).metaRelease(true).options(); releaserProperties.setPostReleaseTasksOnly(true); releaserProperties.getMetaRelease().setReleaseTrainProjectName("foo"); ProjectsToRun projectsToRun = projectsToRun(options, releaserProperties); - BDDMockito.given(factory.postReleaseTrain(BDDMockito.any())) - .willReturn(projectsToRun); + BDDMockito.given(factory.postReleaseTrain(BDDMockito.any())).willReturn(projectsToRun); TasksToRun tasks = new TasksToRun(new MyPostTrainReleaseTask()); - ExecutionResult executionResult = runner.runReleaseTasks(options, - releaserProperties, projectsToRun, tasks); + ExecutionResult executionResult = runner.runReleaseTasks(options, releaserProperties, projectsToRun, tasks); BDDAssertions.then(executionResult.isSkipped()).isTrue(); - executionResult = runner.runPostReleaseTrainTasks(options, releaserProperties, - "post-release", tasks); + executionResult = runner.runPostReleaseTrainTasks(options, releaserProperties, "post-release", tasks); BDDAssertions.then(executionResult.isSuccess()).isTrue(); } - private ProjectsToRun projectsToRun(Options options, - ReleaserProperties releaserProperties) { - return new ProjectsToRun(new ProjectToRun.ProjectToRunSupplier("test", - () -> projectToRun(options, releaserProperties))); + private ProjectsToRun projectsToRun(Options options, ReleaserProperties releaserProperties) { + return new ProjectsToRun( + new ProjectToRun.ProjectToRunSupplier("test", () -> projectToRun(options, releaserProperties))); } - private ProjectToRun projectToRun(Options options, - ReleaserProperties releaserProperties) { - return new ProjectToRun(new File("."), - new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "0.0.1")), + private ProjectToRun projectToRun(Options options, ReleaserProperties releaserProperties) { + return new ProjectToRun(new File("."), new ProjectsFromBom(new Projects(), new ProjectVersion("foo", "0.0.1")), new ProjectVersion("foo", "0.0.1"), releaserProperties, options); } @@ -139,9 +129,8 @@ class MyProjectPostReleaseTask implements ProjectPostReleaseReleaserTask { @Override public ExecutionResult runTask(Arguments args) { - return ExecutionResult.unstable( - HttpServerErrorException.create(HttpStatus.INTERNAL_SERVER_ERROR, "foo", - new HttpHeaders(), "".getBytes(), Charset.defaultCharset())); + return ExecutionResult.unstable(HttpServerErrorException.create(HttpStatus.INTERNAL_SERVER_ERROR, "foo", + new HttpHeaders(), "".getBytes(), Charset.defaultCharset())); } @Override diff --git a/releaser-test/pom.xml b/releaser-test/pom.xml index 0de13123..88a91e34 100644 --- a/releaser-test/pom.xml +++ b/releaser-test/pom.xml @@ -40,6 +40,11 @@ spring-boot-starter-test compile + + org.junit.vintage + junit-vintage-engine + compile + diff --git a/releaser-test/src/main/java/releaser/internal/buildsystem/MavenBomParserAccessor.java b/releaser-test/src/main/java/releaser/internal/buildsystem/MavenBomParserAccessor.java index 048cd052..12f776ad 100644 --- a/releaser-test/src/main/java/releaser/internal/buildsystem/MavenBomParserAccessor.java +++ b/releaser-test/src/main/java/releaser/internal/buildsystem/MavenBomParserAccessor.java @@ -21,8 +21,7 @@ import releaser.internal.ReleaserProperties; public class MavenBomParserAccessor { - public static BomParser bomParser(ReleaserProperties properties, - CustomBomParser parser) { + public static BomParser bomParser(ReleaserProperties properties, CustomBomParser parser) { return new MavenBomParser(properties, Collections.singletonList(parser)); } diff --git a/releaser-test/src/main/java/releaser/internal/buildsystem/TestUtils.java b/releaser-test/src/main/java/releaser/internal/buildsystem/TestUtils.java index 1996a573..e1a66c5f 100644 --- a/releaser-test/src/main/java/releaser/internal/buildsystem/TestUtils.java +++ b/releaser-test/src/main/java/releaser/internal/buildsystem/TestUtils.java @@ -31,15 +31,13 @@ public final class TestUtils { prepareLocalRepo("target/test-classes/projects/", "spring-cloud"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-wiki"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-release"); - prepareLocalRepo("target/test-classes/projects/", - "spring-cloud-release-with-snapshot"); + prepareLocalRepo("target/test-classes/projects/", "spring-cloud-release-with-snapshot"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-consul"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-build"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-static-angel"); } - private static void prepareLocalRepo(String buildDir, String repoPath) - throws IOException { + private static void prepareLocalRepo(String buildDir, String repoPath) throws IOException { File dotGit = new File(buildDir + repoPath + "/.git"); File git = new File(buildDir + repoPath + "/git"); if (git.exists()) { diff --git a/releaser-test/src/main/java/releaser/internal/docs/TestReleaseContentsUpdater.java b/releaser-test/src/main/java/releaser/internal/docs/TestReleaseContentsUpdater.java index b54ddf77..2c084df5 100644 --- a/releaser-test/src/main/java/releaser/internal/docs/TestReleaseContentsUpdater.java +++ b/releaser-test/src/main/java/releaser/internal/docs/TestReleaseContentsUpdater.java @@ -25,8 +25,8 @@ import releaser.internal.template.TemplateGenerator; */ public class TestReleaseContentsUpdater extends ReleaseTrainContentsUpdater { - public TestReleaseContentsUpdater(ReleaserProperties properties, - ProjectGitHandler handler, TemplateGenerator templateGenerator) { + public TestReleaseContentsUpdater(ReleaserProperties properties, ProjectGitHandler handler, + TemplateGenerator templateGenerator) { super(properties, handler, templateGenerator); } diff --git a/releaser-test/src/main/java/releaser/internal/git/GitTestUtils.java b/releaser-test/src/main/java/releaser/internal/git/GitTestUtils.java index 38b80e13..9ad4f806 100644 --- a/releaser-test/src/main/java/releaser/internal/git/GitTestUtils.java +++ b/releaser-test/src/main/java/releaser/internal/git/GitTestUtils.java @@ -57,8 +57,7 @@ public final class GitTestUtils { return new GitRepo.JGitFactory().init(project); } - public static File clonedProject(File baseDir, File projectToClone) - throws IOException { + public static File clonedProject(File baseDir, File projectToClone) throws IOException { GitRepo projectRepo = new GitRepo(baseDir); return projectRepo.cloneProject(new URIish(projectToClone.toURI().toURL())); } diff --git a/releaser-test/src/main/java/releaser/internal/spring/AbstractSpringAcceptanceTests.java b/releaser-test/src/main/java/releaser/internal/spring/AbstractSpringAcceptanceTests.java index 72435549..b42d61d6 100644 --- a/releaser-test/src/main/java/releaser/internal/spring/AbstractSpringAcceptanceTests.java +++ b/releaser-test/src/main/java/releaser/internal/spring/AbstractSpringAcceptanceTests.java @@ -77,15 +77,15 @@ public abstract class AbstractSpringAcceptanceTests { public static Project newProject() { Project project = new Project(); - project.projectReleases.addAll(Arrays.asList(release("1.0.0.M8"), - release("1.1.0.M8"), release("1.2.0.M8"), release("2.0.0.M8"))); + project.setReleases( + Arrays.asList(release("1.0.0.M8"), release("1.1.0.M8"), release("1.2.0.M8"), release("2.0.0.M8"))); return project; } public static Release release(String version) { Release release = new Release(); - release.version = version; - release.current = true; + release.setVersion(version); + release.setCurrent(true); return release; } @@ -114,13 +114,11 @@ public abstract class AbstractSpringAcceptanceTests { } public void thenRunUpdatedTestsWereCalled(PostReleaseActions postReleaseActions) { - BDDMockito.then(postReleaseActions).should() - .runUpdatedTests(BDDMockito.any(Projects.class)); + BDDMockito.then(postReleaseActions).should().runUpdatedTests(BDDMockito.any(Projects.class)); } public void thenRunUpdatedTestsWereNotCalled(PostReleaseActions postReleaseActions) { - BDDMockito.then(postReleaseActions).should(BDDMockito.never()) - .runUpdatedTests(BDDMockito.any(Projects.class)); + BDDMockito.then(postReleaseActions).should(BDDMockito.never()).runUpdatedTests(BDDMockito.any(Projects.class)); } public Iterable listOfCommits(File project) throws GitAPIException { @@ -146,10 +144,8 @@ public abstract class AbstractSpringAcceptanceTests { } } - public void tagIsPresentInOrigin(File origin, String expectedTag) - throws GitAPIException { - then(GitTestUtils.openGitProject(origin).tagList().call().iterator().next() - .getName()).endsWith(expectedTag); + public void tagIsPresentInOrigin(File origin, String expectedTag) throws GitAPIException { + then(GitTestUtils.openGitProject(origin).tagList().call().iterator().next().getName()).endsWith(expectedTag); } public Model pom(File dir) { @@ -197,8 +193,7 @@ public abstract class AbstractSpringAcceptanceTests { } public File file(String relativePath) throws URISyntaxException { - return new File( - AbstractSpringAcceptanceTests.class.getResource(relativePath).toURI()); + return new File(AbstractSpringAcceptanceTests.class.getResource(relativePath).toURI()); } public String text(File file) throws IOException { @@ -221,13 +216,12 @@ public abstract class AbstractSpringAcceptanceTests { } public Git clonedProject(NonAssertingTestProjectGitHandler handler, String name) { - return GitTestUtils.openGitProject(handler.clonedProjects.stream() - .filter(file -> file.getName().equals(name)).findFirst().get()); + return GitTestUtils.openGitProject( + handler.clonedProjects.stream().filter(file -> file.getName().equals(name)).findFirst().get()); } public void thenUpdateReleaseTrainDocsWasCalled(PostReleaseActions actions) { - BDDMockito.then(actions).should() - .generateReleaseTrainDocumentation(BDDMockito.any(Projects.class)); + BDDMockito.then(actions).should().generateReleaseTrainDocumentation(BDDMockito.any(Projects.class)); } public void thenUpdateReleaseTrainDocsWasNotCalled(PostReleaseActions actions) { @@ -241,8 +235,7 @@ public abstract class AbstractSpringAcceptanceTests { public void run(SpringApplicationBuilder application, Props properties, CatchingConsumer consumer) { - try (ConfigurableApplicationContext context = application.build() - .run(properties.toCommandLineProps())) { + try (ConfigurableApplicationContext context = application.build().run(properties.toCommandLineProps())) { consumer.accept(context); } catch (Exception e) { @@ -262,8 +255,7 @@ public abstract class AbstractSpringAcceptanceTests { public Set clonedProjects = new HashSet<>(); - public NonAssertingTestProjectGitHandler(ReleaserProperties properties, - Consumer docsConsumer) { + public NonAssertingTestProjectGitHandler(ReleaserProperties properties, Consumer docsConsumer) { super(properties); this.docsConsumer = docsConsumer; } @@ -306,8 +298,7 @@ public abstract class AbstractSpringAcceptanceTests { } - public static class TestExecutionResultHandler - extends SpringBatchExecutionResultHandler { + public static class TestExecutionResultHandler extends SpringBatchExecutionResultHandler { public boolean exitedSuccessOrUnstable; @@ -333,16 +324,12 @@ public abstract class AbstractSpringAcceptanceTests { public static class DefaultTestConfiguration { @Bean - SpringBatchFlowRunner mySpringBatchFlowRunner( - StepBuilderFactory stepBuilderFactory, - JobBuilderFactory jobBuilderFactory, - ProjectsToRunFactory projectsToRunFactory, JobLauncher jobLauncher, - FlowRunnerTaskExecutorSupplier flowRunnerTaskExecutorSupplier, - ConfigurableApplicationContext context, + SpringBatchFlowRunner mySpringBatchFlowRunner(StepBuilderFactory stepBuilderFactory, + JobBuilderFactory jobBuilderFactory, ProjectsToRunFactory projectsToRunFactory, JobLauncher jobLauncher, + FlowRunnerTaskExecutorSupplier flowRunnerTaskExecutorSupplier, ConfigurableApplicationContext context, ReleaserProperties releaserProperties, BuildReportHandler reportHandler) { - return new SpringBatchFlowRunner(stepBuilderFactory, jobBuilderFactory, - projectsToRunFactory, jobLauncher, flowRunnerTaskExecutorSupplier, - context, releaserProperties, reportHandler) { + return new SpringBatchFlowRunner(stepBuilderFactory, jobBuilderFactory, projectsToRunFactory, jobLauncher, + flowRunnerTaskExecutorSupplier, context, releaserProperties, reportHandler) { @Override Decision decide(Options options, ReleaserTask task) { return Decision.CONTINUE; @@ -362,8 +349,7 @@ public abstract class AbstractSpringAcceptanceTests { } @Bean - TestExecutionResultHandler testExecutionResultHandler( - BuildReportHandler buildReportHandler, + TestExecutionResultHandler testExecutionResultHandler(BuildReportHandler buildReportHandler, ConfigurableApplicationContext context) { return new TestExecutionResultHandler(buildReportHandler, context); } @@ -384,8 +370,7 @@ public abstract class AbstractSpringAcceptanceTests { } public String[] toCommandLineProps() { - return this.args.stream().map(s -> "--" + s).collect(Collectors.toList()) - .toArray(new String[0]); + return this.args.stream().map(s -> "--" + s).collect(Collectors.toList()).toArray(new String[0]); } } diff --git a/releaser-test/src/main/java/releaser/internal/spring/ArgsBuilder.java b/releaser-test/src/main/java/releaser/internal/spring/ArgsBuilder.java index b26c6005..00a4a5e2 100644 --- a/releaser-test/src/main/java/releaser/internal/spring/ArgsBuilder.java +++ b/releaser-test/src/main/java/releaser/internal/spring/ArgsBuilder.java @@ -83,14 +83,12 @@ public class ArgsBuilder { } private void removeIfPresent(String string) { - this.args.stream().filter(s -> s.startsWith(string)).findAny() - .ifPresent(s -> this.args.remove(s)); + this.args.stream().filter(s -> s.startsWith(string)).findAny().ifPresent(s -> this.args.remove(s)); } public ArgsBuilder projectsToSkip(String... toSkip) throws Exception { removeIfPresent("releaser.meta-release.projects-to-skip"); - this.args.add( - "releaser.meta-release.projects-to-skip=" + String.join(",", toSkip)); + this.args.add("releaser.meta-release.projects-to-skip=" + String.join(",", toSkip)); return this; } @@ -149,18 +147,15 @@ public class ArgsBuilder { return this; } - public ArgsBuilder cloneDestinationDirectory(File cloneDestinationDirectory) - throws Exception { + public ArgsBuilder cloneDestinationDirectory(File cloneDestinationDirectory) throws Exception { removeIfPresent("releaser.git.clone-destination-dir"); - this.args.add("releaser.git.clone-destination-dir=" - + cloneDestinationDirectory.toString()); + this.args.add("releaser.git.clone-destination-dir=" + cloneDestinationDirectory.toString()); return this; } public ArgsBuilder releaseTrainUrl(String relativePath) throws Exception { removeIfPresent("releaser.git.release-train-bom-url"); - this.args.add("releaser.git.release-train-bom-url=" - + file(relativePath).toURI().toString()); + this.args.add("releaser.git.release-train-bom-url=" + file(relativePath).toURI().toString()); return this; } diff --git a/releaser-test/src/main/java/releaser/internal/spring/meta/AbstractSpringMetaReleaseAcceptanceTests.java b/releaser-test/src/main/java/releaser/internal/spring/meta/AbstractSpringMetaReleaseAcceptanceTests.java index 7cd5d863..765f7aa7 100644 --- a/releaser-test/src/main/java/releaser/internal/spring/meta/AbstractSpringMetaReleaseAcceptanceTests.java +++ b/releaser-test/src/main/java/releaser/internal/spring/meta/AbstractSpringMetaReleaseAcceptanceTests.java @@ -36,45 +36,34 @@ import static org.assertj.core.api.BDDAssertions.then; /** * @author Marcin Grzejszczak */ -public abstract class AbstractSpringMetaReleaseAcceptanceTests - extends AbstractSpringAcceptanceTests { +public abstract class AbstractSpringMetaReleaseAcceptanceTests extends AbstractSpringAcceptanceTests { public ArgsBuilder metaReleaseArgs(File project) throws Exception { - return new ArgsBuilder(project, this.tmp) - .releaseTrainUrl("/projects/spring-cloud-release/") - .projectsToSkip("spring-boot", "spring-cloud-build", - "spring-cloud-commons", "spring-cloud-stream", - "spring-cloud-task", "spring-cloud-function", "spring-cloud-aws", - "spring-cloud-bus", "spring-cloud-config", "spring-cloud-netflix", - "spring-cloud-cloudfoundry", "spring-cloud-gateway", - "spring-cloud-security", "spring-cloud-zookeeper", - "spring-cloud-sleuth", "spring-cloud-contract", - "spring-cloud-vault") + return new ArgsBuilder(project, this.tmp).releaseTrainUrl("/projects/spring-cloud-release/") + .projectsToSkip("spring-boot", "spring-cloud-build", "spring-cloud-commons", "spring-cloud-stream", + "spring-cloud-task", "spring-cloud-function", "spring-cloud-aws", "spring-cloud-bus", + "spring-cloud-config", "spring-cloud-netflix", "spring-cloud-cloudfoundry", + "spring-cloud-gateway", "spring-cloud-security", "spring-cloud-zookeeper", + "spring-cloud-sleuth", "spring-cloud-contract", "spring-cloud-vault") .mavenBuildCommand("echo '{{profiles}}' > /tmp/executed_build") .mavenPublishCommand("echo '{{profiles}}' > /tmp/executed_docs") .mavenDeployCommand("echo '{{profiles}}' > /tmp/executed_deploy") .gitOrgUrl("file://" + this.temporaryFolder.getAbsolutePath()) - .releaseTrainBomUrl( - file("/projects/spring-cloud-release/").toURI().toString()); + .releaseTrainBomUrl(file("/projects/spring-cloud-release/").toURI().toString()); } public ArgsBuilder metaReleaseArgsForParallel(File project) throws Exception { - return new ArgsBuilder(project, this.tmp) - .releaseTrainUrl("/projects/spring-cloud-release/") - .projectsToSkip("spring-boot", "spring-cloud-commons", - "spring-cloud-stream", "spring-cloud-task", - "spring-cloud-function", "spring-cloud-aws", "spring-cloud-bus", - "spring-cloud-config", "spring-cloud-netflix", - "spring-cloud-cloudfoundry", "spring-cloud-gateway", - "spring-cloud-security", "spring-cloud-zookeeper", - "spring-cloud-sleuth", "spring-cloud-contract", - "spring-cloud-vault") + return new ArgsBuilder(project, this.tmp).releaseTrainUrl("/projects/spring-cloud-release/") + .projectsToSkip("spring-boot", "spring-cloud-commons", "spring-cloud-stream", "spring-cloud-task", + "spring-cloud-function", "spring-cloud-aws", "spring-cloud-bus", "spring-cloud-config", + "spring-cloud-netflix", "spring-cloud-cloudfoundry", "spring-cloud-gateway", + "spring-cloud-security", "spring-cloud-zookeeper", "spring-cloud-sleuth", + "spring-cloud-contract", "spring-cloud-vault") .mavenBuildCommand("echo '{{profiles}}' > /tmp/executed_build") .mavenPublishCommand("echo '{{profiles}}' > /tmp/executed_docs") .mavenDeployCommand("echo '{{profiles}}' > /tmp/executed_deploy") .gitOrgUrl("file://" + this.temporaryFolder.getAbsolutePath()) - .releaseTrainBomUrl( - file("/projects/spring-cloud-release/").toURI().toString()); + .releaseTrainBomUrl(file("/projects/spring-cloud-release/").toURI().toString()); } public Map edgwareSr10() { @@ -104,12 +93,9 @@ public abstract class AbstractSpringMetaReleaseAcceptanceTests public void thenAllStepsWereExecutedForEachProject( NonAssertingTestProjectGitHandler nonAssertingTestProjectGitHandler) { nonAssertingTestProjectGitHandler.clonedProjects.stream() - .filter(f -> !f.getName().contains("angel") - && !f.getName().equals("spring-cloud")) - .forEach(project -> { - then(Arrays.asList("spring-cloud-starter-build", - "spring-cloud-consul")) - .contains(pom(project).getArtifactId()); + .filter(f -> !f.getName().contains("angel") && !f.getName().equals("spring-cloud")).forEach(project -> { + then(Arrays.asList("spring-cloud-starter-build", "spring-cloud-consul")) + .contains(pom(project).getArtifactId()); then(new File("/tmp/executed_build")).exists(); then(new File("/tmp/executed_deploy")).exists(); then(new File("/tmp/executed_docs")).exists(); @@ -117,21 +103,18 @@ public abstract class AbstractSpringMetaReleaseAcceptanceTests } public void thenSaganWasCalled(SaganUpdater saganUpdater) { - BDDMockito.then(saganUpdater).should(BDDMockito.atLeastOnce()).updateSagan( - BDDMockito.any(File.class), BDDMockito.anyString(), - BDDMockito.any(ProjectVersion.class), - BDDMockito.any(ProjectVersion.class), BDDMockito.any(Projects.class)); + BDDMockito.then(saganUpdater).should(BDDMockito.atLeastOnce()).updateSagan(BDDMockito.any(File.class), + BDDMockito.anyString(), BDDMockito.any(ProjectVersion.class), BDDMockito.any(ProjectVersion.class), + BDDMockito.any(Projects.class)); } public void thenSaganWasNotCalled(SaganUpdater saganUpdater) { - BDDMockito.then(saganUpdater).should(BDDMockito.never()).updateSagan( - BDDMockito.any(File.class), BDDMockito.anyString(), - BDDMockito.any(ProjectVersion.class), - BDDMockito.any(ProjectVersion.class), BDDMockito.any(Projects.class)); + BDDMockito.then(saganUpdater).should(BDDMockito.never()).updateSagan(BDDMockito.any(File.class), + BDDMockito.anyString(), BDDMockito.any(ProjectVersion.class), BDDMockito.any(ProjectVersion.class), + BDDMockito.any(Projects.class)); } - public static class NonAssertingTestProjectGitHubHandler - extends ProjectGitHubHandler { + public static class NonAssertingTestProjectGitHubHandler extends ProjectGitHubHandler { boolean closedMilestones = false; @@ -154,8 +137,7 @@ public abstract class AbstractSpringMetaReleaseAcceptanceTests } @Override - public void createIssueInStartSpringIo(Projects projects, - ProjectVersion version) { + public void createIssueInStartSpringIo(Projects projects, ProjectVersion version) { this.issueCreatedInStartSpringIo = true; } diff --git a/spring-cloud-info/pom.xml b/spring-cloud-info/pom.xml index 195b358b..597d8cfc 100644 --- a/spring-cloud-info/pom.xml +++ b/spring-cloud-info/pom.xml @@ -17,8 +17,9 @@ 1.1.4 3.6.3 3.1.6.RELEASE - Greenwich.RELEASE - 2.0.5.RELEASE + 0.2.0-RELEASE + 2021.0.0 + 2.0.6.RELEASE @@ -58,6 +59,10 @@ org.springframework.boot spring-boot-starter-actuator + + org.springframework.cloud + spring-cloud-starter-bootstrap + org.springframework.boot @@ -69,6 +74,11 @@ spring-restdocs-mockmvc test + + org.junit.vintage + junit-vintage-engine + test + diff --git a/spring-cloud-info/src/main/java/org/springframework/cloud/info/InitializrSpringCloudInfoService.java b/spring-cloud-info/src/main/java/org/springframework/cloud/info/InitializrSpringCloudInfoService.java index 1b79d37c..6992ccfc 100644 --- a/spring-cloud-info/src/main/java/org/springframework/cloud/info/InitializrSpringCloudInfoService.java +++ b/spring-cloud-info/src/main/java/org/springframework/cloud/info/InitializrSpringCloudInfoService.java @@ -35,8 +35,7 @@ public class InitializrSpringCloudInfoService extends SpringCloudRelease { private RestTemplate rest; - public InitializrSpringCloudInfoService(RestTemplate rest, Github github, - GithubPomReader reader) { + public InitializrSpringCloudInfoService(RestTemplate rest, Github github, GithubPomReader reader) { super(github, reader); this.rest = rest; } @@ -48,17 +47,16 @@ public class InitializrSpringCloudInfoService extends SpringCloudRelease { Map cache = new HashMap<>(); Map response = rest.getForObject(INITIALIZR_URL, Map.class); if (!response.containsKey("bom-ranges")) { - throw new SpringCloudVersionNotFoundException(new InitializrParseException( - "bom-ranges key not found in Initializr info endpoint")); + throw new SpringCloudVersionNotFoundException( + new InitializrParseException("bom-ranges key not found in Initializr info endpoint")); } Map bomRanges = (Map) response.get("bom-ranges"); if (!bomRanges.containsKey("spring-cloud")) { - throw new SpringCloudVersionNotFoundException(new InitializrParseException( - "spring-cloud key not found in Initializr info endpoint")); + throw new SpringCloudVersionNotFoundException( + new InitializrParseException("spring-cloud key not found in Initializr info endpoint")); } - Map springCloud = (Map) bomRanges - .get("spring-cloud"); + Map springCloud = (Map) bomRanges.get("spring-cloud"); for (String key : springCloud.keySet()) { String rangeString = springCloud.get(key); cache.put(key, parseRangeString(rangeString, key)); @@ -71,8 +69,7 @@ public class InitializrSpringCloudInfoService extends SpringCloudRelease { throw new SpringCloudVersionNotFoundException(springBootVersion); } - private SpringBootAndCloudVersion parseRangeString(String rangeString, - String springCloudVersion) { + private SpringBootAndCloudVersion parseRangeString(String rangeString, String springCloudVersion) { // Example of rangeString Spring Boot >=2.0.0.M3 and <2.0.0.M5 String versions = rangeString.substring(13); boolean startVersionInclusive = true; @@ -94,12 +91,11 @@ public class InitializrSpringCloudInfoService extends SpringCloudRelease { cleanedVersions = versions.split(" and <"); } if (cleanedVersions.length == 1) { - return new SpringBootAndCloudVersion(cleanedVersions[0], - startVersionInclusive, "99999.99999.99999.RELEASE", + return new SpringBootAndCloudVersion(cleanedVersions[0], startVersionInclusive, "99999.99999.99999.RELEASE", endVersionInclusive, springCloudVersion); } - return new SpringBootAndCloudVersion(cleanedVersions[0], startVersionInclusive, - cleanedVersions[1], endVersionInclusive, springCloudVersion); + return new SpringBootAndCloudVersion(cleanedVersions[0], startVersionInclusive, cleanedVersions[1], + endVersionInclusive, springCloudVersion); } } diff --git a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringBootAndCloudVersion.java b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringBootAndCloudVersion.java index 56930aa6..f3ebe0a0 100644 --- a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringBootAndCloudVersion.java +++ b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringBootAndCloudVersion.java @@ -37,8 +37,7 @@ public class SpringBootAndCloudVersion { private String springCloudVersion; - public SpringBootAndCloudVersion(String bootStartVersion, - boolean statVersionInclusive, String bootEndVersion, + public SpringBootAndCloudVersion(String bootStartVersion, boolean statVersionInclusive, String bootEndVersion, boolean endVersionInclusive, String springCloudVersion) { this.bootEndVersion = bootEndVersion; this.comparableBootEndVersion = new ComparableVersion(bootEndVersion); @@ -80,10 +79,8 @@ public class SpringBootAndCloudVersion { boolean matchesSpringBootVersion(ComparableVersion versionToCheck) { int startVersionComparison = comparableBootStartVersion.compareTo(versionToCheck); int endVersionComparison = versionToCheck.compareTo(comparableBootEndVersion); - return ((startVersionInclusive && startVersionComparison == 0) - || startVersionComparison <= -1) - && ((endVersionInclusive && endVersionComparison == 0) - || endVersionComparison <= -1); + return ((startVersionInclusive && startVersionComparison == 0) || startVersionComparison <= -1) + && ((endVersionInclusive && endVersionComparison == 0) || endVersionComparison <= -1); } } diff --git a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoApplication.java b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoApplication.java index 093567bb..8de2b467 100644 --- a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoApplication.java +++ b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoApplication.java @@ -45,8 +45,7 @@ public class SpringCloudInfoApplication { SpringCloudInfoConfigurationProperties properties) { Github github = new RtGithub(properties.getGit().getOauthToken()); RestTemplate rest = new RestTemplateBuilder().build(); - return new InitializrSpringCloudInfoService(rest, github, - new GithubPomReader(new MavenXpp3Reader(), rest)); + return new InitializrSpringCloudInfoService(rest, github, new GithubPomReader(new MavenXpp3Reader(), rest)); } @Configuration @@ -54,8 +53,7 @@ public class SpringCloudInfoApplication { @Override protected void configure(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().permitAll().and().httpBasic().disable() - .csrf().disable(); + http.authorizeRequests().anyRequest().permitAll().and().httpBasic().disable().csrf().disable(); } } diff --git a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoRestController.java b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoRestController.java index 85639a5a..e9394e6e 100644 --- a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoRestController.java +++ b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoRestController.java @@ -57,8 +57,7 @@ public class SpringCloudInfoRestController { } @GetMapping("/bomversions/{bomVersion}") - public Map bomVersions(@PathVariable String bomVersion) - throws IOException { + public Map bomVersions(@PathVariable String bomVersion) throws IOException { try { return versionService.getReleaseVersions(bomVersion); } @@ -74,8 +73,7 @@ public class SpringCloudInfoRestController { } @GetMapping("/milestones/{name}/duedate") - public SpringCloudInfoService.Milestone milestoneDueDate(@PathVariable String name) - throws IOException { + public SpringCloudInfoService.Milestone milestoneDueDate(@PathVariable String name) throws IOException { try { return versionService.getMilestoneDueDate(name); } diff --git a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoService.java b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoService.java index 1540b7c8..d435174a 100644 --- a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoService.java +++ b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudInfoService.java @@ -29,18 +29,15 @@ import org.springframework.cloud.info.exceptions.SpringCloudVersionNotFoundExcep */ public interface SpringCloudInfoService { - SpringCloudVersion getSpringCloudVersion(String bootVersion) - throws SpringCloudVersionNotFoundException; + SpringCloudVersion getSpringCloudVersion(String bootVersion) throws SpringCloudVersionNotFoundException; Collection getSpringCloudVersions() throws IOException; - Map getReleaseVersions(String bomVersion) - throws SpringCloudVersionNotFoundException, IOException; + Map getReleaseVersions(String bomVersion) throws SpringCloudVersionNotFoundException, IOException; Collection getMilestones() throws IOException; - Milestone getMilestoneDueDate(String name) - throws SpringCloudMilestoneNotFoundException, IOException; + Milestone getMilestoneDueDate(String name) throws SpringCloudMilestoneNotFoundException, IOException; class Milestone { diff --git a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudRelease.java b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudRelease.java index 18b3056f..471613e2 100644 --- a/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudRelease.java +++ b/spring-cloud-info/src/main/java/org/springframework/cloud/info/SpringCloudRelease.java @@ -56,8 +56,7 @@ public abstract class SpringCloudRelease implements SpringCloudInfoService { /** * Github tags path. */ - public static final String SPRING_CLOUD_RELEASE_TAGS_PATH = "repos/" - + SPRING_CLOUD_RELEASE_COORDINATES + "/tags"; + public static final String SPRING_CLOUD_RELEASE_TAGS_PATH = "repos/" + SPRING_CLOUD_RELEASE_COORDINATES + "/tags"; private static final String SPRING_CLOUD_RELEASE_RAW = "https://raw.githubusercontent.com/" + SPRING_CLOUD_RELEASE_COORDINATES; @@ -87,8 +86,8 @@ public abstract class SpringCloudRelease implements SpringCloudInfoService { @Cacheable("springCloudVersions") public Collection getSpringCloudVersions() throws IOException { List releaseVersions = new ArrayList<>(); - JsonReader reader = github.entry().uri().path(SPRING_CLOUD_RELEASE_TAGS_PATH) - .back().fetch().as(JsonResponse.class).json(); + JsonReader reader = github.entry().uri().path(SPRING_CLOUD_RELEASE_TAGS_PATH).back().fetch() + .as(JsonResponse.class).json(); JsonArray tags = reader.readArray(); reader.close(); List tagsList = tags.getValuesAs(JsonObject.class); @@ -108,12 +107,10 @@ public abstract class SpringCloudRelease implements SpringCloudInfoService { } try { Map versions = new HashMap<>(); - Model model = reader.readPomFromUrl( - String.format(SPRING_CLOUD_RELEASE_DEPENDENCIES_RAW, bomVersion)); + Model model = reader.readPomFromUrl(String.format(SPRING_CLOUD_RELEASE_DEPENDENCIES_RAW, bomVersion)); for (String name : model.getProperties().stringPropertyNames()) { if (name.startsWith("spring-cloud-")) { - versions.put(name.replace(".version", ""), - model.getProperties().getProperty(name)); + versions.put(name.replace(".version", ""), model.getProperties().getProperty(name)); } } versions.put("spring-boot", getSpringCloudBootVersion(bomVersion)); @@ -138,8 +135,7 @@ public abstract class SpringCloudRelease implements SpringCloudInfoService { @Override @Cacheable("milestoneDueDate") - public Milestone getMilestoneDueDate(String name) - throws SpringCloudMilestoneNotFoundException, IOException { + public Milestone getMilestoneDueDate(String name) throws SpringCloudMilestoneNotFoundException, IOException { Iterable milestones = getMilestonesFromGithub(); for (com.jcabi.github.Milestone milestone : milestones) { JsonObject json = milestone.json(); @@ -149,8 +145,7 @@ public abstract class SpringCloudRelease implements SpringCloudInfoService { } else { Instant instant = Instant.parse(json.getString("due_on")); - return new Milestone(LocalDateTime - .ofInstant(instant, ZoneId.of(ZoneOffset.UTC.getId())) + return new Milestone(LocalDateTime.ofInstant(instant, ZoneId.of(ZoneOffset.UTC.getId())) .toLocalDate().toString()); } } @@ -161,15 +156,12 @@ public abstract class SpringCloudRelease implements SpringCloudInfoService { private Iterable getMilestonesFromGithub() { Map params = new HashMap<>(); params.put("state", "open"); - return github.repos() - .get(new Coordinates.Simple(SPRING_CLOUD_RELEASE_COORDINATES)) - .milestones().iterate(params); + return github.repos().get(new Coordinates.Simple(SPRING_CLOUD_RELEASE_COORDINATES)).milestones() + .iterate(params); } - private String getSpringCloudBootVersion(String bomVersion) - throws IOException, XmlPullParserException { - Model model = reader.readPomFromUrl( - String.format(SPRING_CLOUD_STARTER_PARENT_RAW, bomVersion)); + private String getSpringCloudBootVersion(String bomVersion) throws IOException, XmlPullParserException { + Model model = reader.readPomFromUrl(String.format(SPRING_CLOUD_STARTER_PARENT_RAW, bomVersion)); return model.getParent().getVersion(); } diff --git a/spring-cloud-info/src/main/java/org/springframework/cloud/info/exceptions/SpringCloudMilestoneNotFoundException.java b/spring-cloud-info/src/main/java/org/springframework/cloud/info/exceptions/SpringCloudMilestoneNotFoundException.java index ccb26f2c..2330114f 100644 --- a/spring-cloud-info/src/main/java/org/springframework/cloud/info/exceptions/SpringCloudMilestoneNotFoundException.java +++ b/spring-cloud-info/src/main/java/org/springframework/cloud/info/exceptions/SpringCloudMilestoneNotFoundException.java @@ -22,8 +22,7 @@ package org.springframework.cloud.info.exceptions; public class SpringCloudMilestoneNotFoundException extends Exception { public SpringCloudMilestoneNotFoundException(String name) { - super("Spring Cloud milestone " + name - + " was not found in Spring Cloud Release"); + super("Spring Cloud milestone " + name + " was not found in Spring Cloud Release"); } } diff --git a/spring-cloud-info/src/main/java/org/springframework/cloud/info/exceptions/SpringCloudVersionNotFoundException.java b/spring-cloud-info/src/main/java/org/springframework/cloud/info/exceptions/SpringCloudVersionNotFoundException.java index 85a0a442..b1fdd31f 100644 --- a/spring-cloud-info/src/main/java/org/springframework/cloud/info/exceptions/SpringCloudVersionNotFoundException.java +++ b/spring-cloud-info/src/main/java/org/springframework/cloud/info/exceptions/SpringCloudVersionNotFoundException.java @@ -22,8 +22,7 @@ package org.springframework.cloud.info.exceptions; public class SpringCloudVersionNotFoundException extends Exception { public SpringCloudVersionNotFoundException(String springBootVersion) { - super("Spring Cloud version not found for Spring Boot Version " - + springBootVersion); + super("Spring Cloud version not found for Spring Boot Version " + springBootVersion); } public SpringCloudVersionNotFoundException(Exception e) { diff --git a/spring-cloud-info/src/test/java/org/springframework/cloud/info/InitializrSpringCloudInfoServiceTests.java b/spring-cloud-info/src/test/java/org/springframework/cloud/info/InitializrSpringCloudInfoServiceTests.java index a69d706c..4f0aa910 100644 --- a/spring-cloud-info/src/test/java/org/springframework/cloud/info/InitializrSpringCloudInfoServiceTests.java +++ b/spring-cloud-info/src/test/java/org/springframework/cloud/info/InitializrSpringCloudInfoServiceTests.java @@ -75,8 +75,7 @@ public class InitializrSpringCloudInfoServiceTests { Github github = mock(Github.class); GithubPomReader githubPomReader = mock(GithubPomReader.class); when(rest.getForObject(anyString(), eq(Map.class))).thenReturn(new HashMap()); - InitializrSpringCloudInfoService service = new InitializrSpringCloudInfoService( - rest, github, githubPomReader); + InitializrSpringCloudInfoService service = new InitializrSpringCloudInfoService(rest, github, githubPomReader); try { service.getSpringCloudVersion("2.1.0"); fail("Exception should have been thrown"); @@ -94,8 +93,7 @@ public class InitializrSpringCloudInfoServiceTests { Map> info = new HashMap<>(); info.put("bom-ranges", new HashMap<>()); when(rest.getForObject(anyString(), eq(Map.class))).thenReturn(info); - InitializrSpringCloudInfoService service = new InitializrSpringCloudInfoService( - rest, github, githubPomReader); + InitializrSpringCloudInfoService service = new InitializrSpringCloudInfoService(rest, github, githubPomReader); try { service.getSpringCloudVersion("2.1.0"); fail("Exception should have been thrown"); @@ -111,25 +109,19 @@ public class InitializrSpringCloudInfoServiceTests { RestTemplate rest = mock(RestTemplate.class); Github github = mock(Github.class); GithubPomReader githubPomReader = mock(GithubPomReader.class); - when(githubPomReader.readPomFromUrl(eq(String - .format(SpringCloudRelease.SPRING_CLOUD_STARTER_PARENT_RAW, bomVersion)))) - .thenReturn(new MavenXpp3Reader() - .read(new FileReader(new ClassPathResource( - "spring-cloud-starter-parent-pom.xml") - .getFile()))); - when(githubPomReader.readPomFromUrl(eq(String.format( - SpringCloudRelease.SPRING_CLOUD_RELEASE_DEPENDENCIES_RAW, bomVersion)))) + when(githubPomReader + .readPomFromUrl(eq(String.format(SpringCloudRelease.SPRING_CLOUD_STARTER_PARENT_RAW, bomVersion)))) .thenReturn(new MavenXpp3Reader().read(new FileReader( - new ClassPathResource("spring-cloud-dependencies-pom.xml") - .getFile()))); + new ClassPathResource("spring-cloud-starter-parent-pom.xml").getFile()))); + when(githubPomReader.readPomFromUrl( + eq(String.format(SpringCloudRelease.SPRING_CLOUD_RELEASE_DEPENDENCIES_RAW, bomVersion)))) + .thenReturn(new MavenXpp3Reader().read( + new FileReader(new ClassPathResource("spring-cloud-dependencies-pom.xml").getFile()))); InitializrSpringCloudInfoService service = spy( new InitializrSpringCloudInfoService(rest, github, githubPomReader)); - doReturn(Arrays.asList(new String[] { bomVersion })).when(service) - .getSpringCloudVersions(); - Map releaseVersionsResult = service - .getReleaseVersions(bomVersion); - assertThat(releaseVersionsResult, - Matchers.equalTo(SpringCloudInfoTestData.releaseVersions)); + doReturn(Arrays.asList(new String[] { bomVersion })).when(service).getSpringCloudVersions(); + Map releaseVersionsResult = service.getReleaseVersions(bomVersion); + assertThat(releaseVersionsResult, Matchers.equalTo(SpringCloudInfoTestData.releaseVersions)); } @Test(expected = SpringCloudVersionNotFoundException.class) @@ -138,17 +130,14 @@ public class InitializrSpringCloudInfoServiceTests { RestTemplate rest = mock(RestTemplate.class); Github github = mock(Github.class); GithubPomReader githubPomReader = mock(GithubPomReader.class); - when(githubPomReader.readPomFromUrl(eq(String - .format(SpringCloudRelease.SPRING_CLOUD_STARTER_PARENT_RAW, bomVersion)))) - .thenReturn(new MavenXpp3Reader() - .read(new FileReader(new ClassPathResource( - "spring-cloud-starter-parent-pom.xml") - .getFile()))); - when(githubPomReader.readPomFromUrl(eq(String.format( - SpringCloudRelease.SPRING_CLOUD_RELEASE_DEPENDENCIES_RAW, bomVersion)))) + when(githubPomReader + .readPomFromUrl(eq(String.format(SpringCloudRelease.SPRING_CLOUD_STARTER_PARENT_RAW, bomVersion)))) .thenReturn(new MavenXpp3Reader().read(new FileReader( - new ClassPathResource("spring-cloud-dependencies-pom.xml") - .getFile()))); + new ClassPathResource("spring-cloud-starter-parent-pom.xml").getFile()))); + when(githubPomReader.readPomFromUrl( + eq(String.format(SpringCloudRelease.SPRING_CLOUD_RELEASE_DEPENDENCIES_RAW, bomVersion)))) + .thenReturn(new MavenXpp3Reader().read( + new FileReader(new ClassPathResource("spring-cloud-dependencies-pom.xml").getFile()))); InitializrSpringCloudInfoService service = spy( new InitializrSpringCloudInfoService(rest, github, githubPomReader)); doReturn(new ArrayList()).when(service).getSpringCloudVersions(); @@ -163,10 +152,8 @@ public class InitializrSpringCloudInfoServiceTests { Response response = mock(Response.class); Request request = mock(Request.class); RequestURI requestURI = mock(RequestURI.class); - JsonResponse jsonResponse = new JsonResponse(new DefaultResponse(request, 200, "", - new Array<>(), - IOUtils.toByteArray(new ClassPathResource("spring-cloud-versions.json") - .getInputStream()))); + JsonResponse jsonResponse = new JsonResponse(new DefaultResponse(request, 200, "", new Array<>(), + IOUtils.toByteArray(new ClassPathResource("spring-cloud-versions.json").getInputStream()))); doReturn(request).when(requestURI).back(); doReturn(requestURI).when(requestURI).path(eq(SPRING_CLOUD_RELEASE_TAGS_PATH)); doReturn(requestURI).when(request).uri(); @@ -175,9 +162,8 @@ public class InitializrSpringCloudInfoServiceTests { doReturn(request).when(github).entry(); InitializrSpringCloudInfoService service = spy( new InitializrSpringCloudInfoService(rest, github, githubPomReader)); - assertThat(service.getSpringCloudVersions(), - Matchers.equalTo(SpringCloudInfoTestData.springCloudVersions.stream() - .map(v -> v.replaceFirst("v", "")).collect(Collectors.toList()))); + assertThat(service.getSpringCloudVersions(), Matchers.equalTo(SpringCloudInfoTestData.springCloudVersions + .stream().map(v -> v.replaceFirst("v", "")).collect(Collectors.toList()))); } @Test @@ -226,8 +212,7 @@ public class InitializrSpringCloudInfoServiceTests { for (String m : milestoneStrings.keySet()) { Milestone milestone = mock(Milestone.class); String dueDate = milestoneStrings.get(m); - JsonObjectBuilder builder = builderFactory.createObjectBuilder().add("title", - m); + JsonObjectBuilder builder = builderFactory.createObjectBuilder().add("title", m); if (dueDate == null) { builder.add("due_on", JsonValue.NULL); } @@ -256,8 +241,7 @@ public class InitializrSpringCloudInfoServiceTests { Map>> info = new HashMap<>(); info.put("bom-ranges", springCloud); when(rest.getForObject(anyString(), eq(Map.class))).thenReturn(info); - InitializrSpringCloudInfoService service = new InitializrSpringCloudInfoService( - rest, github, githubPomReader); + InitializrSpringCloudInfoService service = new InitializrSpringCloudInfoService(rest, github, githubPomReader); String version = service.getSpringCloudVersion("2.1.0.RELEASE").getVersion(); assertThat(version, Matchers.equalTo("Greenwich.SR1")); version = service.getSpringCloudVersion("2.1.4.RELEASE").getVersion(); @@ -273,20 +257,16 @@ public class InitializrSpringCloudInfoServiceTests { private Map generateSpringCloudData() { Map data = new HashMap<>(); data.put("Edgware.SR5", "Spring Boot >=1.5.0.RELEASE and <=1.5.20.RELEASE"); - data.put("Edgware.BUILD-SNAPSHOT", - "Spring Boot >=1.5.21.BUILD-SNAPSHOT and <2.0.0.M1"); + data.put("Edgware.BUILD-SNAPSHOT", "Spring Boot >=1.5.21.BUILD-SNAPSHOT and <2.0.0.M1"); data.put("Finchley.M2", "Spring Boot >=2.0.0.M3 and <2.0.0.M5"); data.put("Finchley.M3", "Spring Boot >=2.0.0.M5 and <=2.0.0.M5"); data.put("Finchley.M4", "Spring Boot >=2.0.0.M6 and <=2.0.0.M6"); data.put("Finchley.RC1", "Spring Boot >=2.0.1.RELEASE and <2.0.2.RELEASE"); data.put("Finchley.RC2", "Spring Boot >=2.0.2.RELEASE and <2.0.3.RELEASE"); - data.put("Finchley.SR3", - "Spring Boot >=2.0.3.RELEASE and <2.0.999.BUILD-SNAPSHOT"); - data.put("Finchley.BUILD-SNAPSHO", - "Spring Boot >=2.0.999.BUILD-SNAPSHOT and <2.1.0.M3"); + data.put("Finchley.SR3", "Spring Boot >=2.0.3.RELEASE and <2.0.999.BUILD-SNAPSHOT"); + data.put("Finchley.BUILD-SNAPSHO", "Spring Boot >=2.0.999.BUILD-SNAPSHOT and <2.1.0.M3"); data.put("Greenwich.M1", "Spring Boot >=2.1.0.M3 and <2.1.0.RELEASE"); - data.put("Greenwich.SR1", - "Spring Boot >=2.1.0.RELEASE and <2.1.5.BUILD-SNAPSHOT"); + data.put("Greenwich.SR1", "Spring Boot >=2.1.0.RELEASE and <2.1.5.BUILD-SNAPSHOT"); data.put("Greenwich.BUILD-SNAPSHOT", "Spring Boot >=2.1.5.BUILD-SNAPSHOT"); return data; diff --git a/spring-cloud-info/src/test/java/org/springframework/cloud/info/SpringCloudInfoRestControllerTests.java b/spring-cloud-info/src/test/java/org/springframework/cloud/info/SpringCloudInfoRestControllerTests.java index 5973e90c..d7467c12 100644 --- a/spring-cloud-info/src/test/java/org/springframework/cloud/info/SpringCloudInfoRestControllerTests.java +++ b/spring-cloud-info/src/test/java/org/springframework/cloud/info/SpringCloudInfoRestControllerTests.java @@ -68,8 +68,8 @@ public class SpringCloudInfoRestControllerTests { @Before public void setUp() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context) - .apply(documentationConfiguration(this.restDocumentation).uris() - .withHost("spring-cloud-info.cfapps.io").withPort(80)) + .apply(documentationConfiguration(this.restDocumentation).uris().withHost("spring-cloud-info.cfapps.io") + .withPort(80)) .build(); } @@ -78,59 +78,47 @@ public class SpringCloudInfoRestControllerTests { doReturn(new SpringCloudVersion("Greenwich.RELEASE")).when(springCloudInfoService) .getSpringCloudVersion(eq("2.1.1.RELEASE")); this.mockMvc - .perform(get("/springcloudversion/springboot/{bootVersion}", - "2.1.1.RELEASE").accept(MediaType.APPLICATION_JSON)) + .perform(get("/springcloudversion/springboot/{bootVersion}", "2.1.1.RELEASE") + .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andDo(document("springcloudversion", - pathParameters(parameterWithName("bootVersion") - .description("The Spring Boot version")), - responseFields(fieldWithPath("version") - .description("Spring Cloud version")))); + pathParameters(parameterWithName("bootVersion").description("The Spring Boot version")), + responseFields(fieldWithPath("version").description("Spring Cloud version")))); } @Test public void versions() throws Exception { - doReturn(springCloudVersions.stream().map(v -> v.replaceFirst("v", "")) - .collect(Collectors.toList())).when(springCloudInfoService) - .getSpringCloudVersions(); - this.mockMvc - .perform(get("/springcloudversions").accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andDo(document("springcloudversions", responseFields( - fieldWithPath("[]").description("An array versions")))); + doReturn(springCloudVersions.stream().map(v -> v.replaceFirst("v", "")).collect(Collectors.toList())) + .when(springCloudInfoService).getSpringCloudVersions(); + this.mockMvc.perform(get("/springcloudversions").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()) + .andDo(document("springcloudversions", + responseFields(fieldWithPath("[]").description("An array versions")))); } @Test public void bomVersions() throws Exception { doReturn(SpringCloudInfoTestData.releaseVersions).when(springCloudInfoService) .getReleaseVersions(eq("Finchley.SR1")); - this.mockMvc - .perform(get("/bomversions/Finchley.SR1") - .accept(MediaType.APPLICATION_JSON)) + this.mockMvc.perform(get("/bomversions/Finchley.SR1").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()).andDo(document("bomversions")); } @Test public void milestones() throws Exception { - doReturn(SpringCloudInfoTestData.milestoneStrings.keySet()) - .when(springCloudInfoService).getMilestones(); - this.mockMvc.perform(get("/milestones").accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()).andDo(document("milestones")); + doReturn(SpringCloudInfoTestData.milestoneStrings.keySet()).when(springCloudInfoService).getMilestones(); + this.mockMvc.perform(get("/milestones").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()) + .andDo(document("milestones")); } @Test public void milestoneDueDate() throws Exception { - doReturn(new SpringCloudInfoService.Milestone("2019-07-31")) - .when(springCloudInfoService).getMilestoneDueDate(eq("Hoxton.RELEASE")); - this.mockMvc - .perform(get("/milestones/{release}/duedate", "Hoxton.RELEASE") - .accept(MediaType.APPLICATION_JSON)) + doReturn(new SpringCloudInfoService.Milestone("2019-07-31")).when(springCloudInfoService) + .getMilestoneDueDate(eq("Hoxton.RELEASE")); + this.mockMvc.perform(get("/milestones/{release}/duedate", "Hoxton.RELEASE").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andDo(document("milestoneduedate", - pathParameters(parameterWithName("release") - .description("The Spring Cloud release train name")), - responseFields(fieldWithPath("dueDate") - .description("Spring Cloud milestone due date")))); + pathParameters(parameterWithName("release").description("The Spring Cloud release train name")), + responseFields(fieldWithPath("dueDate").description("Spring Cloud milestone due date")))); } } diff --git a/spring-cloud-info/src/test/java/org/springframework/cloud/info/SpringCloudInfoTestData.java b/spring-cloud-info/src/test/java/org/springframework/cloud/info/SpringCloudInfoTestData.java index 6381a575..4e688500 100644 --- a/spring-cloud-info/src/test/java/org/springframework/cloud/info/SpringCloudInfoTestData.java +++ b/spring-cloud-info/src/test/java/org/springframework/cloud/info/SpringCloudInfoTestData.java @@ -33,29 +33,33 @@ public final class SpringCloudInfoTestData { public static Map milestoneStrings = new HashMap<>(); static { - releaseVersions.put("spring-boot", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-aws", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-bus", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-cloudfoundry", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-commons", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-config", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-consul", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-contract", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-function", "2.1.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-gateway", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-gcp", "1.1.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-kubernetes", "1.1.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-netflix", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-openfeign", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-security", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-sleuth", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-stream", "Germantown.BUILD-SNAPSHOT"); + releaseVersions.put("spring-boot", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-aws", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-bus", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-cloudfoundry", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-commons", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-config", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-consul", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-contract", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-function", "2.1.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-gateway", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-gcp", "1.1.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-kubernetes", "1.1.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-netflix", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-openfeign", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-security", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-sleuth", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-stream", "Germantown-SNAPSHOT"); releaseVersions.put("spring-cloud-task", "2.0.0.RELEASE"); - releaseVersions.put("spring-cloud-vault", "2.2.0.BUILD-SNAPSHOT"); - releaseVersions.put("spring-cloud-zookeeper", "2.2.0.BUILD-SNAPSHOT"); + releaseVersions.put("spring-cloud-vault", "2.2.0-SNAPSHOT"); + releaseVersions.put("spring-cloud-zookeeper", "2.2.0-SNAPSHOT"); } static { + springCloudVersions.add("v2020.0.1"); + springCloudVersions.add("v2020.0.0"); + springCloudVersions.add("v2020.0.0-RC1"); + springCloudVersions.add("v2020.0.0-M1"); springCloudVersions.add("vGreenwich.SR1"); springCloudVersions.add("vGreenwich.RELEASE"); springCloudVersions.add("vGreenwich.RC2"); From 37bb1677d9ac431eebb9bdfc5fce68462f3e92f9 Mon Sep 17 00:00:00 2001 From: Glenn Renfro Date: Fri, 18 Feb 2022 14:36:26 -0500 Subject: [PATCH 2/8] Add section on releasing SC-Build and the entire SC-Suite (#244) Co-authored-by: Spencer Gibb --- README.adoc | 213 ++++++++++++-- docs/src/main/asciidoc/README.adoc | 3 + .../images/build-releaser-buildwithparams.png | Bin 0 -> 60101 bytes .../images/build-releaser-selectdryrun.png | Bin 0 -> 9197 bytes .../images/build-releaser-selectlastrun.png | Bin 0 -> 25129 bytes .../build-releaser-setreleaseversion.png | Bin 0 -> 44619 bytes .../meta-releaser-buildwithparameters.png | Bin 0 -> 42570 bytes .../images/meta-releaser-rebuildlast.png | Bin 0 -> 38713 bytes .../meta-releaser-setreleaseversion.png | Bin 0 -> 50560 bytes .../spring-cloud-release-process.adoc | 112 +++++++ .../asciidoc/spring-cloud-release-tools.adoc | 7 +- .../reference/html/spring-cloud-info.html | 278 ++++-------------- 12 files changed, 356 insertions(+), 257 deletions(-) create mode 100644 docs/src/main/asciidoc/images/build-releaser-buildwithparams.png create mode 100644 docs/src/main/asciidoc/images/build-releaser-selectdryrun.png create mode 100644 docs/src/main/asciidoc/images/build-releaser-selectlastrun.png create mode 100644 docs/src/main/asciidoc/images/build-releaser-setreleaseversion.png create mode 100644 docs/src/main/asciidoc/images/meta-releaser-buildwithparameters.png create mode 100644 docs/src/main/asciidoc/images/meta-releaser-rebuildlast.png create mode 100644 docs/src/main/asciidoc/images/meta-releaser-setreleaseversion.png create mode 100644 docs/src/main/asciidoc/spring-cloud-release-process.adoc diff --git a/README.adoc b/README.adoc index 4791107c..2f39ae0d 100644 --- a/README.adoc +++ b/README.adoc @@ -7,7 +7,7 @@ Edit the files in the src/main/asciidoc/ directory instead. :jdkversion: 1.8 :org: spring-cloud :repo: spring-cloud-release-tools -:branch: master +:branch: main image::https://github.com/{org}/{repo}/workflows/Build/badge.svg?style=svg["Build",link="https://github.com/{org}/{repo}/actions"] @@ -18,8 +18,9 @@ That's why this tool makes it easy to automate the release / dependency update p === Releasing through Jenkins -NOTE: Whenever a release process is broken, Jenkins marks it with a red ball and breaks the build. -Whenever a post-release action went wrong but the release is successful, Jenkins marks the build with a yellow ball and marks the build as unstable. +NOTE: Whenever a release process is broken, Jenkins marks it with a red 'X' and breaks the build. +Whenever a post-release action went wrong but the release is successful, Jenkins marks the build with a yellow exclamation and marks the build as unstable. + ==== Releasing a Single Project @@ -58,19 +59,19 @@ IMPORTANT: If you're doing a e.g. `M1` release, remember to not have any snapsho Since the project is prepared, go to Jenkins and select the https://jenkins.spring.io/view/Spring%20Cloud/view/Releaser/[Releaser view], which the following image shows: -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/master/docs/src/main/asciidoc/images/releasers.png[Releaser view] +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/main/docs/src/main/asciidoc/images/releasers.png[Releaser view] . Pick the proper releaser project (for example, `spring-cloud-build-releaser`). The following image shows the settings for this example: -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/master/docs/src/main/asciidoc/images/scBuildReleaser.png[Spring Cloud Build Releaser - build with parameters] +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/main/docs/src/main/asciidoc/images/scBuildReleaser.png[Spring Cloud Build Releaser - build with parameters] . Next, click `Build with parameters`. The following image shows the UI for doing so: -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/master/docs/src/main/asciidoc/images/runningScBuildReleaser.png[Updated `RELEASER_POM_BRANCH`] +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/main/docs/src/main/asciidoc/images/runningScBuildReleaser.png[Updated `RELEASER_POM_BRANCH`] -Pick from which branch you would like the project (for example, `spring-cloud-build` - defaults to `master`) to be built and update the `RELEASER_POM_BRANCH` to point to the checked-out branch of Spring Cloud Release (for example, `springCloudBuildRelease`). +Pick from which branch you would like the project (for example, `spring-cloud-build` - defaults to `main`) to be built and update the `RELEASER_POM_BRANCH` to point to the checked-out branch of Spring Cloud Release (for example, `springCloudBuildRelease`). You can pick whether you want to perform only post-release tasks or the whole release. . Finally, click `Build`. @@ -142,15 +143,15 @@ $ git add greenwich_sr2.properties && git commit -m "Added Greenwich.SR2 propert Since the project is prepared, go to Jenkins and select the https://jenkins.spring.io/view/Spring%20Cloud/view/Releaser/[Releaser view], as the following image shows: -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/master/docs/src/main/asciidoc/images/releasersForMetaRelease.png[Releaser view] +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/main/docs/src/main/asciidoc/images/releasersForMetaRelease.png[Releaser view] . Pick the proper meta-releaser project (for example, `spring-cloud-meta-releaser`), as the following image shows: -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/master/docs/src/main/asciidoc/images/springCloudMetaRelease.png[Spring Cloud Meta Releaser - build with parameters] +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/main/docs/src/main/asciidoc/images/springCloudMetaRelease.png[Spring Cloud Meta Releaser - build with parameters] . Next, click `Build with parameters`. -image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/master/docs/src/main/asciidoc/images/runningSpringCloudMetaReleaser.png[Spring Cloud Meta Releaser view] +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/main/docs/src/main/asciidoc/images/runningSpringCloudMetaReleaser.png[Spring Cloud Meta Releaser view] You have quite a few options to pick, but the most important one is to set the value of the `RELEASE_VERSION` to the given release train version (for example, `Greenwich.SR2`). Continue updating the rest of the fields if necessary and read the field descriptions and this documentation for more information. @@ -197,7 +198,7 @@ All the tasks are opt in, so if you do opt in for everything you'll get: - Uses the fixed versions to clone and check out each project (e.g. `spring-cloud-sleuth: 2.1.0.RELEASE`) - From the version analyzes the branch and checks it out. E.g. -** for `spring-cloud-release`'s `Finchley.RELEASE` version will resolve either `Finchley` branch or will fallback to `master` if there's no `Finchley` branch. +** for `spring-cloud-release`'s `Finchley.RELEASE` version will resolve either `Finchley` branch or will fallback to `main` if there's no `Finchley` branch. ** for `spring-cloud-sleuth`'s `2.1.0.RELEASE` version will resolve `2.1.x` branch - Performs the release tasks per each project - Performs the post release tasks at the end of the release @@ -604,7 +605,7 @@ Below you can find a table with all the releaser options. |releaser.meta-release.release-train-dependency-names | | All the names of dependencies that should be updated with the release train project version. |releaser.meta-release.release-train-project-name | | Name of the release train project. |releaser.pom.bom-version-pattern | | The pattern to match a version property in a BOM. Remember to catch the dependency name in a group. E.g. "^(spring-cloud-.*)\\.version$". -|releaser.pom.branch | master | Which branch of release train BOM should be checked out. Defaults to {@code master}. +|releaser.pom.branch | main | Which branch of release train BOM should be checked out. Defaults to {@code main}. |releaser.pom.ignored-pom-regex | ^.*\.git/.*$ | List of regular expressions of ignored poms. Defaults to test projects and samples. |releaser.pom.pom-with-boot-starter-parent | | Subfolder of the pom that contains the {@code spring-boot-starer-parent} dependency. |releaser.pom.this-train-bom | | Subfolder of the pom that contains the versions for the release train. @@ -652,7 +653,7 @@ IMPORTANT: For the meta-releaser to work we assume that the path to the configur ==== Specifying A Branch -By deafult the releaser will default to using the `master` branch of `spring-cloud-release`. +By deafult the releaser will default to using the `main` branch of `spring-cloud-release`. If you would like to use another branch you can specify it using the `releaser.pom.branch` property. [source,bash] @@ -721,7 +722,7 @@ If you know what you're doing and want to skip snapshot / milestone version chec == Building -:jdkversion: 1.8 +:jdkversion: 17 === Basic Compile and Test @@ -747,23 +748,9 @@ the `.mvn` configuration, so if you find you have to do it to make a build succeed, please raise a ticket to get the settings added to source control. -For hints on how to build the project look in `.travis.yml` if there -is one. There should be a "script" and maybe "install" command. Also -look at the "services" section to see if any services need to be -running locally (e.g. mongo or rabbit). Ignore the git-related bits -that you might find in "before_install" since they're related to setting git -credentials and you already have those. +The projects that require middleware (i.e. Redis) for testing generally +require that a local instance of [Docker](https://www.docker.com/get-started) is installed and running. -The projects that require middleware generally include a -`docker-compose.yml`, so consider using -https://docs.docker.com/compose/[Docker Compose] to run the middeware servers -in Docker containers. See the README in the -https://github.com/spring-cloud-samples/scripts[scripts demo -repository] for specific instructions about the common cases of mongo, -rabbit and redis. - -NOTE: If all else fails, build with the command from `.travis.yml` (usually -`./mvnw install`). === Documentation @@ -821,6 +808,120 @@ When importing your project to an IDE please activate the `ide` Maven profile to Of course remember that you MUST NOT use Java 1.8 features in the main sources. If you do so your app will break during the Maven build. +== Spring Cloud Release Process +== Spring Cloud Release Process + +This section contains the instructions on releasiong the Spring Cloud project using the Spring Cloud Releaser. + +=== Before you get started +1. Create the Spring Cloud Release project on your local machine. For example: + +```bash +git clone git@github.com:spring-cloud/spring-cloud-release.git +cd spring-cloud-release +``` +[start=2] +. Pull all Spring Cloud projects to your local machine so that if there is a problem during release, you can make the tweaks to the affected project quickly. + +=== Spring Cloud Build Releaser Instructions + +. Go to the spring-cloud-release project and checkout the `jenkins-releaser-config` branch. Then pull the latest from the repository. +```bash +cd spring-cloud-release +git checkout jenkins-releaser-config +git pull origin jenkins-releaser-config +``` +[start=2] +. Find the most recent release in the desired release train. In this document we will use: 2020_0_x.properties +. Create a copy of that file and set the name of the copy to .properties (for example: 2020_0_2.properties) +. Edit this file and update all project versions to their latest release. +.. The latest release for each project can be determined by navigating to the individual Github project and checking for commits since the last release, where the last release is marked by a commit from spring-cloud-issues. If there are commits since the last release, change the value in the properties file. If there are no commits since the last release (i.e. the last commit is from spring-cloud-issues) then do not increment the value. +. Make a note of the projects that did not increment their version number, as those projects will need to be specified later in the “RELEASER_PROJECTS_TO_SKIP” field in the Jenkins project spring-cloud-meta-releaser + +NOTE: Sometimes the release value for a project will need to be incremented by more than one, +for example if there was a release for an individual project due to a CVE and there were commits made after that release. To determine the new version number, look for the latest version in the commit history from spring-cloud-issues. + +[start=6] +. Commit the change +. Push the changes back to github. For example: +```bash +git push origin jenkins-releaser-config +``` +[start=8] +. Request that project owners verify versions in the Spring Cloud Slack room by sharing a github link to the 2020_0_x.properties you just pushed. +. Now go to the `spring-cloud-build-releaser` job on Jenkins + +NOTE: The builder project is required to run first because it is required for spring-cloud-function and spring-cloud-stream. All other spring-cloud builds will run after spring-cloud-function and spring-cloud-stream have performed a successful release + +[start=10] +. Click `Build With Parameters` on the left side of page + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-buildwithparams.png[Build With Params] + +[start=11] +. In the RELEASE_VERSION column enter the name of the file you created without the properties extension + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-setreleaseversion.png[Set The Version] + +[start=12] +. Click the “DRY_RUN” option and then click `Build` button as shown below: + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-selectdryrun.png[Set Dry Run] +[start=13] +. Once the dry run is successfully complete we need to remove all of the artifacts from the dry run. +To do this select the `spring-cloud-purge-worker-artifacts-releaser` job from the list of jobs. +. Once the purge work has completed successfully, +. Select Rebuild Last option on the left side of the page. +. Now go to the `spring-cloud-build-releaser` job on Jenkins +, Select the last build +. When build page appears click the `Rebuild` option. + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-selectlastrun.png[Select Last Run] + +[start=18] +. Deselect “DRY_RUN” then click the `Build` button. + +=== Full Spring Cloud Release + +. Once Spring Cloud Stream and Function projects are released verify that all other builds are succeeding +. Now go to the `Spring-cloud-meta-releaser` job on Jenkins +. Click `Build With Parameters` on the left side of page + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/meta-releaser-buildwithparameters.png[Build With Params] + +[start=4] +. Update RELEASE_VERSION with the current release and corresponds to the release file. + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/meta-releaser-setreleaseversion.png[Set The Version] + +[start=5] +. Add spring-cloud-build to RELEASER_PROJECTS_TO_SKIP, so it won’t be rebuilt. +Also any other projects that did not change in the properties files, add it to the RELEASER_PROJECTS_TO_SKIP so they can be excluded. +. Select Dry Run option +. Click Build + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-selectdryrun.png[Set Dry Run] + + +TIP: If there is a failure you can launch the build from the failed project. To do this: +Click the Rebuild_Last option, then in the START FROM field insert the name of the project. +Then click the Build. + +NOTE: Spring Cloud K8’s Integration tests may time out. Restart the build. + Select Rebuild Last option on the left side of the page. + +[start=8] +. Upon a successful "DRY_RUN". +. Click "Rebuild Last" option on the left side of the page. + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/meta-releaser-rebuildlast.png[Rebuild Last] + +[start=10] +. When the build page is rendered. +. Deselect “DRY_RUN” then click the build button. +. Clear the Start_From field +. Click Rebuild + == Contributing :spring-cloud-build-branch: master @@ -1001,4 +1102,54 @@ Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on t - `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL. - `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`. -IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources. \ No newline at end of file +IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources. + +=== Duplicate Finder + +Spring Cloud Build brings along the `basepom:duplicate-finder-maven-plugin`, that enables flagging duplicate and conflicting classes and resources on the java classpath. + +==== Duplicate Finder configuration + +Duplicate finder is *enabled by default* and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the projecst's `pom.xml`. + +.pom.xml +[source,xml] +---- + + + + org.basepom.maven + duplicate-finder-maven-plugin + + + +---- + +For other properties, we have set defaults as listed in the https://github.com/basepom/duplicate-finder-maven-plugin/wiki[plugin documentation]. + +You can easily override them but setting the value of the selected property prefixed with `duplicate-finder-maven-plugin`. For example, set `duplicate-finder-maven-plugin.skip` to `true` in order to skip duplicates check in your build. + +If you need to add `ignoredClassPatterns` or `ignoredResourcePatterns` to your setup, make sure to add them in the plugin configuration section of your project: + +[source,xml] +---- + + + + org.basepom.maven + duplicate-finder-maven-plugin + + + org.joda.time.base.BaseDateTime + .*module-info + + + changelog.txt + + + + + + + +---- diff --git a/docs/src/main/asciidoc/README.adoc b/docs/src/main/asciidoc/README.adoc index 81e41ace..a8789f6d 100644 --- a/docs/src/main/asciidoc/README.adoc +++ b/docs/src/main/asciidoc/README.adoc @@ -17,6 +17,9 @@ When importing your project to an IDE please activate the `ide` Maven profile to Of course remember that you MUST NOT use Java 1.8 features in the main sources. If you do so your app will break during the Maven build. +== Spring Cloud Release Process +include::/Users/glennrenfro/project/spring-cloud-release-tools/docs/src/main/asciidoc/spring-cloud-release-process.adoc[] + == Contributing include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/src/main/asciidoc/contributing.adoc[] diff --git a/docs/src/main/asciidoc/images/build-releaser-buildwithparams.png b/docs/src/main/asciidoc/images/build-releaser-buildwithparams.png new file mode 100644 index 0000000000000000000000000000000000000000..208bd616bd6720d0339dedbdb8dc9dbcc89caf76 GIT binary patch literal 60101 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�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 literal 0 HcmV?d00001 diff --git a/docs/src/main/asciidoc/images/build-releaser-selectlastrun.png b/docs/src/main/asciidoc/images/build-releaser-selectlastrun.png new file mode 100644 index 0000000000000000000000000000000000000000..7afba932d1eb2d4fa2185e4fad3942297169a1ad GIT binary patch literal 25129 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

%TQliVR^&;X?_U1Wyx;VZ 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%0D|#!s;MOd9)(U#o-niAXf} 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 GFaHnGu`}iX literal 0 HcmV?d00001 diff --git a/docs/src/main/asciidoc/images/build-releaser-setreleaseversion.png b/docs/src/main/asciidoc/images/build-releaser-setreleaseversion.png new file mode 100644 index 0000000000000000000000000000000000000000..e3708cf94e0c1de71b361a47e1d4becb2dbccc08 GIT binary patch literal 44619 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 E4}kS`ng9R* literal 0 HcmV?d00001 diff --git a/docs/src/main/asciidoc/images/meta-releaser-buildwithparameters.png b/docs/src/main/asciidoc/images/meta-releaser-buildwithparameters.png new file mode 100644 index 0000000000000000000000000000000000000000..32d6485dc7bc06bb2f3cc2341c5caab266dc46e7 GIT binary patch literal 42570 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 literal 0 HcmV?d00001 diff --git a/docs/src/main/asciidoc/images/meta-releaser-rebuildlast.png b/docs/src/main/asciidoc/images/meta-releaser-rebuildlast.png new file mode 100644 index 0000000000000000000000000000000000000000..530d063d249f3b6ebfe932f242d7d7675b82e332 GIT binary patch literal 38713 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 Q{{k;9HC@#bl?TE916?fFDgXcg literal 0 HcmV?d00001 diff --git a/docs/src/main/asciidoc/spring-cloud-release-process.adoc b/docs/src/main/asciidoc/spring-cloud-release-process.adoc new file mode 100644 index 00000000..37758cf3 --- /dev/null +++ b/docs/src/main/asciidoc/spring-cloud-release-process.adoc @@ -0,0 +1,112 @@ +== Spring Cloud Release Process + +This section contains the instructions on releasiong the Spring Cloud project using the Spring Cloud Releaser. + +=== Before you get started +1. Create the Spring Cloud Release project on your local machine. For example: + +```bash +git clone git@github.com:spring-cloud/spring-cloud-release.git +cd spring-cloud-release +``` +[start=2] +. Pull all Spring Cloud projects to your local machine so that if there is a problem during release, you can make the tweaks to the affected project quickly. + +=== Spring Cloud Build Releaser Instructions + +. Go to the spring-cloud-release project and checkout the `jenkins-releaser-config` branch. Then pull the latest from the repository. +```bash +cd spring-cloud-release +git checkout jenkins-releaser-config +git pull origin jenkins-releaser-config +``` +[start=2] +. Find the most recent release in the desired release train. In this document we will use: 2020_0_x.properties +. Create a copy of that file and set the name of the copy to .properties (for example: 2020_0_2.properties) +. Edit this file and update all project versions to their latest release. +.. The latest release for each project can be determined by navigating to the individual Github project and checking for commits since the last release, where the last release is marked by a commit from spring-cloud-issues. If there are commits since the last release, change the value in the properties file. If there are no commits since the last release (i.e. the last commit is from spring-cloud-issues) then do not increment the value. +. Make a note of the projects that did not increment their version number, as those projects will need to be specified later in the “RELEASER_PROJECTS_TO_SKIP” field in the Jenkins project spring-cloud-meta-releaser + +NOTE: Sometimes the release value for a project will need to be incremented by more than one, +for example if there was a release for an individual project due to a CVE and there were commits made after that release. To determine the new version number, look for the latest version in the commit history from spring-cloud-issues. + +[start=6] +. Commit the change +. Push the changes back to github. For example: +```bash +git push origin jenkins-releaser-config +``` +[start=8] +. Request that project owners verify versions in the Spring Cloud Slack room by sharing a github link to the 2020_0_x.properties you just pushed. +. Now go to the `spring-cloud-build-releaser` job on Jenkins + +NOTE: The builder project is required to run first because it is required for spring-cloud-function and spring-cloud-stream. All other spring-cloud builds will run after spring-cloud-function and spring-cloud-stream have performed a successful release + +[start=10] +. Click `Build With Parameters` on the left side of page + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-buildwithparams.png[Build With Params] + +[start=11] +. In the RELEASE_VERSION column enter the name of the file you created without the properties extension + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-setreleaseversion.png[Set The Version] + +[start=12] +. Click the “DRY_RUN” option and then click `Build` button as shown below: + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-selectdryrun.png[Set Dry Run] +[start=13] +. Once the dry run is successfully complete we need to remove all of the artifacts from the dry run. +To do this select the `spring-cloud-purge-worker-artifacts-releaser` job from the list of jobs. +. Once the purge work has completed successfully, +. Select Rebuild Last option on the left side of the page. +. Now go to the `spring-cloud-build-releaser` job on Jenkins +, Select the last build +. When build page appears click the `Rebuild` option. + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-selectlastrun.png[Select Last Run] + +[start=18] +. Deselect “DRY_RUN” then click the `Build` button. + +=== Full Spring Cloud Release + +. Once Spring Cloud Stream and Function projects are released verify that all other builds are succeeding +. Now go to the `Spring-cloud-meta-releaser` job on Jenkins +. Click `Build With Parameters` on the left side of page + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/meta-releaser-buildwithparameters.png[Build With Params] + +[start=4] +. Update RELEASE_VERSION with the current release and corresponds to the release file. + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/meta-releaser-setreleaseversion.png[Set The Version] + +[start=5] +. Add spring-cloud-build to RELEASER_PROJECTS_TO_SKIP, so it won’t be rebuilt. +Also any other projects that did not change in the properties files, add it to the RELEASER_PROJECTS_TO_SKIP so they can be excluded. +. Select Dry Run option +. Click Build + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/build-releaser-selectdryrun.png[Set Dry Run] + + +TIP: If there is a failure you can launch the build from the failed project. To do this: +Click the Rebuild_Last option, then in the START FROM field insert the name of the project. +Then click the Build. + +NOTE: Spring Cloud K8’s Integration tests may time out. Restart the build. + Select Rebuild Last option on the left side of the page. + +[start=8] +. Upon a successful "DRY_RUN". +. Click "Rebuild Last" option on the left side of the page. + +image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-release-tools/RELEASE-DOC-UPDATE/docs/src/main/asciidoc/images/meta-releaser-rebuildlast.png[Rebuild Last] + +[start=10] +. When the build page is rendered. +. Deselect “DRY_RUN” then click the build button. +. Clear the Start_From field +. Click Rebuild diff --git a/docs/src/main/asciidoc/spring-cloud-release-tools.adoc b/docs/src/main/asciidoc/spring-cloud-release-tools.adoc index 11e76bb6..befe4d98 100644 --- a/docs/src/main/asciidoc/spring-cloud-release-tools.adoc +++ b/docs/src/main/asciidoc/spring-cloud-release-tools.adoc @@ -5,8 +5,9 @@ That's why this tool makes it easy to automate the release / dependency update p === Releasing through Jenkins -NOTE: Whenever a release process is broken, Jenkins marks it with a red ball and breaks the build. -Whenever a post-release action went wrong but the release is successful, Jenkins marks the build with a yellow ball and marks the build as unstable. +NOTE: Whenever a release process is broken, Jenkins marks it with a red 'X' and breaks the build. +Whenever a post-release action went wrong but the release is successful, Jenkins marks the build with a yellow exclamation and marks the build as unstable. + ==== Releasing a Single Project @@ -621,4 +622,4 @@ If you know what you're doing and want to skip snapshot / milestone version chec 1.19.2-M2 0.6.12 ----- \ No newline at end of file +---- diff --git a/spring-cloud-info/src/main/resources/static/docs/reference/html/spring-cloud-info.html b/spring-cloud-info/src/main/resources/static/docs/reference/html/spring-cloud-info.html index ee292c6c..b085ac0a 100644 --- a/spring-cloud-info/src/main/resources/static/docs/reference/html/spring-cloud-info.html +++ b/spring-cloud-info/src/main/resources/static/docs/reference/html/spring-cloud-info.html @@ -153,67 +153,33 @@ $(addBlockSwitches);

cURL Request

-
-
-
$ curl 'http://spring-cloud-info.cfapps.io/springcloudversions' -i -X GET \
-    -H 'Accept: application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversions/curl-request.adoc[]

HTTPie Request

-
-
-
$ http GET 'http://spring-cloud-info.cfapps.io/springcloudversions' \
-    'Accept:application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversions/httpie-request.adoc[]

HTTP Request

-
-
-
GET /springcloudversions HTTP/1.1
-Accept: application/json
-Host: spring-cloud-info.cfapps.io
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversions/http-request.adoc[]

Response

-
-
-
HTTP/1.1 200 OK
-Content-Type: application/json
-Content-Length: 449
-
-["Greenwich.SR1","Greenwich.RELEASE","Greenwich.RC2","Greenwich.RC1","Greenwich.M3","Greenwich.M2","Greenwich.M1","Finchley.SR3","Finchley.SR2","Finchley.SR1","Finchley.RELEASE","Finchley.RC2","Finchley.RC1","Finchley.M9","Finchley.M8","Finchley.M7","Finchley.M6","Finchley.M5","Finchley.M3","Finchley.M2","Finchley.M1","Edgware.SR5","Edgware.SR4","Edgware.SR3","Edgware.SR2","Edgware.SR1","Edgware.RELEASE","Edgware.M1","Dalston.SR5","Dalston.SR4"]
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversions/http-response.adoc[]

----- - - - - - - - - - - - - - - -
PathTypeDescription

[]

Array

An array versions

+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversions/response-fields.adoc[]

+
@@ -225,90 +191,39 @@ Content-Length: 449

Path Parameters

- - ---- - - - - - - - - - - - - -
Table 1. /springcloudversion/springboot/{bootVersion}
ParameterDescription

bootVersion

The Spring Boot version

+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversion/path-parameters.adoc[]

+

cURL Request

-
-
-
$ curl 'http://spring-cloud-info.cfapps.io/springcloudversion/springboot/2.1.1.RELEASE' -i -X GET \
-    -H 'Accept: application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversion/curl-request.adoc[]

HTTPie Request

-
-
-
$ http GET 'http://spring-cloud-info.cfapps.io/springcloudversion/springboot/2.1.1.RELEASE' \
-    'Accept:application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversion/httpie-request.adoc[]

HTTP Request

-
-
-
GET /springcloudversion/springboot/2.1.1.RELEASE HTTP/1.1
-Accept: application/json
-Host: spring-cloud-info.cfapps.io
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversion/http-request.adoc[]

HTTP Response

-
-
-
HTTP/1.1 200 OK
-Content-Disposition: inline;filename=f.txt
-Content-Type: application/json
-Content-Length: 31
-
-{"version":"Greenwich.RELEASE"}
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversion/http-response.adoc[]

Response Fields

- ----- - - - - - - - - - - - - - - -
PathTypeDescription

version

String

Spring Cloud version

+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/springcloudversion/response-fields.adoc[]

+
@@ -320,43 +235,26 @@ Content-Length: 31

cURL Request

-
-
-
$ curl 'http://spring-cloud-info.cfapps.io/bomversions/Finchley.SR1' -i -X GET \
-    -H 'Accept: application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/bomversions/curl-request.adoc[]

HTTPie Request

-
-
-
$ http GET 'http://spring-cloud-info.cfapps.io/bomversions/Finchley.SR1' \
-    'Accept:application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/bomversions/httpie-request.adoc[]

HTTP Request

-
-
-
GET /bomversions/Finchley.SR1 HTTP/1.1
-Accept: application/json
-Host: spring-cloud-info.cfapps.io
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/bomversions/http-request.adoc[]

HTTP Response

-
-
-
HTTP/1.1 200 OK
-Content-Disposition: inline;filename=f.txt
-Content-Type: application/json
-Content-Length: 904
-
-{"spring-cloud-cloudfoundry":"2.2.0.BUILD-SNAPSHOT","spring-cloud-openfeign":"2.2.0.BUILD-SNAPSHOT","spring-cloud-task":"2.0.0.RELEASE","spring-cloud-security":"2.2.0.BUILD-SNAPSHOT","spring-cloud-zookeeper":"2.2.0.BUILD-SNAPSHOT","spring-cloud-config":"2.2.0.BUILD-SNAPSHOT","spring-cloud-function":"2.1.0.BUILD-SNAPSHOT","spring-cloud-netflix":"2.2.0.BUILD-SNAPSHOT","spring-cloud-vault":"2.2.0.BUILD-SNAPSHOT","spring-cloud-stream":"Germantown.BUILD-SNAPSHOT","spring-cloud-gcp":"1.1.0.BUILD-SNAPSHOT","spring-cloud-sleuth":"2.2.0.BUILD-SNAPSHOT","spring-cloud-kubernetes":"1.1.0.BUILD-SNAPSHOT","spring-cloud-commons":"2.2.0.BUILD-SNAPSHOT","spring-cloud-aws":"2.2.0.BUILD-SNAPSHOT","spring-cloud-contract":"2.2.0.BUILD-SNAPSHOT","spring-cloud-bus":"2.2.0.BUILD-SNAPSHOT","spring-cloud-gateway":"2.2.0.BUILD-SNAPSHOT","spring-boot":"2.2.0.BUILD-SNAPSHOT","spring-cloud-consul":"2.2.0.BUILD-SNAPSHOT"}
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/bomversions/http-response.adoc[]

@@ -369,42 +267,26 @@ Content-Length: 904

cURL Request

-
-
-
$ curl 'http://spring-cloud-info.cfapps.io/milestones' -i -X GET \
-    -H 'Accept: application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestones/curl-request.adoc[]

HTTPie Request

-
-
-
$ http GET 'http://spring-cloud-info.cfapps.io/milestones' \
-    'Accept:application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestones/httpie-request.adoc[]

HTTP Request

-
-
-
GET /milestones HTTP/1.1
-Accept: application/json
-Host: spring-cloud-info.cfapps.io
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestones/http-request.adoc[]

HTTP Response

-
-
-
HTTP/1.1 200 OK
-Content-Type: application/json
-Content-Length: 57
-
-["Hoxton.RELEASE","Finchley.SR4","Hoxton.M1","Hoxton.M2"]
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestones/http-response.adoc[]

@@ -417,89 +299,39 @@ Content-Length: 57

Path Parameters

- - ---- - - - - - - - - - - - - -
Table 2. /milestones/{release}/duedate
ParameterDescription

release

The Spring Cloud release train name

+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestoneduedate/path-parameters.adoc[]

+

cURL Request

-
-
-
$ curl 'http://spring-cloud-info.cfapps.io/milestones/Hoxton.RELEASE/duedate' -i -X GET \
-    -H 'Accept: application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestoneduedate/curl-request.adoc[]

HTTPie Request

-
-
-
$ http GET 'http://spring-cloud-info.cfapps.io/milestones/Hoxton.RELEASE/duedate' \
-    'Accept:application/json'
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestoneduedate/httpie-request.adoc[]

HTTP Request

-
-
-
GET /milestones/Hoxton.RELEASE/duedate HTTP/1.1
-Accept: application/json
-Host: spring-cloud-info.cfapps.io
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestoneduedate/http-request.adoc[]

HTTP Response

-
-
-
HTTP/1.1 200 OK
-Content-Type: application/json
-Content-Length: 24
-
-{"dueDate":"2019-07-31"}
-
+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestoneduedate/http-response.adoc[]

Response Fields

- ----- - - - - - - - - - - - - - - -
PathTypeDescription

dueDate

String

Spring Cloud milestone due date

+
+

Unresolved directive in spring-cloud-info.adoc - include::../../target/generated-snippets/milestoneduedate/response-fields.adoc[]

+
From b5c97cfce68691e567431f3a6b40469f6b2a400d Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 18 Feb 2022 14:51:35 -0500 Subject: [PATCH 3/8] Updates spring-cloud-build to 3.1.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 136b9af1..06fab127 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ org.springframework.cloud spring-cloud-build - 3.1.0 + 3.1.1 From 409a7b2439ff00ec6998fa69e7618f9d19137282 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 18 Feb 2022 14:54:50 -0500 Subject: [PATCH 4/8] Updates jcabi-github to 1.1.2 --- pom.xml | 2 +- .../main/java/releaser/internal/github/CachingGithub.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 06fab127..d3a8cf6a 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ 1.8 Hoxton.SR6 - 1.0 + 1.1.2 0.0.9 5.4.1.Final 5.1.3.201810200350-r diff --git a/releaser-core/src/main/java/releaser/internal/github/CachingGithub.java b/releaser-core/src/main/java/releaser/internal/github/CachingGithub.java index 03973e7a..d882314e 100644 --- a/releaser-core/src/main/java/releaser/internal/github/CachingGithub.java +++ b/releaser-core/src/main/java/releaser/internal/github/CachingGithub.java @@ -180,6 +180,11 @@ class CachingRepos implements Repos, Closeable { return this.delegate.iterate(s); } + @Override + public boolean exists(Coordinates coords) throws IOException { + return this.delegate.exists(coords); + } + @Override public boolean equals(Object o) { return this.delegate.equals(o); From ccd977974b473d13972e528e9b4a3f642125b937 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 18 Feb 2022 14:57:10 -0500 Subject: [PATCH 5/8] removes hibernate-validator dependency declaration. It is brought in by spring-boot-starter-validation --- releaser-core/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/releaser-core/pom.xml b/releaser-core/pom.xml index 98b6e7bd..2d09698a 100644 --- a/releaser-core/pom.xml +++ b/releaser-core/pom.xml @@ -32,11 +32,6 @@ spring-boot-configuration-processor true - - org.hibernate - hibernate-validator - ${hibernate-validator.version} - org.eclipse.jgit org.eclipse.jgit From 7ad0a3c4854f2d6718053b8cc6aa7067020cda66 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 18 Feb 2022 15:05:50 -0500 Subject: [PATCH 6/8] Updates versions-maven-plugin to 2.8.1 --- pom.xml | 2 +- .../src/main/java/releaser/internal/buildsystem/PomUpdater.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d3a8cf6a..ec9881a8 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ 5.1.3.201810200350-r 3.6.3 - 2.7 + 2.8.1 4.2.0 0.10.0-SNAPSHOT 4.0.3 diff --git a/releaser-core/src/main/java/releaser/internal/buildsystem/PomUpdater.java b/releaser-core/src/main/java/releaser/internal/buildsystem/PomUpdater.java index 41706f26..fe074233 100644 --- a/releaser-core/src/main/java/releaser/internal/buildsystem/PomUpdater.java +++ b/releaser-core/src/main/java/releaser/internal/buildsystem/PomUpdater.java @@ -328,7 +328,7 @@ class PomWriter { try { XMLInputFactory inputFactory = XMLInputFactory2.newInstance(); inputFactory.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); - newPom = new ModifiedPomXMLEventReader(input, inputFactory); + newPom = new ModifiedPomXMLEventReader(input, inputFactory, null); } catch (XMLStreamException e) { log.error("Exception occurred while trying to parse pom", e); From 25806c817c147405394e35f398f8b9670c03ba71 Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 18 Feb 2022 15:07:20 -0500 Subject: [PATCH 7/8] removes hibernate validator version --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index ec9881a8..18913faa 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,6 @@ Hoxton.SR6 1.1.2 0.0.9 - 5.4.1.Final 5.1.3.201810200350-r 3.6.3 From ae60af587c3bfe4e809ce1415f48bea257a3ef5c Mon Sep 17 00:00:00 2001 From: spencergibb Date: Fri, 18 Feb 2022 15:13:10 -0500 Subject: [PATCH 8/8] Updates initializr metadata to 0.12.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 18913faa..581abd79 100644 --- a/pom.xml +++ b/pom.xml @@ -38,7 +38,7 @@ 3.6.3 2.8.1 4.2.0 - 0.10.0-SNAPSHOT + 0.12.0 4.0.3 1.0.0-SNAPSHOT 1.1.4