@Override
    public void onChangeLogParsed(Run<?, ?> run, SCM scm, TaskListener listener, ChangeLogSet<?> changelog) throws Exception {

        try {
            JiraSite jiraSite = JiraSite.get(run.getParent());
            if (jiraSite == null) {
                return;
            }
            Collection<String> issueKeys = getIssueKeys(changelog, jiraSite.getIssuePattern());

            if (issueKeys.isEmpty()) {
                return;
            }
            String jql = constructJQLQuery(issueKeys);
            JiraSession session = jiraSite.getSession();
            if (session == null) {
                return;
            }
            // Query for JIRA issues
            List<Issue> issues = session.getIssuesFromJqlSearch(jql);
            Set<JiraIssue> issuesFromJqlSearch = issues == null ? Collections.emptySet() :
                issues.stream().map( JiraIssue::new ).collect( Collectors.toSet() );

            // If there are no JIRA issues, do not update the actions
            if (issuesFromJqlSearch.isEmpty()) {
                return;
            }
            // Create or update the JiraBuildAction
            JiraBuildAction action = run.getAction(JiraBuildAction.class);
            if (action == null) {
                run.addAction(new JiraBuildAction(run, issuesFromJqlSearch));
            } else {
                action.addIssues(issuesFromJqlSearch);
            }
            run.save();
        } catch (Exception e ){ // we do not want to fail the build if an issue happen here
            LOGGER.warn( "Failure executing Jira query to fetch issues. Skipping recording Jira issues.: {}", e.getMessage() );
            // stack trace in debug mode
            LOGGER.debug( e.getMessage(), e);
        }
    }
@Test
    public void onChangeLogParsedCreatesAction() throws Exception {
        JiraSCMListener listener = new JiraSCMListener();

        Job job = mock(Job.class);
        Run run = mock(Run.class);
        ChangeLogSet logSet = mock(ChangeLogSet.class);
        final ChangeLogSet.Entry entry = mock(ChangeLogSet.Entry.class);

        when(entry.getParent()).thenReturn(logSet);
        when(logSet.getRun()).thenReturn(run);
        when(run.getParent()).thenReturn(job);
        when(entry.getMsg()).thenReturn("TEST-123");

        ChangeLogSet<ChangeLogSet.Entry> set = new ChangeLogSet<ChangeLogSet.Entry>(run, null) {
            @Override
            public boolean isEmptySet() {
                return false;
            }

            @Override
            public Iterator<Entry> iterator() {
                return Collections.singletonList(entry).iterator();
            }
        };

        // Setup JIRA site
        jiraSiteMockedStatic = mockStatic(JiraSite.class);
        JiraSite site = mock(JiraSite.class);
        JiraSession session = mock(JiraSession.class);

        when(site.getIssuePattern()).thenReturn(JiraSite.DEFAULT_ISSUE_PATTERN);
        when(site.getSession()).thenReturn(session);
        when(JiraSite.get(job)).thenReturn(site);

        Issue rawIssue = mock(Issue.class);
        when(rawIssue.getKey()).thenReturn("TEST-123");
        when(rawIssue.getSummary()).thenReturn("Foo");

        when(session.getIssuesFromJqlSearch("key in ('TEST-123')")).thenReturn(Collections.singletonList(rawIssue));
        when(run.getAction(JiraBuildAction.class)).thenReturn(null);

        ArgumentCaptor<JiraBuildAction> actionArgumentCaptor = ArgumentCaptor.forClass(JiraBuildAction.class);

        listener.onChangeLogParsed(run, null,null, set);
        verify(run).addAction(actionArgumentCaptor.capture());

        JiraBuildAction action = actionArgumentCaptor.getValue();
        Assert.assertFalse(action.getIssues().isEmpty());
        JiraIssue issue = action.getIssue("TEST-123");
        Assert.assertNotNull(issue);
        Assert.assertEquals("TEST-123", issue.getKey());
    }