diff --git a/src/main/java/org/jboss/jbossset/bugclerk/utils/RulesHelper.java b/src/main/java/org/jboss/jbossset/bugclerk/utils/RulesHelper.java
index b2c1e05..01ce489 100644
--- a/src/main/java/org/jboss/jbossset/bugclerk/utils/RulesHelper.java
+++ b/src/main/java/org/jboss/jbossset/bugclerk/utils/RulesHelper.java
@@ -4,6 +4,7 @@
import java.net.URL;
import java.util.Collection;
+import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -12,10 +13,13 @@
import org.jboss.set.aphrodite.domain.Comment;
import org.jboss.set.aphrodite.domain.FlagStatus;
import org.jboss.set.aphrodite.domain.Issue;
+import org.jboss.set.aphrodite.domain.IssueStatus;
import org.jboss.set.aphrodite.domain.IssueType;
import org.jboss.set.aphrodite.domain.Release;
import org.jboss.set.aphrodite.domain.Stream;
import org.jboss.set.aphrodite.domain.StreamComponent;
+import org.jboss.set.aphrodite.issue.trackers.jira.JiraChangelogGroup;
+import org.jboss.set.aphrodite.issue.trackers.jira.JiraChangelogItem;
import org.jboss.set.aphrodite.issue.trackers.jira.JiraIssue;
/**
*
Regroups a set of static method used by some checks.
@@ -127,6 +131,45 @@ public static boolean isPullRequestAgainstAppropriateBranch(JiraIssue issue, Aph
return false;
}
+ public static boolean isInResolvedState(JiraIssue issue) {
+ return issue.getStatus().equals(IssueStatus.MODIFIED);
+ }
+
+ public static boolean isChangedAfterResolved(List changelog) {
+ Date resolvedDate = getDateWhenResolved(changelog);
+ for (JiraChangelogGroup group : changelog) {
+ if (resolvedDate.before(group.getCreated())) {
+ if (!isAllowedChange(group.getItems()))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static Date getDateWhenResolved(List changelog) {
+ Date dateResolved = new Date();
+ for (JiraChangelogGroup group : changelog) {
+ for (JiraChangelogItem item : group.getItems()) {
+ dateResolved = isStatusChangeToResolved(item) ? group.getCreated() : dateResolved;
+ }
+ }
+ return dateResolved;
+ }
+
+ private static boolean isStatusChangeToResolved(JiraChangelogItem item) {
+ return item.getField().equalsIgnoreCase("Status") &&
+ item.getToString().equalsIgnoreCase("Resolved");
+ }
+
+ private static boolean isAllowedChange(List items) {
+ for (JiraChangelogItem item : items) {
+ if (!item.getField().equalsIgnoreCase("Status")) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private static boolean checkPullRequestsAgainstEachComponentCodebase(JiraIssue issue, Collection streams, AphroditeClient aphrodite) {
for ( StreamComponent component : streams )
if ( doesPullRequestsFilledAgainstAppropriateCodebase(issue.getPullRequests(),component,aphrodite) )
diff --git a/src/main/resources/org/jboss/jbossset/bugclerk/ChangesInResolvedState.drl b/src/main/resources/org/jboss/jbossset/bugclerk/ChangesInResolvedState.drl
new file mode 100644
index 0000000..89b9e9d
--- /dev/null
+++ b/src/main/resources/org/jboss/jbossset/bugclerk/ChangesInResolvedState.drl
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2015, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.jbossset.bugclerk;
+
+import org.jboss.set.aphrodite.domain.Issue;
+import org.jboss.set.aphrodite.domain.IssuePriority;
+import org.jboss.set.aphrodite.domain.Comment;
+import org.jboss.set.aphrodite.domain.IssueStatus;
+import org.jboss.set.aphrodite.domain.FlagStatus;
+import org.jboss.set.aphrodite.issue.trackers.jira.JiraIssue;
+
+import java.util.Date;
+
+import org.jboss.jbossset.bugclerk.Violation;
+import org.jboss.jbossset.bugclerk.Severity;
+import org.jboss.jbossset.bugclerk.utils.RulesHelper;
+
+global java.util.List list
+
+rule "ChangesInResolvedState"
+ salience 0
+ dialect "mvel"
+ when
+ $candidate : Candidate($jiraIssue: bug#JiraIssue, filtered == false);
+ eval(RulesHelper.isInResolvedState($jiraIssue) && RulesHelper.isChangedAfterResolved($jiraIssue.getChangelog()))
+ then
+ $candidate.addViolationOnce( new Violation("ChangesInResolvedState",
+ "There are changes made after issue status set to Resolved.", Severity.MAJOR) );
+end
\ No newline at end of file
diff --git a/src/test/java/org/jboss/jbossset/bugclerk/checks/ChangesInResolvedState.java b/src/test/java/org/jboss/jbossset/bugclerk/checks/ChangesInResolvedState.java
new file mode 100644
index 0000000..51cc64a
--- /dev/null
+++ b/src/test/java/org/jboss/jbossset/bugclerk/checks/ChangesInResolvedState.java
@@ -0,0 +1,137 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2017, Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.jbossset.bugclerk.checks;
+
+import org.jboss.jbossset.bugclerk.AbstractCheckRunner;
+import org.jboss.jbossset.bugclerk.Candidate;
+import org.jboss.jbossset.bugclerk.MockUtils;
+import org.jboss.jbossset.bugclerk.checks.utils.CollectionUtils;
+import org.jboss.jbossset.bugclerk.utils.RulesHelper;
+import org.jboss.set.aphrodite.domain.IssueStatus;
+import org.jboss.set.aphrodite.domain.User;
+import org.jboss.set.aphrodite.issue.trackers.jira.JiraChangelogGroup;
+import org.jboss.set.aphrodite.issue.trackers.jira.JiraChangelogItem;
+import org.jboss.set.aphrodite.issue.trackers.jira.JiraIssue;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+import static org.jboss.jbossset.bugclerk.checks.utils.AssertsHelper.assertResultsIsAsExpected;
+import static org.junit.Assert.assertEquals;
+
+public class ChangesInResolvedState extends AbstractCheckRunner {
+ private String bugId;
+ private List changelog;
+ private IssueStatus issueStatus;
+
+ @Before
+ public void resetMockData() {
+ bugId = "143794";
+ resetChangelog();
+ }
+
+ private void resetChangelog() {
+ changelog = new ArrayList<>();
+ }
+
+ @Test
+ public void testAddedPRAfterIssueInResolvedStatus() {
+ prepareChangelogWithResolvedStatus();
+ addPRToChangelog(new GregorianCalendar(2020, 1, 1).getTime());
+ testJiraIssueViolatesRules(true);
+ }
+
+ @Test
+ public void testAddedPRBeforeIssueInResolvedStatus() {
+ prepareChangelogWithResolvedStatus();
+ addPRToChangelog(new GregorianCalendar(1999, 1, 1).getTime());
+ testJiraIssueViolatesRules(false);
+ }
+
+ @Test
+ public void testAddedLinkAfterIssueInResolvedState() {
+ prepareChangelogWithResolvedStatus();
+ addLinkToChangelog(new GregorianCalendar(2020, 1, 1).getTime());
+ testJiraIssueViolatesRules(true);
+ }
+
+ @Test
+ public void testChangedStatusToOnQA() {
+ prepareChangelogWithResolvedStatus();
+ issueStatus = IssueStatus.ON_QA;
+ addStatusChangeToOnQA(new GregorianCalendar(2020, 1, 1).getTime());
+ testJiraIssueViolatesRules(false);
+ }
+
+ private void prepareChangelogWithResolvedStatus() {
+ resetChangelog();
+ issueStatus = IssueStatus.MODIFIED;
+ addResolvedStateToChangelog();
+ }
+
+ private void addResolvedStateToChangelog() {
+ Date dateResolved = new GregorianCalendar(2000, 1, 1).getTime();
+ addGroupWithItem(new JiraChangelogItem("Status", "null", "null", "null", "Resolved"), dateResolved);
+ }
+
+ private void addPRToChangelog(Date dateCreated) {
+ addGroupWithItem(new JiraChangelogItem("Git pull request", "null", "null", "null",
+ "https://github.com/jbossas/jboss-eap7/pull/578"), dateCreated);
+ }
+
+ private void addLinkToChangelog(Date dateCreated) {
+ addGroupWithItem(new JiraChangelogItem("Link", "null", "null", "null",
+ "This issue incorporates : link"), dateCreated);
+ }
+
+ private void addStatusChangeToOnQA(Date dateCreated) {
+ addGroupWithItem(new JiraChangelogItem("Status", "null", "Resolved", "null",
+ "Ready for QA"), dateCreated);
+ }
+
+ private void addGroupWithItem(JiraChangelogItem item, Date created) {
+ List items = new ArrayList<>();
+ items.add(item);
+ changelog.add(new JiraChangelogGroup(User.createWithUsername("mmarusic"), created, items));
+ }
+
+ private void testJiraIssueViolatesRules(boolean violationExpected) {
+ int numberViolationExpected = violationExpected ? 1 : 0;
+ JiraIssue jiraIssueMock = createJiraIssueMock();
+ assertResultsIsAsExpected(engine.runCheckOnBugs(CollectionUtils.asSetOf(new Candidate(jiraIssueMock)), checkName),
+ checkName, bugId, numberViolationExpected);
+ assertEquals(RulesHelper.isChangedAfterResolved(changelog), violationExpected);
+ }
+
+ private JiraIssue createJiraIssueMock() {
+ JiraIssue mock = (JiraIssue) MockUtils.mockJiraIssue(bugId, "A Summary...");
+ Mockito.when(mock.getChangelog()).thenReturn(changelog);
+ Mockito.when(mock.getStatus()).thenReturn(issueStatus);
+ Mockito.when(mock.getSprintRelease()).thenReturn("EAP 7.0.3");
+ return mock;
+ }
+}