diff --git a/src/main/java/org/springframework/data/release/build/MavenArtifact.java b/src/main/java/org/springframework/data/release/build/MavenArtifact.java index 0dde854..dde07c7 100644 --- a/src/main/java/org/springframework/data/release/build/MavenArtifact.java +++ b/src/main/java/org/springframework/data/release/build/MavenArtifact.java @@ -22,6 +22,7 @@ import lombok.Getter; import org.springframework.data.release.model.ArtifactVersion; import org.springframework.data.release.model.ModuleIteration; +import org.springframework.data.release.model.Project; import org.springframework.util.Assert; /** @@ -34,8 +35,8 @@ public class MavenArtifact { private static final GroupId GROUP_ID = GroupId.of("org.springframework.data"); - private final ModuleIteration module; - private final Repository repository; + private final Project project; + private final @Getter Repository repository; private final @Getter ArtifactVersion version; /** @@ -47,11 +48,22 @@ public class MavenArtifact { Assert.notNull(module, "Module iteration must not be null!"); - this.module = module; + this.project = module.getModule().getProject(); this.repository = new Repository(module.getIteration()); this.version = ArtifactVersion.of(module); } + public MavenArtifact(Project project, ArtifactVersion version) { + + this.project = project; + this.repository = new Repository(version); + this.version = version; + } + + public String getGroupId() { + return GROUP_ID.getValue(); + } + /** * Returns the Maven artifact identifier. * @@ -59,8 +71,9 @@ public class MavenArtifact { */ public String getArtifactId() { - String artifactId = String.format("spring-data-%s", module.getProject().getName().toLowerCase()); - return REST.equals(module.getProject()) ? artifactId.concat("-webmvc") : artifactId; + String artifactId = String.format("spring-data-%s", project.getName().toLowerCase()); + + return REST.equals(project) ? artifactId.concat("-webmvc") : artifactId; } public ArtifactVersion getNextDevelopmentVersion() { diff --git a/src/main/java/org/springframework/data/release/build/Repository.java b/src/main/java/org/springframework/data/release/build/Repository.java index 5119163..43a1a7e 100644 --- a/src/main/java/org/springframework/data/release/build/Repository.java +++ b/src/main/java/org/springframework/data/release/build/Repository.java @@ -17,6 +17,7 @@ package org.springframework.data.release.build; import lombok.Value; +import org.springframework.data.release.model.ArtifactVersion; import org.springframework.data.release.model.Iteration; import org.springframework.util.Assert; @@ -40,6 +41,14 @@ public class Repository { this.url = BASE.concat(iteration.isPublic() ? "release" : "milestone"); } + public Repository(ArtifactVersion version) { + + String suffix = getSuffixFor(version); + + this.id = ID_BASE.concat(suffix); + this.url = BASE.concat(suffix); + } + public String getSnapshotId() { return ID_BASE.concat("snapshot"); } @@ -47,4 +56,21 @@ public class Repository { public String getSnapshotUrl() { return BASE.concat("snapshot"); } + + private static String getSuffixFor(ArtifactVersion version) { + + if (version.isSnapshotVersion()) { + return "snapshot"; + } + + if (version.isMilestoneVersion()) { + return "milestone"; + } + + if (version.isReleaseVersion()) { + return "release"; + } + + throw new IllegalArgumentException(String.format("Unsupported ArtifactVersion %s!", version)); + } } diff --git a/src/main/java/org/springframework/data/release/issues/Tickets.java b/src/main/java/org/springframework/data/release/issues/Tickets.java index 9b74234..c8760ba 100644 --- a/src/main/java/org/springframework/data/release/issues/Tickets.java +++ b/src/main/java/org/springframework/data/release/issues/Tickets.java @@ -18,22 +18,17 @@ package org.springframework.data.release.issues; import lombok.RequiredArgsConstructor; import lombok.Value; -import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Optional; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; import java.util.stream.Collector; import java.util.stream.Stream; import org.springframework.data.release.Streamable; import org.springframework.data.release.model.ModuleIteration; import org.springframework.data.release.model.TrainIteration; +import org.springframework.data.release.utils.ListWrapperCollector; import org.springframework.util.StringUtils; /** @@ -115,56 +110,6 @@ public class Tickets implements Streamable { * @return */ public static Collector toTicketsCollector() { - - return new Collector, Tickets>() { - - /* - * (non-Javadoc) - * @see java.util.stream.Collector#supplier() - */ - @Override - public Supplier> supplier() { - return ArrayList::new; - } - - /* - * (non-Javadoc) - * @see java.util.stream.Collector#accumulator() - */ - @Override - public BiConsumer, Ticket> accumulator() { - return List::add; - } - - /* - * (non-Javadoc) - * @see java.util.stream.Collector#combiner() - */ - @Override - public BinaryOperator> combiner() { - return (left, right) -> { - left.addAll(right); - return left; - }; - } - - /* - * (non-Javadoc) - * @see java.util.stream.Collector#finisher() - */ - @Override - public Function, Tickets> finisher() { - return tickets -> new Tickets(tickets); - } - - /* - * (non-Javadoc) - * @see java.util.stream.Collector#characteristics() - */ - @Override - public Set characteristics() { - return Collections.emptySet(); - } - }; + return ListWrapperCollector.collectInto(Tickets::new); } } diff --git a/src/main/java/org/springframework/data/release/model/ArtifactVersion.java b/src/main/java/org/springframework/data/release/model/ArtifactVersion.java index 57a507c..50097fa 100644 --- a/src/main/java/org/springframework/data/release/model/ArtifactVersion.java +++ b/src/main/java/org/springframework/data/release/model/ArtifactVersion.java @@ -16,6 +16,7 @@ package org.springframework.data.release.model; import lombok.EqualsAndHashCode; +import lombok.Getter; import org.springframework.util.Assert; @@ -35,7 +36,7 @@ public class ArtifactVersion implements Comparable { SNAPSHOT_SUFFIX); private final Version version; - private final String suffix; + private final @Getter String suffix; /** * Creates a new {@link ArtifactVersion} from the given logical {@link Version}. @@ -102,6 +103,10 @@ public class ArtifactVersion implements Comparable { return new ArtifactVersion(version, iteration.getName()); } + public boolean isVersionWithin(Version version) { + return this.version.toMajorMinorBugfix().startsWith(version.toString()); + } + /** * Returns the release version for the current one. * @@ -138,6 +143,14 @@ public class ArtifactVersion implements Comparable { return suffix.matches(MILESTONE_SUFFIX); } + public boolean isSnapshotVersion() { + return suffix.matches(SNAPSHOT_SUFFIX); + } + + public boolean isBugFixVersion() { + return isReleaseVersion() && !version.toMajorMinorBugfix().endsWith("0"); + } + /** * Returns the next development version to be used for the current release version, which means next minor for GA * versions and next bug fix for service releases. Will return the current version as snapshot otherwise. @@ -172,6 +185,19 @@ public class ArtifactVersion implements Comparable { return suffix.equals(SNAPSHOT_SUFFIX) ? this : new ArtifactVersion(version, SNAPSHOT_SUFFIX); } + public String getReleaseTrainSuffix() { + + if (isSnapshotVersion() || isMilestoneVersion()) { + return suffix; + } + + if (isBugFixVersion()) { + return "SR" + version.getBugfix(); + } + + return "GA"; + } + /* * (non-Javadoc) * @see java.lang.Comparable#compareTo(java.lang.Object) diff --git a/src/main/java/org/springframework/data/release/model/Password.java b/src/main/java/org/springframework/data/release/model/Password.java index e06b736..1dbad3c 100644 --- a/src/main/java/org/springframework/data/release/model/Password.java +++ b/src/main/java/org/springframework/data/release/model/Password.java @@ -31,6 +31,8 @@ import org.springframework.util.Assert; @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class Password implements Masked { + public static Password NONE = new Password(""); + @Getter(AccessLevel.NONE) String value; /** diff --git a/src/main/java/org/springframework/data/release/model/Version.java b/src/main/java/org/springframework/data/release/model/Version.java index 1ea2452..9a2576f 100644 --- a/src/main/java/org/springframework/data/release/model/Version.java +++ b/src/main/java/org/springframework/data/release/model/Version.java @@ -1,5 +1,7 @@ package org.springframework.data.release.model; +import lombok.Getter; + import java.util.ArrayList; import java.util.List; @@ -11,6 +13,7 @@ import org.springframework.util.StringUtils; * * @author Oliver Gierke */ +@Getter public class Version implements Comparable { private final int major; diff --git a/src/main/java/org/springframework/data/release/sagan/DefaultSaganClient.java b/src/main/java/org/springframework/data/release/sagan/DefaultSaganClient.java new file mode 100644 index 0000000..3ba36df --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/DefaultSaganClient.java @@ -0,0 +1,107 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; +import net.minidev.json.JSONArray; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.release.model.Project; +import org.springframework.data.release.utils.Logger; +import org.springframework.web.client.RestOperations; + +import com.jayway.jsonpath.JsonPath; + +/** + * Sagan client to interact with the Sagan instance defined through {@link SaganProperties}. + * + * @author Oliver Gierke + */ +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +class DefaultSaganClient implements SaganClient { + + RestOperations operations; + SaganProperties properties; + Logger logger; + + /* + * (non-Javadoc) + * @see org.springframework.data.release.sagan.SaganClient#getProjectMetadata(org.springframework.data.release.sagan.MaintainedVersion) + */ + @Override + public String getProjectMetadata(MaintainedVersion version) { + + URI resource = properties.getProjectMetadataResource(version); + + logger.log(version.getProject(), "Getting project metadata for version %s from %s…", version.getVersion(), + resource); + + return operations.getForObject(resource, String.class); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.release.sagan.SaganClient#getProjectMetadata(org.springframework.data.release.model.Project) + */ + @Override + public String getProjectMetadata(Project project) { + + URI resource = properties.getProjectMetadataResource(project); + + logger.log(project, "Getting project metadata from %s…", resource); + + return operations.getForObject(resource, String.class); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.release.sagan.SaganClient#updateProjectMetadata(org.springframework.data.release.model.Project, java.util.List) + */ + @Override + public void updateProjectMetadata(Project project, MaintainedVersions versions) { + + URI resource = properties.getProjectMetadataResource(project); + + String versionsString = versions.stream()// + .map(MaintainedVersion::getVersion)// + .map(Object::toString) // + .collect(Collectors.joining(", ")); + + logger.log(project, "Updating project metadata to %s via %s…", versionsString, resource); + + // Delete all existing versions first + Arrays.stream(JsonPath.compile("$..version"). read(getProjectMetadata(project)).toArray())// + .map(version -> properties.getProjectMetadataResource(project, version.toString()))// + .peek(uri -> logger.log(project, "Deleting existing project metadata at %s…", uri)) // + .forEach(uri -> operations.delete(uri)); + + logger.log(project, "Writing project metadata for versions %s!", versionsString); + + // Write new ones + List payload = versions.stream() // + .map(version -> new ProjectMetadata(version, versions)) // + .collect(Collectors.toList()); + + operations.put(resource, payload); + } +} diff --git a/src/main/java/org/springframework/data/release/sagan/DummySaganClient.java b/src/main/java/org/springframework/data/release/sagan/DummySaganClient.java new file mode 100644 index 0000000..0c8d4d7 --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/DummySaganClient.java @@ -0,0 +1,86 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.release.model.Project; +import org.springframework.data.release.utils.Logger; + +import com.fasterxml.jackson.core.JsonProcessingException; +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 + */ +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +class DummySaganClient implements SaganClient { + + Logger logger; + ObjectWriter mapper; + + /* + * (non-Javadoc) + * @see org.springframework.data.release.sagan.SaganClient#updateProjectMetadata(org.springframework.data.release.model.Project, org.springframework.data.release.sagan.MaintainedVersions) + */ + @Override + public void updateProjectMetadata(Project project, MaintainedVersions versions) { + + logger.log(project, "Updating released version on Sagan to %s!", versions); + + List payload = versions.stream() // + .map(it -> new ProjectMetadata(it, versions)) // + .collect(Collectors.toList()); + + try { + System.out.println(mapper.writeValueAsString(payload)); + } catch (JsonProcessingException o_O) { + throw new RuntimeException(o_O); + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.release.sagan.SaganClient#getProjectMetadata(org.springframework.data.release.sagan.MaintainedVersion) + */ + @Override + public String getProjectMetadata(MaintainedVersion version) { + + try { + return mapper.writeValueAsString(new ProjectMetadata(version, MaintainedVersions.of(version))); + } 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) + */ + @Override + public String getProjectMetadata(Project project) { + return null; + } +} diff --git a/src/main/java/org/springframework/data/release/sagan/MaintainedVersion.java b/src/main/java/org/springframework/data/release/sagan/MaintainedVersion.java new file mode 100644 index 0000000..1a44bda --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/MaintainedVersion.java @@ -0,0 +1,94 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import lombok.Value; + +import java.util.Comparator; +import java.util.stream.Stream; + +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.util.Assert; + +/** + * Represents a maintained project version to be represented in Sagan. + * + * @author Oliver Gierke + */ +@Value(staticConstructor = "of") +class MaintainedVersion implements Comparable { + + Project project; + ArtifactVersion version; + Train train; + + /** + * Creates a new {@link MaintainedVersion} representing the snaphot version of the given {@link Module} and + * {@link Train}. + * + * @param module must not be {@literal null}. + * @param train must not be {@literal null}. + * @return + */ + public static MaintainedVersion snapshot(Module module, Train train) { + + Assert.notNull(module, "Module must not be null!"); + Assert.notNull(train, "Train must not be null!"); + + ArtifactVersion snapshotVersion = ArtifactVersion.of(module.getVersion()).getSnapshotVersion(); + + return MaintainedVersion.of(module.getProject(), snapshotVersion, train); + } + + /** + * 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 all() { + return version.isSnapshotVersion() ? Stream.of(this) : Stream.of(nextDevelopmentVersion(), this); + } + + /** + * Creates the {@link MaintainedVersion} for the next development version of the current one. + * + * @return + */ + MaintainedVersion nextDevelopmentVersion() { + return MaintainedVersion.of(project, version.getNextDevelopmentVersion(), train); + } + + /* + * (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(MaintainedVersion o) { + return Comparator.comparing(MaintainedVersion::getVersion).compare(this, o); + } + + /* + * (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return String.format("%s - %s - %s", project.getName(), train.getName(), version); + } +} diff --git a/src/main/java/org/springframework/data/release/sagan/MaintainedVersions.java b/src/main/java/org/springframework/data/release/sagan/MaintainedVersions.java new file mode 100644 index 0000000..cf12184 --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/MaintainedVersions.java @@ -0,0 +1,93 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.ToString; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.data.release.Streamable; +import org.springframework.data.release.model.ArtifactVersion; + +/** + * Wrapper type for a {@link List} of {@link MaintainedVersion}. + * + * @author Oliver Gierke + */ +@ToString +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +class MaintainedVersions implements Streamable { + + private final List versions; + + /** + * Creates a new {@link MaintainedVersions} with the given {@link MaintainedVersion}s in descending order (more recent + * versions first). + * + * @param versions must not be {@literal null}. + * @return + */ + static MaintainedVersions of(List versions) { + + return new MaintainedVersions(versions.stream()// + .sorted(Comparator.reverseOrder())// + .collect(Collectors.toList())); + } + + /** + * Creates a new {@link MaintainedVersions} with the given {@link MaintainedVersion}s in descending order (more recent + * versions first). + * + * @param versions must not be {@literal null}. + * @return + */ + static MaintainedVersions of(MaintainedVersion... versions) { + return MaintainedVersions.of(Arrays.asList(versions)); + } + + /** + * Returns whether the given {@link MaintainedVersion} is the main version of the current set. + * + * @param version must not be {@literal null}. + * @return + */ + boolean isMainVersion(MaintainedVersion version) { + + if (!version.getVersion().isReleaseVersion()) { + return false; + } + + return versions.stream() // + .map(it -> it.getVersion()) // + .filter(ArtifactVersion::isReleaseVersion) // + .findFirst() // + .map(it -> it.equals(version.getVersion())) // + .orElse(false); + } + + /* + * (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + @Override + public Iterator iterator() { + return versions.iterator(); + } +} diff --git a/src/main/java/org/springframework/data/release/sagan/ProjectMetadata.java b/src/main/java/org/springframework/data/release/sagan/ProjectMetadata.java new file mode 100644 index 0000000..84bf52d --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/ProjectMetadata.java @@ -0,0 +1,193 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.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.util.Assert; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +/** + * Simple value object to create payloads to update project metadata in Sagan. + * + * @author Oliver Gierke + */ +@JsonInclude(Include.NON_NULL) +class ProjectMetadata { + + private static String DOCS_BASE = "https://docs.spring.io/spring-data/%s/docs/{version}"; + 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; + + /** + * Creates a new {@link ProjectMetadata} instace from the given {@link MaintainedVersion} in the context of the + * {@link MaintainedVersions}. + * + * @param version must not be {@literal null}. + * @param versions must not be {@literal null}. + */ + 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; + } + + /** + * Returns the reference documentation URL for non-snapshot versions and not the build project. + * + * @return + */ + public String getRefDocUrl() { + + return version.getVersion().isSnapshotVersion() || Projects.BUILD.equals(version.getProject()) // + ? "" // + : String.format(DOCS, version.getProject().getName().toLowerCase(Locale.US)); + } + + /** + * Returns the JavaDoc URL for non-snapshot versions and not the build project. + * + * @return + */ + public String getApiDocUrl() { + + return version.getVersion().isSnapshotVersion() || Projects.BUILD.equals(version.getProject()) // + ? "" // + : String.format(JAVADOC, version.getProject().getName().toLowerCase(Locale.US)); + } + + public Repository getRepository() { + return new Repository(); + } + + /** + * Return the version to use. For the build project thats the release train name, for everything else the artifact + * version. + * + * @return + */ + public String getVersion() { + + if (Projects.BUILD.equals(version.getProject())) { + return String.format("%s-%s", version.getTrain().getName(), version.getVersion().getReleaseTrainSuffix()); + } + + return version.getVersion().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(); + } + } +} diff --git a/src/main/java/org/springframework/data/release/sagan/SaganClient.java b/src/main/java/org/springframework/data/release/sagan/SaganClient.java new file mode 100644 index 0000000..b818cc8 --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/SaganClient.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import org.springframework.data.release.model.Project; + +/** + * Interface to abstract the actual interaction with the Sagan server. + * + * @author Oliver Gierke + */ +interface SaganClient { + + /** + * Returns the project metadata for the given {@link MaintainedVersion}. + * + * @param version must not be {@literal null}. + * @return + */ + String getProjectMetadata(MaintainedVersion version); + + /** + * Returns all project release metadata for the given {@link Project}. + * + * @param project must not be {@literal null}. + * @return + */ + String getProjectMetadata(Project project); + + /** + * Updates the project metadata for the given {@link Project} to the given {@link MaintainedVersions}. + * + * @param project must not be {@literal null}. + * @param versions must not be {@literal null}. + */ + void updateProjectMetadata(Project project, MaintainedVersions versions); +} diff --git a/src/main/java/org/springframework/data/release/sagan/SaganCommands.java b/src/main/java/org/springframework/data/release/sagan/SaganCommands.java new file mode 100644 index 0000000..a267c33 --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/SaganCommands.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.springframework.data.release.CliComponent; +import org.springframework.data.release.TimedCommand; +import org.springframework.data.release.model.ReleaseTrains; +import org.springframework.shell.core.annotation.CliCommand; +import org.springframework.shell.core.annotation.CliOption; +import org.springframework.stereotype.Component; + +/** + * Operations for Sagan interaction. + * + * @author Oliver Gierke + */ +@Component +@CliComponent +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +class SaganCommands extends TimedCommand { + + SaganOperations sagan; + + @CliCommand("sagan update") + public void updateProjectInformation(@CliOption(key = "", mandatory = true) String trains) { + + sagan.updateProjectMetadata(Stream.of(trains.split(","))// + .map(train -> ReleaseTrains.getTrainByName(train)) // + .collect(Collectors.toList())); + } +} diff --git a/src/main/java/org/springframework/data/release/sagan/SaganConfiguration.java b/src/main/java/org/springframework/data/release/sagan/SaganConfiguration.java new file mode 100644 index 0000000..5bc3f38 --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/SaganConfiguration.java @@ -0,0 +1,86 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import java.io.IOException; +import java.util.Arrays; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.release.git.GitOperations; +import org.springframework.data.release.utils.Logger; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.RestTemplate; + +/** + * Configuration for the Sagan interaction subsystem. + * + * @author Oliver Gierke + */ +@Configuration +class SaganConfiguration { + + @Autowired SaganProperties properties; + @Autowired Logger logger; + + @Bean + public SaganOperations saganOperations(GitOperations operations) { + return new SaganOperations(operations, saganClient(), logger); + } + + @Bean + SaganClient saganClient() { + + return new DefaultSaganClient(saganRestTemplate(), properties, logger); + // return new DummySaganClient(logger, new ObjectMapper().writerWithDefaultPrettyPrinter()); + } + + @Bean + RestTemplate saganRestTemplate() { + + RestTemplate template = new RestTemplate(); + template.setInterceptors(Arrays.asList(new AuthenticatingClientHttpRequestInterceptor(properties))); + + return template; + } + + @RequiredArgsConstructor + private static class AuthenticatingClientHttpRequestInterceptor implements ClientHttpRequestInterceptor { + + private final @NonNull SaganProperties properties; + + /* + * (non-Javadoc) + * @see org.springframework.http.client.ClientHttpRequestInterceptor#intercept(org.springframework.http.HttpRequest, byte[], org.springframework.http.client.ClientHttpRequestExecution) + */ + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) + throws IOException { + + request.getHeaders().add(HttpHeaders.AUTHORIZATION, properties.getCredentials().toString()); + + return execution.execute(request, body); + } + } +} diff --git a/src/main/java/org/springframework/data/release/sagan/SaganOperations.java b/src/main/java/org/springframework/data/release/sagan/SaganOperations.java new file mode 100644 index 0000000..c51d2e2 --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/SaganOperations.java @@ -0,0 +1,129 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.data.release.git.GitOperations; +import org.springframework.data.release.git.Tag; +import org.springframework.data.release.model.Module; +import org.springframework.data.release.model.Project; +import org.springframework.data.release.model.Projects; +import org.springframework.data.release.model.Train; +import org.springframework.data.release.model.Version; +import org.springframework.data.release.utils.ListWrapperCollector; +import org.springframework.data.release.utils.Logger; +import org.springframework.util.Assert; + +/** + * @author Oliver Gierke + */ +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) +class SaganOperations { + + private static final List TO_FILTER = Arrays.asList(Projects.COMMONS, // + Projects.GEODE, // + Projects.KEY_VALUE); + + GitOperations git; + SaganClient client; + Logger logger; + + /** + * Updates the project metadata for the modules in the given release {@link Train}s. + * + * @param trains must not be {@literal null}. + */ + void updateProjectMetadata(Train... trains) { + + Assert.notNull(trains, "Trains must not be null!"); + + updateProjectMetadata(Arrays.asList(trains)); + } + + void updateProjectMetadata(List trains) { + + Assert.notNull(trains, "Trains must not be null!"); + + findVersions(trains).forEach(client::updateProjectMetadata); + } + + /** + * Returns all {@link MaintainedVersions} grouped by {@link Project} for the given release {@link Train}. + * + * @param trains must not be {@literal null}. + * @return will never be {@literal null}. + */ + Map findVersions(Train... trains) { + + Assert.notNull(trains, "Trains must not be null!"); + + return findVersions(Arrays.asList(trains)); + } + + Map findVersions(List trains) { + + Assert.notNull(trains, "Trains must not be null!"); + + return trains.stream() // + .flatMap(train -> train.stream()// + .filter(module -> !TO_FILTER.contains(module.getProject())) // + .map(module -> getLatestVersion(module, train)) // + .flatMap(MaintainedVersion::all)) // + .collect( + Collectors.groupingBy(it -> it.getProject(), ListWrapperCollector.collectInto(MaintainedVersions::of))); + } + + private MaintainedVersion getLatestVersion(Module module, Train train) { + + Project project = module.getProject(); + + MaintainedVersion version = git.getTags(project).stream()// + .filter(tag -> matches(tag, module.getVersion())) // + .sorted(Comparator.reverseOrder()) // + .findFirst() // + .flatMap(tag -> tag.toArtifactVersion()) // + .map(it -> MaintainedVersion.of(module.getProject(), it, train)) // + .orElseGet(() -> MaintainedVersion.snapshot(module, train)); + + logger.log(project, "Found version %s for train %s!", version.getVersion(), train.getName()); + + return version; + } + + /** + * Returns whether the given {@link Tag} is one that logically belongs to the given version. + * + * @param tag must not be {@literal null}. + * @param version must not be {@literal null}. + * @return + */ + private static boolean matches(Tag tag, Version version) { + + return tag.toArtifactVersion()// + .map(it -> it.isVersionWithin(version))// + .orElse(false); + } +} diff --git a/src/main/java/org/springframework/data/release/sagan/SaganProperties.java b/src/main/java/org/springframework/data/release/sagan/SaganProperties.java new file mode 100644 index 0000000..3910cd5 --- /dev/null +++ b/src/main/java/org/springframework/data/release/sagan/SaganProperties.java @@ -0,0 +1,96 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +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}"); + + @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}. + * + * @param project must not be {@literal null}. + * @return + */ + URI getProjectMetadataResource(Project project) { + + Assert.notNull(project, "Project must not be null!"); + + return new UriTemplate(SAGAN_PROJECT_METADATA).expand(getProjectPathSegment(project)); + } + + /** + * Returns the URI to the resource exposing the project metadata 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) { + + 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); + } + + /** + * Returns the {@link URI} to the resource exposing the project metadata for the given {@link MaintainedVersion}. + * + * @param version must not be {@literal null}. + * @return + */ + URI getProjectMetadataResource(MaintainedVersion version) { + return getProjectMetadataResource(version.getProject(), version.getVersion().toString()); + } + + private static String getProjectPathSegment(Project project) { + return Projects.BUILD.equals(project) ? "spring-data" : project.getFolderName(); + } +} diff --git a/src/main/java/org/springframework/data/release/utils/HttpBasicCredentials.java b/src/main/java/org/springframework/data/release/utils/HttpBasicCredentials.java index 68d86ff..39f325c 100644 --- a/src/main/java/org/springframework/data/release/utils/HttpBasicCredentials.java +++ b/src/main/java/org/springframework/data/release/utils/HttpBasicCredentials.java @@ -15,6 +15,7 @@ */ package org.springframework.data.release.utils; +import lombok.NonNull; import lombok.Value; import java.nio.charset.StandardCharsets; @@ -28,8 +29,8 @@ import org.springframework.data.release.model.Password; @Value public class HttpBasicCredentials { - private final String username; - private final Password password; + private final @NonNull String username; + private final @NonNull Password password; /* * (non-Javadoc) diff --git a/src/main/java/org/springframework/data/release/utils/ListWrapperCollector.java b/src/main/java/org/springframework/data/release/utils/ListWrapperCollector.java new file mode 100644 index 0000000..3baeb10 --- /dev/null +++ b/src/main/java/org/springframework/data/release/utils/ListWrapperCollector.java @@ -0,0 +1,99 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +import org.springframework.util.Assert; + +/** + * Base class to easily create a {@link Collector} to create a collection wrapper type. + * + * @author Oliver Gierke + */ +public abstract class ListWrapperCollector implements Collector, S> { + + /** + * Creates a new {@link Collector} to eventually apply the given function to turn the {@link List} of elements into a + * wrapper type. + * + * @param function must not be {@literal null}. + * @return + */ + public static ListWrapperCollector collectInto(Function, S> function) { + + Assert.notNull(function, "Finisher function must not be null!"); + + return new ListWrapperCollector() { + + /* + * (non-Javadoc) + * @see java.util.stream.Collector#finisher() + */ + @Override + public Function, S> finisher() { + return function; + } + }; + } + + /* + * (non-Javadoc) + * @see java.util.stream.Collector#supplier() + */ + @Override + public Supplier> supplier() { + return ArrayList::new; + } + + /* + * (non-Javadoc) + * @see java.util.stream.Collector#accumulator() + */ + @Override + public BiConsumer, T> accumulator() { + return List::add; + } + + /* + * (non-Javadoc) + * @see java.util.stream.Collector#combiner() + */ + @Override + public BinaryOperator> combiner() { + return (left, right) -> { + left.addAll(right); + return left; + }; + } + + /* + * (non-Javadoc) + * @see java.util.stream.Collector#characteristics() + */ + @Override + public Set characteristics() { + return Collections.emptySet(); + } +} diff --git a/src/test/java/org/springframework/data/release/sagan/MaintainedVersionUnitTests.java b/src/test/java/org/springframework/data/release/sagan/MaintainedVersionUnitTests.java new file mode 100644 index 0000000..60d7aca --- /dev/null +++ b/src/test/java/org/springframework/data/release/sagan/MaintainedVersionUnitTests.java @@ -0,0 +1,42 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; +import org.springframework.data.release.model.ArtifactVersion; +import org.springframework.data.release.model.Projects; +import org.springframework.data.release.model.ReleaseTrains; + +/** + * Unit tests for {@link MaintainedVersion}. + * + * @author Oliver Gierke + */ +public class MaintainedVersionUnitTests { + + @Test + public void newerVersionIsOrderedFirst() { + + MaintainedVersion ingalls = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.13.0.RELEASE"), + ReleaseTrains.INGALLS); + MaintainedVersion hopper = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.12.0.RELEASE"), + ReleaseTrains.HOPPER); + + assertThat(ingalls.compareTo(hopper)).isGreaterThan(0); + } +} diff --git a/src/test/java/org/springframework/data/release/sagan/MaintainedVersionsUnitTests.java b/src/test/java/org/springframework/data/release/sagan/MaintainedVersionsUnitTests.java new file mode 100644 index 0000000..5c6dd1d --- /dev/null +++ b/src/test/java/org/springframework/data/release/sagan/MaintainedVersionsUnitTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.Test; +import org.springframework.data.release.model.ArtifactVersion; +import org.springframework.data.release.model.Projects; +import org.springframework.data.release.model.ReleaseTrains; + +/** + * Unit tests for {@link MaintainedVersions}. + * + * @author Oliver Gierke + */ +public class MaintainedVersionsUnitTests { + + @Test + public void considersMostRecentReleaseVersionTheMainOne() { + + MaintainedVersion ingalls = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.13.0.RELEASE"), + ReleaseTrains.INGALLS); + MaintainedVersion hopper = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.12.0.RELEASE"), + ReleaseTrains.HOPPER); + + MaintainedVersions versions = MaintainedVersions.of(ingalls, hopper); + + assertThat(versions.isMainVersion(ingalls)).isTrue(); + assertThat(versions.isMainVersion(hopper)).isFalse(); + } +} diff --git a/src/test/java/org/springframework/data/release/sagan/ProjectMetadataSerializationTests.java b/src/test/java/org/springframework/data/release/sagan/ProjectMetadataSerializationTests.java new file mode 100644 index 0000000..f8f0323 --- /dev/null +++ b/src/test/java/org/springframework/data/release/sagan/ProjectMetadataSerializationTests.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import org.junit.Test; +import org.springframework.data.release.model.ArtifactVersion; +import org.springframework.data.release.model.Projects; +import org.springframework.data.release.model.ReleaseTrains; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; + +/** + * Tests for serialization of {@link ProjectMetadata}. + * + * @author Oliver Gierke + */ +public class ProjectMetadataSerializationTests { + + @Test + public void serializesMaintainedVersionsIntoProjectMetadata() throws Exception { + + ObjectWriter mapper = new ObjectMapper().writerWithDefaultPrettyPrinter(); + + MaintainedVersion kay = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("2.0.0.RC1"), ReleaseTrains.KAY); + MaintainedVersion ingalls = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.13.5.RELEASE"), + ReleaseTrains.INGALLS); + MaintainedVersion ingallsSnapshot = ingalls.nextDevelopmentVersion(); + MaintainedVersion hopper = MaintainedVersion.of(Projects.COMMONS, ArtifactVersion.of("1.12.8.RELEASE"), + ReleaseTrains.HOPPER); + + MaintainedVersions versions = MaintainedVersions.of(kay, ingalls, ingallsSnapshot, hopper); + + System.out.println(mapper.writeValueAsString(new ProjectMetadata(kay, versions))); + System.out.println(mapper.writeValueAsString(new ProjectMetadata(ingallsSnapshot, versions))); + System.out.println(mapper.writeValueAsString(new ProjectMetadata(ingalls, versions))); + System.out.println(mapper.writeValueAsString(new ProjectMetadata(hopper, versions))); + } +} diff --git a/src/test/java/org/springframework/data/release/sagan/SaganOperationsIntegrationTests.java b/src/test/java/org/springframework/data/release/sagan/SaganOperationsIntegrationTests.java new file mode 100644 index 0000000..0eaaa10 --- /dev/null +++ b/src/test/java/org/springframework/data/release/sagan/SaganOperationsIntegrationTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.release.sagan; + +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.release.AbstractIntegrationTests; +import org.springframework.data.release.model.Projects; +import org.springframework.data.release.model.ReleaseTrains; + +/** + * Integration tests for {@link SaganOperations}. + * + * @author Oliver Gierke + */ +public class SaganOperationsIntegrationTests extends AbstractIntegrationTests { + + @Autowired SaganOperations sagan; + @Autowired SaganClient client; + + @Test + public void detectVersionsToUpdate() { + + sagan.findVersions(ReleaseTrains.LOVELACE, ReleaseTrains.KAY, ReleaseTrains.INGALLS, ReleaseTrains.HOPPER) + .forEach((project, versions) -> { + + System.out.println(project.getName()); + System.out.println("-----"); + + versions.forEach(version -> { + + String output = version.toString(); + System.out.println(versions.isMainVersion(version) ? output.concat(" (main release)") : output); + }); + + System.out.println(); + }); + } + + @Test + public void updateVersions() { + sagan.updateProjectMetadata(ReleaseTrains.KAY, ReleaseTrains.INGALLS, ReleaseTrains.HOPPER); + } + + @Test + public void updateJpa() { + + MaintainedVersions versions = sagan.findVersions(ReleaseTrains.KAY, ReleaseTrains.INGALLS, ReleaseTrains.HOPPER) + .get(Projects.JPA); + + System.out.println(versions); + + client.updateProjectMetadata(Projects.JPA, versions); + } + + @Test + public void getJpa() { + System.out.println(client.getProjectMetadata(Projects.JPA)); + } + + @Test + public void updateBuild() { + + MaintainedVersions versions = sagan.findVersions(ReleaseTrains.KAY, ReleaseTrains.INGALLS, ReleaseTrains.HOPPER) + .get(Projects.BUILD); + + client.updateProjectMetadata(Projects.BUILD, versions); + } +}