Skip to content

Commit

Permalink
yegor256#960 Ensure release tag is valid and is higher than previous …
Browse files Browse the repository at this point in the history
…release tags
  • Loading branch information
gumbelmj committed Feb 21, 2016
1 parent 6f3c082 commit bc5c77b
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,11 @@
<version>2.1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
Expand Down
100 changes: 100 additions & 0 deletions src/main/java/com/rultor/agents/github/CommentsTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@
import com.rultor.agents.daemons.Home;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.ResourceBundle;
import java.util.regex.Pattern;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.xembly.Directive;
import org.xembly.Directives;

Expand All @@ -70,6 +76,12 @@ public final class CommentsTag extends AbstractAgent {
private static final ResourceBundle PHRASES =
ResourceBundle.getBundle("phrases");

/**
* Version pattern.
*/
private static final Pattern VERSION_PATTERN =
Pattern.compile("\\.?(?:\\d+\\.)*\\d+");

/**
* Github.
*/
Expand All @@ -94,6 +106,7 @@ public Iterable<Directive> process(final XML xml) throws IOException {
final String tag = req.xpath("args/arg[@name='tag']/text()").get(0);
final Releases.Smart rels = new Releases.Smart(issue.repo().releases());
final URI home = new Home(xml).uri();
final List<DefaultArtifactVersion> previous = this.transformVers(rels);
if (rels.exists(tag)) {
final Release.Smart rel = new Release.Smart(rels.find(tag));
rel.body(
Expand All @@ -109,6 +122,21 @@ public Iterable<Directive> process(final XML xml) throws IOException {
)
);
Logger.info(this, "duplicate tag %s commented", tag);
} else if (CommentsTag.isVersionValid(tag)
&& !CommentsTag.isReleaseValid(tag, previous)) {
issue.comments().post(
String.format(
CommentsTag.PHRASES.getString("CommentsTag.version-to-low"),
tag,
previous.toString()
)
);
Logger.info(
this,
"tag %s must be greater than previous version %s",
tag,
previous
);
} else {
final Repo repo = issue.repo();
final Date prev = CommentsTag.previous(repo);
Expand All @@ -131,6 +159,78 @@ public Iterable<Directive> process(final XML xml) throws IOException {
return new Directives();
}

/**
* Valid version numbers:
* .1
* 2.2
* .1.2
* 1.2.3.4.5.6.7
*
* Invalid version numbers:
* abc
* a.b.c
* 1.
* 1.2.
* @param version Version number from a release
* @return True if the version is valid, false otherwise
*/
public static boolean isVersionValid(final CharSequence version) {
return CommentsTag.VERSION_PATTERN.matcher(version).matches();
}

/**
* Is this tagged release valid? A tagged release is valid if it's greater
* than any previous release.
* @param tag The release to be tagged
* @param previous The previous releases
* @return True if the release is valid
*/
public static boolean isReleaseValid(final String tag,
final Collection<DefaultArtifactVersion> previous) {
final DefaultArtifactVersion max;
if (previous.isEmpty()) {
max = new DefaultArtifactVersion("0");
} else {
max = Collections.max(previous);
}
return new DefaultArtifactVersion(tag).compareTo(max) == 1;
}

/**
* Transforms the Release into a DefaultArtifactVersion.
* @param release The Release to transform
* @return A DefaultArtifactVersion
*/
private DefaultArtifactVersion transform(final Release release) {
final Release.Smart rel = new Release.Smart(release);
DefaultArtifactVersion ver = null;
try {
ver = new DefaultArtifactVersion(rel.tag());
} catch (final IOException exc) {
Logger.error(this, "Error transforming release", exc);
}
return ver;
}

/**
* Transforms versions from Release to DefaultArtifactVersion and filters
* invalid version numbers. For example in these versions,
* ["1.0", "2.0", "3.0-b"], "3.0-b" is just ignore, therefore version "2.0"
* is the max.
* @param rels All previous releases as Release objects
* @return All prior releases wrapped in a DefaultArtifactVersion
*/
private List<DefaultArtifactVersion> transformVers(final Releases rels) {
final List<DefaultArtifactVersion> versions = new ArrayList<>(1);
for (final Release release : rels.iterate()) {
final DefaultArtifactVersion ver = this.transform(release);
if (ver != null && CommentsTag.isVersionValid(ver.toString())) {
versions.add(ver);
}
}
return versions;
}

/**
* Get previous release time.
* @param repo Repo in which to find the releases.
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/phrases_en_US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ Reports.failure=Oops, I failed. You can see the full log [here](%s) (spent %[ms]
CommentsTag.duplicate=Release `%s` already exists! I can't duplicate it, \
but I posted a comment there. In the future, try to avoid duplicate releases

CommentsTag.version-to-low=Release `%s` version tag is too low! It must be \
greater than the previous release `%s`.

QnByArchitect.denied=Thanks for your request. @%s Please confirm this.

QnReferredTo.mentioned=I see you're talking about me, but I don't understand it. \
Expand Down
80 changes: 80 additions & 0 deletions src/test/java/com/rultor/agents/github/CommentsTagTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*/
package com.rultor.agents.github;

import com.jcabi.github.Comment;
import com.jcabi.github.Issue;
import com.jcabi.github.Release;
import com.jcabi.github.Releases;
Expand All @@ -37,8 +38,12 @@
import com.rultor.spi.Agent;
import com.rultor.spi.Talk;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.xembly.Directives;

Expand Down Expand Up @@ -92,6 +97,81 @@ public void duplicatesRelease() throws Exception {
);
}

/**
* CommentsTag cannot release an older version.
* @throws IOException In case of error.
*/
@Test
public void tooOldRelease() throws IOException {
final Repo repo = new MkGithub().randomRepo();
final Issue issue = repo.issues().create("", "");
final Agent agent = new CommentsTag(repo.github());
repo.releases().create("1.0");
repo.releases().create("2.0");
repo.releases().create("3.0-b");
final Talk talk = CommentsTagTest.talk(issue, "1.5");
agent.execute(talk);
final Comment.Smart response = new Comment.Smart(
repo.issues().get(1).comments().get(1)
);
MatcherAssert.assertThat(
response.body(),
Matchers.containsString("version tag is too low")
);
}

/**
* Tests the method isVersionValid.
*/
@Test
public void testIsVersionValid() {
Assert.assertTrue(
"Version 5.0 should be valid",
CommentsTag.isVersionValid("5.0")
);
Assert.assertTrue(
"Version 0.1 should be valid",
CommentsTag.isVersionValid("0.1")
);
Assert.assertTrue(
"Version .1.2.3.4 should be valid",
CommentsTag.isVersionValid(".1.2.3.4")
);
Assert.assertFalse(
"Version beta should be invalid",
CommentsTag.isVersionValid("beta")
);
Assert.assertFalse(
"Version 1.0-alpha should be invalid",
CommentsTag.isVersionValid("1.0-alpha")
);
Assert.assertFalse(
"Version 1. should be invalid",
CommentsTag.isVersionValid("1.")
);
Assert.assertFalse(
"Version a.b.c should be invalid",
CommentsTag.isVersionValid("a.b.c")
);
}

/**
* Tests the method isReleaseValid.
*/
@Test
public void testIsReleaseValid() {
final Collection<DefaultArtifactVersion> previous = new ArrayList<>(3);
previous.add(new DefaultArtifactVersion("1.0"));
previous.add(new DefaultArtifactVersion("2.0"));
previous.add(new DefaultArtifactVersion("3.0"));
final boolean valida = CommentsTag.isReleaseValid("1.0", previous);
Assert.assertFalse("Release should be invalid", valida);
final boolean validb = CommentsTag.isReleaseValid("3.0", previous);
Assert.assertFalse("Release should be invalid", validb);
final boolean validc = CommentsTag.isReleaseValid("4.0", previous);
Assert.assertTrue("Release should be valid", validc);
}

/**
* CommentsTag can create a proper release message.
* @throws Exception In case of error.
Expand Down

0 comments on commit bc5c77b

Please sign in to comment.