From afb929cae874e300b5503dcd5121bdafe781f382 Mon Sep 17 00:00:00 2001 From: Hakan Uygun Date: Sun, 14 Nov 2021 15:09:51 +0300 Subject: [PATCH] feat: Redmine Support Redmine issue tracker support added --- README.md | 2 +- .../gitchangelog/api/GitChangelogApi.java | 36 ++++++++++ .../api/GitChangelogApiConstants.java | 1 + .../bjurr/gitchangelog/api/model/Issue.java | 5 ++ .../gitchangelog/api/model/IssueType.java | 5 ++ .../redmine/DefaultRedmineClient.java | 59 ++++++++++++++++ .../integrations/redmine/RedmineClient.java | 53 +++++++++++++++ .../redmine/RedmineClientFactory.java | 25 +++++++ .../integrations/redmine/RedmineIssue.java | 44 ++++++++++++ .../internal/issues/IssueParser.java | 58 +++++++++++++++- .../internal/settings/IssuesUtil.java | 24 +++++++ .../internal/settings/Settings.java | 57 ++++++++++++++++ .../internal/settings/SettingsIssueType.java | 3 +- .../gitchangelog/api/GitChangelogApiTest.java | 10 +++ .../bjurr/gitchangelog/api/TemplatesTest.java | 11 +++ .../redmine/RedmineClientIntegrationTest.java | 48 +++++++++++++ .../redmine/RedmineClientTest.java | 68 +++++++++++++++++++ src/test/resources/redmine-issue-1234.json | 44 ++++++++++++ .../settings/git-changelog-test-settings.json | 5 ++ .../templatetest/testIssueType.mustache | 1 + 20 files changed, 556 insertions(+), 3 deletions(-) create mode 100644 src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/DefaultRedmineClient.java create mode 100644 src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClient.java create mode 100644 src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientFactory.java create mode 100644 src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineIssue.java create mode 100644 src/test/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientIntegrationTest.java create mode 100644 src/test/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientTest.java create mode 100644 src/test/resources/redmine-issue-1234.json diff --git a/README.md b/README.md index 8a2064f1..22aa5568 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The changelog can: - Be stored to file, like `CHANGELOG.md`. There are some templates used for testing available [here](/src/test/resources/templatetest). - Or, just rendered to a `String`. -It can integrate with Jira and/or GitHub to retrieve the title of issues. +It can integrate with Jira, Redmine, GitLab and/or GitHub to retrieve the title of issues. ## Usage diff --git a/src/main/java/se/bjurr/gitchangelog/api/GitChangelogApi.java b/src/main/java/se/bjurr/gitchangelog/api/GitChangelogApi.java index 15fe578d..f01a8eb2 100644 --- a/src/main/java/se/bjurr/gitchangelog/api/GitChangelogApi.java +++ b/src/main/java/se/bjurr/gitchangelog/api/GitChangelogApi.java @@ -465,6 +465,42 @@ public GitChangelogApi withJiraUsername(final String string) { return this; } + /** + * Pattern to recognize Redmine:s. #([0-9]+) + */ + public GitChangelogApi withRedmineIssuePattern(final String redmineIssuePattern) { + this.settings.setRedmineIssuePattern(redmineIssuePattern); + return this; + } + + /** Authenticate to Redmine. */ + public GitChangelogApi withRedminePassword(final String string) { + this.settings.setRedminePassword(string); + return this; + } + + /** Authenticate to Redmine with API_KEY */ + public GitChangelogApi withRedmineToken(final String string) { + this.settings.setRedmineToken(string); + return this; + } + + /** + * URL pointing at your Redmine server. When configured, the {@link Issue#getTitle()} will be + * populated with title from Redmine.
+ * https://redmineserver/ + */ + public GitChangelogApi withRedmineServer(final String redmineServer) { + this.settings.setRedmineServer(redmineServer); + return this; + } + + /** Authenticate to Redmine. */ + public GitChangelogApi withRedmineUsername(final String string) { + this.settings.setRedmineUsername(string); + return this; + } + /** * This is a "virtual issue" that is added to {@link Changelog#getIssues()}. It contains all * commits that has no issue in the commit comment. This could be used as a "wall of shame" diff --git a/src/main/java/se/bjurr/gitchangelog/api/GitChangelogApiConstants.java b/src/main/java/se/bjurr/gitchangelog/api/GitChangelogApiConstants.java index 58e0a9fe..5adc8cf0 100644 --- a/src/main/java/se/bjurr/gitchangelog/api/GitChangelogApiConstants.java +++ b/src/main/java/se/bjurr/gitchangelog/api/GitChangelogApiConstants.java @@ -14,6 +14,7 @@ public final class GitChangelogApiConstants { public static final String DEFAULT_GITHUB_ISSUE_PATTERN = "#([0-9]+)"; public static final String DEFAULT_GITLAB_ISSUE_PATTERN = "#([0-9]+)"; public static final String DEFAULT_JIRA_ISSUE_PATTEN = "\\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b"; + public static final String DEFAULT_REDMINE_ISSUE_PATTEN = "#([0-9]+)"; public static final String DEFAULT_MINOR_PATTERN = "^[Ff]eat.*"; public static final String DEFAULT_PATCH_PATTERN = null; diff --git a/src/main/java/se/bjurr/gitchangelog/api/model/Issue.java b/src/main/java/se/bjurr/gitchangelog/api/model/Issue.java index 9b5d1eaa..22555459 100644 --- a/src/main/java/se/bjurr/gitchangelog/api/model/Issue.java +++ b/src/main/java/se/bjurr/gitchangelog/api/model/Issue.java @@ -4,6 +4,7 @@ import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.GITHUB; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.GITLAB; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.JIRA; +import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.REDMINE; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.NOISSUE; import static se.bjurr.gitchangelog.internal.util.Preconditions.checkNotNull; import static se.bjurr.gitchangelog.internal.util.Preconditions.checkState; @@ -95,6 +96,10 @@ public boolean isJira() { return this.issueType == JIRA; } + public boolean isRedmine() { + return this.issueType == REDMINE; + } + public boolean isGitHub() { return this.issueType == GITHUB; } diff --git a/src/main/java/se/bjurr/gitchangelog/api/model/IssueType.java b/src/main/java/se/bjurr/gitchangelog/api/model/IssueType.java index cfe5ca8e..42668182 100644 --- a/src/main/java/se/bjurr/gitchangelog/api/model/IssueType.java +++ b/src/main/java/se/bjurr/gitchangelog/api/model/IssueType.java @@ -4,6 +4,7 @@ import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.GITHUB; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.GITLAB; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.JIRA; +import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.REDMINE; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.NOISSUE; import static se.bjurr.gitchangelog.internal.util.Preconditions.checkNotNull; import static se.bjurr.gitchangelog.internal.util.Preconditions.checkState; @@ -34,6 +35,10 @@ public boolean isJira() { return this.type == JIRA; } + public boolean isRedmine() { + return this.type == REDMINE; + } + public boolean isGitHub() { return this.type == GITHUB; } diff --git a/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/DefaultRedmineClient.java b/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/DefaultRedmineClient.java new file mode 100644 index 00000000..97e79a61 --- /dev/null +++ b/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/DefaultRedmineClient.java @@ -0,0 +1,59 @@ +package se.bjurr.gitchangelog.internal.integrations.redmine; + +import java.io.UnsupportedEncodingException; +import java.util.Base64; +import java.util.Map; +import java.util.Optional; +import se.bjurr.gitchangelog.api.exceptions.GitChangelogIntegrationException; +import se.bjurr.gitchangelog.internal.integrations.rest.RestClient; + +public class DefaultRedmineClient extends RedmineClient { + + private RestClient client; + + public DefaultRedmineClient(final String api) { + super(api); + this.client = new RestClient(); + } + + @Override + public RedmineClient withBasicCredentials(final String username, final String password) { + this.client = this.client.withBasicAuthCredentials(username, password); + return this; + } + + @Override + public RedmineClient withTokenCredentials(final String token) { + String authToken; + try { + authToken = Base64.getEncoder().encodeToString((token + ":changelog" ).getBytes("UTF-8")); + } catch (final UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + this.client = this.client.withTokenAuthCredentials(authToken); + return this; + } + + @Override + public RedmineClient withHeaders(final Map headers) { + this.client = this.client.withHeaders(headers); + return this; + } + + @Override + public Optional getIssue(final String issue) throws GitChangelogIntegrationException { + final String endpoint = this.getEndpoint(issue); + final Optional json = this.client.get(endpoint); + if (json.isPresent()) { + final String jsonString = json.get(); + try { + final RedmineIssue redmineIssue = this.toRedmineIssue(issue, jsonString); + return Optional.of(redmineIssue); + } catch (final Exception e) { + throw new GitChangelogIntegrationException("Unable to parse:\n" + jsonString, e); + } + } + return Optional.empty(); + } + +} diff --git a/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClient.java b/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClient.java new file mode 100644 index 00000000..ee773440 --- /dev/null +++ b/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClient.java @@ -0,0 +1,53 @@ +package se.bjurr.gitchangelog.internal.integrations.redmine; + +import static com.jayway.jsonpath.JsonPath.read; + +import java.util.Map; +import java.util.Optional; + +import se.bjurr.gitchangelog.api.exceptions.GitChangelogIntegrationException; + +public abstract class RedmineClient { + private final String api; + + public RedmineClient(final String api) { + if (api.endsWith("/")) { + this.api = api.substring(0, api.length() - 1); + } else { + this.api = api; + } + } + + public String getApi() { + return this.api; + } + + protected String getEndpoint(final String issue) { + final String issueNo = getIssueNumber(issue); + final String endpoint = this.api + "/issues/" + issueNo + ".json"; + return endpoint; + } + + protected RedmineIssue toRedmineIssue(final String issue, final String json) { + final String issueNo = getIssueNumber(issue); + final String title = read(json, "$.issue.subject"); + final String description = read(json, "$.issue.description"); + final String type = read(json, "$.issue.tracker.name"); + final String link = this.api + "/issues/" + issueNo; + + final RedmineIssue redmineIssue = new RedmineIssue(title, description, link, issue, type); + return redmineIssue; + } + + protected String getIssueNumber( String issue ){ + return issue.startsWith("#") ? issue.substring(1) : issue; + } + + public abstract RedmineClient withBasicCredentials(String username, String password); + + public abstract RedmineClient withTokenCredentials(String token); + + public abstract RedmineClient withHeaders(Map headers); + + public abstract Optional getIssue(String matched) throws GitChangelogIntegrationException; +} diff --git a/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientFactory.java b/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientFactory.java new file mode 100644 index 00000000..b81014cf --- /dev/null +++ b/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientFactory.java @@ -0,0 +1,25 @@ +package se.bjurr.gitchangelog.internal.integrations.redmine; + +public class RedmineClientFactory { + + private static RedmineClient redmineClient; + + public static void reset() { + redmineClient = null; + } + + /** + * The Bitbucket Server plugin uses this method to inject the Atlassian Client. + */ + public static void setRedmineClient(final RedmineClient redmineClient) { + RedmineClientFactory.redmineClient = redmineClient; + } + + public static RedmineClient createRedmineClient(final String apiUrl) { + if (redmineClient != null) { + return redmineClient; + } + return new DefaultRedmineClient(apiUrl); + } + +} diff --git a/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineIssue.java b/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineIssue.java new file mode 100644 index 00000000..ce3d5f2f --- /dev/null +++ b/src/main/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineIssue.java @@ -0,0 +1,44 @@ +package se.bjurr.gitchangelog.internal.integrations.redmine; + +public class RedmineIssue { + private final String title; + private final String link; + private final String issue; + private final String issueType; + private final String description; + + + public RedmineIssue(String title, String description, String link, String issue, String issueType ) { + this.title = title; + this.link = link; + this.issue = issue; + this.issueType = issueType; + this.description = description; + } + + public String getIssue() { + return issue; + } + + public String getLink() { + return link; + } + + public String getTitle() { + return title; + } + + public String getIssueType() { + return issueType; + } + + public String getDescription() { + + return description; + } + + @Override + public String toString() { + return "RedmineIssue [title=" + title + ", link=" + link + ", issue=" + issue + ", issueType=" + issueType + "]"; + } +} diff --git a/src/main/java/se/bjurr/gitchangelog/internal/issues/IssueParser.java b/src/main/java/se/bjurr/gitchangelog/internal/issues/IssueParser.java index 423c5430..af1bd3c2 100644 --- a/src/main/java/se/bjurr/gitchangelog/internal/issues/IssueParser.java +++ b/src/main/java/se/bjurr/gitchangelog/internal/issues/IssueParser.java @@ -8,6 +8,7 @@ import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.GITHUB; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.GITLAB; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.JIRA; +import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.REDMINE; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.NOISSUE; import java.util.ArrayList; @@ -26,6 +27,9 @@ import se.bjurr.gitchangelog.internal.integrations.jira.JiraClient; import se.bjurr.gitchangelog.internal.integrations.jira.JiraClientFactory; import se.bjurr.gitchangelog.internal.integrations.jira.JiraIssue; +import se.bjurr.gitchangelog.internal.integrations.redmine.RedmineClient; +import se.bjurr.gitchangelog.internal.integrations.redmine.RedmineClientFactory; +import se.bjurr.gitchangelog.internal.integrations.redmine.RedmineIssue; import se.bjurr.gitchangelog.internal.model.ParsedIssue; import se.bjurr.gitchangelog.internal.settings.IssuesUtil; import se.bjurr.gitchangelog.internal.settings.Settings; @@ -56,8 +60,9 @@ public List parseForIssues(final boolean useIntegrationIfConfigured final GitHubHelper gitHubHelper = useIntegrationIfConfigured ? this.createGitHubClient() : null; final JiraClient jiraClient = useIntegrationIfConfigured ? this.createJiraClient() : null; + final RedmineClient redmineClient = useIntegrationIfConfigured ? this.createRedmineClient() : null; final GitLabClient gitLabClient = useIntegrationIfConfigured ? this.createGitLabClient() : null; - + final List patterns = new IssuesUtil(this.settings).getIssues(); for (final GitCommit gitCommit : this.commits) { @@ -80,6 +85,8 @@ public List parseForIssues(final boolean useIntegrationIfConfigured this.createParsedIssue(gitLabClient, projectName, issuePattern, matchedIssue); } else if (issuePattern.getType() == JIRA) { parsedIssue = this.createParsedIssue(jiraClient, issuePattern, matchedIssue); + } else if (issuePattern.getType() == REDMINE) { + parsedIssue = this.createParsedIssue(redmineClient, issuePattern, matchedIssue); } else { parsedIssue = this.createParsedIssue(issuePattern, issueMatcher, matchedIssue); } @@ -183,6 +190,23 @@ private JiraClient createJiraClient() { return jiraClient; } + private RedmineClient createRedmineClient() { + RedmineClient redmineClient = null; + if (this.settings.getRedmineServer().isPresent()) { + redmineClient = RedmineClientFactory.createRedmineClient(this.settings.getRedmineServer().get()); + if (this.settings.getRedmineUsername().isPresent()) { + redmineClient.withBasicCredentials( + this.settings.getRedmineUsername().get(), this.settings.getRedminePassword().get()); + } else if (this.settings.getRedmineToken().isPresent()) { + redmineClient.withTokenCredentials(this.settings.getRedmineToken().get()); + } + if (this.settings.getExtendedRestHeaders() != null) { + redmineClient.withHeaders(this.settings.getExtendedRestHeaders()); + } + } + return redmineClient; + } + private GitHubHelper createGitHubClient() { GitHubHelper gitHubHelper = null; if (this.settings.getGitHubApi().isPresent()) { @@ -246,6 +270,38 @@ private ParsedIssue createParsedIssue( labels); } + private ParsedIssue createParsedIssue( + final RedmineClient redmineClient, final SettingsIssue issuePattern, final String matchedIssue) { + String link = ""; + String title = ""; + String desc = ""; + String issueType = null; + List linkedIssues = null; + List labels = null; + try { + if (redmineClient != null && redmineClient.getIssue(matchedIssue).isPresent()) { + final RedmineIssue redmineIssue = redmineClient.getIssue(matchedIssue).get(); + link = redmineIssue.getLink(); + title = redmineIssue.getTitle(); + issueType = redmineIssue.getIssueType(); + desc = redmineIssue.getDescription(); + } + } catch (final GitChangelogIntegrationException e) { + LOG.error(matchedIssue, e); + } + return new ParsedIssue( // + REDMINE, // + issuePattern.getName(), // + matchedIssue, // + desc, + link, // + title, // + issueType, // + linkedIssues, + labels); + } + + private ParsedIssue createParsedIssue( final GitHubHelper gitHubHelper, final SettingsIssue issuePattern, diff --git a/src/main/java/se/bjurr/gitchangelog/internal/settings/IssuesUtil.java b/src/main/java/se/bjurr/gitchangelog/internal/settings/IssuesUtil.java index 979e38b5..e8f3fee8 100644 --- a/src/main/java/se/bjurr/gitchangelog/internal/settings/IssuesUtil.java +++ b/src/main/java/se/bjurr/gitchangelog/internal/settings/IssuesUtil.java @@ -3,6 +3,7 @@ import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.GITHUB; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.GITLAB; import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.JIRA; +import static se.bjurr.gitchangelog.internal.settings.SettingsIssueType.REDMINE; import static se.bjurr.gitchangelog.internal.util.Preconditions.isNullOrEmpty; import java.util.ArrayList; @@ -18,6 +19,7 @@ public IssuesUtil(final Settings settings) { public List getIssues() { final List issues = new ArrayList<>(this.settings.getCustomIssues()); this.addJira(issues); + this.addRedmine(issues); this.addGitHub(issues); this.addGitLab(issues); return issues; @@ -62,4 +64,26 @@ private void addJira(final List issues) { } } } + + private void addRedmine(final List issues) { + if (!isNullOrEmpty(this.settings.getRedmineIssuePattern())) { + if (this.settings.getRedmineServer().isPresent()) { + issues.add( + new SettingsIssue( + REDMINE, + "Redmine", + this.settings.getRedmineIssuePattern(), + this.settings.getRedmineServer().orElse("") + "/issues/${PATTERN_GROUP}", + null)); + } else { + issues.add( + new SettingsIssue( + REDMINE, + "Redmine", + this.settings.getRedmineIssuePattern(), + this.settings.getRedmineServer().orElse(null), + null)); + } + } + } } diff --git a/src/main/java/se/bjurr/gitchangelog/internal/settings/Settings.java b/src/main/java/se/bjurr/gitchangelog/internal/settings/Settings.java index 2e92480f..c6dd6693 100644 --- a/src/main/java/se/bjurr/gitchangelog/internal/settings/Settings.java +++ b/src/main/java/se/bjurr/gitchangelog/internal/settings/Settings.java @@ -7,6 +7,7 @@ import static se.bjurr.gitchangelog.api.GitChangelogApiConstants.DEFAULT_GITLAB_ISSUE_PATTERN; import static se.bjurr.gitchangelog.api.GitChangelogApiConstants.DEFAULT_IGNORE_COMMITS_REGEXP; import static se.bjurr.gitchangelog.api.GitChangelogApiConstants.DEFAULT_JIRA_ISSUE_PATTEN; +import static se.bjurr.gitchangelog.api.GitChangelogApiConstants.DEFAULT_REDMINE_ISSUE_PATTEN; import static se.bjurr.gitchangelog.api.GitChangelogApiConstants.DEFAULT_MINOR_PATTERN; import static se.bjurr.gitchangelog.api.GitChangelogApiConstants.DEFAULT_NO_ISSUE_NAME; import static se.bjurr.gitchangelog.api.GitChangelogApiConstants.DEFAULT_PATCH_PATTERN; @@ -136,6 +137,22 @@ public class Settings implements Serializable { private String jiraPassword; /** Authenticate to JIRA. */ private String jiraToken; + /** + * URL pointing at your Redmine server. When configured, the {@link Issue#getTitle()} will be + * populated with title from Redmine.
+ * https://redmine/redmine + */ + private String redmineServer; + /** + * Pattern to recognize Redmine:s. #([0-9]+) + */ + private String redmineIssuePattern; + /** Authenticate to Redmine. */ + private String redmineUsername; + /** Authenticate to Redmine. */ + private String redminePassword; + /** Authenticate to Redmine whith API_KEY */ + private String redmineToken; /** * URL pointing at GitHub API. When configured, the {@link Issue#getTitle()} will be populated * with title from GitHub.
@@ -266,6 +283,14 @@ public void setJiraServer(final String jiraServer) { this.jiraServer = jiraServer; } + public void setRedmineIssuePattern(final String redmineIssuePattern) { + this.redmineIssuePattern = redmineIssuePattern; + } + + public void setRedmineServer(final String redmineServer) { + this.redmineServer = redmineServer; + } + public void addCustomIssue(final SettingsIssue customIssue) { if (this.customIssues == null) { this.customIssues = new ArrayList<>(); @@ -297,6 +322,14 @@ public Optional getJiraServer() { return ofNullable(this.jiraServer); } + public String getRedmineIssuePattern() { + return ofNullable(this.redmineIssuePattern).orElse(DEFAULT_REDMINE_ISSUE_PATTEN); + } + + public Optional getRedmineServer() { + return ofNullable(this.redmineServer); + } + public static Settings fromFile(final URL url) { try { return gson.fromJson( @@ -446,6 +479,30 @@ public Optional getJiraToken() { return ofNullable(this.jiraToken); } + public Optional getRedmineUsername() { + return ofNullable(this.redmineUsername); + } + + public void setRedminePassword(final String redminePassword) { + this.redminePassword = redminePassword; + } + + public void setRedmineToken(final String redmineToken) { + this.redmineToken = redmineToken; + } + + public void setRedmineUsername(final String redmineUsername) { + this.redmineUsername = redmineUsername; + } + + public Optional getRedminePassword() { + return ofNullable(this.redminePassword); + } + + public Optional getRedmineToken() { + return ofNullable(this.redmineToken); + } + public void setExtendedVariables(final Map extendedVariables) { this.extendedVariables = extendedVariables; } diff --git a/src/main/java/se/bjurr/gitchangelog/internal/settings/SettingsIssueType.java b/src/main/java/se/bjurr/gitchangelog/internal/settings/SettingsIssueType.java index 344319b8..a8990315 100644 --- a/src/main/java/se/bjurr/gitchangelog/internal/settings/SettingsIssueType.java +++ b/src/main/java/se/bjurr/gitchangelog/internal/settings/SettingsIssueType.java @@ -5,5 +5,6 @@ public enum SettingsIssueType { CUSTOM, JIRA, GITHUB, - GITLAB + GITLAB, + REDMINE } diff --git a/src/test/java/se/bjurr/gitchangelog/api/GitChangelogApiTest.java b/src/test/java/se/bjurr/gitchangelog/api/GitChangelogApiTest.java index 0fa6c74a..c0c0a541 100644 --- a/src/test/java/se/bjurr/gitchangelog/api/GitChangelogApiTest.java +++ b/src/test/java/se/bjurr/gitchangelog/api/GitChangelogApiTest.java @@ -18,6 +18,7 @@ import se.bjurr.gitchangelog.internal.integrations.github.GitHubMockInterceptor; import se.bjurr.gitchangelog.internal.integrations.github.GitHubServiceFactory; import se.bjurr.gitchangelog.internal.integrations.jira.JiraClientFactory; +import se.bjurr.gitchangelog.internal.integrations.redmine.RedmineClientFactory; import se.bjurr.gitchangelog.internal.integrations.rest.RestClientMock; import se.bjurr.gitchangelog.test.ApprovalsWrapper; @@ -28,6 +29,7 @@ public class GitChangelogApiTest { @Before public void before() throws Exception { JiraClientFactory.reset(); + RedmineClientFactory.reset(); this.mockedRestClient = new RestClientMock(); this.mockedRestClient // @@ -50,6 +52,13 @@ public void before() throws Exception { Files.readAllBytes( Paths.get( TemplatesTest.class.getResource("/jira-issue-jir-5262.json").toURI())), + UTF_8)) // + .addMockedResponse( + "/redmine/issues/1234.json?null", + new String( + Files.readAllBytes( + Paths.get( + TemplatesTest.class.getResource("/redmine-issue-1234.json").toURI())), UTF_8)); // mock(this.mockedRestClient); @@ -69,6 +78,7 @@ public void before() throws Exception { @After public void after() { JiraClientFactory.reset(); + RedmineClientFactory.reset(); GitHubServiceFactory.setInterceptor(null); mock(null); } diff --git a/src/test/java/se/bjurr/gitchangelog/api/TemplatesTest.java b/src/test/java/se/bjurr/gitchangelog/api/TemplatesTest.java index ea6e3b75..c43754d3 100644 --- a/src/test/java/se/bjurr/gitchangelog/api/TemplatesTest.java +++ b/src/test/java/se/bjurr/gitchangelog/api/TemplatesTest.java @@ -44,6 +44,13 @@ public void before() throws Exception { Files.readAllBytes( Paths.get( TemplatesTest.class.getResource("/jira-issue-jir-5262.json").toURI())), + UTF_8)) // + .addMockedResponse( + "/redmine/issues/1234.json?null", + new String( + Files.readAllBytes( + Paths.get( + TemplatesTest.class.getResource("/redmine-issue-1234.json").toURI())), UTF_8)); mock(mockedRestClient); @@ -75,6 +82,10 @@ public void before() throws Exception { .withJiraIssuePattern("\\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b") // .withJiraUsername("user") // .withJiraPassword("code") // + .withRedmineServer("https://redmineserver/redmine") // + .withRedmineIssuePattern("#([0-9]+)") // + .withRedmineUsername("user") // + .withRedminePassword("code") // .withGitHubApi("https://api.github.com/repos/tomasbjerre/git-changelog-lib") // .withGitHubIssuePattern("#([0-9]+)") // .withCustomIssue( diff --git a/src/test/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientIntegrationTest.java b/src/test/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientIntegrationTest.java new file mode 100644 index 00000000..b504c979 --- /dev/null +++ b/src/test/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientIntegrationTest.java @@ -0,0 +1,48 @@ +package se.bjurr.gitchangelog.internal.integrations.redmine; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + +public class RedmineClientIntegrationTest { + + private static final String EXISTING_REDMINE = "X"; + private static final String REDMINE_API_URL = "https://redmineserver/"; + private static final String USER = "U"; + private static final String PASSWORD = "P"; + private static final String TOKEN = "API_KEY"; + private static final String API_HEADER = "X-Redmine-API-Key"; + + //@Test + public void testThatIssueCanBeFound() throws Exception { + final RedmineClient client = new DefaultRedmineClient(REDMINE_API_URL) // + .withBasicCredentials(USER, PASSWORD); + final java.util.Optional issue = client.getIssue(EXISTING_REDMINE); + assertThat(issue.get().getTitle()) // + .isEqualTo("git-changelog redmine test"); + } + + //@Test + public void testThatIssueCanBeFoundWithToken() throws Exception { + final RedmineClient client = new DefaultRedmineClient(REDMINE_API_URL) // + .withTokenCredentials(TOKEN); + final java.util.Optional issue = client.getIssue(EXISTING_REDMINE); + assertThat(issue.get().getTitle()) // + .isEqualTo("git-changelog redmine test"); + } + + //@Test + public void testThatIssueCanBeFoundWithHeaders() throws Exception { + + Map headers = new HashMap<>(); + headers.put(API_HEADER, TOKEN); + final RedmineClient client = new DefaultRedmineClient(REDMINE_API_URL) // + .withHeaders(headers); + final java.util.Optional issue = client.getIssue(EXISTING_REDMINE); + assertThat(issue.get().getTitle()) // + .isEqualTo("git-changelog redmine test"); + } +} diff --git a/src/test/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientTest.java b/src/test/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientTest.java new file mode 100644 index 00000000..38b64d58 --- /dev/null +++ b/src/test/java/se/bjurr/gitchangelog/internal/integrations/redmine/RedmineClientTest.java @@ -0,0 +1,68 @@ +package se.bjurr.gitchangelog.internal.integrations.redmine; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Test; +import se.bjurr.gitchangelog.api.exceptions.GitChangelogIntegrationException; + +public class RedmineClientTest { + + @Test + public void testThatTrailingSlashIsRemoved() { + final RedmineClient client = this.createClient("https://server.com/redmine/"); + assertThat(client.getApi()) // + .isEqualTo("https://server.com/redmine"); + } + + @Test + public void testThatNoTrailingSlashUrlIsUntouched() { + final RedmineClient client = this.createClient("https://server.com/redmine"); + assertThat(client.getApi()) // + .isEqualTo("https://server.com/redmine"); + } + + @Test + public void testRemineMatcher() { + + Pattern p = Pattern.compile("#([0-9*])"); + final Matcher issueMatcher = p.matcher("refs #1234 ve #234 bişiler ve diğer şeyler"); + while (issueMatcher.find()) { + final String matchedIssue = issueMatcher.group(); + if (matchedIssue.isEmpty()) { + continue; + } + System.out.println(issueMatcher.group(1)); + } + + } + + private RedmineClient createClient(final String api) { + return new RedmineClient(api) { + + @Override + public RedmineClient withBasicCredentials(final String username, final String password) { + return null; + } + + @Override + public RedmineClient withTokenCredentials(final String token) { + return null; + } + + @Override + public RedmineClient withHeaders(final Map headers) { + return null; + } + + @Override + public Optional getIssue(final String matched) throws GitChangelogIntegrationException { + return null; + } + }; + } +} diff --git a/src/test/resources/redmine-issue-1234.json b/src/test/resources/redmine-issue-1234.json new file mode 100644 index 00000000..a1edfff5 --- /dev/null +++ b/src/test/resources/redmine-issue-1234.json @@ -0,0 +1,44 @@ +{ + "issue": { + "id": 1234, + "project": { + "id": 1, + "name": "Test" + }, + "tracker": { + "id": 2, + "name": "Feature" + }, + "status": { + "id": 4, + "name": "WIP" + }, + "priority": { + "id": 13, + "name": "Medium" + }, + "author": { + "id": 5, + "name": "Hakan Uygun" + }, + "assigned_to": { + "id": 6, + "name": "Hakan Uygun" + }, + "subject": "git-changelog-lib test", + "description": "git-changelog-lib redmine support test", + "start_date": null, + "due_date": null, + "done_ratio": 0, + "is_private": false, + "estimated_hours": null, + "total_estimated_hours": null, + "spent_hours": 0.0, + "total_spent_hours": 0.0, + "custom_fields": [ + ], + "created_on": "2021-10-23T16:28:47Z", + "updated_on": "2021-11-07T18:27:16Z", + "closed_on": null + } + } \ No newline at end of file diff --git a/src/test/resources/settings/git-changelog-test-settings.json b/src/test/resources/settings/git-changelog-test-settings.json index 5bec8891..ebed761f 100644 --- a/src/test/resources/settings/git-changelog-test-settings.json +++ b/src/test/resources/settings/git-changelog-test-settings.json @@ -19,6 +19,11 @@ "jiraUsername": "user", "jiraPassword": "code", + "redmineServer": "https://redmineserver/redmine", + "redmineIssuePattern": "#([0-9]+)", + "redmineUsername": "user", + "redminePassword": "code", + "gitHubApi": "https://api.github.com/repos/tomasbjerre/git-changelog-lib", "gitHubIssuePattern": "#([0-9]+)", diff --git a/src/test/resources/templatetest/testIssueType.mustache b/src/test/resources/templatetest/testIssueType.mustache index 6107bb14..a5fdd85f 100644 --- a/src/test/resources/templatetest/testIssueType.mustache +++ b/src/test/resources/templatetest/testIssueType.mustache @@ -7,6 +7,7 @@ isGitHub: {{isGitHub}} isGitLab: {{isGitLab}} isJira: {{isJira}} +isRedmine: {{isRedmine}} isCustom: {{isCustom}} isNoIssue: {{isNoIssue}}