Initial commit.

This commit is contained in:
Oliver Gierke
2014-03-17 09:05:46 +01:00
commit 092663da01
57 changed files with 3218 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
target/
.settings/
.project
.classpath
.springBeans
jira.properties
spring-shell.log

View File

@@ -0,0 +1,136 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-release-cli</artifactId>
<version>5.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.0.0.RC4</version>
</parent>
<properties>
<jar.mainclass>org.springframework.shell.Bootstrap</jar.mainclass>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.shell</groupId>
<artifactId>spring-shell</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.xmlbeam</groupId>
<artifactId>xmlprojector</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.12.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- Shell packaging -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<programs>
<program>
<mainClass>org.springframework.shell.Bootstrap</mainClass>
<id>spring-data-release-shell</id>
</program>
</programs>
</configuration>
</plugin>
<!-- <plugin> -->
<!-- <groupId>org.apache.maven.plugins</groupId> -->
<!-- <artifactId>maven-dependency-plugin</artifactId> -->
<!-- <executions> -->
<!-- <execution> -->
<!-- <id>copy-dependencies</id> -->
<!-- <phase>prepare-package</phase> -->
<!-- <goals> -->
<!-- <goal>copy-dependencies</goal> -->
<!-- </goals> -->
<!-- <configuration> -->
<!-- <outputDirectory>${project.build.directory}/lib</outputDirectory> -->
<!-- <overWriteReleases>true</overWriteReleases> -->
<!-- <overWriteSnapshots>true</overWriteSnapshots> -->
<!-- <overWriteIfNewer>true</overWriteIfNewer> -->
<!-- </configuration> -->
<!-- </execution> -->
<!-- </executions> -->
<!-- </plugin> -->
<!-- <plugin> -->
<!-- <groupId>org.apache.maven.plugins</groupId> -->
<!-- <artifactId>maven-jar-plugin</artifactId> -->
<!-- <configuration> -->
<!-- <archive> -->
<!-- <manifest> -->
<!-- <addClasspath>true</addClasspath> -->
<!-- <useUniqueVersions>false</useUniqueVersions> -->
<!-- <classpathPrefix>lib/</classpathPrefix> -->
<!-- <mainClass>${jar.mainclass}</mainClass> -->
<!-- </manifest> -->
<!-- <manifestEntries> -->
<!-- <version>${project.version}</version> -->
<!-- </manifestEntries> -->
<!-- </archive> -->
<!-- </configuration> -->
<!-- </plugin> -->
</plugins>
</build>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>http://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
</project>

137
files/sample-pom.xml Normal file
View File

@@ -0,0 +1,137 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-release-cli</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.0.0.RC4</version>
</parent>
<properties>
<jar.mainclass>org.springframework.shell.Bootstrap</jar.mainclass>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.shell</groupId>
<artifactId>spring-shell</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.xmlbeam</groupId>
<artifactId>xmlprojector</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.12.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- Shell packaging -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<programs>
<program>
<mainClass>org.springframework.shell.Bootstrap</mainClass>
<id>spring-data-release-shell</id>
</program>
</programs>
</configuration>
</plugin>
<!-- <plugin> -->
<!-- <groupId>org.apache.maven.plugins</groupId> -->
<!-- <artifactId>maven-dependency-plugin</artifactId> -->
<!-- <executions> -->
<!-- <execution> -->
<!-- <id>copy-dependencies</id> -->
<!-- <phase>prepare-package</phase> -->
<!-- <goals> -->
<!-- <goal>copy-dependencies</goal> -->
<!-- </goals> -->
<!-- <configuration> -->
<!-- <outputDirectory>${project.build.directory}/lib</outputDirectory> -->
<!-- <overWriteReleases>true</overWriteReleases> -->
<!-- <overWriteSnapshots>true</overWriteSnapshots> -->
<!-- <overWriteIfNewer>true</overWriteIfNewer> -->
<!-- </configuration> -->
<!-- </execution> -->
<!-- </executions> -->
<!-- </plugin> -->
<!-- <plugin> -->
<!-- <groupId>org.apache.maven.plugins</groupId> -->
<!-- <artifactId>maven-jar-plugin</artifactId> -->
<!-- <configuration> -->
<!-- <archive> -->
<!-- <manifest> -->
<!-- <addClasspath>true</addClasspath> -->
<!-- <useUniqueVersions>false</useUniqueVersions> -->
<!-- <classpathPrefix>lib/</classpathPrefix> -->
<!-- <mainClass>${jar.mainclass}</mainClass> -->
<!-- </manifest> -->
<!-- <manifestEntries> -->
<!-- <version>${project.version}</version> -->
<!-- </manifestEntries> -->
<!-- </archive> -->
<!-- </configuration> -->
<!-- </plugin> -->
</plugins>
</build>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>http://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
</project>

View File

@@ -0,0 +1 @@
io.workDir=~/temp/spring-data-shell

147
pom.xml Normal file
View File

@@ -0,0 +1,147 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-release-cli</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.0.0.RC4</version>
</parent>
<properties>
<jar.mainclass>org.springframework.shell.Bootstrap</jar.mainclass>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.shell</groupId>
<artifactId>spring-shell</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.xmlbeam</groupId>
<artifactId>xmlprojector</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.12.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- Shell packaging -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<programs>
<program>
<mainClass>org.springframework.shell.Bootstrap</mainClass>
<id>spring-data-release-shell</id>
</program>
</programs>
</configuration>
</plugin>
<!-- <plugin> -->
<!-- <groupId>org.apache.maven.plugins</groupId> -->
<!-- <artifactId>maven-dependency-plugin</artifactId> -->
<!-- <executions> -->
<!-- <execution> -->
<!-- <id>copy-dependencies</id> -->
<!-- <phase>prepare-package</phase> -->
<!-- <goals> -->
<!-- <goal>copy-dependencies</goal> -->
<!-- </goals> -->
<!-- <configuration> -->
<!-- <outputDirectory>${project.build.directory}/lib</outputDirectory> -->
<!-- <overWriteReleases>true</overWriteReleases> -->
<!-- <overWriteSnapshots>true</overWriteSnapshots> -->
<!-- <overWriteIfNewer>true</overWriteIfNewer> -->
<!-- </configuration> -->
<!-- </execution> -->
<!-- </executions> -->
<!-- </plugin> -->
<!-- <plugin> -->
<!-- <groupId>org.apache.maven.plugins</groupId> -->
<!-- <artifactId>maven-jar-plugin</artifactId> -->
<!-- <configuration> -->
<!-- <archive> -->
<!-- <manifest> -->
<!-- <addClasspath>true</addClasspath> -->
<!-- <useUniqueVersions>false</useUniqueVersions> -->
<!-- <classpathPrefix>lib/</classpathPrefix> -->
<!-- <mainClass>${jar.mainclass}</mainClass> -->
<!-- </manifest> -->
<!-- <manifestEntries> -->
<!-- <version>${project.version}</version> -->
<!-- </manifestEntries> -->
<!-- </archive> -->
<!-- </configuration> -->
<!-- </plugin> -->
</plugins>
</build>
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>http://repo.spring.io/libs-snapshot</url>
</repository>
</repositories>
</project>

