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; + } +}