Updates the Release Train table in Spring project
fixes gh-93
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<Row> rows;
|
||||
|
||||
ReleaseTrainContents(Title title, List<Row> 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<Row> getRows() {
|
||||
return this.rows;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, Object> map = ImmutableMap.<String, Object>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<Row> 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("<!-- (BEGIN|END) COMPONENTS -->");
|
||||
if (split.length != 3) {
|
||||
log.warn("The page is missing the components table markers. Please add [<!-- BEGIN COMPONENTS -->] and [<!-- END COMPONENTS -->] 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<Row> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Row> 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<VersionNumber> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
---
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
|
||||
|
||||
{% 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.
|
||||
|
||||
<span id="quick-start"></span>
|
||||
|
||||
## 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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<a name="main-projects"></a>
|
||||
|
||||
## Main Projects
|
||||
|
||||
<!-- Spring Cloud Config -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Netflix -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Bus -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Cloudfoundry -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Open Service Broker -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Cluster -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Consul -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Security -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Sleuth -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Data Flow -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Stream -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Stream App Starters -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Task -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Task App Starters -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Zookeeper -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud AWS -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Connectors -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Starters -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud CLI -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Contract -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Gateway -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud OpenFeign -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Pipelines -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Function -->
|
||||
{% 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:
|
||||
|
||||
<!-- BEGIN COMPONENTS -->
|
||||
|Component |{{lastGaTrainName}}|{{currentGaTrainName}}|{{currentSnapshotTrainName}}|
|
||||
|--------------------------------------|-----------------|---------------------|------------------------|
|
||||
{{#each projects}} |{{componentName}}|{{lastGaVersion}}|{{currentGaVersion}}|{{currentSnapshotVersion}}|
|
||||
{{/each}}
|
||||
<!-- END COMPONENTS -->
|
||||
|
||||
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 %}
|
||||
</html>
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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<Row> 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"));
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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<Row> 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<Row> 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");
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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.
|
||||
@@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
||||
@@ -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+"$@"}
|
||||
:
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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+"$@"}
|
||||
:
|
||||
@@ -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 --
|
||||
@@ -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:
|
||||
#
|
||||
# <local ref> <local sha1> <remote ref> <remote sha1>
|
||||
#
|
||||
# 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 <ref> <oldrev> <newrev>)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||
echo "usage: $0 <ref> <oldrev> <newrev>" >&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
|
||||
Binary file not shown.
@@ -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]
|
||||
# *~
|
||||
@@ -0,0 +1,3 @@
|
||||
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git
|
||||
70c9a49fdcedbfad87ac23ea6862322578ac4c31 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539863113 +0200 checkout: moving from master to gh-pages
|
||||
66f767411e396c28b8ae4ca638824a741e9c2767 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539863139 +0200 checkout: moving from gh-pages to master
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539863113 +0200 branch: Created from refs/remotes/origin/gh-pages
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
66f767411e396c28b8ae4ca638824a741e9c2767
|
||||
@@ -0,0 +1 @@
|
||||
70c9a49fdcedbfad87ac23ea6862322578ac4c31
|
||||
@@ -0,0 +1 @@
|
||||
ref: refs/remotes/origin/master
|
||||
@@ -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
|
||||
|
||||
|
||||
---
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
|
||||
|
||||
{% 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.
|
||||
|
||||
<span id="quick-start"></span>
|
||||
|
||||
## 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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<a name="main-projects"></a>
|
||||
|
||||
## Main Projects
|
||||
|
||||
<!-- Spring Cloud Config -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Netflix -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Bus -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Cloudfoundry -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Open Service Broker -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Cluster -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Consul -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Security -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Sleuth -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Data Flow -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Stream -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Stream App Starters -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Task -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Task App Starters -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Zookeeper -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud AWS -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Connectors -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Starters -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud CLI -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Contract -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Gateway -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud OpenFeign -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Pipelines -->
|
||||
{% 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 %}
|
||||
|
||||
<!-- Spring Cloud Function -->
|
||||
{% 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:
|
||||
|
||||
<!-- BEGIN COMPONENTS -->
|
||||
|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 |
|
||||
<!-- END COMPONENTS -->
|
||||
|
||||
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 %}
|
||||
</html>
|
||||
@@ -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
|
||||
|
||||
@@ -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<Task> DEFAULT_TASKS_PER_PROJECT = Stream.of(
|
||||
Tasks.UPDATING_POMS,
|
||||
@@ -87,7 +93,8 @@ class Tasks {
|
||||
static final List<Task> 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<Task> NON_COMPOSITE_TASKS = new ArrayList<Task>() {
|
||||
|
||||
@@ -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 "<!DOCTYPE HTML>\n"
|
||||
+ "\n"
|
||||
+ "<meta charset=\"UTF-8\">\n"
|
||||
+ "<meta http-equiv=\"refresh\" content=\"1; url=http://cloud.spring.io/spring-cloud-static/" + this.version + "/\">\n"
|
||||
+ "\n"
|
||||
+ "<script>\n"
|
||||
+ " window.location.href = \"http://cloud.spring.io/spring-cloud-static/" + this.version + "/\"\n"
|
||||
+ "</script>\n"
|
||||
+ "\n"
|
||||
+ "<title>Page Redirection</title>\n"
|
||||
+ "\n"
|
||||
+ "<!-- Note: don't tell people to `click` the link, just tell them that it is a link. -->\n"
|
||||
+ "If you are not redirected automatically, follow the <a href='http://cloud.spring.io/spring-cloud-static/" + this.version + "/'>link to latest release</a>\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 "<!DOCTYPE HTML>\n"
|
||||
+ "\n"
|
||||
+ "<meta charset=\"UTF-8\">\n"
|
||||
+ "<meta http-equiv=\"refresh\" content=\"1; url=http://cloud.spring.io/spring-cloud-static/" + this.version + "/\">\n"
|
||||
+ "\n"
|
||||
+ "<script>\n"
|
||||
+ " window.location.href = \"http://cloud.spring.io/spring-cloud-static/" + this.version + "/\"\n"
|
||||
+ "</script>\n"
|
||||
+ "\n"
|
||||
+ "<title>Page Redirection</title>\n"
|
||||
+ "\n"
|
||||
+ "<!-- Note: don't tell people to `click` the link, just tell them that it is a link. -->\n"
|
||||
+ "If you are not redirected automatically, follow the <a href='http://cloud.spring.io/spring-cloud-static/" + this.version + "/'>link to latest release</a>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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<String, String> edgwareSr5() {
|
||||
private Map<String, String> edgwareSr10() {
|
||||
Map<String, String> 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);
|
||||
|
||||
@@ -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.
|
||||
@@ -0,0 +1 @@
|
||||
ref: refs/heads/master
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
Unnamed repository; edit this file 'description' to name the repository.
|
||||
@@ -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+"$@"}
|
||||
:
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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+"$@"}
|
||||
:
|
||||
@@ -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 --
|
||||
@@ -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:
|
||||
#
|
||||
# <local ref> <local sha1> <remote ref> <remote sha1>
|
||||
#
|
||||
# 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 <ref> <oldrev> <newrev>)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||
echo "usage: $0 <ref> <oldrev> <newrev>" >&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
|
||||
Binary file not shown.
@@ -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]
|
||||
# *~
|
||||
@@ -0,0 +1,3 @@
|
||||
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git
|
||||
70c9a49fdcedbfad87ac23ea6862322578ac4c31 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539863113 +0200 checkout: moving from master to gh-pages
|
||||
66f767411e396c28b8ae4ca638824a741e9c2767 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539863139 +0200 checkout: moving from gh-pages to master
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539863113 +0200 branch: Created from refs/remotes/origin/gh-pages
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git
|
||||
@@ -0,0 +1 @@
|
||||
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
66f767411e396c28b8ae4ca638824a741e9c2767
|
||||
@@ -0,0 +1 @@
|
||||
70c9a49fdcedbfad87ac23ea6862322578ac4c31
|
||||
@@ -0,0 +1 @@
|
||||
ref: refs/remotes/origin/master
|
||||
Reference in New Issue
Block a user