#151 - Adapt project metadata update to new Sagan API.
This commit is contained in:
@@ -21,12 +21,15 @@ import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -38,10 +41,12 @@ import org.eclipse.jgit.api.CherryPickResult.CherryPickStatus;
|
||||
import org.eclipse.jgit.api.CommitCommand;
|
||||
import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.LogCommand;
|
||||
import org.eclipse.jgit.api.ResetCommand.ResetType;
|
||||
import org.eclipse.jgit.api.errors.RefNotFoundException;
|
||||
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
@@ -67,6 +72,7 @@ import org.springframework.data.release.model.Train;
|
||||
import org.springframework.data.release.model.TrainIteration;
|
||||
import org.springframework.data.release.utils.ExecutionUtils;
|
||||
import org.springframework.data.release.utils.Logger;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.plugin.core.PluginRegistry;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -309,11 +315,38 @@ public class GitOperations {
|
||||
|
||||
return doWithGit(project, git -> {
|
||||
return new VersionTags(git.tagList().call().stream()//
|
||||
.map(ref -> Tag.of(ref.getName()))//
|
||||
.map(ref -> {
|
||||
|
||||
RevCommit commit = getCommit(git.getRepository(), ref);
|
||||
|
||||
PersonIdent authorIdent = commit.getAuthorIdent();
|
||||
Date authorDate = authorIdent.getWhen();
|
||||
TimeZone authorTimeZone = authorIdent.getTimeZone();
|
||||
LocalDateTime localDate = authorDate.toInstant().atZone(authorTimeZone.toZoneId()).toLocalDateTime();
|
||||
|
||||
return Tag.of(ref.getName(), localDate);
|
||||
})//
|
||||
.collect(Collectors.toList()));
|
||||
});
|
||||
}
|
||||
|
||||
private RevCommit getCommit(Repository repository, Ref ref) {
|
||||
|
||||
return doWithGit(repository, git -> {
|
||||
|
||||
Ref peeledRef = git.getRepository().getRefDatabase().peel(ref);
|
||||
LogCommand log = git.log();
|
||||
if (peeledRef.getPeeledObjectId() != null) {
|
||||
log.add(peeledRef.getPeeledObjectId());
|
||||
} else {
|
||||
log.add(ref.getObjectId());
|
||||
}
|
||||
|
||||
return Streamable.of(log.call()).stream().findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Cannot resolve commit for " + ref));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of remote branches where their related ticket is resolved.
|
||||
*
|
||||
@@ -788,9 +821,16 @@ public class GitOperations {
|
||||
private <T> T doWithGit(Project project, GitCallback<T> callback) {
|
||||
|
||||
try (Git git = new Git(getRepository(project))) {
|
||||
T result = callback.doWithGit(git);
|
||||
Thread.sleep(100);
|
||||
return result;
|
||||
return callback.doWithGit(git);
|
||||
} catch (Exception o_O) {
|
||||
throw new RuntimeException(o_O);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T doWithGit(Repository repository, GitCallback<T> callback) {
|
||||
|
||||
try (Git git = new Git(repository)) {
|
||||
return callback.doWithGit(git);
|
||||
} catch (Exception o_O) {
|
||||
throw new RuntimeException(o_O);
|
||||
}
|
||||
|
||||
@@ -17,34 +17,43 @@ package org.springframework.data.release.git;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.data.release.model.ArtifactVersion;
|
||||
|
||||
/**
|
||||
* Value object to represent an SCM tag.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@EqualsAndHashCode
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
public class Tag implements Comparable<Tag> {
|
||||
|
||||
private final String name;
|
||||
private final LocalDateTime creationDate;
|
||||
|
||||
public static Tag of(String source) {
|
||||
return of(source, LocalDateTime.now());
|
||||
}
|
||||
|
||||
public static Tag of(String source, LocalDateTime creationDate) {
|
||||
|
||||
int slashIndex = source.lastIndexOf('/');
|
||||
|
||||
return new Tag(source.substring(slashIndex == -1 ? 0 : slashIndex + 1));
|
||||
return new Tag(source.substring(slashIndex == -1 ? 0 : slashIndex + 1), creationDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the part of the name of the tag that is suitable to derive a version from the tag. Will transparently strip
|
||||
* a {@code v} prefix from the name.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private String getVersionSource() {
|
||||
@@ -66,15 +75,15 @@ public class Tag implements Comparable<Tag> {
|
||||
|
||||
/**
|
||||
* Creates a new {@link Tag} for the given {@link ArtifactVersion} based on the format of the current one.
|
||||
*
|
||||
*
|
||||
* @param version
|
||||
* @return
|
||||
*/
|
||||
public Tag createNew(ArtifactVersion version) {
|
||||
return new Tag(name.startsWith("v") ? "v".concat(version.toString()) : version.toString());
|
||||
return new Tag(name.startsWith("v") ? "v".concat(version.toString()) : version.toString(), LocalDateTime.now());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@@ -83,7 +92,7 @@ public class Tag implements Comparable<Tag> {
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
|
||||
@@ -272,4 +272,8 @@ public class ArtifactVersion implements Comparable<ArtifactVersion> {
|
||||
private String getSnapshotSuffix() {
|
||||
return modifierFormat ? SNAPSHOT_MODIFIER : SNAPSHOT_SUFFIX;
|
||||
}
|
||||
|
||||
public String getGeneration() {
|
||||
return String.format("%s.%s.x", version.getMajor(), version.getMinor());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import lombok.experimental.FieldDefaults;
|
||||
import net.minidev.json.JSONArray;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -67,9 +68,9 @@ class DefaultSaganClient implements SaganClient {
|
||||
@Override
|
||||
public String getProjectMetadata(Project project) {
|
||||
|
||||
URI resource = properties.getProjectMetadataResource(project);
|
||||
URI resource = properties.getProjectReleasesResource(project);
|
||||
|
||||
logger.log(project, "Getting project metadata from %s…", resource);
|
||||
logger.log(project, "Getting project releases from %s…", resource);
|
||||
|
||||
return operations.getForObject(resource, String.class);
|
||||
}
|
||||
@@ -81,28 +82,44 @@ class DefaultSaganClient implements SaganClient {
|
||||
@Override
|
||||
public void updateProjectMetadata(Project project, MaintainedVersions versions) {
|
||||
|
||||
URI resource = properties.getProjectMetadataResource(project);
|
||||
URI resource = properties.getProjectReleasesResource(project);
|
||||
|
||||
String versionsString = versions.stream()//
|
||||
.map(MaintainedVersion::getVersion)//
|
||||
.map(Object::toString) //
|
||||
.collect(Collectors.joining(", "));
|
||||
List<String> versionsToRetain = versions.stream() //
|
||||
.map(version -> new ProjectMetadata(version, versions)).map(ProjectMetadata::getVersion)
|
||||
.collect(Collectors.toList());
|
||||
List<String> versionsInSagan = new ArrayList<>();
|
||||
|
||||
logger.log(project, "Updating project metadata to %s via %s…", versionsString, resource);
|
||||
logger.log(project, "Updating project version to %s via %s…", versionsString, resource);
|
||||
|
||||
// Delete all existing versions first
|
||||
Arrays.stream(JsonPath.compile("$..version").<JSONArray> read(getProjectMetadata(project)).toArray())//
|
||||
.map(version -> properties.getProjectMetadataResource(project, version.toString()))//
|
||||
.peek(uri -> logger.log(project, "Deleting existing project metadata at %s…", uri)) //
|
||||
.forEach(operations::delete);
|
||||
deleteExistingVersions(project, versionsToRetain, versionsInSagan);
|
||||
|
||||
logger.log(project, "Writing project metadata for versions %s!", versionsString);
|
||||
logger.log(project, "Writing project versions %s.", versionsString);
|
||||
|
||||
// Write new ones
|
||||
List<ProjectMetadata> payload = versions.stream() //
|
||||
.map(version -> new ProjectMetadata(version, versions)) //
|
||||
.collect(Collectors.toList());
|
||||
createVersions(versions, resource, versionsInSagan);
|
||||
}
|
||||
|
||||
operations.put(resource, payload);
|
||||
private void createVersions(MaintainedVersions versions, URI resource, List<String> versionsInSagan) {
|
||||
|
||||
versions.stream() //
|
||||
.map(it -> new ProjectMetadata(it, versions)) //
|
||||
.filter(version -> !versionsInSagan.contains(version.getVersion())) //
|
||||
.forEach(payload -> operations.postForObject(resource, payload, String.class));
|
||||
}
|
||||
|
||||
private void deleteExistingVersions(Project project, List<String> versionsToRetain, List<String> versionsInSagan) {
|
||||
|
||||
Arrays.stream(JsonPath.compile("$..version").<JSONArray> read(getProjectMetadata(project)).toArray())//
|
||||
.map(Object::toString) //
|
||||
.peek(versionsInSagan::add) //
|
||||
.filter(version -> !versionsToRetain.contains(version)) //
|
||||
.map(version -> properties.getProjectReleaseResource(project, version))//
|
||||
.peek(uri -> logger.log(project, "Deleting existing project version at %s…", uri)) //
|
||||
.forEach(operations::delete);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -31,8 +32,9 @@ import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
/**
|
||||
* Dummy implementation of {@link SaganClient} to just dump the request payloads into {@link System#out} instead of
|
||||
* communicating with a real server.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
|
||||
@@ -61,7 +63,7 @@ class DummySaganClient implements SaganClient {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.release.sagan.SaganClient#getProjectMetadata(org.springframework.data.release.sagan.MaintainedVersion)
|
||||
*/
|
||||
@@ -69,13 +71,13 @@ class DummySaganClient implements SaganClient {
|
||||
public String getProjectMetadata(MaintainedVersion version) {
|
||||
|
||||
try {
|
||||
return mapper.writeValueAsString(new ProjectMetadata(version, MaintainedVersions.of(version)));
|
||||
return mapper.writeValueAsString(new ProjectMetadata(version, MaintainedVersions.of(Collections.emptyList())));
|
||||
} catch (JsonProcessingException o_O) {
|
||||
throw new RuntimeException(o_O);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.release.sagan.SaganClient#getProjectMetadata(org.springframework.data.release.model.Project)
|
||||
*/
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.release.sagan;
|
||||
|
||||
import lombok.Value;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -24,12 +25,14 @@ import org.springframework.data.release.model.ArtifactVersion;
|
||||
import org.springframework.data.release.model.Module;
|
||||
import org.springframework.data.release.model.Project;
|
||||
import org.springframework.data.release.model.Train;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Represents a maintained project version to be represented in Sagan.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Value(staticConstructor = "of")
|
||||
class MaintainedVersion implements Comparable<MaintainedVersion> {
|
||||
@@ -37,16 +40,19 @@ class MaintainedVersion implements Comparable<MaintainedVersion> {
|
||||
Project project;
|
||||
ArtifactVersion version;
|
||||
Train train;
|
||||
@Nullable LocalDate releaseDate;
|
||||
@Nullable LocalDate generationInception;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MaintainedVersion} representing the snaphot version of the given {@link Module} and
|
||||
* Creates a new {@link MaintainedVersion} representing the snapshot version of the given {@link Module} and
|
||||
* {@link Train}.
|
||||
*
|
||||
*
|
||||
* @param module must not be {@literal null}.
|
||||
* @param train must not be {@literal null}.
|
||||
* @param train can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static MaintainedVersion snapshot(Module module, Train train) {
|
||||
public static MaintainedVersion snapshot(Module module, Train train, LocalDate generationInception) {
|
||||
|
||||
Assert.notNull(module, "Module must not be null!");
|
||||
Assert.notNull(train, "Train must not be null!");
|
||||
@@ -54,13 +60,13 @@ class MaintainedVersion implements Comparable<MaintainedVersion> {
|
||||
ArtifactVersion snapshotVersion = ArtifactVersion.of(module.getVersion()).withModifierFormat(train.usesCalver())
|
||||
.getSnapshotVersion();
|
||||
|
||||
return MaintainedVersion.of(module.getProject(), snapshotVersion, train);
|
||||
return MaintainedVersion.of(module.getProject(), snapshotVersion, train, null, generationInception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Stream} of {@link MaintainedVersion} that are related to the current one. In case the current one
|
||||
* is not a snapshot version in the first place, the next development version is added, too.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Stream<MaintainedVersion> all() {
|
||||
@@ -69,14 +75,14 @@ class MaintainedVersion implements Comparable<MaintainedVersion> {
|
||||
|
||||
/**
|
||||
* Creates the {@link MaintainedVersion} for the next development version of the current one.
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
MaintainedVersion nextDevelopmentVersion() {
|
||||
return MaintainedVersion.of(project, version.getNextBugfixVersion(), train);
|
||||
return MaintainedVersion.of(project, version.getNextBugfixVersion(), train, LocalDate.now(), generationInception);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.data.release.sagan;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.data.release.build.MavenArtifact;
|
||||
import org.springframework.data.release.model.ArtifactVersion;
|
||||
import org.springframework.data.release.model.Projects;
|
||||
import org.springframework.data.release.model.Train;
|
||||
@@ -25,11 +24,13 @@ import org.springframework.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Simple value object to create payloads to update project metadata in Sagan.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
class ProjectMetadata {
|
||||
@@ -38,13 +39,11 @@ class ProjectMetadata {
|
||||
private static String DOCS = DOCS_BASE.concat("/reference/html/");
|
||||
private static String JAVADOC = DOCS_BASE.concat("/api");
|
||||
|
||||
private final MaintainedVersions versions;
|
||||
private final MaintainedVersion version;
|
||||
private final MavenArtifact artifact;
|
||||
private final MaintainedVersions versions;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ProjectMetadata} instace from the given {@link MaintainedVersion} in the context of the
|
||||
* {@link MaintainedVersions}.
|
||||
* Creates a new {@link ProjectMetadata} instance from the given {@link MaintainedVersion}.
|
||||
*
|
||||
* @param version must not be {@literal null}.
|
||||
* @param versions must not be {@literal null}.
|
||||
@@ -52,67 +51,9 @@ class ProjectMetadata {
|
||||
public ProjectMetadata(MaintainedVersion version, MaintainedVersions versions) {
|
||||
|
||||
Assert.notNull(version, "MaintainedVersion must not be null!");
|
||||
Assert.notNull(versions, "MaintainedVersions must not be null!");
|
||||
|
||||
this.version = version;
|
||||
this.versions = versions;
|
||||
this.artifact = new MavenArtifact(version.getProject(), version.getVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the release status used on Sagan.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getReleaseStatus() {
|
||||
|
||||
ArtifactVersion artifactVersion = version.getVersion();
|
||||
|
||||
if (artifactVersion.isReleaseVersion()) {
|
||||
return "GENERAL_AVAILABILITY";
|
||||
}
|
||||
|
||||
if (artifactVersion.isMilestoneVersion()) {
|
||||
return "PRERELEASE";
|
||||
}
|
||||
|
||||
if (artifactVersion.isSnapshotVersion()) {
|
||||
return "SNAPSHOT";
|
||||
}
|
||||
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group identifier of the release.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getGroupId() {
|
||||
return artifact.getGroupId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the artifact identifier.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getArtifactId() {
|
||||
|
||||
if (Projects.BUILD.equals(version.getProject())) {
|
||||
return "spring-data-releasetrain";
|
||||
}
|
||||
|
||||
return artifact.getArtifactId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the version is the most current one.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Boolean getCurrent() {
|
||||
return versions.isMainVersion(version) ? true : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,13 +61,23 @@ class ProjectMetadata {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getRefDocUrl() {
|
||||
public String getReferenceDocUrl() {
|
||||
|
||||
return version.getVersion().isSnapshotVersion() || Projects.BUILD.equals(version.getProject()) //
|
||||
? "" //
|
||||
: String.format(DOCS, version.getProject().getName().toLowerCase(Locale.US));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the version is the most current one.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@JsonProperty("isCurrent")
|
||||
public boolean getCurrent() {
|
||||
return versions.isMainVersion(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JavaDoc URL for non-snapshot versions and not the build project.
|
||||
*
|
||||
@@ -139,10 +90,6 @@ class ProjectMetadata {
|
||||
: String.format(JAVADOC, version.getProject().getName().toLowerCase(Locale.US));
|
||||
}
|
||||
|
||||
public Repository getRepository() {
|
||||
return new Repository();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the version to use. For the build project that's the release train name, for everything else the artifact
|
||||
* version.
|
||||
@@ -172,38 +119,4 @@ class ProjectMetadata {
|
||||
|
||||
return version.toString();
|
||||
}
|
||||
|
||||
public class Repository {
|
||||
|
||||
public String getId() {
|
||||
return artifact.getRepository().getId();
|
||||
}
|
||||
|
||||
public boolean isSnapshotsEnabled() {
|
||||
return version.getVersion().isSnapshotVersion();
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return artifact.getRepository().getUrl();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
String result = "Spring ";
|
||||
|
||||
if (version.getVersion().isMilestoneVersion()) {
|
||||
return result.concat("Milestones");
|
||||
}
|
||||
|
||||
if (version.getVersion().isReleaseVersion()) {
|
||||
return result.concat("Releases");
|
||||
}
|
||||
|
||||
if (isSnapshotsEnabled()) {
|
||||
return result.concat("Snapshots");
|
||||
}
|
||||
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
* Configuration for the Sagan interaction subsystem.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Configuration
|
||||
class SaganConfiguration {
|
||||
@@ -50,6 +51,6 @@ class SaganConfiguration {
|
||||
|
||||
@Bean
|
||||
RestTemplate saganRestTemplate() {
|
||||
return new RestTemplateBuilder().basicAuthentication(properties.key, "").build();
|
||||
return new RestTemplateBuilder().basicAuthentication("mp911de", properties.key).build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@ import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.release.git.GitOperations;
|
||||
@@ -106,22 +108,25 @@ class SaganOperations {
|
||||
return ExecutionUtils.runAndReturn(executor,
|
||||
Streamable.of(() -> train.stream().filter(module -> !TO_FILTER.contains(module.getProject()))), module -> {
|
||||
return getLatestVersion(module, train);
|
||||
}).stream().flatMap(MaintainedVersion::all);
|
||||
}).stream().flatMap(Function.identity()).collect(
|
||||
});
|
||||
}).stream().flatMap(Collection::stream).flatMap(Collection::stream).collect(
|
||||
Collectors.groupingBy(MaintainedVersion::getProject, ListWrapperCollector.collectInto(MaintainedVersions::of)));
|
||||
}
|
||||
|
||||
private MaintainedVersion getLatestVersion(Module module, Train train) {
|
||||
private List<MaintainedVersion> getLatestVersion(Module module, Train train) {
|
||||
|
||||
Project project = module.getProject();
|
||||
|
||||
MaintainedVersion version = git.getTags(project).stream()//
|
||||
List<MaintainedVersion> version = git.getTags(project).stream()//
|
||||
.filter(tag -> matches(tag, module.getVersion())).max(Comparator.naturalOrder()) //
|
||||
.flatMap(Tag::toArtifactVersion) //
|
||||
.map(it -> MaintainedVersion.of(module.getProject(), it, train)) //
|
||||
.orElseGet(() -> MaintainedVersion.snapshot(module, train));
|
||||
.map(it -> {
|
||||
MaintainedVersion maintainedVersion = MaintainedVersion.of(module.getProject(), it.toArtifactVersion().get(),
|
||||
train, it.getCreationDate().toLocalDate(), it.getCreationDate().toLocalDate());
|
||||
return Arrays.asList(maintainedVersion, maintainedVersion.nextDevelopmentVersion());
|
||||
}) //
|
||||
.orElseGet(() -> Collections.singletonList(MaintainedVersion.snapshot(module, train, LocalDate.now())));
|
||||
|
||||
logger.log(project, "Found version %s for train %s!", version.getVersion(), train.getName());
|
||||
logger.log(project, "Found version %s for train %s!", version, train.getName());
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -20,74 +20,78 @@ import lombok.Setter;
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.data.release.model.Password;
|
||||
import org.springframework.data.release.model.Project;
|
||||
import org.springframework.data.release.model.Projects;
|
||||
import org.springframework.data.release.utils.HttpBasicCredentials;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
|
||||
/**
|
||||
* Configuration properties for the Sagan instance to talk to.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "sagan")
|
||||
class SaganProperties {
|
||||
|
||||
private static String SAGAN_PROJECT_METADATA = "https://spring.io/project_metadata/{project}/releases";
|
||||
private static String SAGAN_PROJECT_VERSION_METADATA = SAGAN_PROJECT_METADATA.concat("/{version}");
|
||||
private static String SAGAN_BASE = "https://spring.io/api/";
|
||||
private static String SAGAN_RELEASES = SAGAN_BASE.concat("projects/{project}/releases");
|
||||
private static String SAGAN_GENERATIONS = SAGAN_BASE.concat("projects/{project}/generations");
|
||||
private static String SAGAN_RELEASE_VERSION = SAGAN_RELEASES.concat("/{version}");
|
||||
|
||||
@Setter String key;
|
||||
|
||||
/**
|
||||
* Returns the {@link HttpBasicCredentials} to be used when talking to the server.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
HttpBasicCredentials getCredentials() {
|
||||
return new HttpBasicCredentials(key, Password.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI to the resource exposing the project metadata for the given {@link Project}.
|
||||
*
|
||||
* Returns the URI to the resource exposing the project releases for the given {@link Project}.
|
||||
*
|
||||
* @param project must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
URI getProjectMetadataResource(Project project) {
|
||||
URI getProjectReleasesResource(Project project) {
|
||||
|
||||
Assert.notNull(project, "Project must not be null!");
|
||||
Assert.notNull(project, "Project must not be null!");
|
||||
|
||||
return new UriTemplate(SAGAN_PROJECT_METADATA).expand(getProjectPathSegment(project));
|
||||
return new UriTemplate(SAGAN_RELEASES).expand(getProjectPathSegment(project));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI to the resource exposing the project metadata for the given {@link Project} and version
|
||||
* Returns the URI to the resource exposing the project generations for the given {@link Project}.
|
||||
*
|
||||
* @param project must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
URI getProjectGenerationsResource(Project project) {
|
||||
|
||||
Assert.notNull(project, "Project must not be null!");
|
||||
|
||||
return new UriTemplate(SAGAN_GENERATIONS).expand(getProjectPathSegment(project));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI to the resource exposing the project version for the given {@link Project} and version
|
||||
* {@link String}.
|
||||
*
|
||||
*
|
||||
* @param project must not be {@literal null}.
|
||||
* @param version must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
URI getProjectMetadataResource(Project project, String version) {
|
||||
URI getProjectReleaseResource(Project project, String version) {
|
||||
|
||||
Assert.notNull(project, "Project must not be null!");
|
||||
Assert.hasText(version, "Version must not be null!");
|
||||
|
||||
return new UriTemplate(SAGAN_PROJECT_VERSION_METADATA).expand(getProjectPathSegment(project), version);
|
||||
return new UriTemplate(SAGAN_RELEASE_VERSION).expand(getProjectPathSegment(project), version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link URI} to the resource exposing the project metadata for the given {@link MaintainedVersion}.
|
||||
*
|
||||
* Returns the {@link URI} to the resource exposing the project version for the given {@link MaintainedVersion}.
|
||||
*
|
||||
* @param version must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
URI getProjectMetadataResource(MaintainedVersion version) {
|
||||
return getProjectMetadataResource(version.getProject(), version.getVersion().toString());
|
||||
return getProjectReleaseResource(version.getProject(), version.getVersion().toString());
|
||||
}
|
||||
|
||||
private static String getProjectPathSegment(Project project) {
|
||||
|
||||
@@ -91,6 +91,6 @@ class MavenIntegrationTests extends AbstractIntegrationTests {
|
||||
@Test
|
||||
void findsSnapshotDependencies() throws Exception {
|
||||
|
||||
Pom pom = projection.io().file(workspace.getFile("bom/pom.xml", Projects.BUILD)).read(Pom.class);
|
||||
Pom pom = projection.io().file(workspace.getFile("pom.xml", Projects.BUILD)).read(Pom.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,14 +105,25 @@ class GitHubIssueTrackerIntegrationTests extends AbstractIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // #5
|
||||
void noReleaseTicketFound() {
|
||||
void noMilestoneNoReleaseTicketFound() {
|
||||
|
||||
mockGetMilestonesWith("emptyMilestones.json");
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> github.getReleaseTicketFor(BUILD_HOPPER_RC1))
|
||||
assertThatIllegalStateException().isThrownBy(() -> github.getReleaseTicketFor(BUILD_HOPPER_RC1))
|
||||
.withMessageContaining("No milestone for Spring Data Build found containing 1.8 RC1 (Hopper)!");
|
||||
}
|
||||
|
||||
@Test // #5
|
||||
void noReleaseTicketFound() {
|
||||
|
||||
mockGetMilestonesWith("milestones.json");
|
||||
mockGetIssuesWith("emptyIssues.json");
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> github.getReleaseTicketFor(BUILD_HOPPER_RC1))
|
||||
.withMessageContaining(
|
||||
"Did not find a release ticket for Spring Data Build 1.8 RC1 (Hopper) containing Release 1.8 RC1 (Hopper)!");
|
||||
}
|
||||
|
||||
@Test // #5
|
||||
void createReleaseVersionShouldCreateAVersion() {
|
||||
|
||||
@@ -156,7 +167,7 @@ class GitHubIssueTrackerIntegrationTests extends AbstractIntegrationTests {
|
||||
mockGetIssuesWith("emptyIssues.json");
|
||||
mockGetMilestonesWith("emptyMilestones.json");
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> github.createReleaseTicket(moduleIteration))
|
||||
assertThatIllegalStateException().isThrownBy(() -> github.createReleaseTicket(moduleIteration))
|
||||
.withMessageContaining("No milestone for Spring Data Build found containing 1.8 RC1 (Hopper)!");
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.data.release.model.ReleaseTrains;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MaintainedVersion}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class MaintainedVersionUnitTests {
|
||||
@@ -33,9 +33,9 @@ class MaintainedVersionUnitTests {
|
||||
void newerVersionIsOrderedFirst() {
|
||||
|
||||
MaintainedVersion ingalls = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.13.0.RELEASE"),
|
||||
ReleaseTrains.INGALLS);
|
||||
ReleaseTrains.INGALLS, null, null);
|
||||
MaintainedVersion hopper = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.12.0.RELEASE"),
|
||||
ReleaseTrains.HOPPER);
|
||||
ReleaseTrains.HOPPER, null, null);
|
||||
|
||||
assertThat(ingalls.compareTo(hopper)).isGreaterThan(0);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.data.release.model.ReleaseTrains;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MaintainedVersions}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class MaintainedVersionsUnitTests {
|
||||
@@ -33,9 +33,9 @@ class MaintainedVersionsUnitTests {
|
||||
void considersMostRecentReleaseVersionTheMainOne() {
|
||||
|
||||
MaintainedVersion ingalls = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.13.0.RELEASE"),
|
||||
ReleaseTrains.INGALLS);
|
||||
ReleaseTrains.INGALLS, null, null);
|
||||
MaintainedVersion hopper = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.12.0.RELEASE"),
|
||||
ReleaseTrains.HOPPER);
|
||||
ReleaseTrains.HOPPER, null, null);
|
||||
|
||||
MaintainedVersions versions = MaintainedVersions.of(ingalls, hopper);
|
||||
|
||||
|
||||
@@ -25,8 +25,9 @@ import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
|
||||
/**
|
||||
* Tests for serialization of {@link ProjectMetadata}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class ProjectMetadataSerializationTests {
|
||||
|
||||
@@ -35,14 +36,15 @@ class ProjectMetadataSerializationTests {
|
||||
|
||||
ObjectWriter mapper = new ObjectMapper().writerWithDefaultPrettyPrinter();
|
||||
|
||||
MaintainedVersion kay = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("2.0.0.RC1"), ReleaseTrains.KAY);
|
||||
MaintainedVersion kay = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("2.0.0.RC1"), ReleaseTrains.KAY,
|
||||
null, null);
|
||||
MaintainedVersion ingalls = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.13.5.RELEASE"),
|
||||
ReleaseTrains.INGALLS);
|
||||
ReleaseTrains.INGALLS, null, null);
|
||||
MaintainedVersion ingallsSnapshot = ingalls.nextDevelopmentVersion();
|
||||
MaintainedVersion hopper = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.12.8.RELEASE"),
|
||||
ReleaseTrains.HOPPER);
|
||||
ReleaseTrains.HOPPER, null, null);
|
||||
|
||||
MaintainedVersions versions = MaintainedVersions.of(kay, ingalls, ingallsSnapshot, hopper);
|
||||
MaintainedVersions versions = MaintainedVersions.of(kay, ingalls, hopper);
|
||||
|
||||
System.out.println(mapper.writeValueAsString(new ProjectMetadata(kay, versions)));
|
||||
System.out.println(mapper.writeValueAsString(new ProjectMetadata(ingallsSnapshot, versions)));
|
||||
|
||||
@@ -15,11 +15,17 @@
|
||||
*/
|
||||
package org.springframework.data.release.sagan;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.release.AbstractIntegrationTests;
|
||||
import org.springframework.data.release.model.Project;
|
||||
import org.springframework.data.release.model.Projects;
|
||||
import org.springframework.data.release.model.ReleaseTrains;
|
||||
|
||||
@@ -48,8 +54,6 @@ class SaganOperationsIntegrationTests extends AbstractIntegrationTests {
|
||||
String output = version.toString();
|
||||
System.out.println(versions.isMainVersion(version) ? output.concat(" (main release)") : output);
|
||||
});
|
||||
|
||||
System.out.println();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -58,6 +62,19 @@ class SaganOperationsIntegrationTests extends AbstractIntegrationTests {
|
||||
sagan.updateProjectMetadata(ReleaseTrains.KAY, ReleaseTrains.INGALLS, ReleaseTrains.HOPPER);
|
||||
}
|
||||
|
||||
@Test
|
||||
void findVersions() {
|
||||
Map<Project, MaintainedVersions> versions = sagan.findVersions(ReleaseTrains.LOVELACE, ReleaseTrains.MOORE,
|
||||
ReleaseTrains.NEUMANN);
|
||||
|
||||
List<MaintainedVersion> maintainedVersions = versions.get(Projects.ELASTICSEARCH)
|
||||
.filter(it -> it.getVersion().isReleaseVersion()).toList();
|
||||
|
||||
assertThat(maintainedVersions).isNotEmpty();
|
||||
assertThat(maintainedVersions.get(0).getGenerationInception()).isNotNull();
|
||||
assertThat(maintainedVersions.get(0).getReleaseDate()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateJpa() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user