Updates the Release Train table in Spring project

fixes gh-93
This commit is contained in:
Marcin Grzejszczak
2018-10-18 15:27:12 +02:00
parent a9945f2df3
commit 9d8235e310
82 changed files with 3271 additions and 152 deletions

View File

@@ -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.

View File

@@ -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.

View File

@@ -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);
}
}
}

View File

@@ -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 +
'}';
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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) {

View File

@@ -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>

View File

@@ -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());
}
}

View File

@@ -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"));
}
}

View File

@@ -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"));
}
}

View File

@@ -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");
}
}

View File

@@ -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");
}
}

View File

@@ -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;
/**

View File

@@ -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);
}

View File

@@ -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");

View 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.

View File

@@ -0,0 +1 @@
ref: refs/heads/master

View File

@@ -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

View File

@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

View File

@@ -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+"$@"}
:

View File

@@ -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
}

View File

@@ -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

View File

@@ -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+"$@"}
:

View File

@@ -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 --

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]
# *~

View File

@@ -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

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539863113 +0200 branch: Created from refs/remotes/origin/gh-pages

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git

View File

@@ -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

View File

@@ -0,0 +1 @@
66f767411e396c28b8ae4ca638824a741e9c2767

View File

@@ -0,0 +1 @@
70c9a49fdcedbfad87ac23ea6862322578ac4c31

View File

@@ -0,0 +1 @@
ref: refs/remotes/origin/master

View File

@@ -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>

View File

@@ -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

View File

@@ -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>() {

View File

@@ -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";
}
}
}

View File

@@ -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");

View File

@@ -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);

View 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.

View File

@@ -0,0 +1 @@
ref: refs/heads/master

View File

@@ -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

View File

@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

View File

@@ -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+"$@"}
:

View File

@@ -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
}

View File

@@ -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

View File

@@ -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+"$@"}
:

View File

@@ -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 --

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]
# *~

View File

@@ -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

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 66f767411e396c28b8ae4ca638824a741e9c2767 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539863113 +0200 branch: Created from refs/remotes/origin/gh-pages

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 70c9a49fdcedbfad87ac23ea6862322578ac4c31 Marcin Grzejszczak <mgrzejszczak@pivotal.io> 1539862036 +0200 clone: from git@github.com:spring-projects/spring-cloud.git

View File

@@ -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

View File

@@ -0,0 +1 @@
66f767411e396c28b8ae4ca638824a741e9c2767

View File

@@ -0,0 +1 @@
70c9a49fdcedbfad87ac23ea6862322578ac4c31

View File

@@ -0,0 +1 @@
ref: refs/remotes/origin/master