diff --git a/README.adoc b/README.adoc index 86378692..da97b8f7 100644 --- a/README.adoc +++ b/README.adoc @@ -283,8 +283,11 @@ The following properties are used for both meta release and a release of an indi - `releaser.git.release-train-bom-url` - URL to a project containing a BOM. Defaults to Spring Cloud Release Git repository: `https://github.com/spring-cloud/spring-cloud-release`. - `releaser.git.documentation-url` - URL to the documentation Git repository. Defaults to `https://github.com/spring-cloud/spring-cloud-static`. - `releaser.git.documentation-branch` - Branch to check out for the documentation project. Defaults to `gh-pages`. +- `releaser.git.spring-project-url` - URL to the documentation Git repository. Defaults to `https://github.com/spring-projects/spring-cloud`. +- `releaser.git.spring-project-branch` - Branch to check out for the documentation project. Defaults to `gh-pages`. - `releaser.git.update-documentation-repo` - If `true` then will update documentation repository with the `current` URL. Defaults to `true`. - `releaser.git.update-spring-guides` - If `true` then will update Spring Guides with the current release train. Defaults to `true`. +- `releaser.git.update-spring-project` - If `true` then will update Spring Project page with the current release train values. Defaults to `true`. - `releaser.git.oauth-token` - GitHub OAuth token to be used to interact with GitHub repo. - `releaser.git.username` - Optional Git username. If not passed keys will be used for authentication. - `releaser.git.password` - Optional Git password. If not passed keys will be used for authentication. diff --git a/docs/src/main/asciidoc/spring-cloud-release-tools.adoc b/docs/src/main/asciidoc/spring-cloud-release-tools.adoc index a40c2fed..60327703 100644 --- a/docs/src/main/asciidoc/spring-cloud-release-tools.adoc +++ b/docs/src/main/asciidoc/spring-cloud-release-tools.adoc @@ -273,8 +273,11 @@ The following properties are used for both meta release and a release of an indi - `releaser.git.release-train-bom-url` - URL to a project containing a BOM. Defaults to Spring Cloud Release Git repository: `https://github.com/spring-cloud/spring-cloud-release`. - `releaser.git.documentation-url` - URL to the documentation Git repository. Defaults to `https://github.com/spring-cloud/spring-cloud-static`. - `releaser.git.documentation-branch` - Branch to check out for the documentation project. Defaults to `gh-pages`. +- `releaser.git.spring-project-url` - URL to the documentation Git repository. Defaults to `https://github.com/spring-projects/spring-cloud`. +- `releaser.git.spring-project-branch` - Branch to check out for the documentation project. Defaults to `gh-pages`. - `releaser.git.update-documentation-repo` - If `true` then will update documentation repository with the `current` URL. Defaults to `true`. - `releaser.git.update-spring-guides` - If `true` then will update Spring Guides with the current release train. Defaults to `true`. +- `releaser.git.update-spring-project` - If `true` then will update Spring Project page with the current release train values. Defaults to `true`. - `releaser.git.oauth-token` - GitHub OAuth token to be used to interact with GitHub repo. - `releaser.git.username` - Optional Git username. If not passed keys will be used for authentication. - `releaser.git.password` - Optional Git password. If not passed keys will be used for authentication. diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java index edc129f4..86ff68e5 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/Releaser.java @@ -196,4 +196,16 @@ public class Releaser { log.warn("\nUnable to update documentation repository for branch ["+ releaseBranch + "]", e); } } + + public void updateSpringProjectPage(Projects projects) { + try { + if (this.documentationUpdater.updateProjectRepo(projects) != null) { + log.info("\nSuccessfully updated Spring project page"); + } else { + log.warn("\nFailed to update Spring Project page"); + } + } catch (Exception e) { + log.warn("\nUnable to update Spring Project page", e); + } + } } diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/ReleaserProperties.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/ReleaserProperties.java index 382a2409..217d7b2d 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/ReleaserProperties.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/ReleaserProperties.java @@ -22,7 +22,6 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.regex.Pattern; import org.apache.commons.lang.SerializationUtils; @@ -147,11 +146,21 @@ public class ReleaserProperties implements Serializable { */ private String documentationUrl = "https://github.com/spring-cloud/spring-cloud-static"; + /** + * URL to main release train project repository + */ + private String springProjectUrl = "https://github.com/spring-projects/spring-cloud"; + /** * Branch to check out for the documentation project */ private String documentationBranch = "gh-pages"; + /** + * Branch to check out for the release train project + */ + private String springProjectBranch = "gh-pages"; + /** * If {@code false}, will not update the documentation repository. */ @@ -193,6 +202,12 @@ public class ReleaserProperties implements Serializable { */ private boolean updateSpringGuides = true; + /** + * If set to {@code false}, will not update the Spring Project for a release train. + * E.g. for Spring Cloud will not update https://cloud.spring.io + */ + private boolean updateSpringProject = true; + public String getReleaseTrainBomUrl() { return this.releaseTrainBomUrl; } @@ -209,6 +224,14 @@ public class ReleaserProperties implements Serializable { this.documentationUrl = documentationUrl; } + public String getSpringProjectUrl() { + return this.springProjectUrl; + } + + public void setSpringProjectUrl(String springProjectUrl) { + this.springProjectUrl = springProjectUrl; + } + public String getDocumentationBranch() { return this.documentationBranch; } @@ -217,6 +240,14 @@ public class ReleaserProperties implements Serializable { this.documentationBranch = documentationBranch; } + public String getSpringProjectBranch() { + return this.springProjectBranch; + } + + public void setSpringProjectBranch(String springProjectBranch) { + this.springProjectBranch = springProjectBranch; + } + public boolean isUpdateDocumentationRepo() { return this.updateDocumentationRepo; } @@ -281,6 +312,14 @@ public class ReleaserProperties implements Serializable { this.updateSpringGuides = updateSpringGuides; } + public boolean isUpdateSpringProject() { + return this.updateSpringProject; + } + + public void setUpdateSpringProject(boolean updateSpringProject) { + this.updateSpringProject = updateSpringProject; + } + @Override public String toString() { return "Git{" + @@ -288,11 +327,14 @@ public class ReleaserProperties implements Serializable { ", documentationUrl='" + this.documentationUrl + '\'' + ", documentationBranch='" + this.documentationBranch + '\'' + ", updateDocumentationRepo=" + this.updateDocumentationRepo + + ", springProjectUrl=" + this.springProjectUrl+ + ", springProjectBranch=" + this.springProjectBranch + ", cloneDestinationDir='" + this.cloneDestinationDir + '\'' + ", fetchVersionsFromGit=" + this.fetchVersionsFromGit + ", oauthToken='" + this.oauthToken + '\'' + ", numberOfCheckedMilestones=" + this.numberOfCheckedMilestones + ", updateSpringGuides=" + this.updateSpringGuides + + ", updateSpringProject=" + this.updateSpringProject + '}'; } } diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/DocumentationUpdater.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/DocumentationUpdater.java index 19f0e058..082e25d6 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/DocumentationUpdater.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/DocumentationUpdater.java @@ -1,31 +1,33 @@ package org.springframework.cloud.release.internal.docs; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.cloud.release.internal.ReleaserProperties; +import org.springframework.cloud.release.internal.ReleaserPropertiesAware; import org.springframework.cloud.release.internal.git.ProjectGitHandler; import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; /** * @author Marcin Grzejszczak */ -public class DocumentationUpdater { +public class DocumentationUpdater implements ReleaserPropertiesAware { - private static final String SC_STATIC_URL = "http://cloud.spring.io/spring-cloud-static/"; - private static final Logger log = LoggerFactory.getLogger(DocumentationUpdater.class); + private final ProjectDocumentationUpdater projectDocumentationUpdater; + private final ReleaseTrainContentsUpdater releaseTrainContentsUpdater; + private ReleaserProperties properties; - private final ProjectGitHandler gitHandler; - private final ReleaserProperties properties; - - public DocumentationUpdater(ReleaserProperties properties, - ProjectGitHandler gitHandler) { - this.gitHandler = gitHandler; + public DocumentationUpdater(ProjectGitHandler gitHandler, ReleaserProperties properties) { this.properties = properties; + this.projectDocumentationUpdater = new ProjectDocumentationUpdater(this.properties, gitHandler); + this.releaseTrainContentsUpdater = new ReleaseTrainContentsUpdater(this.properties, gitHandler); + } + + DocumentationUpdater(ReleaserProperties properties, ProjectDocumentationUpdater updater, + ReleaseTrainContentsUpdater contentsUpdater) { + this.properties = properties; + this.projectDocumentationUpdater = updater; + this.releaseTrainContentsUpdater = contentsUpdater; } /** @@ -37,70 +39,25 @@ public class DocumentationUpdater { * @return {@link File cloned temporary directory} - {@code null} if wrong version is used */ public File updateDocsRepo(ProjectVersion currentProject, String springCloudReleaseBranch) { - if (!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"); - return null; - } - if (!currentProject.isReleaseOrServiceRelease()) { - log.info("Will not update documentation repository for non release or service release [{}]", currentProject.version); - return null; - } - File documentationProject = this.gitHandler.cloneDocumentationProject(); - log.debug("Cloning the doc project to [{}]", documentationProject); - String pathToIndexHtml = "current/index.html"; - File indexHtml = new File(documentationProject, pathToIndexHtml); - if (!indexHtml.exists()) { - throw new IllegalStateException("index.html is not present at [" + pathToIndexHtml + "]"); - } - try { - String indexHtmlText = readIndexHtmlContents(indexHtml); - int index = indexHtmlText.indexOf(SC_STATIC_URL); - if (index == -1) { - throw new IllegalStateException("The URL to the documentation repo not found in the index.html file"); - } - int beginIndex = index + SC_STATIC_URL.length(); - String storedReleaseTrainLine = indexHtmlText.substring(beginIndex); - String storedReleaseTrain = storedReleaseTrainLine.substring(0, storedReleaseTrainLine.indexOf("/")); - String firstLetterOfReleaseTrain = String.valueOf(storedReleaseTrain.charAt(0)); - String currentReleaseTrainVersion = branchToReleaseVersion(springCloudReleaseBranch); - String firstLetterOfCurrentReleaseTrain = String.valueOf(currentReleaseTrainVersion.charAt(0)); - boolean newerOrEqualReleaseTrain = (!storedReleaseTrain.equals(currentReleaseTrainVersion)) && firstLetterOfCurrentReleaseTrain - .compareToIgnoreCase(firstLetterOfReleaseTrain) >= 0; - if (!newerOrEqualReleaseTrain) { - log.info("Current release train [{}] is not newer than the stored one [{}]", - currentReleaseTrainVersion, storedReleaseTrain); - return documentationProject; - } - return pushCommitedChanges(currentReleaseTrainVersion, documentationProject, - indexHtml, indexHtmlText, storedReleaseTrain); - } - catch (IOException e) { - throw new IllegalStateException(e); - } + return this.projectDocumentationUpdater + .updateDocsRepo(currentProject, springCloudReleaseBranch); } - private String branchToReleaseVersion(String springCloudReleaseBranch) { - if (springCloudReleaseBranch.startsWith("v")) { - return springCloudReleaseBranch.substring(1); - } - return springCloudReleaseBranch; + /** + * Updates the project page if current release train version is greater or equal + * than the one stored in the repo. + * + * @param projects + * @return {@link File cloned temporary directory} - {@code null} if wrong version is used or the switch is turned off + */ + public File updateProjectRepo(Projects projects) { + return this.releaseTrainContentsUpdater.updateProjectRepo(projects); } - private File pushCommitedChanges(String currentReleaseTrainVersion, - File documentationProject, File indexHtml, String indexHtmlText, - String storedReleaseTrain) throws IOException { - String replacedIndexHtml = indexHtmlText.replace(storedReleaseTrain, currentReleaseTrainVersion); - Files.write(indexHtml.toPath(), replacedIndexHtml.getBytes()); - log.info("Stored the release train [{}] in [{}]", - currentReleaseTrainVersion, indexHtml.getAbsolutePath()); - this.gitHandler.commit(documentationProject, "Updating the link to the current version to [" + currentReleaseTrainVersion + "]"); - this.gitHandler.pushCurrentBranch(documentationProject); - log.info("Committed and pushed changes to the documentation project"); - return documentationProject; - } - - String readIndexHtmlContents(File indexHtml) throws IOException { - return new String(Files.readAllBytes(indexHtml.toPath())); + @Override + public void setReleaserProperties(ReleaserProperties properties) { + this.properties = properties; + this.projectDocumentationUpdater.setReleaserProperties(properties); + this.releaseTrainContentsUpdater.setReleaserProperties(properties); } } diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ProjectDocumentationUpdater.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ProjectDocumentationUpdater.java new file mode 100644 index 00000000..d7a6a056 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ProjectDocumentationUpdater.java @@ -0,0 +1,116 @@ +package org.springframework.cloud.release.internal.docs; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.release.internal.ReleaserProperties; +import org.springframework.cloud.release.internal.ReleaserPropertiesAware; +import org.springframework.cloud.release.internal.git.ProjectGitHandler; +import org.springframework.cloud.release.internal.pom.ProjectVersion; + +/** + * @author Marcin Grzejszczak + */ +class ProjectDocumentationUpdater implements ReleaserPropertiesAware { + + private static final String SC_STATIC_URL = "http://cloud.spring.io/spring-cloud-static/"; + private static final Logger log = LoggerFactory.getLogger(ProjectDocumentationUpdater.class); + + private final ProjectGitHandler gitHandler; + private ReleaserProperties properties; + + ProjectDocumentationUpdater(ReleaserProperties properties, + ProjectGitHandler gitHandler) { + this.gitHandler = gitHandler; + this.properties = properties; + } + + /** + * Updates the documentation repository if current release train version is greater or equal + * than the one stored in the repo. + * + * @param currentProject + * @param springCloudReleaseBranch + * @return {@link File cloned temporary directory} - {@code null} if wrong version is used + */ + File updateDocsRepo(ProjectVersion currentProject, String springCloudReleaseBranch) { + if (!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"); + return null; + } + if (!currentProject.isReleaseOrServiceRelease()) { + log.info("Will not update documentation repository for non release or service release [{}]", currentProject.version); + return null; + } + File documentationProject = this.gitHandler.cloneDocumentationProject(); + log.debug("Cloning the doc project to [{}]", documentationProject); + String pathToIndexHtml = "current/index.html"; + File indexHtml = new File(documentationProject, pathToIndexHtml); + if (!indexHtml.exists()) { + throw new IllegalStateException("index.html is not present at [" + pathToIndexHtml + "]"); + } + return updateTheDocsRepo(springCloudReleaseBranch, documentationProject, indexHtml); + } + + private File updateTheDocsRepo(String springCloudReleaseBranch, File documentationProject, File indexHtml) { + try { + String indexHtmlText = readIndexHtmlContents(indexHtml); + int index = indexHtmlText.indexOf(SC_STATIC_URL); + if (index == -1) { + throw new IllegalStateException("The URL to the documentation repo not found in the index.html file"); + } + int beginIndex = index + SC_STATIC_URL.length(); + String storedReleaseTrainLine = indexHtmlText.substring(beginIndex); + String storedReleaseTrain = storedReleaseTrainLine.substring(0, storedReleaseTrainLine.indexOf("/")); + String firstLetterOfReleaseTrain = String.valueOf(storedReleaseTrain.charAt(0)); + String currentReleaseTrainVersion = branchToReleaseVersion(springCloudReleaseBranch); + String firstLetterOfCurrentReleaseTrain = String.valueOf(currentReleaseTrainVersion.charAt(0)); + boolean newerOrEqualReleaseTrain = (!storedReleaseTrain.equals(currentReleaseTrainVersion)) && firstLetterOfCurrentReleaseTrain + .compareToIgnoreCase(firstLetterOfReleaseTrain) >= 0; + if (!newerOrEqualReleaseTrain) { + log.info("Current release train [{}] is not newer than the stored one [{}]", + currentReleaseTrainVersion, storedReleaseTrain); + return documentationProject; + } + return pushCommitedChanges(currentReleaseTrainVersion, documentationProject, + indexHtml, indexHtmlText, storedReleaseTrain); + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private String branchToReleaseVersion(String springCloudReleaseBranch) { + if (springCloudReleaseBranch.startsWith("v")) { + return springCloudReleaseBranch.substring(1); + } + return springCloudReleaseBranch; + } + + private File pushCommitedChanges(String currentReleaseTrainVersion, + File documentationProject, File indexHtml, String indexHtmlText, + String storedReleaseTrain) throws IOException { + String replacedIndexHtml = indexHtmlText.replace(storedReleaseTrain, currentReleaseTrainVersion); + Files.write(indexHtml.toPath(), replacedIndexHtml.getBytes()); + log.info("Stored the release train [{}] in [{}]", + currentReleaseTrainVersion, indexHtml.getAbsolutePath()); + this.gitHandler.commit(documentationProject, "Updating the link to the current version to [" + currentReleaseTrainVersion + "]"); + this.gitHandler.pushCurrentBranch(documentationProject); + log.info("Committed and pushed changes to the documentation project"); + return documentationProject; + } + + String readIndexHtmlContents(File indexHtml) throws IOException { + return new String(Files.readAllBytes(indexHtml.toPath())); + } + + @Override + public void setReleaserProperties(ReleaserProperties properties) { + this.properties = properties; + } +} diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContents.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContents.java new file mode 100644 index 00000000..2f2a6a1a --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContents.java @@ -0,0 +1,37 @@ +package org.springframework.cloud.release.internal.docs; + +import java.util.List; +import java.util.Objects; + +public class ReleaseTrainContents { + final Title title; + final List rows; + + ReleaseTrainContents(Title title, List rows) { + this.title = title; + this.rows = rows; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ReleaseTrainContents contents = (ReleaseTrainContents) o; + return Objects.equals(this.title, contents.title) && + Objects.equals(this.rows, contents.rows); + } + + @Override + public int hashCode() { + return Objects.hash(this.title, this.rows); + } + + public Title getTitle() { + return this.title; + } + + public List getRows() { + return this.rows; + } +} + diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsUpdater.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsUpdater.java new file mode 100644 index 00000000..996b8a43 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsUpdater.java @@ -0,0 +1,249 @@ +package org.springframework.cloud.release.internal.docs; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.github.jknack.handlebars.Template; +import com.google.common.collect.ImmutableMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.release.internal.ReleaserProperties; +import org.springframework.cloud.release.internal.ReleaserPropertiesAware; +import org.springframework.cloud.release.internal.git.ProjectGitHandler; +import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; +import org.springframework.cloud.release.internal.tech.HandlebarsHelper; +import org.springframework.util.StringUtils; + +/** + * @author Marcin Grzejszczak + */ +class ReleaseTrainContentsUpdater implements ReleaserPropertiesAware { + + private static final Logger log = LoggerFactory + .getLogger(ReleaseTrainContentsUpdater.class); + + private ReleaserProperties properties; + private final ReleaseTrainContentsGitHandler handler; + private final ReleaseTrainContentsParser parser; + private final ReleaseTrainContentsGenerator generator; + + ReleaseTrainContentsUpdater(ReleaserProperties properties, ProjectGitHandler handler) { + this.properties = properties; + this.handler = new ReleaseTrainContentsGitHandler(handler); + this.parser = new ReleaseTrainContentsParser(); + this.generator = new ReleaseTrainContentsGenerator(this.properties); + } + + /** + * Updates the project page if current release train version is greater or equal + * than the one stored in the repo. + * + * @param projects + * @return {@link File cloned temporary directory} - {@code null} if wrong version is used or the switch is turned off + */ + File updateProjectRepo(Projects projects) { + if (!this.properties.getGit().isUpdateSpringProject()) { + log.info("Will not update the Spring Project cause the switch is turned off. Set [releaser.git.update-spring-project=true]."); + return null; + } + File releaseTrainProject = this.handler.cloneSpringDocProject(); + File index = new File(releaseTrainProject, "index.html"); + ReleaseTrainContents contents = this.parser.parse(index); + String newContents = this.generator.releaseTrainContents(contents, projects); + if (StringUtils.isEmpty(newContents)) { + log.info("No changes to commit to the Spring Project page."); + return releaseTrainProject; + } + return pushNewContents(projects, releaseTrainProject, index, newContents); + } + + private File pushNewContents(Projects projects, File releaseTrainProject, + File index, String newContents) { + try { + log.debug("Storing new contents to the page"); + Files.write(index.toPath(), newContents.getBytes()); + log.info("Successfully stored new contents of the page"); + this.handler.commitAndPushChanges(releaseTrainProject, + this.generator.currentReleaseTrainProject(projects)); + return releaseTrainProject; + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void setReleaserProperties(ReleaserProperties properties) { + this.properties = properties; + this.generator.setReleaserProperties(properties); + } +} + +/** + * @author Marcin Grzejszczak + */ +class ReleaseTrainContentsGenerator implements ReleaserPropertiesAware { + + private static final Logger log = LoggerFactory + .getLogger(ReleaseTrainContentsGenerator.class); + private static final String SPRING_PROJECT_TEMPLATE = "spring-project"; + + private ReleaserProperties properties; + private final File projectOutput; + + ReleaseTrainContentsGenerator(ReleaserProperties properties) { + this.properties = properties; + this.projectOutput = new File("target/index.html"); + } + + String releaseTrainContents(ReleaseTrainContents currentContents, Projects projects) { + String trainProject = this.properties.getMetaRelease().getReleaseTrainProjectName(); + ProjectVersion currentReleaseTrainProject = currentReleaseTrainProject(projects); + ProjectVersion lastGa = new ProjectVersion(trainProject, currentContents.title.lastGaTrainName); + ProjectVersion currentGa = new ProjectVersion(trainProject, currentContents.title.currentGaTrainName); + ReleaseTrainContents newReleaseTrainContents = updateReleaseTrainContentsIfNecessary(currentContents, projects, + currentReleaseTrainProject, lastGa, currentGa); + if (!currentContents.equals(newReleaseTrainContents)) { + Template template = HandlebarsHelper.template(this.properties.getTemplate() + .getTemplateFolder(), SPRING_PROJECT_TEMPLATE); + return generate(this.projectOutput, template, newReleaseTrainContents); + } + log.warn("Current release train [{}] is neither last [{}] or current [{}] or the projects haven't changed. Will not update the contents", + currentReleaseTrainProject.version, lastGa, currentGa); + return ""; + } + + ProjectVersion currentReleaseTrainProject(Projects projects) { + return projects.forName(this.properties.getMetaRelease().getReleaseTrainProjectName()); + } + + private String generate(File contentOutput, Template template, ReleaseTrainContents releaseTrainContents) { + try { + Map map = ImmutableMap.builder() + .put("lastGaTrainName", releaseTrainContents.title.lastGaTrainName) + .put("currentGaTrainName", releaseTrainContents.title.currentGaTrainName) + .put("currentSnapshotTrainName", releaseTrainContents.title.currentSnapshotTrainName) + .put("projects", releaseTrainContents.rows) + .build(); + String contents = template.apply(map); + Files.write(contentOutput.toPath(), contents.getBytes()); + return contents; + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private ReleaseTrainContents updateReleaseTrainContentsIfNecessary(ReleaseTrainContents currentContents, Projects projects, + ProjectVersion currentReleaseTrainProject, ProjectVersion lastGa, ProjectVersion currentGa) { + ReleaseTrainContents newReleaseTrainContents = currentContents; + // current GA is greater than the last GA + if (greaterMinorOfLastGaReleaseTrain(currentReleaseTrainProject, lastGa)) { + Title title = new Title(currentReleaseTrainProject.version, currentContents.title.currentGaTrainName, + currentContents.title.currentSnapshotTrainName); + return updatedReleaseTrainContents(currentContents, projects, title, true); + } else if (currentReleaseTrainProject.isSameReleaseTrainName(currentGa.version)) { + Title title = new Title(currentContents.title.lastGaTrainName, currentReleaseTrainProject.isReleaseOrServiceRelease() ? + currentReleaseTrainProject.version : currentContents.title.currentGaTrainName, currentReleaseTrainProject.isSnapshot() ? + currentReleaseTrainProject.version : currentContents.title.currentSnapshotTrainName); + return updatedReleaseTrainContents(currentContents, projects, title, false); + } + return newReleaseTrainContents; + } + + private boolean greaterMinorOfLastGaReleaseTrain(ProjectVersion currentReleaseTrainProject, ProjectVersion lastGa) { + return currentReleaseTrainProject.isSameReleaseTrainName(lastGa.version) && + currentReleaseTrainProject.isReleaseOrServiceRelease() && + currentReleaseTrainProject.compareToReleaseTrainName(lastGa.version) > 0; + } + + private ReleaseTrainContents updatedReleaseTrainContents(ReleaseTrainContents currentContents, Projects projects, + Title title, boolean lastGa) { + List rows = Row.fromProjects(projects, lastGa); + return new ReleaseTrainContents( + title, currentContents.rows.stream().map(current -> { + Row projectRow = rows.stream().filter(row -> + current.componentName.equals(row.componentName)).findFirst().orElse(current); + if (projectRow == current) { + return projectRow; + } + return from(current, projectRow); + }).collect(Collectors.toCollection(LinkedList::new))); + } + + private Row from(Row current, Row project) { + return new Row(current.componentName, StringUtils.hasText(project.lastGaVersion) ? + project.lastGaVersion : current.lastGaVersion, + StringUtils.hasText(project.currentGaVersion) ? + project.currentGaVersion : current.currentGaVersion, + StringUtils.hasText(project.currentSnapshotVersion) ? + project.currentSnapshotVersion : current.currentSnapshotVersion); + } + + @Override + public void setReleaserProperties(ReleaserProperties properties) { + this.properties = properties; + } +} + +class ReleaseTrainContentsGitHandler { + + 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]"; + + private final ProjectGitHandler handler; + + ReleaseTrainContentsGitHandler(ProjectGitHandler handler) { + this.handler = handler; + } + + // clones the project and checks out the branch + File cloneSpringDocProject() { + return this.handler.cloneSpringDocProject(); + } + + 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.pushCurrentBranch(repo); + } + +} + +class ReleaseTrainContentsParser { + + private static final Logger log = LoggerFactory + .getLogger(ReleaseTrainContentsParser.class); + + ReleaseTrainContents parse(File rawHtml) { + try { + String contents = new String(Files.readAllBytes(rawHtml.toPath())); + String[] split = contents.split(""); + if (split.length != 3) { + log.warn("The page is missing the components table markers. Please add [] and [] to the file."); + return null; + } + String table = split[1]; + String[] components = table.trim().split("\n"); + String[] titleRow = components[0].trim().split("\\|"); + Title title = new Title(titleRow); + List rows = new LinkedList<>(); + for (int i = 2; i < components.length; i++) { + String[] splitRow = components[i].split("\\|"); + rows.add(new Row(splitRow)); + } + return new ReleaseTrainContents(title, rows); + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/Row.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/Row.java new file mode 100644 index 00000000..11a44844 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/Row.java @@ -0,0 +1,81 @@ +package org.springframework.cloud.release.internal.docs; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; + +/** + * @author Marcin Grzejszczak + */ +public class Row { + final String componentName; + final String lastGaVersion; + final String currentGaVersion; + final String currentSnapshotVersion; + + Row(String[] row) { + int initialIndex = row.length == 4 ? 0 : 1; + this.componentName = row[initialIndex].trim(); + this.lastGaVersion = row[initialIndex + 1].trim(); + this.currentGaVersion = row[initialIndex + 2].trim(); + this.currentSnapshotVersion = row[initialIndex + 3].trim(); + } + + Row(String componentName, String lastGaVersion, String currentGaVersion, String currentSnapshotVersion) { + this.componentName = componentName.trim(); + this.lastGaVersion = lastGaVersion.trim(); + this.currentGaVersion = currentGaVersion.trim(); + this.currentSnapshotVersion = currentSnapshotVersion.trim(); + } + + 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 : "")) + .collect(Collectors.toCollection(LinkedList::new)); + } + + private static String versionOrEmptyForGa(ProjectVersion v) { + return v.isReleaseOrServiceRelease() ? + v.version : ""; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + 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); + } + + @Override + public int hashCode() { + return Objects + .hash(this.componentName, this.lastGaVersion, + this.currentGaVersion, this.currentSnapshotVersion); + } + + public String getComponentName() { + return this.componentName; + } + + public String getLastGaVersion() { + return this.lastGaVersion; + } + + public String getCurrentGaVersion() { + return this.currentGaVersion; + } + + public String getCurrentSnapshotVersion() { + return this.currentSnapshotVersion; + } +} diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/Title.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/Title.java new file mode 100644 index 00000000..fe5bfbe5 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/docs/Title.java @@ -0,0 +1,55 @@ +package org.springframework.cloud.release.internal.docs; + +import java.util.Objects; + +/** + * @author Marcin Grzejszczak + */ +public class Title { + + final String lastGaTrainName; + final String currentGaTrainName; + final String currentSnapshotTrainName; + + Title(String[] row) { + int initialIndex = row.length == 4 ? 1 : 2; + this.lastGaTrainName = row[initialIndex].trim(); + this.currentGaTrainName = row[initialIndex + 1].trim(); + this.currentSnapshotTrainName = row[initialIndex + 2].trim(); + } + + Title(String lastGaTrainName, String currentGaTrainName, String currentSnapshotTrainName) { + this.lastGaTrainName = lastGaTrainName.trim(); + this.currentGaTrainName = currentGaTrainName.trim(); + this.currentSnapshotTrainName = currentSnapshotTrainName.trim(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Title title = (Title) o; + return Objects.equals(this.lastGaTrainName, title.lastGaTrainName) && + Objects.equals(this.currentGaTrainName, title.currentGaTrainName) && + Objects + .equals(this.currentSnapshotTrainName, title.currentSnapshotTrainName); + } + + @Override + public int hashCode() { + return Objects + .hash(this.lastGaTrainName, this.currentGaTrainName, this.currentSnapshotTrainName); + } + + public String getLastGaTrainName() { + return this.lastGaTrainName; + } + + public String getCurrentGaTrainName() { + return this.currentGaTrainName; + } + + public String getCurrentSnapshotTrainName() { + return this.currentSnapshotTrainName; + } +} diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/ProjectGitHandler.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/ProjectGitHandler.java index 5d81d8e1..35571526 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/ProjectGitHandler.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/git/ProjectGitHandler.java @@ -6,6 +6,7 @@ import java.nio.file.Files; import org.eclipse.jgit.transport.URIish; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.ReleaserPropertiesAware; import org.springframework.cloud.release.internal.pom.ProjectVersion; @@ -25,10 +26,9 @@ public class ProjectGitHandler implements ReleaserPropertiesAware { private static final String PRE_RELEASE_MSG = "Update SNAPSHOT to %s"; private static final String POST_RELEASE_MSG = "Going back to snapshots"; private static final String POST_RELEASE_BUMP_MSG = "Bumping versions to %s after release"; - - private ReleaserProperties properties; private final GithubMilestones githubMilestones; private final GithubIssues githubIssues; + private ReleaserProperties properties; public ProjectGitHandler(ReleaserProperties properties) { this.properties = properties; @@ -41,7 +41,8 @@ public class ProjectGitHandler implements ReleaserPropertiesAware { if (version.isSnapshot()) { log.info("Snapshot version [{}] found. Will only commit the changed poms", version); gitRepo.commit(MSG); - } else { + } + else { 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; @@ -53,8 +54,10 @@ public class ProjectGitHandler implements ReleaserPropertiesAware { public void commitAfterBumpingVersions(File project, ProjectVersion version) { if (version.isSnapshot()) { log.info("Snapshot version [{}] found. Will only commit the changed poms", version); - commit(project, String.format(POST_RELEASE_BUMP_MSG, version.bumpedVersion())); - } else { + commit(project, String + .format(POST_RELEASE_BUMP_MSG, version.bumpedVersion())); + } + else { log.info("Non snapshot version [{}] found. Won't do anything", version); } } @@ -69,8 +72,20 @@ public class ProjectGitHandler implements ReleaserPropertiesAware { } public File cloneDocumentationProject() { - File clonedProject = cloneProject(this.properties.getGit().getDocumentationUrl()); - checkout(clonedProject, this.properties.getGit().getDocumentationBranch()); + return cloneAndCheckOut(this.properties.getGit() + .getDocumentationUrl(), this.properties.getGit() + .getDocumentationBranch()); + } + + public File cloneSpringDocProject() { + return cloneAndCheckOut(this.properties.getGit() + .getSpringProjectUrl(), this.properties.getGit() + .getSpringProjectBranch()); + } + + private File cloneAndCheckOut(String springProjectUrl, String springProjectUrlBranch) { + File clonedProject = cloneProject(springProjectUrl); + checkout(clonedProject, springProjectUrlBranch); return clonedProject; } @@ -115,7 +130,8 @@ public class ProjectGitHandler implements ReleaserPropertiesAware { new File(properties.getGit().getCloneDestinationDir()) : Files.createTempDirectory("releaser").toFile(); return gitRepo(destinationDir).cloneProject(new URIish(url)); - } catch (Exception e) { + } + catch (Exception e) { throw new IllegalStateException(e); } } @@ -137,7 +153,8 @@ public class ProjectGitHandler implements ReleaserPropertiesAware { if (splitVersion.length == 3) { // [2,3,4] -> 2.3.x return splitVersion[0] + "." + splitVersion[1] + ".x"; - } else if (splitVersion.length == 1) { + } + else if (splitVersion.length == 1) { // [Camden] -> [Camden.x] return splitVersion[0]; } @@ -178,7 +195,8 @@ public class ProjectGitHandler implements ReleaserPropertiesAware { return new GitRepo(workingDir, this.properties); } - @Override public void setReleaserProperties(ReleaserProperties properties) { + @Override + public void setReleaserProperties(ReleaserProperties properties) { this.properties = properties; } } diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java index 37caa9b5..e06960ce 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/pom/ProjectVersion.java @@ -107,6 +107,34 @@ public class ProjectVersion { splitThis[0].equals(splitThat[0]) && splitThis[1].equals(splitThat[1]); } + public boolean isSameReleaseTrainName(String version) { + assertVersionSet(); + String[] splitThis = this.version.split("\\."); + String[] splitThat = version.split("\\."); + return splitThis[0].compareToIgnoreCase(splitThat[0]) == 0; + } + + private void assertVersionSet() { + if (this.version == null) { + throw new IllegalStateException("Version is not set"); + } + } + + public int compareToReleaseTrainName(String version) { + assertVersionSet(); + String[] split = version.split("\\."); + String thatName = split[0]; + String thatValue = split[1]; + String[] thisSplit = this.version.split("\\."); + String thisName = thisSplit[0]; + String thisValue = thisSplit[1]; + int nameComparison = thisName.compareTo(thatName); + if (nameComparison != 0) { + return nameComparison; + } + return new VersionNumber(thisValue).compareTo(new VersionNumber(thatValue)); + } + @Override public String toString() { return this.version; } @@ -124,3 +152,25 @@ public class ProjectVersion { return Objects.hash(this.projectName); } } + +class VersionNumber implements Comparable { + private final String version; + + VersionNumber(String version) { + this.version = version; + } + + @Override + public int compareTo(VersionNumber o) { + char thisFirst = this.version.toLowerCase().charAt(0); + char thatFirst = o.version.toLowerCase().charAt(0); + // B < M < RC < R < S + int charComparison = Character.compare(thisFirst, thatFirst); + if (charComparison != 0) { + return charComparison; + } + Integer thisNumber = Integer.valueOf(this.version.replaceAll("\\D+","")); + Integer thatNumber = Integer.valueOf(o.version.replaceAll("\\D+","")); + return thisNumber.compareTo(thatNumber); + } +} \ No newline at end of file diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/tech/HandlebarsHelper.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/tech/HandlebarsHelper.java new file mode 100644 index 00000000..6e29af25 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/tech/HandlebarsHelper.java @@ -0,0 +1,27 @@ +package org.springframework.cloud.release.internal.tech; + +import java.io.IOException; + +import com.github.jknack.handlebars.Handlebars; +import com.github.jknack.handlebars.Template; +import com.github.jknack.handlebars.helper.StringHelpers; +import com.github.jknack.handlebars.io.ClassPathTemplateLoader; + +/** + * @author Marcin Grzejszczak + */ +public final class HandlebarsHelper { + + public static Template template(String templateSubFolder, String templateName) { + try { + Handlebars handlebars = new Handlebars(new ClassPathTemplateLoader("/templates/" + + templateSubFolder)); + handlebars.registerHelper("replace", StringHelpers.replace); + handlebars.registerHelper("capitalizeFirst", StringHelpers.capitalizeFirst); + return handlebars.compile(templateName); + } + catch (IOException e) { + throw new IllegalStateException(e); + } + } +} diff --git a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/TemplateGenerator.java b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/TemplateGenerator.java index f56fb458..29c8e6ea 100644 --- a/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/TemplateGenerator.java +++ b/spring-cloud-release-tools-core/src/main/java/org/springframework/cloud/release/internal/template/TemplateGenerator.java @@ -12,6 +12,7 @@ import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.ReleaserPropertiesAware; import org.springframework.cloud.release.internal.git.ProjectGitHandler; import org.springframework.cloud.release.internal.pom.Projects; +import org.springframework.cloud.release.internal.tech.HandlebarsHelper; /** * @author Marcin Grzejszczak @@ -101,15 +102,7 @@ public class TemplateGenerator implements ReleaserPropertiesAware { } private Template template(String template) { - try { - Handlebars handlebars = new Handlebars(new ClassPathTemplateLoader("/templates/" + - this.props.getTemplate().getTemplateFolder())); - handlebars.registerHelper("replace", StringHelpers.replace); - handlebars.registerHelper("capitalizeFirst", StringHelpers.capitalizeFirst); - return handlebars.compile(template); - } catch (IOException e) { - throw new IllegalStateException(e); - } + return HandlebarsHelper.template(this.props.getTemplate().getTemplateFolder(), template); } @Override public void setReleaserProperties(ReleaserProperties properties) { diff --git a/spring-cloud-release-tools-core/src/main/resources/templates/cloud/spring-project.hbs b/spring-cloud-release-tools-core/src/main/resources/templates/cloud/spring-project.hbs new file mode 100644 index 00000000..3e245243 --- /dev/null +++ b/spring-cloud-release-tools-core/src/main/resources/templates/cloud/spring-project.hbs @@ -0,0 +1,357 @@ +--- +# The name of your project +title: Spring Cloud + +badges: + + + # Customize your project's badges. Delete any entries that do not apply. + custom: + - name: Source (GitHub) + url: https://github.com/spring-cloud + icon: github + + - name: StackOverflow + url: http://stackoverflow.com/questions/tagged/spring-cloud + icon: stackoverflow + + +--- + + + + +{% capture billboard_description %} + +Spring Cloud provides tools for developers to quickly build some of +the common patterns in distributed systems (e.g. configuration +management, service discovery, circuit breakers, intelligent routing, +micro-proxy, control bus, one-time tokens, global locks, leadership +election, distributed sessions, cluster state). Coordination of +distributed systems leads to boiler plate patterns, and using Spring +Cloud developers can quickly stand up services and applications that +implement those patterns. They will work well in any distributed +environment, including the developer's own laptop, bare metal data +centres, and managed platforms such as Cloud Foundry. + +{% endcapture %} + +{% capture main_content %} + +Spring Cloud builds on Spring Boot by providing a bunch of libraries +that enhance the behaviour of an application when added to the +classpath. You can take advantage of the basic default behaviour to +get started really quickly, and then when you need to, you can +configure or extend to create a custom solution. + + + +## Quick Start + +The release train label (see below) is actually only used explicitly +in one artifact: "spring-cloud-dependencies" (all the others have +normal numeric release labels tied to their parent project). The +dependencies POM is the one you can use as a BOM for dependency +management. Example using the latest version with the config client +and eureka (change the artifact ids to pull in other starters): + +{% include download_widget.md %} + +## Features + +Spring Cloud focuses on providing good out of box experience for typical use cases and extensibility mechanism to cover others. + +* Distributed/versioned configuration +* Service registration and discovery +* Routing +* Service-to-service calls +* Load balancing +* Circuit Breakers +* Global locks +* Leadership election and cluster state +* Distributed messaging + +Spring Cloud takes a very declarative approach, and often you get a +lot of fetaures with just a classpath change and/or an +annotation. Example application that is a discovery client: + +```java +@SpringBootApplication +@EnableDiscoveryClient +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} +``` + + + +## Main Projects + + +{% capture project_description %} +Centralized external configuration management backed by a git repository. The configuration resources map directly to Spring `Environment` but could be used by non-Spring applications if desired. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-config" repo_url="http://github.com/spring-cloud/spring-cloud-config" project_title="Spring Cloud Config" project_description=project_description %} + + +{% capture project_description %} +Integration with various Netflix OSS components (Eureka, Hystrix, Zuul, Archaius, etc.). +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-netflix" repo_url="http://github.com/spring-cloud/spring-cloud-netflix" project_title="Spring Cloud Netflix" project_description=project_description %} + + +{% capture project_description %} +An event bus for linking services and service instances together with distributed messaging. Useful for propagating state changes across a cluster (e.g. config change events). +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-bus" repo_url="http://github.com/spring-cloud/spring-cloud-bus" project_title="Spring Cloud Bus" project_description=project_description %} + + +{% capture project_description %} +Integrates your application with Pivotal Cloud Foundry. Provides a service discovery implementation and also makes it easy to implement SSO and OAuth2 protected resources. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-cloudfoundry" repo_url="http://github.com/spring-cloud/spring-cloud-cloudfoundry" project_title="Spring Cloud for Cloud Foundry" project_description=project_description %} + + +{% capture project_description %} +Provides a starting point for building a service broker that implements the Open Service Broker API. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-open-service-broker/" repo_url="http://github.com/spring-cloud/spring-cloud-open-service-broker" project_title="Spring Cloud Open Service Broker" project_description=project_description %} + + +{% capture project_description %} +Leadership election and common stateful patterns with an abstraction and implementation for Zookeeper, Redis, Hazelcast, Consul. +{% endcapture %} + +{% include project_block.md site_url="/spring-cloud" repo_url="http://github.com/spring-cloud/spring-cloud-cluster" project_title="Spring Cloud Cluster" project_description=project_description %} + + +{% capture project_description %} +Service discovery and configuration management with Hashicorp Consul. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-consul" repo_url="http://github.com/spring-cloud/spring-cloud-consul" project_title="Spring Cloud Consul" project_description=project_description %} + + +{% capture project_description %} +Provides support for load-balanced OAuth2 rest client and authentication header relays in a Zuul proxy. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-security" repo_url="http://github.com/spring-cloud/spring-cloud-security" project_title="Spring Cloud Security" project_description=project_description %} + + +{% capture project_description %} +Distributed tracing for Spring Cloud applications, compatible with Zipkin, HTrace and log-based (e.g. ELK) tracing. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-sleuth" repo_url="http://github.com/spring-cloud/spring-cloud-sleuth" project_title="Spring Cloud Sleuth" project_description=project_description %} + + +{% capture project_description %} +A cloud-native orchestration service for composable microservice applications on modern runtimes. Easy-to-use DSL, drag-and-drop GUI, and REST-APIs together simplifies the overall orchestration of microservice based data pipelines. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-dataflow" repo_url="https://github.com/spring-cloud/spring-cloud-dataflow" project_title="Spring Cloud Data Flow" project_description=project_description %} + + +{% capture project_description %} +A lightweight event-driven microservices framework to quickly build applications that can connect to external systems. Simple declarative model to send and receive messages using Apache Kafka or RabbitMQ between Spring Boot apps. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-stream" repo_url="http://github.com/spring-cloud/spring-cloud-stream" project_title="Spring Cloud Stream" project_description=project_description %} + + +{% capture project_description %} +Spring Cloud Stream App Starters are Spring Boot based Spring Integration applications that provide integration with external systems. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-stream-app-starters" repo_url="https://github.com/spring-cloud/spring-cloud-stream-app-starters" project_title="Spring Cloud Stream App Starters" project_description=project_description %} + + +{% capture project_description %} +A short-lived microservices framework to quickly build applications that perform finite amounts of data processing. Simple declarative for adding both functional and non-functional features to Spring Boot apps. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-task" repo_url="http://github.com/spring-cloud/spring-cloud-task" project_title="Spring Cloud Task" project_description=project_description %} + + +{% capture project_description %} +Spring Cloud Task App Starters are Spring Boot applications that may be any process including Spring Batch jobs that do not run forever, and they end/stop after a finite period of data processing. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-task-app-starters" repo_url="https://github.com/spring-cloud/spring-cloud-task-app-starters" project_title="Spring Cloud Task App Starters" project_description=project_description %} + + +{% capture project_description %} +Service discovery and configuration management with Apache Zookeeper. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-zookeeper" repo_url="http://github.com/spring-cloud/spring-cloud-zookeeper" project_title="Spring Cloud Zookeeper" project_description=project_description %} + + +{% capture project_description %} +Easy integration with hosted Amazon Web Services. It offers a convenient way to interact with AWS provided services using well-known Spring idioms and APIs, such as the messaging or caching API. Developers can build their application around the hosted services without having to care about infrastructure or maintenance. +{% endcapture %} + +{% capture site_url %} +{{ site.projects_site_url }}/spring-cloud-aws +{% endcapture %} + +{% include project_block.md site_url=site_url repo_url="http://github.com/spring-cloud/spring-cloud-aws" project_title="Spring Cloud for Amazon Web Services" project_description=project_description %} + + +{% capture project_description %} +Makes it easy for PaaS applications in a variety of platforms to connect to backend services like +databases and message brokers (the project formerly known as "Spring Cloud"). +{% endcapture %} + +{% capture site_url %} +{{ site.projects_site_url }}/spring-cloud-connectors +{% endcapture %} + +{% include project_block.md site_url=site_url repo_url="http://github.com/spring-cloud/spring-cloud-connectors" project_title="Spring Cloud Connectors" project_description=project_description %} + + +{% capture project_description %} +Spring Boot-style starter projects to ease dependency management for consumers of Spring Cloud. (Discontinued as a project and merged with the other projects after Angel.SR2.) +{% endcapture %} + +{% include project_block.md site_url="http://github.com/spring-cloud/spring-cloud-starters" repo_url="http://github.com/spring-cloud/spring-cloud-starters" project_title="Spring Cloud Starters" project_description=project_description %} + + +{% capture project_description %} +Spring Boot CLI plugin for creating Spring Cloud component applications quickly in Groovy +{% endcapture %} + +{% include project_block.md site_url="http://github.com/spring-cloud/spring-cloud-cli" repo_url="http://github.com/spring-cloud/spring-cloud-cli" project_title="Spring Cloud CLI" project_description=project_description %} + + +{% capture project_description %} +Spring Cloud Contract is an umbrella project holding solutions that help users in successfully implementing the Consumer Driven Contracts approach. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-contract" repo_url="http://github.com/spring-cloud/spring-cloud-contract" project_title="Spring Cloud Contract" project_description=project_description %} + + +{% capture project_description %} +Spring Cloud Gateway is an intelligent and programmable router based on Project Reactor. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-gateway" repo_url="http://github.com/spring-cloud/spring-cloud-gateway" project_title="Spring Cloud Gateway" project_description=project_description %} + + +{% capture project_description %} +Spring Cloud OpenFeign provides integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-openfeign" repo_url="http://github.com/spring-cloud/spring-cloud-openfeign" project_title="Spring Cloud OpenFeign" project_description=project_description %} + + +{% capture project_description %} +Spring Cloud Pipelines provides an opinionated deployment pipeline with steps to ensure that your application can be deployed in zero downtime fashion and easilly rolled back of something goes wrong. +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-pipelines" repo_url="http://github.com/spring-cloud/spring-cloud-pipelines" project_title="Spring Cloud Pipelines" project_description=project_description %} + + +{% capture project_description %} +Spring Cloud Function promotes the implementation of business logic via functions. It supports a uniform programming model across serverless providers, as well as the ability to run standalone (locally or in a PaaS). +{% endcapture %} + +{% include project_block.md site_url="http://cloud.spring.io/spring-cloud-function" repo_url="http://github.com/spring-cloud/spring-cloud-function" project_title="Spring Cloud Function" project_description=project_description %} + +## Release Trains + +Spring Cloud is an umbrella project consisting of independent projects with, in principle, different +release cadences. To manage the portfolio a BOM (Bill of Materials) is published with a curated +set of dependencies on the individual project (see below). The release trains have names, not +versions, to avoid confusion with the sub-projects. The names are an alphabetic sequence (so +you can sort them chronologically) with names of London Tube stations ("Angel" is the first +release, "Brixton" is the second). When point releases of the individual projects accumulate to +a critical mass, or if there is a critical bug in one of them that needs to be available to everyone, +the release train will push out "service releases" with names ending ".SRX", where "X" +is a number. + +Release train contents: + + +|Component |{{lastGaTrainName}}|{{currentGaTrainName}}|{{currentSnapshotTrainName}}| +|--------------------------------------|-----------------|---------------------|------------------------| +{{#each projects}} |{{componentName}}|{{lastGaVersion}}|{{currentGaVersion}}|{{currentSnapshotVersion}}| +{{/each}} + + +Finchley builds and works with Spring Boot 2.0.x, and is not expected +to work with Spring Boot 1.5.x. + +Note: The Dalston release train will [reach end-of-life](https://spring.io/blog/2018/06/19/spring-cloud-finchley-release-is-available) in December 2018. Edgware will follow the end-of-life cycle of Spring Boot 1.5.x. + +The Dalston and Edgware release trains build on Spring Boot 1.5.x, and +are not expected to work with Spring Boot 2.0.x. + +NOTE: The Camden release train was [marked end-of-life](https://spring.io/blog/2018/06/19/spring-cloud-finchley-release-is-available). + +The Camden release train builds on Spring Boot 1.4.x, but is also +tested with 1.5.x. + +NOTE: The Brixton and Angel release trains were [marked end-of-life](https://spring.io/blog/2017/07/21/spring-cloud-dalston-sr2-is-available-now#end-of-life-for-angel-and-brixton-release-trains) +(EOL) in July 2017. + +The Brixton release train builds on Spring Boot 1.3.x, but is also +tested with 1.4.x. + +The Angel release train builds on Spring Boot 1.2.x, and is +incompatible in some areas with Spring Boot 1.3.x. Brixton builds on +Spring Boot 1.3.x and is similarly incompatible with 1.2.x. Some +libraries and most apps built on Angel will run fine on Brixton, but +changes will be required anywhere that the OAuth2 features from +spring-cloud-security 1.0.x are used (they were mostly moved to Spring +Boot in 1.3.0). + +Use your dependency management tools to control the version. If you +are using Maven remember that the first version declared wins, so +declare the BOMs in order, with the first one usually being the most +recent (e.g. if you want to use Spring Boot 1.3.6 with Brixton.RELEASE, put +the Boot BOM first). The same rule applies to Gradle if you use the +Spring dependency management plugin. + +> NOTE: The release train contains a +> `spring-cloud-dependencies` as well as the +> `spring-cloud-starter-parent`. You can use the parent as you would +> the `spring-boot-starter-parent` (if you are using Maven). +> If you only need dependency management, the "dependencies" +> version is a BOM-only version of the same thing (it just +> contains dependency management and no plugin declarations +> or direct references to Spring or Spring Boot). If you are +> using the Spring Boot parent POM, then you can use the BOM from +> Spring Cloud. The opposite is not true: using the Cloud parent +> makes it impossible, or at least unreliable, to also use the +> Boot BOM to change the version of Spring Boot and its dependencies. + +> NOTE: If you find anything wrong or outdated on this page, please open an issue in [this](https://github.com/spring-projects/spring-cloud) repo. + +{% endcapture %} + +{% capture related_resources %} + +### Sample Projects + +* [Config Server](https://github.com/spring-cloud-samples/configserver) +* [Service Registry](https://github.com/spring-cloud-samples/eureka) +* [Circuit Breaker Dashboard](https://github.com/spring-cloud-samples/hystrix-dashboard) +* [Business Application](https://github.com/spring-cloud-samples/customers-stores) (Customers and Stores) +* [OAuth2 Authorization Server](https://github.com/spring-cloud-samples/authserver) +* [OAuth2 SSO Client](https://github.com/spring-cloud-samples/sso) +* [Integration Test Samples](https://github.com/spring-cloud-samples/tests) +* [Spring Cloud Contract Samples](https://github.com/spring-cloud-samples/spring-cloud-contract-samples) + +{% endcapture %} + +{% include project_page.html %} + \ No newline at end of file diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/DocumentationUpdaterTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ProjectDocumentationUpdaterTests.java similarity index 86% rename from spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/DocumentationUpdaterTests.java rename to spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ProjectDocumentationUpdaterTests.java index 4c38b5c0..bb70d3ff 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/DocumentationUpdaterTests.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ProjectDocumentationUpdaterTests.java @@ -24,7 +24,7 @@ import static org.assertj.core.api.BDDAssertions.then; /** * @author Marcin Grzejszczak */ -public class DocumentationUpdaterTests { +public class ProjectDocumentationUpdaterTests { @Rule public TemporaryFolder tmp = new TemporaryFolder(); File project; @@ -37,10 +37,10 @@ public class DocumentationUpdaterTests { public void setup() throws IOException, URISyntaxException { this.tmpFolder = this.tmp.newFolder(); this.project = new File( - DocumentationUpdaterTests.class.getResource("/projects/spring-cloud-static").toURI()); + ProjectDocumentationUpdaterTests.class.getResource("/projects/spring-cloud-static").toURI()); TestUtils.prepareLocalRepo(); FileSystemUtils.copyRecursively(file("/projects"), this.tmpFolder); - 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(properties); this.clonedDocProject = this.handler.cloneDocumentationProject(); } @@ -54,7 +54,7 @@ public class DocumentationUpdaterTests { properties.getGit().setDocumentationUrl(file("/projects/spring-cloud-release/").toURI().toString()); BDDAssertions.thenThrownBy(() -> - new DocumentationUpdater(properties, new ProjectGitHandler(properties)) + new ProjectDocumentationUpdater(properties, new ProjectGitHandler(properties)) .updateDocsRepo(releaseTrainVersion, "vAngel.SR33")) .isInstanceOf(IllegalStateException.class) .hasMessageContaining("index.html is not present"); @@ -68,7 +68,7 @@ public class DocumentationUpdaterTests { properties.getGit().setDocumentationUrl(file("/projects/spring-cloud-static/").toURI().toString()); BDDAssertions.thenThrownBy(() -> - new DocumentationUpdater(properties, new ProjectGitHandler(properties)) { + new ProjectDocumentationUpdater(properties, new ProjectGitHandler(properties)) { @Override String readIndexHtmlContents(File indexHtml) throws IOException { return ""; @@ -83,7 +83,7 @@ public class DocumentationUpdaterTests { ProjectVersion releaseTrainVersion = new ProjectVersion("spring-cloud-sleuth", "2.0.0.BUILD-SNAPSHOT"); ReleaserProperties properties = new ReleaserProperties(); - File updatedDocs = new DocumentationUpdater(properties, new ProjectGitHandler(properties)) + File updatedDocs = new ProjectDocumentationUpdater(properties, new ProjectGitHandler(properties)) .updateDocsRepo(releaseTrainVersion, "vAngel.M7"); then(updatedDocs).isNull(); @@ -96,7 +96,7 @@ public class DocumentationUpdaterTests { ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setDocumentationUrl(file("/projects/spring-cloud-static/").toURI().toString()); - File updatedDocs = new DocumentationUpdater(properties, new ProjectGitHandler(properties)) + File updatedDocs = new ProjectDocumentationUpdater(properties, new ProjectGitHandler(properties)) .updateDocsRepo(releaseTrainVersion, "vAngel.SR33"); String indexHtmlContent = new String(Files.readAllBytes( @@ -113,7 +113,7 @@ public class DocumentationUpdaterTests { properties.getGit().setDocumentationUrl(this.clonedDocProject.toURI().toString()); ProjectGitHandler handler = BDDMockito.spy(new ProjectGitHandler(properties)); - new DocumentationUpdater(properties, handler) + new ProjectDocumentationUpdater(properties, handler) .updateDocsRepo(releaseTrainVersion, "vDalston.SR3"); BDDMockito.then(handler).should(BDDMockito.never()) @@ -127,7 +127,7 @@ public class DocumentationUpdaterTests { ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setDocumentationUrl(this.clonedDocProject.toURI().toString()); - File updatedDocs = new DocumentationUpdater(properties, new ProjectGitHandler(properties)) + File updatedDocs = new ProjectDocumentationUpdater(properties, new ProjectGitHandler(properties)) .updateDocsRepo(releaseTrainVersion, "Angel.SR33"); String indexHtmlContent = new String(Files.readAllBytes( @@ -143,7 +143,7 @@ public class DocumentationUpdaterTests { ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setDocumentationUrl(this.clonedDocProject.toURI().toString()); - File updatedDocs = new DocumentationUpdater(properties, new ProjectGitHandler(properties)) + File updatedDocs = new ProjectDocumentationUpdater(properties, new ProjectGitHandler(properties)) .updateDocsRepo(releaseTrainVersion, "vFinchley.SR33"); String indexHtmlContent = new String(Files.readAllBytes( @@ -159,7 +159,7 @@ public class DocumentationUpdaterTests { ReleaserProperties properties = new ReleaserProperties(); properties.getGit().setDocumentationUrl(this.clonedDocProject.toURI().toString()); - File updatedDocs = new DocumentationUpdater(properties, new ProjectGitHandler(properties)) + File updatedDocs = new ProjectDocumentationUpdater(properties, new ProjectGitHandler(properties)) .updateDocsRepo(releaseTrainVersion, "Finchley.SR33"); String indexHtmlContent = new String(Files.readAllBytes( @@ -176,13 +176,13 @@ public class DocumentationUpdaterTests { properties.getGit().setDocumentationUrl(this.clonedDocProject.toURI().toString()); properties.getGit().setUpdateDocumentationRepo(false); - File updatedDocs = new DocumentationUpdater(properties, new ProjectGitHandler(properties)) + File updatedDocs = new ProjectDocumentationUpdater(properties, new ProjectGitHandler(properties)) .updateDocsRepo(releaseTrainVersion, "Finchley.SR33"); then(updatedDocs).isNull(); } private File file(String relativePath) throws URISyntaxException { - return new File(DocumentationUpdaterTests.class.getResource(relativePath).toURI()); + return new File(ProjectDocumentationUpdaterTests.class.getResource(relativePath).toURI()); } } \ No newline at end of file diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsGeneratorTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsGeneratorTests.java new file mode 100644 index 00000000..0c978d9f --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsGeneratorTests.java @@ -0,0 +1,217 @@ +package org.springframework.cloud.release.internal.docs; + +import java.util.Arrays; +import java.util.List; + +import org.assertj.core.api.BDDAssertions; +import org.junit.Test; + +import org.springframework.cloud.release.internal.ReleaserProperties; +import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; + +import static org.junit.Assert.*; + +/** + * @author Marcin Grzejszczak + */ +public class ReleaseTrainContentsGeneratorTests { + + @Test + public void should_return_empty_contents_if_there_versions_are_lower_than_current_ones() { + ReleaseTrainContentsGenerator generator = new ReleaseTrainContentsGenerator(new ReleaserProperties()); + + String contents = generator + .releaseTrainContents(contents(), olderReleaseTrain()); + + BDDAssertions.then(contents).isEmpty(); + } + + @Test + public void should_return_empty_contents_if_there_are_no_changes_in_the_versions() { + ReleaseTrainContentsGenerator generator = new ReleaseTrainContentsGenerator(new ReleaserProperties()); + + String contents = generator + .releaseTrainContents(contents(), sameProjectsForCurrentGa()); + + BDDAssertions.then(contents).isEmpty(); + } + + @Test + public void should_return_contents_with_updated_current_release_train() { + ReleaseTrainContentsGenerator generator = new ReleaseTrainContentsGenerator(new ReleaserProperties()); + + String contents = generator + .releaseTrainContents(contents(), newerProjectsForNewGa()); + + BDDAssertions.then(contents).contains("|Edgware.SR5|Finchley.SR2|Finchley.BUILD-SNAPSHOT|"); + BDDAssertions.then(contents).contains(" |spring-cloud-cli|1.4.1.RELEASE|3.0.0.RELEASE|2.0.1.BUILD-SNAPSHOT|"); + } + + @Test + public void should_return_contents_with_updated_previous_release_train() { + ReleaseTrainContentsGenerator generator = new ReleaseTrainContentsGenerator(new ReleaserProperties()); + + String contents = generator + .releaseTrainContents(contents(), newerProjectsForOldGa()); + + BDDAssertions.then(contents).contains("|Edgware.SR6|Finchley.SR1|Finchley.BUILD-SNAPSHOT|"); + BDDAssertions.then(contents).contains(" |spring-cloud-cli|3.0.0.RELEASE|2.0.0.RELEASE|2.0.1.BUILD-SNAPSHOT|"); + } + + @Test + public void should_return_contents_with_updated_current_snapshot_train() { + ReleaseTrainContentsGenerator generator = new ReleaseTrainContentsGenerator(new ReleaserProperties()); + + String contents = generator + .releaseTrainContents(contents(), newerProjectsForCurrentSnapshot()); + + BDDAssertions.then(contents).contains("|Edgware.SR5|Finchley.SR1|Finchley.BUILD-SNAPSHOT|"); + BDDAssertions.then(contents).contains(" |spring-cloud-cli|1.4.1.RELEASE|2.0.0.RELEASE|3.0.0.BUILD-SNAPSHOT|"); + } + + ReleaseTrainContents contents() { + Title title = new Title("Edgware.SR5", "Finchley.SR1", "Finchley.BUILD-SNAPSHOT"); + List rows = Arrays.asList( + 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")); + return new ReleaseTrainContents(title, rows); + } + + Projects olderReleaseTrain() { + return new Projects( + new ProjectVersion("spring-cloud-aws", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-bus", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cli", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-commons", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-contract", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-config", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-netflix", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-security", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cloudfoundry", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-consul", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-sleuth", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-stream", "Elmhurst.SR1"), + new ProjectVersion("spring-cloud-zookeeper", "2.0.0.RELEASE"), + new ProjectVersion("spring-boot", "2.0.4.RELEASE"), + new ProjectVersion("spring-cloud-task", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-release", "Dalston.SR1"), + new ProjectVersion("spring-cloud-vault", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-gateway", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-openfeign", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-function", "1.0.0.RELEASE")); + } + + Projects sameProjectsForCurrentGa() { + return new Projects( + new ProjectVersion("spring-cloud-aws", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-bus", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cli", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-commons", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-contract", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-config", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-netflix", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-security", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cloudfoundry", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-consul", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-sleuth", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-stream", "Elmhurst.SR1"), + new ProjectVersion("spring-cloud-zookeeper", "2.0.0.RELEASE"), + new ProjectVersion("spring-boot", "2.0.4.RELEASE"), + new ProjectVersion("spring-cloud-task", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-release", "Finchley.SR1"), + new ProjectVersion("spring-cloud-vault", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-gateway", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-openfeign", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-function", "1.0.0.RELEASE")); + } + + Projects newerProjectsForNewGa() { + return new Projects( + new ProjectVersion("spring-cloud-aws", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-bus", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cli", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-commons", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-contract", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-config", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-netflix", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-security", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cloudfoundry", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-consul", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-sleuth", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-stream", "Elmhurst.SR1"), + new ProjectVersion("spring-cloud-zookeeper", "3.0.0.RELEASE"), + new ProjectVersion("spring-boot", "3.0.4.RELEASE"), + new ProjectVersion("spring-cloud-task", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-release", "Finchley.SR2"), + new ProjectVersion("spring-cloud-vault", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-gateway", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-openfeign", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-function", "1.0.0.RELEASE")); + } + + Projects newerProjectsForOldGa() { + return new Projects( + new ProjectVersion("spring-cloud-aws", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-bus", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cli", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-commons", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-contract", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-config", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-netflix", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-security", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cloudfoundry", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-consul", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-sleuth", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-stream", "Elmhurst.SR1"), + new ProjectVersion("spring-cloud-zookeeper", "3.0.0.RELEASE"), + new ProjectVersion("spring-boot", "3.0.4.RELEASE"), + new ProjectVersion("spring-cloud-task", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-release", "Edgware.SR6"), + new ProjectVersion("spring-cloud-vault", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-gateway", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-openfeign", "3.0.1.RELEASE"), + new ProjectVersion("spring-cloud-function", "1.0.0.RELEASE")); + } + + Projects newerProjectsForCurrentSnapshot() { + return new Projects( + new ProjectVersion("spring-cloud-aws", "2.0.0.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-bus", "3.0.0.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-cli", "3.0.0.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-commons", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-contract", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-config", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-netflix", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-security", "3.0.0.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-cloudfoundry", "3.0.0.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-consul", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-sleuth", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-stream", "Elmhurst.SR1"), + new ProjectVersion("spring-cloud-zookeeper", "3.0.0.BUILD-SNAPSHOT"), + new ProjectVersion("spring-boot", "3.0.4.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-task", "3.0.0.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-release", "Finchley.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-vault", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-gateway", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-openfeign", "3.0.1.BUILD-SNAPSHOT"), + new ProjectVersion("spring-cloud-function", "1.0.0.BUILD-SNAPSHOT")); + } +} \ No newline at end of file diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsUpdaterTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsUpdaterTests.java new file mode 100644 index 00000000..a3cb98ee --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/ReleaseTrainContentsUpdaterTests.java @@ -0,0 +1,126 @@ +package org.springframework.cloud.release.internal.docs; + +import java.io.File; +import java.net.URISyntaxException; + +import org.assertj.core.api.BDDAssertions; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import org.springframework.cloud.release.internal.ReleaserProperties; +import org.springframework.cloud.release.internal.git.GitTestUtils; +import org.springframework.cloud.release.internal.git.ProjectGitHandler; +import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; +import org.springframework.cloud.release.internal.pom.TestUtils; +import org.springframework.util.FileSystemUtils; + +/** + * @author Marcin Grzejszczak + */ +public class ReleaseTrainContentsUpdaterTests { + + ReleaserProperties properties = new ReleaserProperties(); + ProjectGitHandler projectGitHandler = new ProjectGitHandler(this.properties); + ReleaseTrainContentsUpdater updater = new ReleaseTrainContentsUpdater(this.properties, + this.projectGitHandler); + File springCloudRepo; + @Rule public TemporaryFolder tmp = new TemporaryFolder(); + File temporaryFolder; + + @Before + public void setup() throws Exception { + this.temporaryFolder = this.tmp.newFolder(); + TestUtils.prepareLocalRepo(); + FileSystemUtils.copyRecursively(file("/projects/spring-cloud"), this.temporaryFolder); + this.springCloudRepo = this.temporaryFolder; + } + + private File file(String relativePath) throws URISyntaxException { + return new File(ReleaseTrainContentsUpdaterTests.class.getResource(relativePath).toURI()); + } + + @Test + public void should_do_nothing_when_switch_is_off() { + this.properties.getGit().setUpdateSpringProject(false); + + File file = this.updater.updateProjectRepo(oldReleaseTrain()); + + BDDAssertions.then(file).isNull(); + } + + @Test + public void should_not_update_the_contents_of_spring_project_repo_when_release_train_smaller() throws GitAPIException { + this.properties.getGit().setSpringProjectUrl(this.springCloudRepo.getAbsolutePath() + "/"); + + File file = this.updater.updateProjectRepo(oldReleaseTrain()); + + BDDAssertions.then(file).isNotNull(); + BDDAssertions.then(GitTestUtils.openGitProject(file).log().call().iterator().next().getShortMessage()) + .doesNotContain("Updating project page to release train"); + } + + @Test + public void should_update_the_contents_of_spring_project_repo_when_release_train_greater() throws GitAPIException { + this.properties.getGit().setSpringProjectUrl(this.springCloudRepo.getAbsolutePath() + "/"); + + File file = this.updater.updateProjectRepo(newReleaseTrain()); + + BDDAssertions.then(file).isNotNull(); + BDDAssertions.then(GitTestUtils.openGitProject(file).log().call().iterator().next().getShortMessage()) + .contains("Updating project page to release train [Edgware.SR7]"); + } + + Projects oldReleaseTrain() { + return new Projects( + new ProjectVersion("spring-cloud-aws", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-bus", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cli", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-commons", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-contract", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-config", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-netflix", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-security", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cloudfoundry", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-consul", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-sleuth", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-stream", "Elmhurst.SR1"), + new ProjectVersion("spring-cloud-zookeeper", "2.0.0.RELEASE"), + new ProjectVersion("spring-boot", "2.0.4.RELEASE"), + new ProjectVersion("spring-cloud-task", "2.0.0.RELEASE"), + // old release train + new ProjectVersion("spring-cloud-release", "Dalston.SR1"), + new ProjectVersion("spring-cloud-vault", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-gateway", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-openfeign", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-function", "1.0.0.RELEASE")); + } + + Projects newReleaseTrain() { + return new Projects( + new ProjectVersion("spring-cloud-aws", "3.0.0.RELEASE"), + new ProjectVersion("spring-cloud-bus", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cli", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-commons", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-contract", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-config", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-netflix", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-security", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-cloudfoundry", "2.0.0.RELEASE"), + new ProjectVersion("spring-cloud-consul", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-sleuth", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-stream", "Elmhurst.SR1"), + new ProjectVersion("spring-cloud-zookeeper", "2.0.0.RELEASE"), + new ProjectVersion("spring-boot", "2.0.4.RELEASE"), + new ProjectVersion("spring-cloud-task", "2.0.0.RELEASE"), + // newer release train + new ProjectVersion("spring-cloud-release", "Edgware.SR7"), + new ProjectVersion("spring-cloud-vault", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-gateway", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-openfeign", "2.0.1.RELEASE"), + new ProjectVersion("spring-cloud-function", "1.0.0.RELEASE")); + } +} \ No newline at end of file diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/RowTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/RowTests.java new file mode 100644 index 00000000..82cce31a --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/RowTests.java @@ -0,0 +1,59 @@ +package org.springframework.cloud.release.internal.docs; + +import java.util.List; + +import org.assertj.core.api.BDDAssertions; +import org.junit.Test; + +import org.springframework.cloud.release.internal.pom.ProjectVersion; +import org.springframework.cloud.release.internal.pom.Projects; + +import static org.junit.Assert.*; + +/** + * @author Marcin Grzejszczak + */ +public class RowTests { + + @Test + public void should_convert_projects_to_rows_for_last_ga() { + 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, true); + + Row release = rows.get(0); + BDDAssertions.then(release.componentName).isEqualTo("sc-release"); + BDDAssertions.then(release.currentGaVersion).isEmpty(); + BDDAssertions.then(release.currentSnapshotVersion).isEmpty(); + BDDAssertions.then(release.lastGaVersion).isEqualTo("2.0.1.RELEASE"); + Row foo = rows.get(1); + BDDAssertions.then(foo.componentName).isEqualTo("foo"); + BDDAssertions.then(foo.currentSnapshotVersion).isEqualTo("1.0.0.BUILD-SNAPSHOT"); + BDDAssertions.then(foo.currentGaVersion).isEmpty(); + BDDAssertions.then(foo.lastGaVersion).isEmpty(); + } + + @Test + public void should_convert_projects_to_rows_for_current_ga() { + 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); + + Row release = rows.get(0); + BDDAssertions.then(release.componentName).isEqualTo("sc-release"); + BDDAssertions.then(release.lastGaVersion).isEmpty(); + BDDAssertions.then(release.currentSnapshotVersion).isEmpty(); + BDDAssertions.then(release.currentGaVersion).isEqualTo("2.0.1.RELEASE"); + Row foo = rows.get(1); + BDDAssertions.then(foo.componentName).isEqualTo("foo"); + BDDAssertions.then(foo.lastGaVersion).isEmpty(); + BDDAssertions.then(foo.currentGaVersion).isEmpty(); + BDDAssertions.then(foo.currentSnapshotVersion).isEqualTo("1.0.0.BUILD-SNAPSHOT"); + } +} \ No newline at end of file diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/SpringCloudGhPagesParserTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/SpringCloudGhPagesParserTests.java new file mode 100644 index 00000000..b10d9b81 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/docs/SpringCloudGhPagesParserTests.java @@ -0,0 +1,69 @@ +package org.springframework.cloud.release.internal.docs; + +import java.io.File; +import java.net.URISyntaxException; + +import org.assertj.core.api.BDDAssertions; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.test.rule.OutputCapture; + +/** + * @author Marcin Grzejszczak + */ +public class SpringCloudGhPagesParserTests { + + @Rule + public OutputCapture capture = new OutputCapture(); + 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()); + + public SpringCloudGhPagesParserTests() throws URISyntaxException { + } + + @Test + public void should_parse_the_components_table() { + ReleaseTrainContents contents = new ReleaseTrainContentsParser() + .parse(this.rawHtml); + + BDDAssertions.then(contents).isNotNull(); + 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")); + } + + @Test + public void should_not_parse_the_components_table_when_markers_are_not_found() { + ReleaseTrainContents contents = new ReleaseTrainContentsParser() + .parse(this.wrongHtml); + + BDDAssertions.then(contents).isNull(); + BDDAssertions.then(capture.toString()) + .contains("The page is missing the components table markers"); + } +} \ No newline at end of file diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/git/ProjectGitHandlerTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/git/ProjectGitHandlerTests.java index 2aa7eef0..c93076dd 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/git/ProjectGitHandlerTests.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/git/ProjectGitHandlerTests.java @@ -6,16 +6,15 @@ import org.assertj.core.api.BDDAssertions; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; + import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.pom.ProjectVersion; -import org.springframework.cloud.release.internal.sagan.Release; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; /** diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java index e1b8ab8f..5a123bd3 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/ProjectVersionTests.java @@ -203,6 +203,64 @@ public class ProjectVersionTests { then(projectVersion.groupId()).isEmpty(); } + @Test + public void should_return_true_when_release_train_names_are_the_same() { + String thisVersion = "Finchley.SR1"; + String thatVersion = "Finchley.SR2"; + + then(projectVersion(thisVersion).isSameReleaseTrainName(thatVersion)).isTrue(); + } + + @Test + public void should_return_true_when_sr_has_two_digits() { + String thisVersion = "Finchley.SR1"; + String thatVersion = "Finchley.SR10"; + + then(projectVersion(thatVersion).compareToReleaseTrainName(thisVersion)).isPositive(); + } + + @Test + public void should_return_false_when_release_train_name_are_different() { + String thisVersion = "Finchley.SR1"; + String thatVersion = "Greenwich.SR1"; + + then(projectVersion(thisVersion).isSameReleaseTrainName(thatVersion)).isFalse(); + } + + @Test + public void should_return_positive_when_release_train_is_greater_than_the_other_one() { + String thisVersion = "Finchley.SR2"; + String thatVersion = "Finchley.SR1"; + + then(projectVersion(thisVersion).compareToReleaseTrainName(thatVersion)).isPositive(); + + thisVersion = "Greenwich.SR1"; + thatVersion = "Finchley.SR2"; + + then(projectVersion(thisVersion).compareToReleaseTrainName(thatVersion)).isPositive(); + } + + @Test + public void should_return_0_when_release_train_is_equal_than_the_other_one() { + String thisVersion = "Finchley.SR1"; + String thatVersion = "Finchley.SR1"; + + then(projectVersion(thisVersion).compareToReleaseTrainName(thatVersion)).isZero(); + } + + @Test + public void should_return_minus_1_when_release_train_is_smaller_than_the_other_one() { + String thisVersion = "Finchley.SR1"; + String thatVersion = "Finchley.SR2"; + + then(projectVersion(thisVersion).compareToReleaseTrainName(thatVersion)).isNegative(); + + thisVersion = "Finchley.SR2"; + thatVersion = "Greenwich.SR1"; + + then(projectVersion(thisVersion).compareToReleaseTrainName(thatVersion)).isNegative(); + } + private ProjectVersion projectVersion(String version) { return new ProjectVersion("foo", version); } diff --git a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/TestUtils.java b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/TestUtils.java index 634da05e..3b2dc61a 100644 --- a/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/TestUtils.java +++ b/spring-cloud-release-tools-core/src/test/java/org/springframework/cloud/release/internal/pom/TestUtils.java @@ -8,6 +8,7 @@ import org.eclipse.jgit.util.FileUtils; public class TestUtils { public static void prepareLocalRepo() throws IOException { + prepareLocalRepo("target/test-classes/projects/", "spring-cloud"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-release"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-consul"); prepareLocalRepo("target/test-classes/projects/", "spring-cloud-static"); diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/README.md b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/README.md new file mode 100644 index 00000000..daf5fc9a --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/README.md @@ -0,0 +1,11 @@ +This project is an umbrella and the git repository is used only for +documentation (see gh-pages branch). Home page: http://projects.spring.io/spring-cloud. + +The sub-projects of Spring Cloud live in a different Github +organization: https://github.com/spring-cloud. Please use the +issue trackers in the individual projects there to report bugs and +request new features. Each project has a README with instructions +on how to build the source code and how to contribute ideas and code. + +If you are looking for the project formerly known as Spring Cloud, please +go https://github.com/spring-cloud/spring-cloud-connectors. diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/HEAD b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/HEAD new file mode 100644 index 00000000..cb089cd8 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/config b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/config new file mode 100644 index 00000000..94ade795 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/config @@ -0,0 +1,16 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = git@github.com:spring-projects/spring-cloud.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master +[branch "gh-pages"] + remote = origin + merge = refs/heads/gh-pages diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/description b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/description new file mode 100644 index 00000000..498b267a --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/applypatch-msg.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/applypatch-msg.sample new file mode 100755 index 00000000..a5d7b84a --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/commit-msg.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/commit-msg.sample new file mode 100755 index 00000000..b58d1184 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/post-update.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/post-update.sample new file mode 100755 index 00000000..ec17ec19 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-applypatch.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-applypatch.sample new file mode 100755 index 00000000..4142082b --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-commit.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-commit.sample new file mode 100755 index 00000000..68d62d54 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-push.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-push.sample new file mode 100755 index 00000000..6187dbf4 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-rebase.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-rebase.sample new file mode 100755 index 00000000..6cbef5c3 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-receive.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-receive.sample new file mode 100755 index 00000000..a1fd29ec --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/prepare-commit-msg.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/prepare-commit-msg.sample new file mode 100755 index 00000000..10fa14c5 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/update.sample b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/update.sample new file mode 100755 index 00000000..80ba9413 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/index b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/index new file mode 100644 index 00000000..12ffd2a8 Binary files /dev/null and b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/index differ diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/info/exclude b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/info/exclude new file mode 100644 index 00000000..a5196d1b --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/HEAD b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/HEAD new file mode 100644 index 00000000..9c6ddf07 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/HEAD @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git +70c9a49fdcedbfad87ac23ea6862322578ac4c31 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak 1539863113 +0200 checkout: moving from master to gh-pages +66f767411e396c28b8ae4ca638824a741e9c2767 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak 1539863139 +0200 checkout: moving from gh-pages to master diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/heads/gh-pages b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/heads/gh-pages new file mode 100644 index 00000000..b7632cb6 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/heads/gh-pages @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak 1539863113 +0200 branch: Created from refs/remotes/origin/gh-pages diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/heads/master b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/heads/master new file mode 100644 index 00000000..848b7d09 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/remotes/origin/HEAD b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/remotes/origin/HEAD new file mode 100644 index 00000000..848b7d09 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.idx b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.idx new file mode 100644 index 00000000..3eb45120 Binary files /dev/null and b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.idx differ diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.pack b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.pack new file mode 100644 index 00000000..43172341 Binary files /dev/null and b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.pack differ diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/packed-refs b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/packed-refs new file mode 100644 index 00000000..685caab2 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/packed-refs @@ -0,0 +1,5 @@ +# pack-refs with: peeled fully-peeled sorted +66f767411e396c28b8ae4ca638824a741e9c2767 refs/remotes/origin/gh-pages +f14c1c0297fbb27491043aef018208adff0523b9 refs/remotes/origin/gh-pages-borked +cad5fcc769356792f511970c41dab283eab2bbd6 refs/remotes/origin/gh-pages-old +70c9a49fdcedbfad87ac23ea6862322578ac4c31 refs/remotes/origin/master diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/heads/gh-pages b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/heads/gh-pages new file mode 100644 index 00000000..32180923 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/heads/gh-pages @@ -0,0 +1 @@ +66f767411e396c28b8ae4ca638824a741e9c2767 diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/heads/master b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/heads/master new file mode 100644 index 00000000..40d77bd6 --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/heads/master @@ -0,0 +1 @@ +70c9a49fdcedbfad87ac23ea6862322578ac4c31 diff --git a/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/remotes/origin/HEAD b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/remotes/origin/HEAD new file mode 100644 index 00000000..6efe28ff --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/projects/spring-cloud/git/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/master diff --git a/spring-cloud-release-tools-core/src/test/resources/raw/some-file.html b/spring-cloud-release-tools-core/src/test/resources/raw/some-file.html new file mode 100644 index 00000000..e69de29b diff --git a/spring-cloud-release-tools-core/src/test/resources/raw/spring-cloud-gh-pages-index.html b/spring-cloud-release-tools-core/src/test/resources/raw/spring-cloud-gh-pages-index.html new file mode 100644 index 00000000..d0b577cc --- /dev/null +++ b/spring-cloud-release-tools-core/src/test/resources/raw/spring-cloud-gh-pages-index.html @@ -0,0 +1,374 @@ +--- +# The name of your project +title: Spring Cloud + +badges: + + +# Customize your project's badges. Delete any entries that do not apply. +custom: +- name: Source (GitHub) +url: https://github.com/spring-cloud +icon: github + +- name: StackOverflow +url: http://stackoverflow.com/questions/tagged/spring-cloud +icon: stackoverflow + + +--- + + + + + {% capture billboard_description %} + + Spring Cloud provides tools for developers to quickly build some of + the common patterns in distributed systems (e.g. configuration + management, service discovery, circuit breakers, intelligent routing, + micro-proxy, control bus, one-time tokens, global locks, leadership + election, distributed sessions, cluster state). Coordination of + distributed systems leads to boiler plate patterns, and using Spring + Cloud developers can quickly stand up services and applications that + implement those patterns. They will work well in any distributed + environment, including the developer's own laptop, bare metal data + centres, and managed platforms such as Cloud Foundry. + + {% endcapture %} + + {% capture main_content %} + + Spring Cloud builds on Spring Boot by providing a bunch of libraries + that enhance the behaviour of an application when added to the + classpath. You can take advantage of the basic default behaviour to + get started really quickly, and then when you need to, you can + configure or extend to create a custom solution. + + + + ## Quick Start + + The release train label (see below) is actually only used explicitly + in one artifact: "spring-cloud-dependencies" (all the others have + normal numeric release labels tied to their parent project). The + dependencies POM is the one you can use as a BOM for dependency + management. Example using the latest version with the config client + and eureka (change the artifact ids to pull in other starters): + + {% include download_widget.md %} + + ## Features + + Spring Cloud focuses on providing good out of box experience for typical use cases and extensibility mechanism to cover others. + + * Distributed/versioned configuration + * Service registration and discovery + * Routing + * Service-to-service calls + * Load balancing + * Circuit Breakers + * Global locks + * Leadership election and cluster state + * Distributed messaging + + Spring Cloud takes a very declarative approach, and often you get a + lot of fetaures with just a classpath change and/or an + annotation. Example application that is a discovery client: + + ```java + @SpringBootApplication + @EnableDiscoveryClient + public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + } + ``` + + + + ## Main Projects + + + {% capture project_description %} + Centralized external configuration management backed by a git repository. The configuration resources map directly to Spring `Environment` but could be used by non-Spring applications if desired. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-config" repo_url="http://github.com/spring-cloud/spring-cloud-config" project_title="Spring Cloud Config" project_description=project_description %} + + + {% capture project_description %} + Integration with various Netflix OSS components (Eureka, Hystrix, Zuul, Archaius, etc.). + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-netflix" repo_url="http://github.com/spring-cloud/spring-cloud-netflix" project_title="Spring Cloud Netflix" project_description=project_description %} + + + {% capture project_description %} + An event bus for linking services and service instances together with distributed messaging. Useful for propagating state changes across a cluster (e.g. config change events). + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-bus" repo_url="http://github.com/spring-cloud/spring-cloud-bus" project_title="Spring Cloud Bus" project_description=project_description %} + + + {% capture project_description %} + Integrates your application with Pivotal Cloud Foundry. Provides a service discovery implementation and also makes it easy to implement SSO and OAuth2 protected resources. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-cloudfoundry" repo_url="http://github.com/spring-cloud/spring-cloud-cloudfoundry" project_title="Spring Cloud for Cloud Foundry" project_description=project_description %} + + + {% capture project_description %} + Provides a starting point for building a service broker that implements the Open Service Broker API. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-open-service-broker/" repo_url="http://github.com/spring-cloud/spring-cloud-open-service-broker" project_title="Spring Cloud Open Service Broker" project_description=project_description %} + + + {% capture project_description %} + Leadership election and common stateful patterns with an abstraction and implementation for Zookeeper, Redis, Hazelcast, Consul. + {% endcapture %} + + {% include project_block.md site_url="/spring-cloud" repo_url="http://github.com/spring-cloud/spring-cloud-cluster" project_title="Spring Cloud Cluster" project_description=project_description %} + + + {% capture project_description %} + Service discovery and configuration management with Hashicorp Consul. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-consul" repo_url="http://github.com/spring-cloud/spring-cloud-consul" project_title="Spring Cloud Consul" project_description=project_description %} + + + {% capture project_description %} + Provides support for load-balanced OAuth2 rest client and authentication header relays in a Zuul proxy. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-security" repo_url="http://github.com/spring-cloud/spring-cloud-security" project_title="Spring Cloud Security" project_description=project_description %} + + + {% capture project_description %} + Distributed tracing for Spring Cloud applications, compatible with Zipkin, HTrace and log-based (e.g. ELK) tracing. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-sleuth" repo_url="http://github.com/spring-cloud/spring-cloud-sleuth" project_title="Spring Cloud Sleuth" project_description=project_description %} + + + {% capture project_description %} + A cloud-native orchestration service for composable microservice applications on modern runtimes. Easy-to-use DSL, drag-and-drop GUI, and REST-APIs together simplifies the overall orchestration of microservice based data pipelines. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-dataflow" repo_url="https://github.com/spring-cloud/spring-cloud-dataflow" project_title="Spring Cloud Data Flow" project_description=project_description %} + + + {% capture project_description %} + A lightweight event-driven microservices framework to quickly build applications that can connect to external systems. Simple declarative model to send and receive messages using Apache Kafka or RabbitMQ between Spring Boot apps. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-stream" repo_url="http://github.com/spring-cloud/spring-cloud-stream" project_title="Spring Cloud Stream" project_description=project_description %} + + + {% capture project_description %} + Spring Cloud Stream App Starters are Spring Boot based Spring Integration applications that provide integration with external systems. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-stream-app-starters" repo_url="https://github.com/spring-cloud/spring-cloud-stream-app-starters" project_title="Spring Cloud Stream App Starters" project_description=project_description %} + + + {% capture project_description %} + A short-lived microservices framework to quickly build applications that perform finite amounts of data processing. Simple declarative for adding both functional and non-functional features to Spring Boot apps. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-task" repo_url="http://github.com/spring-cloud/spring-cloud-task" project_title="Spring Cloud Task" project_description=project_description %} + + + {% capture project_description %} + Spring Cloud Task App Starters are Spring Boot applications that may be any process including Spring Batch jobs that do not run forever, and they end/stop after a finite period of data processing. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-task-app-starters" repo_url="https://github.com/spring-cloud/spring-cloud-task-app-starters" project_title="Spring Cloud Task App Starters" project_description=project_description %} + + + {% capture project_description %} + Service discovery and configuration management with Apache Zookeeper. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-zookeeper" repo_url="http://github.com/spring-cloud/spring-cloud-zookeeper" project_title="Spring Cloud Zookeeper" project_description=project_description %} + + + {% capture project_description %} + Easy integration with hosted Amazon Web Services. It offers a convenient way to interact with AWS provided services using well-known Spring idioms and APIs, such as the messaging or caching API. Developers can build their application around the hosted services without having to care about infrastructure or maintenance. + {% endcapture %} + + {% capture site_url %} + {{ site.projects_site_url }}/spring-cloud-aws + {% endcapture %} + + {% include project_block.md site_url=site_url repo_url="http://github.com/spring-cloud/spring-cloud-aws" project_title="Spring Cloud for Amazon Web Services" project_description=project_description %} + + + {% capture project_description %} + Makes it easy for PaaS applications in a variety of platforms to connect to backend services like + databases and message brokers (the project formerly known as "Spring Cloud"). + {% endcapture %} + + {% capture site_url %} + {{ site.projects_site_url }}/spring-cloud-connectors + {% endcapture %} + + {% include project_block.md site_url=site_url repo_url="http://github.com/spring-cloud/spring-cloud-connectors" project_title="Spring Cloud Connectors" project_description=project_description %} + + + {% capture project_description %} + Spring Boot-style starter projects to ease dependency management for consumers of Spring Cloud. (Discontinued as a project and merged with the other projects after Angel.SR2.) + {% endcapture %} + + {% include project_block.md site_url="http://github.com/spring-cloud/spring-cloud-starters" repo_url="http://github.com/spring-cloud/spring-cloud-starters" project_title="Spring Cloud Starters" project_description=project_description %} + + + {% capture project_description %} + Spring Boot CLI plugin for creating Spring Cloud component applications quickly in Groovy + {% endcapture %} + + {% include project_block.md site_url="http://github.com/spring-cloud/spring-cloud-cli" repo_url="http://github.com/spring-cloud/spring-cloud-cli" project_title="Spring Cloud CLI" project_description=project_description %} + + + {% capture project_description %} + Spring Cloud Contract is an umbrella project holding solutions that help users in successfully implementing the Consumer Driven Contracts approach. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-contract" repo_url="http://github.com/spring-cloud/spring-cloud-contract" project_title="Spring Cloud Contract" project_description=project_description %} + + + {% capture project_description %} + Spring Cloud Gateway is an intelligent and programmable router based on Project Reactor. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-gateway" repo_url="http://github.com/spring-cloud/spring-cloud-gateway" project_title="Spring Cloud Gateway" project_description=project_description %} + + + {% capture project_description %} + Spring Cloud OpenFeign provides integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-openfeign" repo_url="http://github.com/spring-cloud/spring-cloud-openfeign" project_title="Spring Cloud OpenFeign" project_description=project_description %} + + + {% capture project_description %} + Spring Cloud Pipelines provides an opinionated deployment pipeline with steps to ensure that your application can be deployed in zero downtime fashion and easilly rolled back of something goes wrong. + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-pipelines" repo_url="http://github.com/spring-cloud/spring-cloud-pipelines" project_title="Spring Cloud Pipelines" project_description=project_description %} + + + {% capture project_description %} + Spring Cloud Function promotes the implementation of business logic via functions. It supports a uniform programming model across serverless providers, as well as the ability to run standalone (locally or in a PaaS). + {% endcapture %} + + {% include project_block.md site_url="http://cloud.spring.io/spring-cloud-function" repo_url="http://github.com/spring-cloud/spring-cloud-function" project_title="Spring Cloud Function" project_description=project_description %} + + ## Release Trains + + Spring Cloud is an umbrella project consisting of independent projects with, in principle, different + release cadences. To manage the portfolio a BOM (Bill of Materials) is published with a curated + set of dependencies on the individual project (see below). The release trains have names, not + versions, to avoid confusion with the sub-projects. The names are an alphabetic sequence (so + you can sort them chronologically) with names of London Tube stations ("Angel" is the first + release, "Brixton" is the second). When point releases of the individual projects accumulate to + a critical mass, or if there is a critical bug in one of them that needs to be available to everyone, + the release train will push out "service releases" with names ending ".SRX", where "X" + is a number. + + Release train contents: + + + |Component | Edgware.SR5 | Finchley.SR1 | Finchley.BUILD-SNAPSHOT| + |--------------------------------------|-----------------|---------------------|------------------------| + |spring-cloud-aws | 1.2.3.RELEASE | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT | + |spring-cloud-bus | 1.3.3.RELEASE | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT | + |spring-cloud-cli | 1.4.1.RELEASE | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT | + |spring-cloud-commons | 1.3.5.RELEASE | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-contract | 1.2.6.RELEASE | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-config | 1.4.5.RELEASE | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-netflix | 1.4.6.RELEASE | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-security | 1.2.3.RELEASE | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT | + |spring-cloud-cloudfoundry | 1.1.2.RELEASE | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT | + |spring-cloud-consul | 1.3.5.RELEASE | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-sleuth | 1.3.5.RELEASE | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-stream | Ditmars.SR4 | Elmhurst.SR1 | Elmhurst.BUILD-SNAPSHOT| + |spring-cloud-zookeeper | 1.2.2.RELEASE | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT | + |spring-boot | 1.5.16.RELEASE | 2.0.4.RELEASE | 2.0.4.BUILD-SNAPSHOT | + |spring-cloud-task | 1.2.3.RELEASE | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT | + |spring-cloud-vault | 1.1.2.RELEASE | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-gateway | 1.0.2.RELEASE | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-openfeign | | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT | + |spring-cloud-function | 1.0.1.RELEASE | 1.0.0.RELEASE | 1.0.1.BUILD-SNAPSHOT | + + + Finchley builds and works with Spring Boot 2.0.x, and is not expected + to work with Spring Boot 1.5.x. + + Note: The Dalston release train will [reach end-of-life](https://spring.io/blog/2018/06/19/spring-cloud-finchley-release-is-available) in December 2018. Edgware will follow the end-of-life cycle of Spring Boot 1.5.x. + + The Dalston and Edgware release trains build on Spring Boot 1.5.x, and + are not expected to work with Spring Boot 2.0.x. + + NOTE: The Camden release train was [marked end-of-life](https://spring.io/blog/2018/06/19/spring-cloud-finchley-release-is-available). + + The Camden release train builds on Spring Boot 1.4.x, but is also + tested with 1.5.x. + + NOTE: The Brixton and Angel release trains were [marked end-of-life](https://spring.io/blog/2017/07/21/spring-cloud-dalston-sr2-is-available-now#end-of-life-for-angel-and-brixton-release-trains) + (EOL) in July 2017. + + The Brixton release train builds on Spring Boot 1.3.x, but is also + tested with 1.4.x. + + The Angel release train builds on Spring Boot 1.2.x, and is + incompatible in some areas with Spring Boot 1.3.x. Brixton builds on + Spring Boot 1.3.x and is similarly incompatible with 1.2.x. Some + libraries and most apps built on Angel will run fine on Brixton, but + changes will be required anywhere that the OAuth2 features from + spring-cloud-security 1.0.x are used (they were mostly moved to Spring + Boot in 1.3.0). + + Use your dependency management tools to control the version. If you + are using Maven remember that the first version declared wins, so + declare the BOMs in order, with the first one usually being the most + recent (e.g. if you want to use Spring Boot 1.3.6 with Brixton.RELEASE, put + the Boot BOM first). The same rule applies to Gradle if you use the + Spring dependency management plugin. + + > NOTE: The release train contains a + > `spring-cloud-dependencies` as well as the + > `spring-cloud-starter-parent`. You can use the parent as you would + > the `spring-boot-starter-parent` (if you are using Maven). + > If you only need dependency management, the "dependencies" + > version is a BOM-only version of the same thing (it just + > contains dependency management and no plugin declarations + > or direct references to Spring or Spring Boot). If you are + > using the Spring Boot parent POM, then you can use the BOM from + > Spring Cloud. The opposite is not true: using the Cloud parent + > makes it impossible, or at least unreliable, to also use the + > Boot BOM to change the version of Spring Boot and its dependencies. + + > NOTE: If you find anything wrong or outdated on this page, please open an issue in [this](https://github.com/spring-projects/spring-cloud) repo. + + {% endcapture %} + + {% capture related_resources %} + + ### Sample Projects + + * [Config Server](https://github.com/spring-cloud-samples/configserver) + * [Service Registry](https://github.com/spring-cloud-samples/eureka) + * [Circuit Breaker Dashboard](https://github.com/spring-cloud-samples/hystrix-dashboard) + * [Business Application](https://github.com/spring-cloud-samples/customers-stores) (Customers and Stores) + * [OAuth2 Authorization Server](https://github.com/spring-cloud-samples/authserver) + * [OAuth2 SSO Client](https://github.com/spring-cloud-samples/sso) + * [Integration Test Samples](https://github.com/spring-cloud-samples/tests) + * [Spring Cloud Contract Samples](https://github.com/spring-cloud-samples/spring-cloud-contract-samples) + + {% endcapture %} + + {% include project_page.html %} + \ No newline at end of file diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java index 9bda36d1..dfb9ec24 100644 --- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java +++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/ReleaserConfiguration.java @@ -76,8 +76,9 @@ class ReleaserConfiguration { } @Bean - DocumentationUpdater documentationUpdater(ReleaserProperties properties, ProjectGitHandler handler) { - return new DocumentationUpdater(properties, handler); + DocumentationUpdater documentationUpdater(ProjectGitHandler projectGitHandler, + ReleaserProperties properties) { + return new DocumentationUpdater(projectGitHandler, properties); } @Bean diff --git a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Tasks.java b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Tasks.java index 9bf404f6..f694dce1 100644 --- a/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Tasks.java +++ b/spring-cloud-release-tools-spring/src/main/java/org/springframework/cloud/release/internal/spring/Tasks.java @@ -71,6 +71,12 @@ class Tasks { args -> { args.releaser.updateDocumentationRepository(args.properties, args.versionFromScRelease); },TaskType.POST_RELEASE); + static Task UPDATE_SPRING_PROJECT_PAGE = task("updateSpringProjectPage", "up", + "UPDATE SPRING PROJECT PAGE", + "Updating Spring Project page", + args -> { + args.releaser.updateSpringProjectPage(args.projects); + },TaskType.POST_RELEASE); static final List DEFAULT_TASKS_PER_PROJECT = Stream.of( Tasks.UPDATING_POMS, @@ -87,7 +93,8 @@ class Tasks { static final List DEFAULT_TASKS_PER_RELEASE = Stream.of( Tasks.CREATE_TEMPLATES, Tasks.UPDATE_GUIDES, - Tasks.UPDATE_DOCUMENTATION + Tasks.UPDATE_DOCUMENTATION, + Tasks.UPDATE_SPRING_PROJECT_PAGE ).collect(Collectors.toList()); static final List NON_COMPOSITE_TASKS = new ArrayList() { diff --git a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/docs/TestDocumentationUpdater.java b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/docs/TestDocumentationUpdater.java index 75fc91c8..ba121acd 100644 --- a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/docs/TestDocumentationUpdater.java +++ b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/docs/TestDocumentationUpdater.java @@ -5,38 +5,60 @@ import java.io.IOException; import org.springframework.cloud.release.internal.ReleaserProperties; import org.springframework.cloud.release.internal.git.ProjectGitHandler; +import org.springframework.cloud.release.internal.pom.Projects; /** * @author Marcin Grzejszczak */ public class TestDocumentationUpdater extends DocumentationUpdater { - private final String version; - public TestDocumentationUpdater(ReleaserProperties properties, - ProjectGitHandler gitHandler, String version) { - super(properties, gitHandler); - this.version = version; + TestProjectDocumentationUpdater updater, TestReleaseContentsUpdater testRelease) { + super(properties, updater, testRelease); } - @Override - String readIndexHtmlContents(File indexHtml) throws IOException { - return response(); + public static class TestReleaseContentsUpdater extends ReleaseTrainContentsUpdater { + + public TestReleaseContentsUpdater(ReleaserProperties properties, ProjectGitHandler handler) { + super(properties, handler); + } + + @Override + public File updateProjectRepo(Projects projects) { + return super.updateProjectRepo(projects); + } } - private String response() { - return "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "Page Redirection\n" - + "\n" - + "\n" - + "If you are not redirected automatically, follow the link to latest release\n"; + public static class TestProjectDocumentationUpdater extends ProjectDocumentationUpdater { + + private final String version; + + public TestProjectDocumentationUpdater(ReleaserProperties properties, ProjectGitHandler gitHandler, String version) { + super(properties, gitHandler); + this.version = version; + } + + @Override + String readIndexHtmlContents(File indexHtml) throws IOException { + return response(); + } + + private String response() { + return "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "Page Redirection\n" + + "\n" + + "\n" + + "If you are not redirected automatically, follow the link to latest release\n"; + } } } + + diff --git a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/pom/TestUtils.java b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/pom/TestUtils.java index a39faf6e..c29e180c 100644 --- a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/pom/TestUtils.java +++ b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/pom/TestUtils.java @@ -8,6 +8,7 @@ import org.eclipse.jgit.util.FileUtils; public class TestUtils { public static void prepareLocalRepo() throws IOException { + prepareLocalRepo("target/test-classes/projects/", "spring-cloud"); 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-consul"); diff --git a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java index 7601efc0..ad5229ff 100644 --- a/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java +++ b/spring-cloud-release-tools-spring/src/test/java/org/springframework/cloud/release/internal/spring/AcceptanceTests.java @@ -63,6 +63,7 @@ public class AcceptanceTests { File springCloudConsulProject; File temporaryFolder; File documentationFolder; + File cloudProjectFolder; TestProjectGitHandler gitHandler; NonAssertingTestProjectGitHandler nonAssertingGitHandler; SaganClient saganClient = Mockito.mock(SaganClient.class); @@ -194,21 +195,23 @@ public class AcceptanceTests { @Test public void should_perform_a_meta_release_of_sc_release_and_consul() throws Exception { // simulates an org - SpringReleaser releaser = metaReleaser(edgwareSr5()); + SpringReleaser releaser = metaReleaser(edgwareSr10()); releaser.release(new OptionsBuilder().metaRelease(true).options()); - // consul, release, documentation - then(this.nonAssertingGitHandler.clonedProjects).hasSize(3); + // consul, release, documentation, spring-cloud + then(this.nonAssertingGitHandler.clonedProjects).hasSize(4); // don't want to verify the docs thenAllStepsWereExecutedForEachProject(); thenSaganWasCalled(); thenDocumentationWasUpdated(); BDDAssertions.then(clonedProject("spring-cloud-consul").tagList().call()) .extracting("name").contains("refs/tags/v1.3.5.RELEASE"); + BDDAssertions.then(gitProject(this.cloudProjectFolder).log().call().iterator().next().getShortMessage()) + .contains("Updating project page to release train [Edgware.SR10]"); } - private Map edgwareSr5() { + private Map edgwareSr10() { Map versions = new LinkedHashMap<>(); versions.put("spring-boot", "1.5.16.RELEASE"); versions.put("spring-cloud-build", "1.3.11.RELEASE"); @@ -228,17 +231,22 @@ public class AcceptanceTests { versions.put("spring-cloud-sleuth", "1.3.5.RELEASE"); versions.put("spring-cloud-contract", "1.2.6.RELEASE"); versions.put("spring-cloud-vault", "1.1.2.RELEASE"); - versions.put("spring-cloud-release", "Edgware.SR5"); + versions.put("spring-cloud-release", "Edgware.SR10"); return versions; } private Git clonedProject(String name) { return GitTestUtils .openGitProject(this.nonAssertingGitHandler.clonedProjects.stream() - .filter(file -> file.getName().contains(name)) + .filter(file -> file.getName().equals(name)) .findFirst().get()); } + private Git gitProject(File file) { + return GitTestUtils + .openGitProject(file); + } + private void thenSaganWasCalled() { BDDMockito.then(saganUpdater).should(BDDMockito.atLeastOnce()) .updateSagan(BDDMockito.anyString(), @@ -248,7 +256,7 @@ public class AcceptanceTests { private void thenAllStepsWereExecutedForEachProject() { this.nonAssertingGitHandler.clonedProjects - .stream().filter(f -> !f.getName().contains("angel")) + .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()); @@ -269,7 +277,7 @@ public class AcceptanceTests { releaser.release(new OptionsBuilder().metaRelease(true).options()); - then(temporaryDestination.list()).isEmpty(); + then(temporaryDestination.list()).containsOnly("spring-cloud"); } @Test @@ -285,8 +293,10 @@ public class AcceptanceTests { .startFrom("spring-cloud-consul") .options()); - then(this.nonAssertingGitHandler.clonedProjects).hasSize(1); + // consul, cloud + then(this.nonAssertingGitHandler.clonedProjects).hasSize(2); this.nonAssertingGitHandler.clonedProjects + .stream().filter(file -> file.getName().equals("spring-cloud-consul")) .forEach(project -> { then(pom(project).getArtifactId()).isEqualTo("spring-cloud-consul"); then(capture.toString()).contains("executed_build", "executed_deploy", "executed_docs"); @@ -308,8 +318,10 @@ public class AcceptanceTests { .taskNames(Collections.singletonList("spring-cloud-consul")) .options()); - then(this.nonAssertingGitHandler.clonedProjects).hasSize(1); + // consul, cloud + then(this.nonAssertingGitHandler.clonedProjects).hasSize(2); this.nonAssertingGitHandler.clonedProjects + .stream().filter(file -> !file.getName().equals("spring-cloud")) .forEach(project -> { then(Collections.singletonList("spring-cloud-consul")) .contains(pom(project).getArtifactId()); @@ -593,7 +605,8 @@ public class AcceptanceTests { GradleUpdater gradleUpdater = new GradleUpdater(properties); SaganUpdater saganUpdater = new SaganUpdater(this.saganClient); DocumentationUpdater documentationUpdater = new TestDocumentationUpdater(properties, - handler, "Brixton.SR1") { + new TestDocumentationUpdater.TestProjectDocumentationUpdater(properties, handler, "Brixton.SR1"), + new TestDocumentationUpdater.TestReleaseContentsUpdater(properties, handler)) { @Override public File updateDocsRepo(ProjectVersion currentProject, String springCloudReleaseBranch) { File file = super.updateDocsRepo(currentProject, springCloudReleaseBranch); @@ -614,7 +627,16 @@ public class AcceptanceTests { TemplateGenerator templateGenerator = Mockito.spy(new TemplateGenerator(properties, handler)); GradleUpdater gradleUpdater = new GradleUpdater(properties); SaganUpdater saganUpdater = Mockito.spy(new SaganUpdater(this.saganClient)); - DocumentationUpdater documentationUpdater = Mockito.spy(new DocumentationUpdater(properties, handler) { + DocumentationUpdater documentationUpdater = Mockito.spy(new TestDocumentationUpdater(properties, + new TestDocumentationUpdater.TestProjectDocumentationUpdater(properties, handler, "Brixton.SR1"), + new TestDocumentationUpdater.TestReleaseContentsUpdater(properties, handler) { + @Override + public File updateProjectRepo(Projects projects) { + File file = super.updateProjectRepo(projects); + cloudProjectFolder = file; + return file; + } + }) { @Override public File updateDocsRepo(ProjectVersion currentProject, String springCloudReleaseBranch) { File file = super.updateDocsRepo(currentProject, springCloudReleaseBranch); @@ -633,13 +655,17 @@ public class AcceptanceTests { private ReleaserProperties releaserProperties(File project, String branch) throws URISyntaxException { ReleaserProperties releaserProperties = new ReleaserProperties(); - releaserProperties.getGit().setReleaseTrainBomUrl(file("/projects/spring-cloud-release/").toURI().toString()); - releaserProperties.getGit().setDocumentationUrl(file("/projects/spring-cloud-static-angel/").toURI().toString()); + releaserProperties.getGit().setReleaseTrainBomUrl( + file("/projects/spring-cloud-release/").toURI().toString()); + releaserProperties.getGit().setDocumentationUrl( + file("/projects/spring-cloud-static-angel/").toURI().toString()); releaserProperties.getMaven().setBuildCommand("echo build"); releaserProperties.getMaven().setDeployCommand("echo deploy"); releaserProperties.getMaven().setPublishDocsCommands(new String[] { "echo docs"} ); releaserProperties.setWorkingDir(project.getPath()); releaserProperties.getPom().setBranch(branch); + releaserProperties.getGit().setSpringProjectUrl( + tmpFile("spring-cloud").getAbsolutePath() + "/"); this.releaserProperties = releaserProperties; return releaserProperties; } @@ -659,6 +685,8 @@ public class AcceptanceTests { releaserProperties.getMaven().setPublishDocsCommands(new String[] { "echo executed_docs"} ); releaserProperties.getMetaRelease().setGitOrgUrl("file://" + this.temporaryFolder.getAbsolutePath()); releaserProperties.getMetaRelease().setEnabled(true); + releaserProperties.getGit().setSpringProjectUrl( + tmpFile("spring-cloud").getAbsolutePath() + "/"); releaserProperties.setFixedVersions(versions); this.releaserProperties = releaserProperties; return releaserProperties; @@ -737,6 +765,13 @@ public class AcceptanceTests { return file; } + @Override + public File cloneSpringDocProject() { + File file = super.cloneSpringDocProject(); + this.clonedProjects.add(file); + return file; + } + @Override public File cloneProjectFromOrg(String projectName) { File file = super.cloneProjectFromOrg(projectName); this.clonedProjects.add(file); diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/README.md b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/README.md new file mode 100644 index 00000000..daf5fc9a --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/README.md @@ -0,0 +1,11 @@ +This project is an umbrella and the git repository is used only for +documentation (see gh-pages branch). Home page: http://projects.spring.io/spring-cloud. + +The sub-projects of Spring Cloud live in a different Github +organization: https://github.com/spring-cloud. Please use the +issue trackers in the individual projects there to report bugs and +request new features. Each project has a README with instructions +on how to build the source code and how to contribute ideas and code. + +If you are looking for the project formerly known as Spring Cloud, please +go https://github.com/spring-cloud/spring-cloud-connectors. diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/HEAD b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/HEAD new file mode 100644 index 00000000..cb089cd8 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/config b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/config new file mode 100644 index 00000000..94ade795 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/config @@ -0,0 +1,16 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true + precomposeunicode = true +[remote "origin"] + url = git@github.com:spring-projects/spring-cloud.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "master"] + remote = origin + merge = refs/heads/master +[branch "gh-pages"] + remote = origin + merge = refs/heads/gh-pages diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/description b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/description new file mode 100644 index 00000000..498b267a --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/applypatch-msg.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/applypatch-msg.sample new file mode 100755 index 00000000..a5d7b84a --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +commitmsg="$(git rev-parse --git-path hooks/commit-msg)" +test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"} +: diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/commit-msg.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/commit-msg.sample new file mode 100755 index 00000000..b58d1184 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/post-update.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/post-update.sample new file mode 100755 index 00000000..ec17ec19 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-applypatch.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-applypatch.sample new file mode 100755 index 00000000..4142082b --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +precommit="$(git rev-parse --git-path hooks/pre-commit)" +test -x "$precommit" && exec "$precommit" ${1+"$@"} +: diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-commit.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-commit.sample new file mode 100755 index 00000000..68d62d54 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-commit.sample @@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-push.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-push.sample new file mode 100755 index 00000000..6187dbf4 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-push.sample @@ -0,0 +1,53 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo >&2 "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0 diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-rebase.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-rebase.sample new file mode 100755 index 00000000..6cbef5c3 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up to date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +<<\DOC_END + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". + +DOC_END diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-receive.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-receive.sample new file mode 100755 index 00000000..a1fd29ec --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/pre-receive.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to make use of push options. +# The example simply echoes all push options that start with 'echoback=' +# and rejects all pushes when the "reject" push option is used. +# +# To enable this hook, rename this file to "pre-receive". + +if test -n "$GIT_PUSH_OPTION_COUNT" +then + i=0 + while test "$i" -lt "$GIT_PUSH_OPTION_COUNT" + do + eval "value=\$GIT_PUSH_OPTION_$i" + case "$value" in + echoback=*) + echo "echo from the pre-receive-hook: ${value#*=}" >&2 + ;; + reject) + exit 1 + esac + i=$((i + 1)) + done +fi diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/prepare-commit-msg.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/prepare-commit-msg.sample new file mode 100755 index 00000000..10fa14c5 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/prepare-commit-msg.sample @@ -0,0 +1,42 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first one removes the +# "# Please enter the commit message..." help message. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +COMMIT_MSG_FILE=$1 +COMMIT_SOURCE=$2 +SHA1=$3 + +/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE" + +# case "$COMMIT_SOURCE,$SHA1" in +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;; +# *) ;; +# esac + +# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE" +# if test -z "$COMMIT_SOURCE" +# then +# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE" +# fi diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/update.sample b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/update.sample new file mode 100755 index 00000000..80ba9413 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to block unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/index b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/index new file mode 100644 index 00000000..12ffd2a8 Binary files /dev/null and b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/index differ diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/info/exclude b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/info/exclude new file mode 100644 index 00000000..a5196d1b --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/HEAD b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/HEAD new file mode 100644 index 00000000..9c6ddf07 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/HEAD @@ -0,0 +1,3 @@ +0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git +70c9a49fdcedbfad87ac23ea6862322578ac4c31 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak 1539863113 +0200 checkout: moving from master to gh-pages +66f767411e396c28b8ae4ca638824a741e9c2767 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak 1539863139 +0200 checkout: moving from gh-pages to master diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/heads/gh-pages b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/heads/gh-pages new file mode 100644 index 00000000..b7632cb6 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/heads/gh-pages @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak 1539863113 +0200 branch: Created from refs/remotes/origin/gh-pages diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/heads/master b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/heads/master new file mode 100644 index 00000000..848b7d09 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/remotes/origin/HEAD b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/remotes/origin/HEAD new file mode 100644 index 00000000..848b7d09 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/logs/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.idx b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.idx new file mode 100644 index 00000000..3eb45120 Binary files /dev/null and b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.idx differ diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.pack b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.pack new file mode 100644 index 00000000..43172341 Binary files /dev/null and b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/objects/pack/pack-7cc9dd9765fae316909a346d62200f0c00f1e86f.pack differ diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/packed-refs b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/packed-refs new file mode 100644 index 00000000..685caab2 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/packed-refs @@ -0,0 +1,5 @@ +# pack-refs with: peeled fully-peeled sorted +66f767411e396c28b8ae4ca638824a741e9c2767 refs/remotes/origin/gh-pages +f14c1c0297fbb27491043aef018208adff0523b9 refs/remotes/origin/gh-pages-borked +cad5fcc769356792f511970c41dab283eab2bbd6 refs/remotes/origin/gh-pages-old +70c9a49fdcedbfad87ac23ea6862322578ac4c31 refs/remotes/origin/master diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/heads/gh-pages b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/heads/gh-pages new file mode 100644 index 00000000..32180923 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/heads/gh-pages @@ -0,0 +1 @@ +66f767411e396c28b8ae4ca638824a741e9c2767 diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/heads/master b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/heads/master new file mode 100644 index 00000000..40d77bd6 --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/heads/master @@ -0,0 +1 @@ +70c9a49fdcedbfad87ac23ea6862322578ac4c31 diff --git a/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/remotes/origin/HEAD b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/remotes/origin/HEAD new file mode 100644 index 00000000..6efe28ff --- /dev/null +++ b/spring-cloud-release-tools-spring/src/test/resources/projects/spring-cloud/git/refs/remotes/origin/HEAD @@ -0,0 +1 @@ +ref: refs/remotes/origin/master