Skip to content

Commit

Permalink
BITCONDEC-5: Create JUnit tests (#5)
Browse files Browse the repository at this point in the history
* Mock CommitService and test method getCommitsOfPullRequest()

* Mock ApplicationLinkService

* Rename ApiLinkService to JiraClient and add test class for JiraClient

* Add version to bitbucket dependencies in pom.xml

* Test method getDecisionKnowledgeFromJira()

* Enable parsing of single project

* Test CompletenessMergeCheck

* Add test class for KnowledgeRest class

* Add model class and interface for pull requests

* Add screenshots to README
  • Loading branch information
kleebaum authored Oct 9, 2019
1 parent 00d9d02 commit fbbe003
Show file tree
Hide file tree
Showing 29 changed files with 1,351 additions and 252 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## 1.1.0 (2019-05-13)
## 0.1.0 (2019-05-13)


### Bug Fixes
Expand Down
64 changes: 41 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,11 @@ For example, the developers responsible for implementing a task must have at lea

## Installation

to support the release and commit standards install commitizen:
```
npm install commitizen -g
```
Install all npm modules:
```
npm install
```

## Commits and releases

after staging the files run:
```
git cz
```


to make a standard release:
```
npm run release
```

### Prerequisites

The following prerequisites are necessary to compile the plug-in from source code:

- Java 8 JDK
- Java 11 JDK
- [Atlassian SDK](https://developer.atlassian.com/docs/getting-started/set-up-the-atlassian-plugin-sdk-and-build-a-project)

### Compilation via Terminal
Expand All @@ -66,3 +44,43 @@ atlas-run
### Download of Precompiled .jar-File

The precompiled .jar-File for the latest release can be found here: https://github.com/cures-hub/cures-condec-bitbucket/releases/latest

## User Interface

The ConDec Bitbucket plugin integrates in the pull request page.
The branch can only be merged if at least one decision problem and one decision is documented for every associated Jira issue.

![Bitbucket ConDec plug-in](https://github.com/cures-hub/cures-condec-bitbucket/raw/master/doc/merge_check_tooltip.png)
*Pull request view with disabled merge possibility*

![Bitbucket ConDec plug-in](https://github.com/cures-hub/cures-condec-bitbucket/raw/master/doc/merge_check_detail.png)
*Pull request view with detailed documentation hint*

## Contribution

### Commits and Releases

to support the release and commit standards install commitizen:

```
npm install commitizen -g
```

Install all npm modules:

```
npm install
```

after staging the files run:

```
git cz
```


to make a standard release:

```
npm run release
```
Binary file added doc/merge_check_detail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/merge_check_tooltip.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/merge_check_tooltip_focused.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
75 changes: 39 additions & 36 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@
</dependency>
<dependency>
<groupId>com.atlassian.bitbucket.server</groupId>
<artifactId>bitbucket-api</artifactId>
<artifactId>bitbucket-spi</artifactId>
<version>${bitbucket.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.bitbucket.server</groupId>
<artifactId>bitbucket-spi</artifactId>
<scope>provided</scope>
<artifactId>bitbucket-test-util</artifactId>
<version>${bitbucket.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atlassian.bitbucket.server</groupId>
<artifactId>bitbucket-page-objects</artifactId>
<version>${bitbucket.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand Down Expand Up @@ -190,39 +193,39 @@
</plugin>
</plugins>
</build>

<profiles>
<!-- Creates coverage reports in target/site/jacoco/ -->
<profile>
<id>jacoco</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-version}</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<!-- attached to Maven test phase -->
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<!-- Creates coverage reports in target/site/jacoco/ -->
<profile>
<id>jacoco</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-version}</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<!-- attached to Maven test phase -->
<execution>
<id>report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>

<properties>
Expand All @@ -233,7 +236,7 @@
<jacoco-version>0.8.4</jacoco-version>
<!-- This key is used to keep the consistency between the key in atlassian-plugin.xml and the key to
generate bundle. -->
<atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
<atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package de.uhd.ifi.se.decision.management.bitbucket.merge.checks;

import java.util.Locale;
import java.util.Set;

/**
Expand All @@ -22,25 +21,4 @@ public interface CompletenessCheckHandler {
* @return set of Jira issue keys.
*/
Set<String> getJiraIssuesWithIncompleteDocumentation();

/**
* Looks for the first Jira issue key (e.g. CONDEC-1) in a String and returns the
* Jira project key (e.g. CONDEC).
*
* @param text
* that might contain a project key, e.g., a commit message, branch
* name oder pull request title.
* @return potential project key in upper case.
*/
static String retrieveProjectKey(String text) {
if (text.indexOf("-") == -1) {
// there is no Jira issue key (e.g. CONDEC-1) in the text
return "";
}
String splitted = text.split("-")[0];
String[] words = splitted.split(" ");
String projectKey = words[words.length - 1];
return projectKey.toUpperCase(Locale.ENGLISH);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
import com.atlassian.bitbucket.hook.repository.PullRequestMergeHookRequest;
import com.atlassian.bitbucket.hook.repository.RepositoryHookResult;
import com.atlassian.bitbucket.hook.repository.RepositoryMergeCheck;
import com.atlassian.bitbucket.pull.PullRequest;

import de.uhd.ifi.se.decision.management.bitbucket.merge.checks.impl.CompletenessCheckHandlerImpl;
import de.uhd.ifi.se.decision.management.bitbucket.model.PullRequest;
import de.uhd.ifi.se.decision.management.bitbucket.model.impl.PullRequestImpl;

/**
* Enforces that pull requests can only be accepted, i.e., the respective branch
Expand All @@ -26,7 +27,7 @@ public class CompletenessMergeCheck implements RepositoryMergeCheck {
@Override
public RepositoryHookResult preUpdate(@Nonnull PreRepositoryHookContext context,
@Nonnull PullRequestMergeHookRequest request) {
PullRequest pullRequest = request.getPullRequest();
PullRequest pullRequest = new PullRequestImpl(request);

CompletenessCheckHandler completenessCheckHandler = new CompletenessCheckHandlerImpl(pullRequest);
if (completenessCheckHandler.isDocumentationComplete()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,101 +1,32 @@
package de.uhd.ifi.se.decision.management.bitbucket.merge.checks.impl;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONObject;

import com.atlassian.bitbucket.commit.Commit;
import com.atlassian.bitbucket.commit.CommitService;
import com.atlassian.bitbucket.commit.CommitsBetweenRequest;
import com.atlassian.bitbucket.pull.PullRequest;
import com.atlassian.bitbucket.pull.PullRequestRef;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequestImpl;
import com.atlassian.sal.api.component.ComponentLocator;

import de.uhd.ifi.se.decision.management.bitbucket.merge.checks.CompletenessCheckHandler;
import de.uhd.ifi.se.decision.management.bitbucket.oauth.ApiLinkService;
import de.uhd.ifi.se.decision.management.bitbucket.model.PullRequest;
import de.uhd.ifi.se.decision.management.bitbucket.oauth.JiraClient;

/**
* Class to check the completeness of the documentation of decision knowledge
* related to a pull request.
*/
public class CompletenessCheckHandlerImpl implements CompletenessCheckHandler {

public static String JIRA_QUERY;
public static String PROJECT_KEY;
private PullRequest pullRequest;
public PullRequest pullRequest;
private Set<String> jiraIssuesWithIncompleteDocumentation;

public CompletenessCheckHandlerImpl(PullRequest pullRequest) {
this.pullRequest = pullRequest;
this.jiraIssuesWithIncompleteDocumentation = new HashSet<String>();
}

public Iterable<Commit> getCommitsOfPullRequest() {
try {
CommitService commitService = ComponentLocator.getComponent(CommitService.class);
CommitsBetweenRequest.Builder builder = new CommitsBetweenRequest.Builder(pullRequest);
CommitsBetweenRequest commitsBetweenRequest = builder.build();
Page<Commit> pageWithCommits = commitService.getCommitsBetween(commitsBetweenRequest,
new PageRequestImpl(0, 1048476));
return pageWithCommits.getValues();
} catch (NullPointerException e) {

}
return new ArrayList<Commit>();
}

/**
* @param commits
* @param branchId
* @return String "(TEST-5, TEST-7,etc...)"
*/
public String getJiraCallQuery(Iterable<Commit> commits, String branchId, String branchTitle) {
String query = "(";
ArrayList<String> messageList = new ArrayList<String>();

for (Commit commit : commits) {
String message = commit.getMessage();
messageList.add(message);
}
for (String message : messageList) {
// Split message after first space
if (message.contains(" ")) {
String[] parts = message.split(" ");
query = query + parts[0] + ",";
}
}

// add Branch ID
query += branchId + ",";
// add Branch Title

query += branchTitle;
// add )
query += ")";
return query;
}

@Override
public boolean isDocumentationComplete() {
// find correct query out of projects, commitMessages and BranchId
Iterable<Commit> commits = getCommitsOfPullRequest();
String pullRequestTitle = pullRequest.getTitle();
PullRequestRef pullRequestRef = pullRequest.getFromRef();
String branchName = pullRequestRef.getDisplayId();
String queryWithJiraIssues = "?jql=key in " + getJiraCallQuery(commits, pullRequestTitle, branchName);

JIRA_QUERY = queryWithJiraIssues;
PROJECT_KEY = getProjectKeyFromJiraAndCheckWhichOneCouldBe(commits, branchName, pullRequestTitle);

// get decision knowledge out of Jira
String knowledgeElementsAsJsonString = ApiLinkService.instance.getDecisionKnowledgeFromJira(queryWithJiraIssues,
PROJECT_KEY);

String knowledgeElementsAsJsonString = JiraClient.instance.getDecisionKnowledgeFromJira(pullRequest.getJiraIssueKeys());
return isDocumentationComplete(knowledgeElementsAsJsonString);
}

Expand Down Expand Up @@ -137,37 +68,6 @@ public boolean checkIfDecisionsExists(JSONArray decisions) {
return hasIssue && hasDecision;
}

public String getProjectKeyFromJiraAndCheckWhichOneCouldBe(Iterable<Commit> commits, String branchId,
String branchTitle) {
Set<String> projectKeys = ApiLinkService.instance.getCurrentActiveJiraProjects();

// check branch name, e.g. "CONDEC-1.create.a.great.plugin"
String projectKey = CompletenessCheckHandler.retrieveProjectKey(branchId);
if (isProjectKeyExisting(projectKey, projectKeys)) {
return projectKey;
}

// check pull request title, e.g. "ConDec-1: Create a great plugin"
String projectKeyInBranchName = CompletenessCheckHandler.retrieveProjectKey(branchTitle);
if (isProjectKeyExisting(projectKeyInBranchName, projectKeys)) {
return branchTitle;
}

// check commit messages
for (Commit commit : commits) {
String projectKeyInCommitMessage = CompletenessCheckHandler.retrieveProjectKey(commit.getMessage());
if (isProjectKeyExisting(projectKeyInCommitMessage, projectKeys)) {
return projectKeyInCommitMessage;
}
}

return "";
}

private boolean isProjectKeyExisting(String projectKey, Set<String> projectKeys) {
return !projectKey.isEmpty() && projectKeys.contains(projectKey);
}

public Set<String> getJiraIssuesWithIncompleteDocumentation() {
return jiraIssuesWithIncompleteDocumentation;
}
Expand Down
Loading

0 comments on commit fbbe003

Please sign in to comment.