1
readme.md Normal file
View File

@@ -0,0 +1 @@
`mvn package appassembler:assemble && sh target/appassembler/bin/spring-data-release-shell`

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2014 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.cli;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.release.jira.Credentials;
import org.springframework.data.release.jira.JiraConnector;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* @author Oliver Gierke
*/
@Component
public class JiraCommands implements CommandMarker {
private final JiraConnector connector;
private final Credentials credentials;
/**
* @param connector
* @param environment
*/
@Autowired
public JiraCommands(JiraConnector connector, Environment environment) {
String username = environment.getProperty("jira.username", (String) null);
String password = environment.getProperty("jira.password", (String) null);
this.connector = connector;
this.credentials = StringUtils.hasText(username) ? new Credentials(username, password) : null;
}
@CliCommand("jira evict")
public void jiraEvict() {
connector.reset();
}
@CliCommand(value = "jira tickets")
public String jira(
//
@CliOption(key = { "", "train" }, mandatory = true, help = "The name of the release train.") String trainName, //
@CliOption(key = "iteration", mandatory = true, help = "An iteration key (one of M1, RC1, GA).") String iterationName, //
@CliOption(key = "for-current-user", specifiedDefaultValue = "true", unspecifiedDefaultValue = "false") boolean forCurrentUser) {
if (forCurrentUser && credentials == null) {
return "No authentication specified! Use 'jira authenticate' first!";
}
Train train = ReleaseTrains.getTrainByName(trainName);
Iteration iteration = train.getIterations().getIterationByName(iterationName);
return connector.getTicketsFor(train, iteration, forCurrentUser ? credentials : null).toString();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2014 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.cli;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* @author Oliver Gierke
*/
@Component
public class ModelCommands implements CommandMarker {
@CliCommand("trains")
public String train(@CliOption(key = { "", "train" }) String trainName) {
if (StringUtils.hasText(trainName)) {
return ReleaseTrains.getTrainByName(trainName).toString();
}
List<String> names = new ArrayList<>();
for (Train train : ReleaseTrains.TRAINS) {
names.add(train.getName());
}
return StringUtils.collectionToDelimitedString(names, ", ");
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2014 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.cli;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.maven.MavenOperations;
import org.springframework.data.release.maven.Pom;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.stereotype.Component;
/**
* @author Oliver Gierke
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ReleaseCommands implements CommandMarker {
private final MavenOperations mavenOperations;
@CliCommand("release predict")
public String predictTrainAndIteration() throws IOException {
Project commons = ReleaseTrains.COMMONS;
Pom pom = mavenOperations.getMavenProject(commons);
for (Train train : ReleaseTrains.TRAINS) {
Module module = train.getModule(commons);
if (!pom.getVersion().startsWith(module.getVersion().toMajorMinorBugfix())) {
continue;
}
return train.getName();
}
return null;
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2014 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.cli;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.shell.plugin.BannerProvider;
import org.springframework.shell.support.util.FileUtils;
import org.springframework.shell.support.util.OsUtils;
import org.springframework.stereotype.Component;
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
class SpringDataReleaseCliBannerProvider implements BannerProvider {
/*
* (non-Javadoc)
* @see org.springframework.shell.plugin.NamedProvider#getProviderName()
*/
@Override
public String getProviderName() {
return "Spring Data Release Shell";
}
/*
* (non-Javadoc)
* @see org.springframework.shell.plugin.BannerProvider#getBanner()
*/
@Override
public String getBanner() {
StringBuilder builder = new StringBuilder();
builder.append(FileUtils.readBanner(SpringDataReleaseCliBannerProvider.class, "banner.txt"));
builder.append(getVersion()).append(OsUtils.LINE_SEPARATOR);
builder.append(OsUtils.LINE_SEPARATOR);
return builder.toString();
}
/*
* (non-Javadoc)
* @see org.springframework.shell.plugin.BannerProvider#getVersion()
*/
@Override
public String getVersion() {
return "1.0";
}
/*
* (non-Javadoc)
* @see org.springframework.shell.plugin.BannerProvider#getWelcomeMessage()
*/
@Override
public String getWelcomeMessage() {
return "Welcome to the Spring Data Release Shell!";
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2014 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.cli;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.shell.plugin.PromptProvider;
import org.springframework.stereotype.Component;
/**
* @author Oliver Gierke
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class SpringDataReleaseCliPromptProvider implements PromptProvider {
/*
* (non-Javadoc)
* @see org.springframework.shell.plugin.PromptProvider#getPrompt()
*/
@Override
public String getPrompt() {
return "$ ";
}
/*
* (non-Javadoc)
* @see org.springframework.shell.plugin.NamedProvider#getProviderName()
*/
@Override
public String getProviderName() {
return "spring-data-release-cli";
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2014 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.git;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.shell.core.CommandMarker;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* @author Oliver Gierke
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GiCommands implements CommandMarker {
private final GitOperations gitOperations;
@CliCommand("git update")
public void checkout(@CliOption(key = { "train" }, mandatory = true) String trainName) throws IOException,
InterruptedException {
gitOperations.update(ReleaseTrains.getProjectByName(trainName));
}
@CliCommand("git tags")
public String tags(@CliOption(key = { "project" }, mandatory = true) String projectName) throws IOException {
Project project = ReleaseTrains.getProjectByName(projectName);
return StringUtils.collectionToDelimitedString(gitOperations.getTags(project), "\n");
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2014 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.git;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.io.CommandExecution;
import org.springframework.data.release.io.OsCommandOperations;
import org.springframework.data.release.io.Workspace;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.Project;
import org.springframework.data.release.model.Train;
import org.springframework.shell.support.logging.HandlerUtils;
import org.springframework.stereotype.Component;
/**
* @author Oliver Gierke
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GitOperations {
private static final Logger LOGGER = HandlerUtils.getLogger(GitOperations.class);
private final GitServer server = new GitServer();
private final OsCommandOperations osCommandOperations;
private final Workspace workspace;
public GitProject getGitProject(Project project) {
return new GitProject(project, server);
}
public void update(Train train) throws IOException, InterruptedException {
List<CommandExecution> executions = new ArrayList<>();
for (Module module : train) {
executions.add(update(module.getProject()));
}
for (CommandExecution execution : executions) {
execution.waitForResult();
}
}
public CommandExecution update(Project project) throws IOException {
GitProject gitProject = new GitProject(project, server);
String repositoryName = gitProject.getRepositoryName();
if (workspace.hasProjectDirectory(project)) {
LOGGER.info(String.format("Found existing repository %s. Obtaining latest changes…", repositoryName));
return osCommandOperations.executeCommand("git pull origin master", project);
} else {
File projectDirectory = workspace.getProjectDirectory(project);
LOGGER.info(String.format("No repository found for project %s. Cloning repository from %s…", repositoryName,
gitProject.getProjectUri()));
return osCommandOperations.executeCommand(String.format("git clone %s %s", gitProject.getProjectUri(),
projectDirectory.getName()));
}
}
public List<Tag> getTags(Project project) throws IOException {
CommandExecution command = osCommandOperations.executeCommand("git tag -l", project);
List<Tag> tags = new ArrayList<>();
for (String line : command.waitAndGetOutput().split("\n")) {
tags.add(new Tag(line));
}
return tags;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2014 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.git;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
import org.springframework.data.release.model.Project;
/**
* @author Oliver Gierke
*/
@EqualsAndHashCode
@RequiredArgsConstructor
public class GitProject {
private static final String PROJECT_PREFIX = "spring-data";
private final Project project;
private final GitServer server;
public String getRepositoryName() {
return String.format("%s-%s", PROJECT_PREFIX, project.getName().toLowerCase());
}
public String getProjectUri() {
return server.getUri() + getRepositoryName();
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2014 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.git;
/**
* @author Oliver Gierke
*/
public class GitServer {
private static final String SERVER_URI = "https://www.github.com/spring-projects/";
public String getUri() {
return SERVER_URI;
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2014 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.git;
import lombok.Value;
/**
* @author Oliver Gierke
*/
@Value
public class Tag {
private final String name;
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2014 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.io;
import java.io.StringWriter;
import lombok.RequiredArgsConstructor;
import org.apache.commons.exec.DefaultExecuteResultHandler;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Oliver Gierke
*/
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CommandExecution {
private final DefaultExecuteResultHandler resultHandler;
private final StringWriter writer;
private String output;
public Exception getException() {
return resultHandler.getException();
}
public int getExitValue() {
return resultHandler.getExitValue();
}
public String waitAndGetOutput() {
if (output != null) {
return output;
}
try {
waitForResult();
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
this.output = writer.toString();
IOUtils.closeQuietly(writer);
return output;
}
public void waitForResult() throws InterruptedException {
resultHandler.waitFor();
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2011-2012 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.io;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import lombok.RequiredArgsConstructor;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecuteResultHandler;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.io.output.WriterOutputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.model.Project;
import org.springframework.stereotype.Component;
/**
* Implementation of {@link OsCommandOperations} interface.
*
* @author Stefan Schmidt
* @author Oliver Gierke
* @since 1.2.0
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
class IoConfigAwareOsCommandOperations implements OsCommandOperations {
private final Workspace workspace;
/*
* (non-Javadoc)
* @see org.springframework.shell.commands.OsOperations#executeCommand(java.lang.String)
*/
public CommandExecution executeCommand(String command) throws IOException {
return executeCommand(command, (String) null);
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.io.OsCommandOperations#executeCommand(java.lang.String, org.springframework.data.release.model.Project)
*/
@Override
public CommandExecution executeCommand(String command, Project project) throws IOException {
return executeCommand(command, workspace.getProjectDirectory(project));
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.io.OsCommandOperations#executeCommand(java.lang.String, java.io.File)
*/
@Override
public CommandExecution executeCommand(String command, String subfolder) throws IOException {
File workingDirectory = workspace.getWorkingDirectory();
File executionDirectory = subfolder == null ? workingDirectory : new File(workingDirectory, subfolder);
return executeCommand(command, executionDirectory);
}
private CommandExecution executeCommand(String command, File executionDirectory) throws IOException {
StringWriter writer = new StringWriter();
WriterOutputStream outputStream = new WriterOutputStream(writer);
CommandLine commandLine = CommandLine.parse(command);
DefaultExecuteResultHandler executeResultHandler = new DefaultExecuteResultHandler();
DefaultExecutor executor = new DefaultExecutor();
executor.setWorkingDirectory(executionDirectory);
executor.setStreamHandler(new PumpStreamHandler(outputStream, null));
executor.execute(commandLine, executeResultHandler);
return new CommandExecution(executeResultHandler, writer);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2011-2012 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.io;
import java.io.IOException;
import org.springframework.data.release.model.Project;
/**
* Operations type to allow execution of native OS commands from the Spring Roo shell.
*
* @author Stefan Schmidt
* @since 1.2.0
*/
public interface OsCommandOperations {
/**
* Attempts the execution of a commands and delegates the output to the standard logger.
*
* @param command the command to execute
* @throws IOException if an error occurs
*/
CommandExecution executeCommand(String command) throws IOException;
CommandExecution executeCommand(String command, Project project) throws IOException;
CommandExecution executeCommand(String command, String subfolder) throws IOException;
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2014 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.io;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* @author Oliver Gierke
*/
@Configuration
@PropertySource("file:infrastructure.properties")
class OsConfiguration {
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2014 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.io;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.release.model.Project;
import org.springframework.stereotype.Component;
/**
* @author Oliver Gierke
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Workspace {
public static final String WORK_DIR_PROPERTY = "io.workDir";
private final Environment environment;
public File getWorkingDirectory() {
String workDir = environment.getProperty("io.workDir");
return new File(workDir.replace("~", System.getProperty("user.home")));
}
public File getProjectDirectory(Project project) {
return new File(getWorkingDirectory(), project.getName());
}
public boolean hasProjectDirectory(Project project) {
return getProjectDirectory(project).exists();
}
public File getFile(String name, Project project) {
return new File(new File(getWorkingDirectory(), project.getName()), name);
}
public boolean exists(String subfolder) {
return new File(getWorkingDirectory(), subfolder).exists();
}
@PostConstruct
public void setUp() throws IOException {
Path path = getWorkingDirectory().toPath();
if (!Files.exists(path)) {
Files.createDirectories(path);
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2014 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.jira;
import javax.xml.bind.DatatypeConverter;
import lombok.Value;
/**
* @author Oliver Gierke
*/
@Value
public class Credentials {
private final String username, password;
public String asBase64() {
return DatatypeConverter.printBase64Binary(String.format("%s:%s", username, password).getBytes());
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2014 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.jira;
import java.util.ArrayList;
import java.util.List;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author Oliver Gierke
*/
@Configuration
@EnableCaching
@PropertySource(value = "file:jira.properties", ignoreResourceNotFound = true)
class JiraConfiguration {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager();
}
@Bean
public ObjectMapper jacksonObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper;
}
@Bean
public RestTemplate restTemplate() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(jacksonObjectMapper());
List<HttpMessageConverter<?>> converters = new ArrayList<>();
converters.add(converter);
RestTemplate template = new RestTemplate();
template.setMessageConverters(converters);
return template;
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2013-2014 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.jira;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Train;
/**
* @author Oliver Gierke
*/
public interface JiraConnector {
void reset();
/**
* Returns all {@link Tickets} for the given {@link Train} and {@link Iteration}.
*
* @param train must not be {@literal null}.
* @param iteration must not be {@literal null}.
* @return
*/
Tickets getTicketsFor(Train train, Iteration iteration, Credentials credentials);
void verifyBeforeRelease(Train train, Iteration iteration);
void closeIteration(Train train, Iteration iteration, Credentials credentials);
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2014 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.jira;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.release.model.Train;
/**
* Value object to bind REST responses to.
*
* @author Oliver Gierke
*/
@Data
class JiraIssue {
private String key;
private Fields fields;
/**
* Returns whether the ticket is only fixed in the given {@link Train}. {@literal false} indicates the {@link Ticket}
* has been resolved for
*
* @param train
* @return
*/
public boolean wasBackportedFrom(Train train) {
List<FixVersions> fixVersions = fields.getFixVersions();
return !(fixVersions.size() == 1 && fixVersions.get(0).name.contains(train.getName()));
}
@Data
static class Fields {
String summary;
List<FixVersions> fixVersions;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
static class FixVersions {
String name;
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2014 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.jira;
import java.util.Iterator;
import java.util.List;
import lombok.Data;
/**
* @author Oliver Gierke
*/
@Data
class JiraIssues implements Iterable<JiraIssue> {
private int startAt;
private int maxResults;
private int total;
private List<JiraIssue> issues;
public int getNextStartAt() {
return startAt + issues.size();
}
public boolean hasMoreResults() {
return startAt + issues.size() < total;
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<JiraIssue> iterator() {
return issues.iterator();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2014 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.jira;
import lombok.Value;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.Train;
/**
* @author Oliver Gierke
*/
@Value
class JiraVersion {
private final Module module;
private final Train train;
private final Iteration iteration;
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
Iteration iteration = module.hasCustomFirstIteration() ? module.getCustomFirstIteration() : this.iteration;
if (iteration.isServiceIteration()) {
return String.format("%s.%s (%s %s)", module.getVersion(), iteration.getBugfixValue(), train.getName(),
iteration.getName());
}
return String.format("%s %s (%s)", module.getVersion(), iteration.getName(), train.getName());
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2014 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.jira;
import java.util.ArrayList;
import java.util.List;
import lombok.Value;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.Train;
import org.springframework.util.StringUtils;
/**
* @author Oliver Gierke
*/
@Value
class JqlQuery {
private static final String PROJECT_VERSION_TEMPLATE = "project = %s AND fixVersion = \"%s\"";
private final String query;
public JqlQuery and(String clause) {
return new JqlQuery(String.format("(%s) AND %s", query, clause));
}
public JqlQuery orderBy(String orderBy) {
return new JqlQuery(String.format("%s ORDER BY %s", query, orderBy));
}
public static JqlQuery from(Train train, Iteration iteration) {
List<String> parts = new ArrayList<>();
for (Module module : train) {
JiraVersion version = new JiraVersion(module, train, iteration);
parts.add(String.format(PROJECT_VERSION_TEMPLATE, module.getProject().getKey(), version));
}
return new JqlQuery(StringUtils.collectionToDelimitedString(parts, " OR "));
}
@Override
public String toString() {
return query;
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2013 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.jira;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Train;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestOperations;
/**
* @author Oliver Gierke
*/
@Component
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
class RestJiraConnector implements JiraConnector {
protected final Logger LOGGER = Logger.getLogger(getClass().getName());
private static final String JIRA_HOST = "https://jira.spring.io";
private static final String BASE_URI = "/rest/api/2";
private static final String SEARCH_TEMPLATE = JIRA_HOST + BASE_URI
+ "/search?jql={jql}&fields={fields}&startAt={startAt}";
private final RestOperations operations;
/*
* (non-Javadoc)
* @see org.springframework.data.release.jira.JiraConnector#flushTickets()
*/
@Override
@CacheEvict(value = "tickets", allEntries = true)
public void reset() {
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.jira.JiraConnector#getTicketsFor(org.springframework.data.release.model.Train, org.springframework.data.release.model.Iteration, org.springframework.data.release.jira.Credentials)
*/
@Override
@Cacheable("tickets")
public Tickets getTicketsFor(Train train, Iteration iteration, Credentials credentials) {
JqlQuery query = JqlQuery.from(train, iteration);
HttpHeaders headers = new HttpHeaders();
int startAt = 0;
List<Ticket> tickets = new ArrayList<>();
JiraIssues issues = null;
if (credentials != null) {
query = query.and("assignee = currentUser()");
headers.set("Authorization", String.format("Basic %s", credentials.asBase64()));
LOGGER.info(String.format("Retrieving tickets for %s %s (for user %s).", train.getName(), iteration.getName(),
credentials.getUsername()));
} else {
LOGGER.info(String.format("Retrieving tickets for %s %s.", train.getName(), iteration.getName()));
}
query = query.orderBy("updatedDate DESC");
do {
Map<String, Object> parameters = new HashMap<>();
parameters.put("jql", query);
parameters.put("fields", "summary,fixVersions");
parameters.put("startAt", startAt);
issues = operations.exchange(SEARCH_TEMPLATE, HttpMethod.GET, new HttpEntity<>(headers), JiraIssues.class,
parameters).getBody();
LOGGER.info(String.format("Got tickets %s to %s of %s.", startAt, issues.getNextStartAt(), issues.getTotal()));
for (JiraIssue issue : issues) {
if (!issue.wasBackportedFrom(train)) {
tickets.add(new Ticket(issue.getKey(), issue.getFields().getSummary()));
}
}
startAt = issues.getNextStartAt();
} while (issues.hasMoreResults());
return new Tickets(Collections.unmodifiableList(tickets), issues.getTotal());
}
/*
* (non-Javadoc)
* @see org.springframework.data.release.jira.JiraConnector#verifyBeforeRelease(org.springframework.data.release.model.Train, org.springframework.data.release.model.Iteration)
*/
@Override
public void verifyBeforeRelease(Train train, Iteration iteration) {
// for each module
// - make sure only one ticket is open
}
/*
*
* (non-Javadoc)
* @see org.springframework.data.release.jira.JiraConnector#closeIteration(org.springframework.data.release.model.Train, org.springframework.data.release.model.Iteration, org.springframework.data.release.jira.Credentials)
*/
@Override
public void closeIteration(Train train, Iteration iteration, Credentials credentials) {
// for each module
// - close all tickets
// -- make sure only one ticket is open
// -- resolve open ticket
// -- close tickets
// - mark version as releases
// - if no next version exists, create
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2014 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.jira;
import lombok.Value;
/**
* Value object to represent a {@link Ticket}.
*
* @author Oliver Gierke
*/
@Value
public class Ticket {
private final String id;
private final String summary;
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("%13s - %s", id, summary);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2014 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.jira;
import java.util.Iterator;
import java.util.List;
import lombok.Value;
import org.springframework.util.StringUtils;
/**
* Value object to represent a list of {@link Ticket}s.
*
* @author Oliver Gierke
*/
@Value
public class Tickets implements Iterable<Ticket> {
private final List<Ticket> tickets;
private final int overallTotal;
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<Ticket> iterator() {
return tickets.iterator();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(String.format("Train only tickets: %s of %s", tickets.size(), overallTotal));
builder.append("\n");
builder.append(StringUtils.collectionToDelimitedString(tickets, "\n"));
return builder.toString();
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2014 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.maven;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.xmlbeam.ProjectionFactory;
import org.xmlbeam.XBProjector;
import org.xmlbeam.XBProjector.Flags;
import org.xmlbeam.config.DefaultXMLFactoriesConfig;
import org.xmlbeam.config.DefaultXMLFactoriesConfig.NamespacePhilosophy;
/**
* @author Oliver Gierke
*/
@Configuration
public class MavenConfig {
@Bean
public ProjectionFactory projectionFactory() {
DefaultXMLFactoriesConfig config = new DefaultXMLFactoriesConfig();
config.setNamespacePhilosophy(NamespacePhilosophy.AGNOSTIC);
return new XBProjector(config, Flags.TO_STRING_RENDERS_XML);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2014 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.maven;
import java.io.File;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.io.Workspace;
import org.springframework.data.release.model.Project;
import org.springframework.stereotype.Component;
import org.xmlbeam.ProjectionFactory;
/**
* @author Oliver Gierke
*/
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MavenOperations {
private static final String POM_XML = "pom.xml";
private final Workspace workspace;
private final ProjectionFactory projectionFactory;
public Pom getMavenProject(Project project) throws IOException {
File file = workspace.getFile(POM_XML, project);
return projectionFactory.io().file(file).read(Pom.class);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2014 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.maven;
import lombok.Value;
import org.springframework.data.release.model.Module;
/**
* @author Oliver Gierke
*/
@Value
public class MavenProject {
private final Module module;
public String getGroupId() {
return "org.springframework.data";
}
public String getArtifactId() {
return String.format("spring-data-%s", module.getProject().getName().toLowerCase());
}
public MavenVersion getVersion() {
return new MavenVersion(module.getVersion());
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2014 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.maven;
import lombok.Value;
import org.springframework.data.release.model.Version;
/**
* @author Oliver Gierke
*/
@Value
public class MavenVersion {
private final Version version;
public String getReleaseVersion() {
return String.format("%s.RELEASE", version.toMajorMinorBugfix());
}
public String getSnapshotVersion() {
return String.format("%s.BUILD-SNAPSHOT", version.toMajorMinorBugfix());
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2014 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.maven;
import org.xmlbeam.annotation.XBRead;
import org.xmlbeam.annotation.XBWrite;
/**
* @author Oliver Gierke
*/
public interface Pom {
@XBRead("/project")
Artifact getArtifactId();
@XBRead("/project/version")
String getVersion();
@XBWrite("/project/version")
void setVersion(String version);
@XBRead("/project/repositories/repository[id=\"spring-libs-snapshot\"]")
Repository getSpringRepository();
public interface Repository {
@XBRead("child::id")
String getId();
@XBRead("child::url")
String getUrl();
}
public interface Artifact {
@XBRead("child::groupId")
String getGroupId();
@XBRead("child::artifactId")
String getArtifactId();
@XBRead("child::version")
String getVersion();
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2014 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.model;
import lombok.NonNull;
import lombok.Value;
/**
* Value object to represent an individual release train iteration.
*
* @author Oliver Gierke
*/
@Value
public class Iteration {
public static final Iteration SR4 = new Iteration("SR4", null);
public static final Iteration SR3 = new Iteration("SR3", SR4);
public static final Iteration SR2 = new Iteration("SR2", SR3);
public static final Iteration SR1 = new Iteration("SR1", SR2);
public static final Iteration GA = new Iteration("GA", SR1);
public static final Iteration RC1 = new Iteration("RC1", GA);
public static final Iteration M1 = new Iteration("M1", RC1);
/**
* The name of the iteration.
*/
private final @NonNull String name;
private final Iteration next;
public boolean isPublicVersion() {
return isServiceIteration() || this.equals(GA);
}
public boolean isServiceIteration() {
return name.startsWith("SR");
}
public int getBugfixValue() {
return name.startsWith("SR") ? Integer.parseInt(name.substring(2)) : 0;
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2014 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.model;
import static org.springframework.data.release.model.Iteration.*;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import lombok.Value;
import org.springframework.util.Assert;
/**
* Value object to represent a set of {@link Iteration}s.
*
* @author Oliver Gierke
*/
@Value
public class Iterations implements Iterable<Iteration> {
public static Iterations DEFAULT = new Iterations(M1, RC1, GA, SR1, SR2, SR3, SR4);
private final List<Iteration> iterations;
/**
* Creates a new {@link Iterations} from the given {@link Iteration}.
*
* @param iterations
*/
Iterations(Iteration... iterations) {
this.iterations = Arrays.asList(iterations);
}
/**
* Returns the iteration with the given name.
*
* @param name must not be {@literal null} or empty.
* @return
*/
public Iteration getIterationByName(String name) {
Assert.hasText(name, "Name must not be null or empty!");
for (Iteration iteration : this) {
if (iteration.getName().equalsIgnoreCase(name)) {
return iteration;
}
}
return null;
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<Iteration> iterator() {
return iterations.iterator();
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2014 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.model;
import lombok.Value;
import org.springframework.util.Assert;
/**
* @author Oliver Gierke
*/
@Value
public class Module {
private final Project project;
private final Version version;
private final Iteration customFirstIteration;
public Module(Project project, String version) {
this(project, version, null);
}
public Module(Project project, String version, String customFirstIteration) {
Assert.notNull(project, "Project must not be null!");
this.project = project;
this.version = Version.parse(version);
this.customFirstIteration = customFirstIteration == null ? null
: new Iteration(customFirstIteration, Iteration.RC1);
}
public boolean hasCustomFirstIteration() {
return customFirstIteration != null;
}
public Module next(Transition transition) {
Version nextVersion = Transition.MAJOR.equals(transition) ? version.nextMajor() : version.nextMinor();
return new Module(project, nextVersion.toString());
}
@Override
public String toString() {
return String.format("Spring Data %s %s - %s", project.getName(), version, project.getKey());
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2014 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.model;
import lombok.Value;
/**
* @author Oliver Gierke
*/
@Value
public class ModuleIteration {
private final Module module;
private final Iteration iteration;
private final Train train;
public ProjectKey getProjectKey() {
return module.getProject().getKey();
}
public String getJiraVersionName() {
Iteration iteration = module.hasCustomFirstIteration() ? module.getCustomFirstIteration() : this.iteration;
return String.format("%s %s (%s)", module.getVersion(), iteration.getName(), train.getName());
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2014 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.model;
import lombok.Value;
/**
* @author Oliver Gierke
*/
@Value
public class Project {
private final ProjectKey key;
private final String name;
public Project(String key, String name) {
this.key = new ProjectKey(key);
this.name = name;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2013 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.model;
import lombok.NonNull;
import lombok.Value;
/**
* @author Oliver Gierke
*/
@Value
public class ProjectKey {
private final @NonNull String key;
@Override
public String toString() {
return key;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2013 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.model;
import lombok.Value;
import org.joda.time.LocalDate;
/**
* @author Oliver Gierke
*/
@Value
public class Release {
private final String id;
private final ProjectKey projectKey;
private final String name;
private final String description;
private final LocalDate date;
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2014 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.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Oliver Gierke
*/
public class ReleaseTrains {
public static final List<Train> TRAINS;
public static final Train CODD, DIJKSTRA, EVANS, FOWLER;
public static final Project COMMONS;
private static final Project JPA, MONGO_DB, NEO4J, SOLR, COUCHBASE, CASSANDRA, ELASTICSEARCH, REDIS, GEMFIRE, REST;
private static final List<Project> PROJECTS;
static {
COMMONS = new Project("DATACMNS", "Commons");
JPA = new Project("DATAJPA", "JPA");
MONGO_DB = new Project("DATAMONGO", "MongoDB");
NEO4J = new Project("DATAGRAPH", "Neo4j");
SOLR = new Project("DATASOLR", "Solr");
COUCHBASE = new Project("DATACOUCH", "Couchbase");
CASSANDRA = new Project("DATACASS", "Cassandra");
ELASTICSEARCH = new Project("DATAES", "Elasticsearch");
REDIS = new Project("DATAREDIS", "Redis");
GEMFIRE = new Project("SGF", "Gemfire");
REST = new Project("DATAREST", "REST");
PROJECTS = Arrays.asList(COMMONS, JPA, MONGO_DB, NEO4J, SOLR, COUCHBASE, CASSANDRA, ELASTICSEARCH, REDIS, GEMFIRE,
REST);
CODD = codd();
DIJKSTRA = dijkstra();
EVANS = DIJKSTRA.next("Evans", Transition.MINOR);
FOWLER = EVANS.next("Fowler", Transition.MAJOR);
// Trains
TRAINS = Arrays.asList(CODD, DIJKSTRA, EVANS, FOWLER);
// Train names
List<String> names = new ArrayList<>(TRAINS.size());
for (Train train : TRAINS) {
names.add(train.getName());
}
}
private static Train codd() {
Module commons = new Module(COMMONS, "1.7");
Module jpa = new Module(JPA, "1.5");
Module mongoDb = new Module(MONGO_DB, "1.4");
Module neo4j = new Module(NEO4J, "3.0");
Module solr = new Module(SOLR, "1.1");
Module rest = new Module(REST, "2.1");
return new Train("Codd", commons, jpa, mongoDb, neo4j, solr, rest);
}
private static Train dijkstra() {
Module commons = new Module(COMMONS, "1.8");
Module jpa = new Module(JPA, "1.6");
Module mongoDb = new Module(MONGO_DB, "1.5");
Module neo4j = new Module(NEO4J, "3.1");
Module solr = new Module(SOLR, "1.2");
Module couchbase = new Module(COUCHBASE, "1.1");
Module cassandra = new Module(CASSANDRA, "1.0");
Module elasticsearch = new Module(ELASTICSEARCH, "1.0", "M2");
Module gemfire = new Module(GEMFIRE, "1.4");
Module redis = new Module(REDIS, "1.3");
Module rest = new Module(REST, "2.1");
return new Train("Dijkstra", commons, jpa, mongoDb, neo4j, solr, couchbase, cassandra, elasticsearch, gemfire,
redis, rest);
}
public static Train getTrainByName(String name) {
for (Train train : TRAINS) {
if (train.getName().equalsIgnoreCase(name)) {
return train;
}
}
return null;
}
public static Project getProjectByName(String name) {
for (Project project : PROJECTS) {
if (project.getName().equalsIgnoreCase(name)) {
return project;
}
}
return null;
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2014 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.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import lombok.Value;
import org.springframework.shell.support.util.OsUtils;
import org.springframework.util.StringUtils;
/**
* @author Oliver Gierke
*/
@Value
public class Train implements Iterable<Module> {
private final String name;;
private final List<Module> modules;
private final Iterations iterations;
public Train(String name, Module... modules) {
this.name = name;
this.modules = Arrays.asList(modules);
this.iterations = Iterations.DEFAULT;
}
public Train(String name, List<Module> modules) {
this.name = name;
this.modules = Collections.unmodifiableList(modules);
this.iterations = Iterations.DEFAULT;
}
/*
* (non-Javadoc)
* @see java.lang.Iterable#iterator()
*/
@Override
public Iterator<Module> iterator() {
return modules.iterator();
}
public Module getModule(String name) {
for (Module module : this) {
if (module.getProject().getName().equals(name)) {
return module;
}
}
return null;
}
public Module getModule(Project project) {
for (Module module : this) {
if (module.getProject().equals(project)) {
return module;
}
}
return null;
}
public Train next(String name, Transition transition) {
List<Module> nextModules = new ArrayList<>();
for (Module module : modules) {
nextModules.add(module.next(transition));
}
return new Train(name, nextModules);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(name).append(OsUtils.LINE_SEPARATOR).append(OsUtils.LINE_SEPARATOR);
builder.append(StringUtils.collectionToDelimitedString(modules, OsUtils.LINE_SEPARATOR));
return builder.toString();
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2014 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.model;
/**
* @author Oliver Gierke
*/
public enum Transition {
MAJOR, MINOR;
}

View File

@@ -0,0 +1,210 @@
package org.springframework.data.release.model;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Value object to represent a Version consisting of major, minor and bugfix part.
*
* @author Oliver Gierke
*/
public class Version implements Comparable<Version> {
private final int major;
private final int minor;
private final int bugfix;
private final int build;
/**
* Creates a new {@link Version} from the given integer values. At least one value has to be given but a maximum of 4.
*
* @param parts must not be {@literal null} or empty.
*/
public Version(int... parts) {
Assert.notNull(parts);
Assert.isTrue(parts.length > 0 && parts.length < 5);
this.major = parts[0];
this.minor = parts.length > 1 ? parts[1] : 0;
this.bugfix = parts.length > 2 ? parts[2] : 0;
this.build = parts.length > 3 ? parts[3] : 0;
Assert.isTrue(major >= 0, "Major version must be greater or equal zero!");
Assert.isTrue(minor >= 0, "Minor version must be greater or equal zero!");
Assert.isTrue(bugfix >= 0, "Bugfix version must be greater or equal zero!");
Assert.isTrue(build >= 0, "Build version must be greater or equal zero!");
}
/**
* Parses the given string representation of a version into a {@link Version} object.
*
* @param version must not be {@literal null} or empty.
* @return
*/
public static Version parse(String version) {
Assert.hasText(version);
String[] parts = version.trim().split("\\.");
int[] intParts = new int[parts.length];
for (int i = 0; i < parts.length; i++) {
intParts[i] = Integer.parseInt(parts[i]);
}
return new Version(intParts);
}
/**
* Returns whether the current {@link Version} is greater (newer) than the given one.
*
* @param version
* @return
*/
public boolean isGreaterThan(Version version) {
return compareTo(version) > 0;
}
/**
* Returns whether the current {@link Version} is greater (newer) or the same as the given one.
*
* @param version
* @return
*/
public boolean isGreaterThanOrEqualTo(Version version) {
return compareTo(version) >= 0;
}
/**
* Returns whether the current {@link Version} is the same as the given one.
*
* @param version
* @return
*/
public boolean is(Version version) {
return equals(version);
}
/**
* Returns whether the current {@link Version} is less (older) than the given one.
*
* @param version
* @return
*/
public boolean isLessThan(Version version) {
return compareTo(version) < 0;
}
/**
* Returns whether the current {@link Version} is less (older) or equal to the current one.
*
* @param version
* @return
*/
public boolean isLessThanOrEqualTo(Version version) {
return compareTo(version) <= 0;
}
public Version nextMajor() {
return new Version(this.major + 1);
}
public Version nextMinor() {
return new Version(this.major, this.minor + 1);
}
public String toMajorMinorBugfix() {
return String.format("%s.%s.%s", major, minor, bugfix);
}
/*
* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(Version that) {
if (that == null) {
return 1;
}
if (major != that.major) {
return major - that.major;
}
if (minor != that.minor) {
return minor - that.minor;
}
if (bugfix != that.bugfix) {
return bugfix - that.bugfix;
}
if (build != that.build) {
return build - that.build;
}
return 0;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Version)) {
return false;
}
Version that = (Version) obj;
return this.major == that.major && this.minor == that.minor && this.bugfix == that.bugfix
&& this.build == that.build;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = 17;
result += 31 * major;
result += 31 * minor;
result += 31 * bugfix;
result += 31 * build;
return result;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
List<Integer> digits = new ArrayList<Integer>();
digits.add(major);
digits.add(minor);
if (build != 0 || bugfix != 0) {
digits.add(bugfix);
}
if (build != 0) {
digits.add(build);
}
return StringUtils.collectionToDelimitedString(digits, ".");
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.springframework.data.release" />
</beans>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.data" level="warn" />
<root level="error">
<appender-ref ref="console" />
</root>
</configuration>

View File

@@ -0,0 +1,8 @@
_____ _ _____ _ _____ _ _____ _ _ _
/ ____| (_) | __ \ | | | __ \ | | / ____| | | | |
| (___ _ __ _ __ _ _ __ __ _ | | | | __ _| |_ __ _ | |__) |___| | ___ __ _ ___ ___ | (___ | |__ ___| | |
\___ \| '_ \| '__| | '_ \ / _` | | | | |/ _` | __/ _` | | _ // _ \ |/ _ \/ _` / __|/ _ \ \___ \| '_ \ / _ \ | |
____) | |_) | | | | | | | (_| | | |__| | (_| | || (_| | | | \ \ __/ | __/ (_| \__ \ __/ ____) | | | | __/ | |
|_____/| .__/|_| |_|_| |_|\__, | |_____/ \__,_|\__\__,_| |_| \_\___|_|\___|\__,_|___/\___| |_____/|_| |_|\___|_|_|
| | __/ |
|_| |___/

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2014 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;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
public abstract class AbstractIntegrationTests {
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2014 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;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author Oliver Gierke
*/
@Configuration
@ComponentScan
public class TestConfig {
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2014 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.cli;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.AbstractIntegrationTests;
/**
* @author Oliver Gierke
*/
public class ReleaseCommandsIntegrationTests extends AbstractIntegrationTests {
@Autowired ReleaseCommands releaseCommands;
@Test
public void foo() throws IOException {
assertThat(releaseCommands.predictTrainAndIteration(), is("Dijkstra"));
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2014 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.git;
import java.io.IOException;
import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.release.AbstractIntegrationTests;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.util.StringUtils;
/**
* @author Oliver Gierke
*/
public class GitOperationsIntegrationTests extends AbstractIntegrationTests {
@Autowired GitOperations gitOperations;
@Test
public void testname() throws IOException, InterruptedException {
gitOperations.update(ReleaseTrains.CODD);
}
@Test
public void showTags() throws IOException {
List<Tag> tags = gitOperations.getTags(ReleaseTrains.COMMONS);
System.out.println(StringUtils.collectionToDelimitedString(tags, "\n"));
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2014 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.git;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.data.release.model.ReleaseTrains;
import org.springframework.data.release.model.Train;
/**
* @author Oliver Gierke
*/
public class GitProjectUnitTests {
@Test
public void testname() {
Train codd = ReleaseTrains.CODD;
GitProject project = new GitProject(codd.getModule("Commons").getProject(), new GitServer());
assertThat(project.getProjectUri(), is("https://www.github.com/spring-projects/spring-data-commons"));
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2014 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.io;
import java.io.File;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author Oliver Gierke
*/
public class OsConfigurationIntegrationTests {
@Test
@Ignore
public void testname() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(OsConfiguration.class);
File file = new File(context.getEnvironment().getProperty("io.workDir"));
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2014 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.jira;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.data.release.model.Iteration;
import org.springframework.data.release.model.Module;
import org.springframework.data.release.model.ReleaseTrains;
/**
* @author Oliver Gierke
*/
public class JiraVersionUnitTests {
@Test
public void rendersJiraGaVersionCorrectly() {
assertIterationVersion(Iteration.M1, "1.8 M1 (Dijkstra)");
assertIterationVersion(Iteration.RC1, "1.8 RC1 (Dijkstra)");
assertIterationVersion(Iteration.GA, "1.8 GA (Dijkstra)");
assertIterationVersion(Iteration.SR1, "1.8.1 (Dijkstra SR1)");
assertIterationVersion(Iteration.SR2, "1.8.2 (Dijkstra SR2)");
assertIterationVersion(Iteration.SR3, "1.8.3 (Dijkstra SR3)");
assertIterationVersion(Iteration.SR4, "1.8.4 (Dijkstra SR4)");
}
@Test
public void usesCustomModuleIterationStartVersion() {
Module commons = ReleaseTrains.DIJKSTRA.getModule("Elasticsearch");
JiraVersion version = new JiraVersion(commons, ReleaseTrains.DIJKSTRA, Iteration.M1);
assertThat(version.toString(), is("1.0 M2 (Dijkstra)"));
}
private void assertIterationVersion(Iteration iteration, String expected) {
Module commons = ReleaseTrains.DIJKSTRA.getModule("Commons");
JiraVersion version = new JiraVersion(commons, ReleaseTrains.DIJKSTRA, iteration);
assertThat(version.toString(), is(expected));
}
}