diff --git a/release-tools/src/main/java/org/springframework/data/release/git/BackportTargets.java b/release-tools/src/main/java/org/springframework/data/release/git/BackportTargets.java new file mode 100644 index 0000000..487a15d --- /dev/null +++ b/release-tools/src/main/java/org/springframework/data/release/git/BackportTargets.java @@ -0,0 +1,64 @@ +/* + * Copyright 2016 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.git; + +import lombok.Getter; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.springframework.data.release.model.ModuleIteration; +import org.springframework.data.release.model.Train; +import org.springframework.util.Assert; + +class BackportTargets implements Iterable { + + private final @Getter Branch source; + private final Set targets; + + /** + * Creates a new {@link BackportTargets} instance for the given {@link ModuleIteration} and + * + * @param module must not be {@literal null}. + * @param targets must not be {@literal null}. + */ + public BackportTargets(ModuleIteration module, Collection targets) { + + Assert.notNull(module, "Module iteration must not be null!"); + Assert.notNull(targets, "Target trains must not be null!"); + + this.source = Branch.from(module); + + Stream branches = targets.stream().map(target -> target.getModuleIfAvailable(module.getProject()))// + .flatMap(o -> o.map(Stream::of).orElse(Stream.empty()))// + .map(Branch::from); + + this.targets = Stream.concat(branches, source.isMasterBranch() ? Stream.empty() : Stream.of(Branch.MASTER)) + .collect(Collectors.toSet()); + } + + /* + * (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + @Override + public Iterator iterator() { + return targets.iterator(); + } +} diff --git a/release-tools/src/main/java/org/springframework/data/release/git/Branch.java b/release-tools/src/main/java/org/springframework/data/release/git/Branch.java index ec42c29..f3919d6 100644 --- a/release-tools/src/main/java/org/springframework/data/release/git/Branch.java +++ b/release-tools/src/main/java/org/springframework/data/release/git/Branch.java @@ -62,13 +62,17 @@ class Branch { return from(version.toString().concat(".x")); } - private static Branch from(String name) { + public static Branch from(String name) { int slashIndex = name.lastIndexOf('/'); return new Branch(slashIndex != -1 ? name.substring(slashIndex + 1) : name); } + public boolean isMasterBranch() { + return MASTER.equals(this); + } + /* * (non-Javadoc) * @see java.lang.Object#toString() diff --git a/release-tools/src/main/java/org/springframework/data/release/git/GitCommands.java b/release-tools/src/main/java/org/springframework/data/release/git/GitCommands.java index 889ede4..994fa17 100644 --- a/release-tools/src/main/java/org/springframework/data/release/git/GitCommands.java +++ b/release-tools/src/main/java/org/springframework/data/release/git/GitCommands.java @@ -17,6 +17,10 @@ package org.springframework.data.release.git; import lombok.RequiredArgsConstructor; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.release.CliComponent; import org.springframework.data.release.model.Project; @@ -104,4 +108,14 @@ public class GitCommands implements CommandMarker { public void removeTags(@CliOption(key = "", mandatory = true) TrainIteration iteration) { git.removeTags(iteration); } + + @CliCommand("git backport changelog") + public void backportChangelogs(@CliOption(key = "", mandatory = true) TrainIteration iteration, // + @CliOption(key = "target", mandatory = true) String trains) { + + List targets = Stream.of(trains.split(",")).map(it -> ReleaseTrains.getTrainByName(it)) + .collect(Collectors.toList()); + + git.backportChangelogs(iteration, targets); + } } diff --git a/release-tools/src/main/java/org/springframework/data/release/git/GitOperations.java b/release-tools/src/main/java/org/springframework/data/release/git/GitOperations.java index 91e443a..bc0d75b 100644 --- a/release-tools/src/main/java/org/springframework/data/release/git/GitOperations.java +++ b/release-tools/src/main/java/org/springframework/data/release/git/GitOperations.java @@ -19,6 +19,7 @@ import lombok.RequiredArgsConstructor; import java.io.File; import java.io.IOException; +import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -26,6 +27,7 @@ import org.eclipse.jgit.api.CheckoutCommand; import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.ResetCommand.ResetType; +import org.eclipse.jgit.api.errors.RefNotFoundException; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; @@ -64,6 +66,12 @@ public class GitOperations { private final PluginRegistry issueTracker; private final GitProperties gitProperties; + /** + * Returns the {@link GitProject} for the given {@link Project}. + * + * @param project + * @return + */ public GitProject getGitProject(Project project) { return new GitProject(project, server); } @@ -74,56 +82,51 @@ public class GitOperations { * @param train must not be {@literal null}. * @throws Exception */ - public void reset(TrainIteration train) throws Exception { + public void reset(TrainIteration train) { Assert.notNull(train, "Train must not be null!"); ExecutionUtils.run(train, module -> { - - Branch branch = Branch.from(module); - - try (Git git = new Git(getRepository(module.getProject()))) { - - logger.log(module, "git reset --hard origin/%s", branch); - - reset(git, branch.toString()); - } + reset(module.getProject(), Branch.from(module)); }); } /** * Checks out all projects of the given {@link TrainIteration}. * - * @param iteration + * @param train * @throws Exception */ public void checkout(Train train) { + Assert.notNull(train, "Train must not be null!"); + update(train); ExecutionUtils.run(train, module -> { - try (Git git = new Git(getRepository(module.getProject()))) { + Project project = module.getProject(); + + doWithGit(project, git -> { Branch branch = Branch.from(module); CheckoutCommand command = git.checkout().setName(branch.toString()); - if (!branchExists(module.getProject(), branch)) { + if (!branchExists(project, branch)) { - logger.log(module.getProject(), "git checkout -b %s --track origin/%s", branch, branch); + logger.log(project, "git checkout -b %s --track origin/%s", branch, branch); command.setCreateBranch(true).// setStartPoint("origin/".concat(branch.toString())).// call(); } else { - logger.log(module.getProject(), "git checkout %s", branch); + logger.log(project, "git checkout %s", branch); command.call(); } - logger.log(module.getProject(), "git reset --hard origin/%s", branch); - reset(git, branch.toString()); - } + reset(project, branch); + }); }); logger.log(train, "Successfully checked out projects."); @@ -132,48 +135,49 @@ public class GitOperations { /** * Checks out all projects of the given {@link TrainIteration}. * - * @param iteration + * @param iteration must not be {@literal null}. * @throws Exception */ public void checkout(TrainIteration iteration) { + Assert.notNull(iteration, "Train iteration must not be null!"); + update(iteration.getTrain()); ExecutionUtils.run(iteration, module -> { Project project = module.getProject(); ArtifactVersion artifactVersion = ArtifactVersion.of(module); - Tag tag = findTagFor(project, artifactVersion).orElseThrow(() -> new IllegalStateException( String.format("No tag found for version %s of project %s, aborting.", artifactVersion, project))); - try (Git git = new Git(getRepository(module.getProject()))) { + doWithGit(project, git -> { logger.log(module, "git checkout %s", tag); - - git.checkout().setStartPoint(tag.toString()).call(); - } + git.checkout().setName(tag.toString()).call(); + }); }); logger.log(iteration, "Successfully checked out projects."); } - public void prepare(TrainIteration iteration) throws Exception { + public void prepare(TrainIteration iteration) { ExecutionUtils.run(iteration, module -> { + Project project = module.getProject(); Branch branch = Branch.from(module); - update(module.getProject()); + update(project); + checkout(project, branch); - logger.log(module.getProject(), "git checkout %s && git pull origin %s", branch, branch); - checkout(module.getProject(), branch); + doWithGit(project, git -> { - try (Git git = new Git(getRepository(module.getProject()))) { + logger.log(project, "git pull origin %s", branch); git.pull().// setRebase(true).// call(); - } + }); }); } @@ -188,16 +192,16 @@ public class GitOperations { Branch branch = Branch.from(module); logger.log(module, "git push origin %s", branch); - try (Git git = new Git(getRepository(module.getProject()))) { + doWithGit(module.getProject(), git -> { - Ref ref = git.getRepository().getRef(branch.toString()); + Ref ref = git.getRepository().findRef(branch.toString()); git.push().// setRemote("origin").// setRefSpecs(new RefSpec(ref.getName())).// setCredentialsProvider(gitProperties.getCredentials()).// call(); - } + }); }); } @@ -205,36 +209,46 @@ public class GitOperations { ExecutionUtils.run(train.getModules(), module -> { - logger.log(module.getProject(), "git push --tags"); + logger.log(module.getProject(), "git push --tags origin"); - try (Git git = new Git(getRepository(module.getProject()))) { + doWithGit(module.getProject(), git -> { git.push().// setRemote("origin").// setPushTags().// setCredentialsProvider(gitProperties.getCredentials()).// call(); - } + }); }); } - public void update(Project project) throws Exception { + /** + * Updates the given {@link Project}. Will either pull the latest changes or clone the project's repository if not + * already available. + * + * @param project must not be {@literal null}. + * @throws Exception + */ + public void update(Project project) { + + Assert.notNull(project, "Project must not be null!"); GitProject gitProject = new GitProject(project, server); String repositoryName = gitProject.getRepositoryName(); - try (Git git = new Git(getRepository(project))) { + doWithGit(project, git -> { if (workspace.hasProjectDirectory(project)) { logger.log(project, "Found existing repository %s. Obtaining latest changes…", repositoryName); - logger.log(project, - "git checkout master && git reset --hard origin/master && git fetch --tags && git pull origin master"); checkout(project, Branch.MASTER); + reset(project, Branch.MASTER); - reset(git, "master"); + logger.log(project, "git fetch --tags"); git.fetch().setTagOpt(TagOpt.FETCH_TAGS).call(); + + logger.log(project, "git pull"); git.pull().call(); } else { @@ -243,20 +257,16 @@ public class GitOperations { clone(project); } - } + }); } public VersionTags getTags(Project project) { - try (Git git = new Git(getRepository(project))) { - + return doWithGit(project, git -> { return new VersionTags(git.tagList().call().stream().// map(ref -> Tag.of(ref.getName())).// collect(Collectors.toList())); - - } catch (Exception o_O) { - throw new RuntimeException(o_O); - } + }); } public void tagRelease(TrainIteration iteration) { @@ -266,12 +276,11 @@ public class GitOperations { Branch branch = Branch.from(module); Project project = module.getProject(); - try (Git git = new Git(getRepository(module.getProject()))) { + doWithGit(project, git -> { - logger.log(module, "git checkout %s", branch); checkout(project, branch); - logger.log(module, "git pull origin %s", branch); + logger.log(module, "git pull", branch); git.pull().call(); ObjectId hash = getReleaseHash(module); @@ -284,7 +293,7 @@ public class GitOperations { logger.log(module, "git tag %s %s", tag, hash.getName()); git.tag().setName(tag.toString()).setObjectId(commit).call(); } - } + }); }); } @@ -296,7 +305,7 @@ public class GitOperations { * @param summary must not be {@literal null} or empty. * @throws Exception */ - public void commit(TrainIteration iteration, String summary) throws Exception { + public void commit(TrainIteration iteration, String summary) { commit(iteration, summary, Optional.empty()); } @@ -307,9 +316,8 @@ public class GitOperations { * @param iteration must not be {@literal null}. * @param summary must not be {@literal null} or empty. * @param details can be {@literal null} or empty. - * @throws Exception */ - public void commit(TrainIteration iteration, String summary, Optional details) throws Exception { + public void commit(TrainIteration iteration, String summary, Optional details) { Assert.notNull(iteration, "Train iteration must not be null!"); Assert.hasText(summary, "Summary must not be null or empty!"); @@ -324,9 +332,8 @@ public class GitOperations { * @param module must not be {@literal null}. * @param summary must not be {@literal null} or empty. * @param files can be empty. - * @throws Exception */ - public void commit(ModuleIteration module, String summary, File... files) throws Exception { + public void commit(ModuleIteration module, String summary, File... files) { commit(module, summary, Optional.empty(), files); } @@ -340,7 +347,7 @@ public class GitOperations { * @param files can be empty. * @throws Exception */ - public void commit(ModuleIteration module, String summary, Optional details, File... files) throws Exception { + public void commit(ModuleIteration module, String summary, Optional details, File... files) { Assert.notNull(module, "Module iteration must not be null!"); Assert.hasText(summary, "Summary must not be null or empty!"); @@ -355,35 +362,55 @@ public class GitOperations { logger.log(module, "git commit -m \"%s\" --author=\"%s <%s>\"", commit, author, email); - try (Git git = new Git(getRepository(module.getProject()))) { + doWithGit(project, git -> { git.commit().// setMessage(commit.toString()).// setAuthor(author, email).// setAll(true).// call(); - } + }); } - public void checkout(Project project, Branch branch) throws Exception { + /** + * Checks out the given {@link Branch} of the given {@link Project}. + * + * @param project must not be {@literal null}. + * @param branch must not be {@literal null}. + * @throws Exception + */ + public void checkout(Project project, Branch branch) { - try (Git git = new Git(getRepository(project))) { + Assert.notNull(project, "Project must not be null!"); + Assert.notNull(branch, "Branch must not be null!"); - Ref ref = git.getRepository().getRef(branch.toString()); + doWithGit(project, git -> { + + Optional ref = Optional.ofNullable(git.getRepository().findRef(branch.toString())); CheckoutCommand checkout = git.checkout().setName(branch.toString()); - if (ref == null) { + if (ref.isPresent()) { + + logger.log(project, "git checkout %s", branch); + + } else { + + logger.log(project, "git checkout --track -b %s origin/%s", branch, branch); checkout.setCreateBranch(true).// setUpstreamMode(SetupUpstreamMode.TRACK).// setStartPoint("origin/".concat(branch.toString())); } - checkout.call(); - } + try { + checkout.call(); + } catch (RefNotFoundException o_O) { + // TODO: + } + }); } - public void createMaintenanceBranches(TrainIteration iteration) throws Exception { + public void createMaintenanceBranches(TrainIteration iteration) { checkout(iteration); @@ -407,24 +434,70 @@ public class GitOperations { return; } - try (Git git = new Git(getRepository(module.getProject()))) { + doWithGit(project, git -> { logger.log(module, "git tag -D %s", tag.get()); - git.tagDelete().setTags(tag.get().toString()).call(); - } + }); }); } - private Branch createMaintenanceBranch(ModuleIteration module) throws Exception { + /** + * Back-ports the change log created for the given {@link TrainIteration} to the given release {@link Train}s. If the + * {@link TrainIteration} is a service iteration itself, the master branch will become an additional port target. + * + * @param iteration must not be {@literal null}. + * @param targets must not be {@literal null}. + */ + public void backportChangelogs(TrainIteration iteration, List targets) { - try (Git git = new Git(getRepository(module.getProject()))) { + Assert.notNull(iteration, "Train iteration must not be null!"); + Assert.notNull(targets, "Target trains must not be null!"); - Branch branch = Branch.from(module); + ExecutionUtils.run(iteration, module -> { + + BackportTargets backportTargets = new BackportTargets(module, targets); + Project project = module.getProject(); + + doWithGit(project, git -> { + + checkout(project, backportTargets.getSource()); + ObjectId objectId = getChangelogUpdate(module); + + backportTargets.forEach(target -> cherryPickCommitToBranch(objectId, project, target)); + }); + }); + + update(iteration.getTrain()); + } + + private void cherryPickCommitToBranch(ObjectId id, Project project, Branch branch) { + + doWithGit(project, git -> { + + try { + checkout(project, branch); + } catch (RuntimeException o_O) { + + logger.log(project, "Couldn't check out branch %s. Skipping cherrypick of commit %s.", branch, id.getName()); + return; + } + + git.cherryPick().include(id).call(); + logger.log(project, "Successfully cherry-picked commit %s to branch %s.", id.getName(), branch); + + }); + } + + private Branch createMaintenanceBranch(ModuleIteration module) { + + Branch branch = Branch.from(module); + + doWithGit(module.getProject(), git -> { git.branchCreate().setName(branch.toString()).call(); + }); - return branch; - } + return branch; } /** @@ -437,14 +510,21 @@ public class GitOperations { * @return * @throws Exception */ - private ObjectId getReleaseHash(ModuleIteration module) throws Exception { + private ObjectId getReleaseHash(ModuleIteration module) { + return findCommit(module, "Release"); + } + + private ObjectId getChangelogUpdate(ModuleIteration module) { + return findCommit(module, "Updated changelog"); + } + + private ObjectId findCommit(ModuleIteration module, String summary) { Project project = module.getProject(); - Ticket releaseTicket = issueTracker.getPluginFor(project).getReleaseTicketFor(module); - String trigger = String.format("%s - Release", releaseTicket.getId()); + String trigger = String.format("%s - %s", releaseTicket.getId(), summary); - try (Git git = new Git(getRepository(module.getProject()))) { + return doWithGit(module.getProject(), git -> { for (RevCommit commit : git.log().setMaxCount(50).call()) { @@ -452,10 +532,11 @@ public class GitOperations { return commit.getId(); } } - } - throw new IllegalStateException( - String.format("Did not find a release commit for project %s (ticket id %s)", project, releaseTicket.getId())); + throw new IllegalStateException( + String.format("Did not find a commit with summary starting with '%s' for project %s", project, trigger)); + + }); } /** @@ -492,18 +573,50 @@ public class GitOperations { try (Git git = new Git(getRepository(project))) { - return git.getRepository().getRef(branch.toString()) != null; + return git.getRepository().findRef(branch.toString()) != null; } catch (Exception o_O) { throw new RuntimeException(o_O); } } - private static void reset(Git git, String name) throws Exception { - git.reset().setMode(ResetType.HARD).setRef("origin/".concat(name)).call(); + private void reset(Project project, Branch branch) throws Exception { + + logger.log(project, "git reset --hard origin/%s", branch); + + try (Git git = new Git(getRepository(project))) { + git.reset().setMode(ResetType.HARD).setRef("origin/".concat(branch.toString())).call(); + } } private static String expandSummary(String summary, ModuleIteration module, TrainIteration iteration) { return summary.contains("%s") ? String.format(summary, module.getMediumVersionString()) : summary; } + + private T doWithGit(Project project, GitCallback callback) { + + try (Git git = new Git(getRepository(project))) { + return callback.doWithGit(git); + } catch (Exception o_O) { + throw new RuntimeException(o_O); + } + } + + private void doWithGit(Project project, VoidGitCallback callback) { + + doWithGit(project, (GitCallback) git -> { + callback.doWithGit(git); + return null; + }); + } + + private static interface GitCallback { + + T doWithGit(Git git) throws Exception; + } + + private static interface VoidGitCallback { + + void doWithGit(Git git) throws Exception; + } } diff --git a/release-tools/src/main/java/org/springframework/data/release/git/GitProject.java b/release-tools/src/main/java/org/springframework/data/release/git/GitProject.java index 543b8fb..56f15a2 100644 --- a/release-tools/src/main/java/org/springframework/data/release/git/GitProject.java +++ b/release-tools/src/main/java/org/springframework/data/release/git/GitProject.java @@ -15,6 +15,7 @@ */ package org.springframework.data.release.git; +import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; @@ -24,7 +25,7 @@ import org.springframework.data.release.model.Project; * @author Oliver Gierke */ @EqualsAndHashCode -@RequiredArgsConstructor +@RequiredArgsConstructor(access = AccessLevel.PACKAGE) public class GitProject { private static final String PROJECT_PREFIX = "spring-data"; @@ -32,6 +33,10 @@ public class GitProject { private final Project project; private final GitServer server; + public static GitProject of(Project project) { + return new GitProject(project, GitServer.INSTANCE); + } + /** * Returns the name of the repository the project is using. * diff --git a/release-tools/src/main/java/org/springframework/data/release/git/GitServer.java b/release-tools/src/main/java/org/springframework/data/release/git/GitServer.java index e6ec68c..3364d66 100644 --- a/release-tools/src/main/java/org/springframework/data/release/git/GitServer.java +++ b/release-tools/src/main/java/org/springframework/data/release/git/GitServer.java @@ -20,6 +20,8 @@ package org.springframework.data.release.git; */ public class GitServer { + public static final GitServer INSTANCE = new GitServer(); + private static final String SERVER_URI = "https://github.com/spring-projects/"; public String getUri() { diff --git a/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java b/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java index d8f3d50..8f5ee2d 100644 --- a/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java +++ b/release-tools/src/main/java/org/springframework/data/release/jira/GitHubIssueTracker.java @@ -30,7 +30,6 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.core.ParameterizedTypeReference; import org.springframework.data.release.git.GitProject; import org.springframework.data.release.git.GitProperties; -import org.springframework.data.release.git.GitServer; import org.springframework.data.release.model.Iteration; import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.Project; @@ -105,7 +104,7 @@ class GitHubIssueTracker implements IssueTracker { private List getIssuesFor(ModuleIteration module) { - String repositoryName = new GitProject(module.getProject(), new GitServer()).getRepositoryName(); + String repositoryName = GitProject.of(module.getProject()).getRepositoryName(); GitHubMilestone milestone = findMilestone(module, repositoryName); diff --git a/release-tools/src/main/java/org/springframework/data/release/model/Train.java b/release-tools/src/main/java/org/springframework/data/release/model/Train.java index de799cc..92544d4 100644 --- a/release-tools/src/main/java/org/springframework/data/release/model/Train.java +++ b/release-tools/src/main/java/org/springframework/data/release/model/Train.java @@ -25,6 +25,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -77,12 +78,33 @@ public class Train implements Streamable { orElseThrow(() -> new IllegalArgumentException(String.format("No Module found with name %s!", name))); } + /** + * Returns the {@link Module} for the given {@link Project} in the current release {@link Train}. + * + * @param project must not be {@literal null}. + * @return + * @throws IllegalArgumentException in case no {@link Module} can be found for the given {@link Project} in the + * current release {@link Train}. + */ public Module getModule(Project project) { - return modules.stream().// - filter(module -> module.getProject().equals(project)).// - findFirst().orElseThrow( - () -> new IllegalArgumentException(String.format("No module found for project %s!", project.getName()))); + Assert.notNull(project, "Project must not be null!"); + + return getModuleIfAvailable(project).orElseThrow(() -> new IllegalArgumentException( + String.format("No module found for project %s in release train %s!", project.getName(), this.name))); + } + + /** + * Returns the {@link Module} for the given {@link Project} in the current release {@link Train}. + * + * @param project must not be {@literal null}. + * @return the {@link Module} wrapped into an {@link Optional} if present, {@link Optional#empty()} otherwise. + */ + public Optional getModuleIfAvailable(Project project) { + + Assert.notNull(project, "Project must not be null!"); + + return modules.stream().filter(module -> module.getProject().equals(project)).findFirst(); } public Train next(String name, Transition transition, Module... additionalModules) { diff --git a/release-tools/src/test/java/org/springframework/data/release/git/BackportTargetsUnitTests.java b/release-tools/src/test/java/org/springframework/data/release/git/BackportTargetsUnitTests.java new file mode 100644 index 0000000..4d2c084 --- /dev/null +++ b/release-tools/src/test/java/org/springframework/data/release/git/BackportTargetsUnitTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2016 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.git; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.util.Arrays; + +import org.junit.Test; +import org.springframework.data.release.model.Iteration; +import org.springframework.data.release.model.ModuleIteration; +import org.springframework.data.release.model.Projects; +import org.springframework.data.release.model.ReleaseTrains; +import org.springframework.data.release.model.Train; +import org.springframework.data.release.model.TrainIteration; + +/** + * Unit tests for {@link BackportTargets}. + * + * @author Oliver Gierke + */ +public class BackportTargetsUnitTests { + + Branch goslingBranch = getBranch(ReleaseTrains.GOSLING); + Branch fowlerBranch = getBranch(ReleaseTrains.FOWLER); + + /** + * @see #11 + */ + @Test + public void returnsModuleBranchesForTrains() { + + TrainIteration iteration = new TrainIteration(ReleaseTrains.HOPPER, Iteration.M1); + ModuleIteration module = iteration.getModule(Projects.COMMONS); + + BackportTargets targets = new BackportTargets(module, Arrays.asList(ReleaseTrains.GOSLING, ReleaseTrains.FOWLER)); + + assertThat(targets, is(iterableWithSize(2))); + assertThat(targets, hasItems(goslingBranch, fowlerBranch)); + } + + /** + * @see #11 + */ + @Test + public void includesMasterBranchForServiceReleaseSource() { + + TrainIteration iteration = new TrainIteration(ReleaseTrains.GOSLING, Iteration.SR2); + ModuleIteration module = iteration.getModule(Projects.COMMONS); + + BackportTargets targets = new BackportTargets(module, Arrays.asList(ReleaseTrains.FOWLER)); + + assertThat(targets, is(iterableWithSize(2))); + assertThat(targets, hasItems(Branch.MASTER, fowlerBranch)); + } + + private static Branch getBranch(Train train) { + return Branch.from(train.getModule(Projects.COMMONS)); + } +}