private void processCreatedEvent(GithubEvent event) { JiraConnector conn = new JiraConnector(config); if (event.hasIssue() && event.hasComment()) { if (event.getIssue().isReallyAPullRequest()) { // Allow comments on pull requests to link to an issue linkPullRequestToIssue(conn, event); } else { String body = event.getComment().getBody(); Matcher m = jiraCommentPattern.matcher(body); if (!m.find()) { // Comment originating on GH, post to JIRA // The JIRA issue key is in the title String issueTitle = event.getIssue().getTitle(); m = jiraIssuePattern.matcher(issueTitle); if (m.find()) { postCommentToJira(conn, m.group(1), event.getComment().getUser().getLogin(), body); } else { // The issue isn't in JIRA. Check to see if we should // import it. This is for when the service is added to // a GH repo with existing issues. Repository repo = config.getRepoForGithubName(event.getRepository().getName()); if (repo.importOnComment()) { String jiraIssueKey = processOpenedEvent(event); // Now we have to import comments GithubConnector ghConn = new GithubConnector(config); GetCommentsOnIssue get = new GetCommentsOnIssue.Builder() .withRepository(repo) .withIssueNumber(event.getIssue().getNumber()) .build(); try { List<GithubEvent.Comment> comments = ghConn.execute(get); for (Comment comment : comments) { postCommentToJira( conn, jiraIssueKey, comment.getUser().getLogin(), comment.getBody()); } } catch (ExecutionException ex) { Logger.getLogger(GithubWebhook.class.getName()).log(Level.SEVERE, null, ex); } } } } } } }
private String processOpenedEvent(GithubEvent event) { JiraConnector conn = new JiraConnector(config); String jiraIssueKey = null; if (event.hasIssue()) { String title = event.getIssue().getTitle(); Matcher m = jiraIssuePattern.matcher(title); if (m.find()) { // Originated from JIRA, need to update JIRA with issue number and external link String githubIssueField = config.getJira().getGithubIssueNumberField(); jiraIssueKey = m.group(1); UpdateIssue update = new UpdateIssue.Builder() .withCustomField(githubIssueField, event.getIssue().getNumber()) .withJiraIssueKey(jiraIssueKey) .build(); try { conn.execute(update); createExternalLink(conn, jiraIssueKey, event); } catch (ExecutionException ex) { Logger.getLogger(GithubWebhook.class.getName()).log(Level.SEVERE, null, ex); } } else { // Originated in github. Create in JIRA and add external link String githubIssueField = config.getJira().getGithubIssueNumberField(); String jiraRepoField = config.getJira().getGithubRepoNameField(); ServiceConfig.Repository repo = config.getRepoForGithubName(event.getRepository().getName()); String jiraProjectKey = repo.getJiraProjectKey(); String jiraRepoName = repo.getJiraName(); int githubIssueNumber = event.getIssue().getNumber(); String body = event.getIssue().getBody() + "\n\n[Created in Github by " + event.getIssue().getUser().getLogin() + " ]"; /* * If we're mapping milestones to eipcs, have some * work to do here. */ String epicJiraKey = null; if (repo.mapEpicsToMilestones() && event.getIssue().hasMilestone()) { Milestone ms = event.getIssue().getMilestone(); String epicName = ms.getTitle(); // Of course, they can't make this easy. Querying custom fields // requires a format of cf[xxxx] rather than, you know, the field // name. m = extractCustomFieldNumber.matcher(config.getJira().getEpicNameField()); m.find(); String cfNumber = m.group(1); String jql = "project = " + jiraProjectKey + " and cf[" + cfNumber + "] = \"" + epicName + "\""; SearchIssues search = new SearchIssues.Builder().withJQL(jql).build(); try { List<JiraEvent.Issue> epicList = conn.execute(search); // Should only return one or zero. if (!epicList.isEmpty()) { JiraEvent.Issue epic = epicList.get(0); epicJiraKey = epic.getJiraIssueKey(); } } catch (ExecutionException ex) { Logger.getLogger(GithubWebhook.class.getName()).log(Level.SEVERE, null, ex); } } CreateIssue.Builder builder = new CreateIssue.Builder() .withProjectKey(jiraProjectKey) .withIssuetype("Task") .withSummary(event.getIssue().getTitle()) .withDescription(body) .withCustomField(githubIssueField, githubIssueNumber) .withCustomField(jiraRepoField, "value", jiraRepoName); // populate any custom fields from repo config for (ServiceConfig.Repository.JiraField field : repo.getJiraFields()) { if (field.getType().equals("object")) { builder.withCustomField(field.getName(), field.getKey(), field.getValue()); } else { builder.withCustomField(field.getName(), field.getValue()); } } if (epicJiraKey != null) { builder.withCustomField(config.getJira().getEpicLinkField(), epicJiraKey); } if (repo.labelVersions()) { List<String> fixVersions = new LinkedList<>(); List<String> affectsVersions = new LinkedList<>(); for (GithubEvent.Issue.Label label : event.getIssue().getLabels()) { m = extractFixedVersion.matcher(label.getName()); if (m.find()) { fixVersions.add(m.group(1)); } else { m = extractAffectsVersion.matcher(label.getName()); if (m.find()) { affectsVersions.add(m.group(1)); } } } builder.withAffectsVersions(affectsVersions).withFixVersions(fixVersions); } if (config.hasUserMappings() && event.getIssue().hasAssignee()) { String jiraAssignee = config.getJiraUser(event.getIssue().getAssignee().getLogin()); builder.withAssignee(jiraAssignee); } try { jiraIssueKey = conn.execute(builder.build()); createExternalLink(conn, jiraIssueKey, event); } catch (ExecutionException ex) { Logger.getLogger(GithubWebhook.class.getName()).log(Level.SEVERE, null, ex); } } } else if (event.hasPullRequest()) { linkPullRequestToIssue(conn, event); } return jiraIssueKey; }
private void linkPullRequestToIssue(JiraConnector conn, GithubEvent event) { // PR created, see if it mentions a GH isse or JIRA issue // If it does, update in JIRA. String body; if (event.hasPullRequest()) { body = event.getPullRequest().getBody(); } else // It's a pull request comment, disguised as an issue (wrapped in an Enigma) { body = event.getComment().getBody(); } List<String> ghIssueNumbers = scanForGithubIssueMentions(body); List<String> directJiraMentions = scanForJiraIssueMentions(body); // For GH issues, we have to query JIRA and get back the issue // keys that have the issue in the github issue id field and add those // to the jira keys. List<String> ghIssueMentions = new LinkedList<>(); // Of course, they can't make this easy. Querying custom fields // requires a format of cf[xxxx] rather than, you know, the field // name. Matcher m = extractCustomFieldNumber.matcher(config.getJira().getGithubIssueNumberField()); m.find(); String cfNumber = m.group(1); ServiceConfig.Repository repo = config.getRepoForGithubName(event.getRepository().getName()); String jiraProjectKey = repo.getJiraProjectKey(); Map<String, String> jiraKeyToGhNum = new HashMap<>(); for (String ghIssueNum : ghIssueNumbers) { String jql = "project = " + jiraProjectKey + " and cf[" + cfNumber + "] = " + ghIssueNum; SearchIssues search = new SearchIssues.Builder().withJQL(jql).build(); try { List<JiraEvent.Issue> issues = conn.execute(search); for (JiraEvent.Issue issue : issues) { ghIssueMentions.add(issue.getJiraIssueKey()); jiraKeyToGhNum.put(issue.getJiraIssueKey(), ghIssueNum); } } catch (ExecutionException ex) { Logger.getLogger(GithubWebhook.class.getName()).log(Level.SEVERE, null, ex); } } // Now we have all the JIRA issues mentioned in this PR, either // directly or indirectly. Update them with the link to the PR List<String> jiraIssueKeys = new LinkedList<>(); jiraIssueKeys.addAll(directJiraMentions); jiraIssueKeys.addAll(ghIssueMentions); for (String jKey : jiraIssueKeys) { try { createExternalLink(conn, jKey, event); } catch (ExecutionException ex) { Logger.getLogger(GithubWebhook.class.getName()).log(Level.SEVERE, null, ex); } } // For direct JIRA mentions, we want to update the PR // with the GH issue #. For GH Issue nums, the JIRA key. Unfortunately when // you add an external link to a JIRA issue it doesn't send an // issue update out. It seems as though editing a PR in GH doesn't // send out a update notice which is kinda annoying on one hand, // but should work well here. GithubConnector ghConn = new GithubConnector(config); for (String jKey : jiraIssueKeys) { try { if (jiraKeyToGhNum.containsKey(jKey)) { String ghIssueNum = jiraKeyToGhNum.get(jKey); body = body.replace("#" + ghIssueNum, "#" + ghIssueNum + " (" + jKey + ")"); } else { // Get GH issue number from issue in JIRA GetIssue get = new GetIssue.Builder().withIssueKey(jKey).build(); JiraEvent.Issue issue = conn.execute(get); // update this PR body with the GH issue number if (issue.hasGithubIssueNumber(config)) { body = body.replace(jKey, jKey + " (#" + issue.getGithubIssueNumber(config) + ")"); } } if (event.hasPullRequest()) { UpdatePullRequest update = new UpdatePullRequest.Builder() .withRepository(repo) .withBody(body) .withPullRequestNumber(event.getPullRequest().getNumber()) .build(); ghConn.execute(update); } else // pull request comment { ModifyComment modify = new ModifyComment.Builder() .withBody(body) .withRepository(repo) .withCommentId(event.getComment().getId()) .build(); ghConn.execute(modify); } } catch (ExecutionException ex) { Logger.getLogger(GithubWebhook.class.getName()).log(Level.SEVERE, null, ex); } } }