Commit 305bf704 authored by Marco Villegas's avatar Marco Villegas
Browse files

Issue #493074: Added an event processor git specific plugin to back-link to...

Issue #493074: Added an event processor git specific plugin to back-link to the commit as a comment on the related issue.
parent e048966b
Loading
Loading
Loading
Loading
+86 −0
Changes for versioncontrol_project_issue/versioncontrol_project_issue_git/plugins/event_processor/VersioncontrolEventProcessorGitCommitsComment.inc: 86 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php
/**
 * @file
 * Maps issues with operations on git repositories based on commit messages.
 */

// @todo Is this possible to be added to the ctools plugins metadada?
require_once drupal_get_path('module', 'versioncontrol_project_issue_git') . '/includes/VersioncontrolEventProcessorGitOperationBase.inc';

class VersioncontrolEventProcessorGitCommitsComment extends VersioncontrolEventProcessorGitOperationBase {
  public function process(VersioncontrolEvent $event) {
    if (!$event instanceof VersioncontrolGitEvent) {
      // Not a git event.
      return;
    }
    $project_nid = db_query("SELECT nid FROM {versioncontrol_project_projects} WHERE repo_id = :repo_id", array(':repo_id' => $event->getRepository()->repo_id))->fetchField();
    if (!$project_nid) {
      // No project associated.
      return;
    }
    // We are depending on getCommitInterval(), so check we are using the right
    // synchronization plugin.
    $synchronizer = $event->getRepository()->getSynchronizer();
    if (!method_exists($synchronizer, 'getCommitInterval')) {
      watchdog('versioncontrol_project_issue', 'git_issue_mapper: Cannot use a repository synchronizer of type %type', array('%type' => get_class($synchronizer)), WATCHDOG_WARNING);
      return;
    }
    $replies_per_nid = array();
    foreach ($event as $ref) {
      if ($ref->reftype != VERSIONCONTROL_GIT_REFTYPE_BRANCH) {
        // Only process branch refs for now.
        return;
      }
      if ($ref->ff != 1) {
        // @fixme support non-ff.
        continue;
      }
      if ($ref->eventDeletedMe()) {
        // Do not announce removal.
        continue;
      }
      // Usual ff ref update.
      $commit_hashes = $synchronizer->getCommitInterval($ref->old_sha1, $ref->new_sha1);
      // Try to deal with big pushes loading operations in chunks of 500 items.
      foreach (array_chunk($commit_hashes, 500) as $commit_hashes_chunk) {
        $related_operations = $event->getRepository()->loadCommits(array(), array('revision' => $commit_hashes_chunk));
        foreach ($related_operations as $operation) {
          $nids_on_message = $this->getIssuesFromMessage($operation->message);
          if (count($nids_on_message) < 1) {
            // Nothing to do.
            continue;
          }
          $valid_issue_nids = $this->checkValidIssues($nids_on_message);
          // Group by node, since we could receive multiple commits in the same
          // event.
          foreach (node_load_multiple($valid_issue_nids) as $node) {
            $comment = theme('versioncontrol_project_issue_git_operation_comment_item', array('operation' => $operation));
            $replies_per_nid[$node->nid]['operation_comments'][] = $comment;
          }

          foreach ($valid_issue_nids as $valid_issue_nid) {
            $operation_nid_maps[] = array(
              'nid' => $valid_issue_nid,
              'vc_op_id' => $operation->vc_op_id
            );
          }
        }
      }
    }
    // Actually make the comments.
    $followup_account = user_load(variable_get('project_issue_followup_user', 0));
    foreach ($replies_per_nid as $nid => $reply) {
      $node = node_load($nid);
      $node->nodechanges_uid = $followup_account->uid;
      $node->nodechanges_comment_body = array(
        'value' => theme('item_list', array('items' => $reply['operation_comments'])),
        'format' => filter_default_format($followup_account),
      );
      // Do not send mail notifications.
      $node->nodechanges_comment_attributes = array(
        'project_issue_no_email' => TRUE,
      );
      node_save($node);
    }
  }
}
+15 −0
Changes for versioncontrol_project_issue/versioncontrol_project_issue_git/plugins/event_processor/git_commits_as_comment.inc: 15 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php
/**
 * @file
 * Event processor plugin to add a comment referencing commits in git push
 * related to an issue.
 */
$plugin = array(
  'vcs' => 'git',
  'title' => t('Git commits as comment'),
  'handler' => array(
    'class' => 'VersioncontrolEventProcessorGitCommitsComment',
    'file' => 'VersioncontrolEventProcessorGitCommitsComment.inc',
    'path' => drupal_get_path('module', 'versioncontrol_project_issue_git') . '/plugins/event_processor',
  ),
);
+71 −0
Changes for versioncontrol_project_issue/versioncontrol_project_issue_git/versioncontrol_project_issue_git.module: 71 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -90,3 +90,74 @@ function versioncontrol_project_issue_git_versioncontrol_repository_post_resync(
  }
  drupal_static_reset('versioncontrol_project_issue_git_resync_recover_' . $repository->repo_id);
}

/**
 * Implements hook_theme().
 */
function versioncontrol_project_issue_git_theme($variables) {
  return array(
    'versioncontrol_project_issue_git_operation_comment_item' => array(
      'variables' => array(
        'operation' => NULL,
      ),
    ),
  );
}

/**
 * Theme for an operation rendered inside a comment.
 */
function theme_versioncontrol_project_issue_git_operation_comment_item($variables) {
  $operation = $variables['operation'];
  $url_handler = $operation->getRepository()->getUrlHandler();
  $label_names = array();
  foreach ($operation->labels as $label) {
    $label_names[] = $label->name;
  }
  $trim_alter = array(
    'max_length' => 73,
    'word_boundary' => TRUE,
    'ellipsis' => TRUE,
    'html' => FALSE,
  );
  $revision = $operation->getBackend()->formatRevisionIdentifier($operation->revision, 'short');
  if (module_exists('commitlog')) {
    $revision = l($revision, sprintf('commitlog/commit/%d/%s', $operation->getRepository()->repo_id, $operation->revision));
  }
  $placeholders = array(
    '!revision' => $revision,
    '@labels' => implode(', ', $label_names),
    // Re-use views function.
    '@message' => views_trim_text($trim_alter, $operation->message),
  );

  if ($operation->committer_uid != 0) {
    $committer_account = user_load($operation->committer_uid);
  }
  if ($operation->author_uid != 0) {
    $author_account = user_load($operation->author_uid);
  }
  if (isset($committer_account)) {
    $placeholders['!committer'] = theme('username', array('account' => $committer_account));
    if (isset($author_account)) {
      $placeholders['!author'] = theme('username', array('account' => $author_account));
      if ($committer_account->uid == $author_account->uid) {
        return t('Commit !revision on @labels by !committer: <pre>@message</pre>', $placeholders);
      }
      else {
        return t('Commit !revision on @labels authored by !author, committed by !committer: <pre>@message</pre>', $placeholders);
      }
    }
    else {
      return t('Commit !revision on @labels by !committer: <pre>@message</pre>', $placeholders);
    }
  }
  elseif (isset($author_account)) {
    $placeholders['!author'] = theme('username', array('account' => $author_account));
    return t('Commit !revision on @labels authored by !author: <pre>@message</pre>', $placeholders);
  }
  else {
    // No uid associated yet.
    return t('Commit !revision on @labels: <pre>@message</pre>', $placeholders);
  }
}