diff --git a/versioncontrol_project.module b/versioncontrol_project.module index 56036c9..aa77484 100644 --- a/versioncontrol_project.module +++ b/versioncontrol_project.module @@ -187,6 +187,21 @@ function versioncontrol_project_repository_load($project_id) { } /** + * Asks if a versioncontrol repository has a valid project associated. + * + * @return boolean + * TRUE if the repository has a valid project associated, FALSE if not. + */ +function versioncontrol_project_repository_has_project(VersioncontrolRepository $repository) { + if (empty($repository->project_nid)) { + // No project associated. + return FALSE; + } + $node = node_load($repository->project_nid); + return project_node_is_project($node); +} + +/** * Load the project object associated with a repo. */ function versioncontrol_project_project_load($repo_id) { diff --git a/versioncontrol_project_issue/versioncontrol_project_issue.module b/versioncontrol_project_issue/versioncontrol_project_issue.module index 2afb20b..6b32fe7 100644 --- a/versioncontrol_project_issue/versioncontrol_project_issue.module +++ b/versioncontrol_project_issue/versioncontrol_project_issue.module @@ -77,6 +77,20 @@ function versioncontrol_project_issue_versioncontrol_entity_commit_delete(Versio * issues are associated). */ function versioncontrol_project_issue_versioncontrol_repository_bypassing_purge(VersioncontrolRepository $repository) { + versioncontrol_project_issue_delete_issue_operation_maps($repository); +} + +/** + * Deletes all relared issue/operation associations. + * + * @param int|VersioncontrolRepository $repository + * Repository object or its repo_id. + */ +function versioncontrol_project_issue_delete_issue_operation_maps($repository) { + if (!$repository instanceof VersioncontrolRepository) { + // Should be a repo_id. + $repository = versioncontrol_repository_load($repository); + } if (empty($repository->project_nid)) { // No project associated. return; diff --git a/versioncontrol_project_issue/versioncontrol_project_issue_git/plugins/event_processor/VersioncontrolEventProcessorGitIssueMapper.inc b/versioncontrol_project_issue/versioncontrol_project_issue_git/plugins/event_processor/VersioncontrolEventProcessorGitIssueMapper.inc index 9164b17..ae873da 100644 --- a/versioncontrol_project_issue/versioncontrol_project_issue_git/plugins/event_processor/VersioncontrolEventProcessorGitIssueMapper.inc +++ b/versioncontrol_project_issue/versioncontrol_project_issue_git/plugins/event_processor/VersioncontrolEventProcessorGitIssueMapper.inc @@ -61,22 +61,10 @@ class VersioncontrolEventProcessorGitIssueMapper implements VersioncontrolSynchr // Nothing to do. continue; } - // Make sure we are dealing with project issues. - $possible_issues = node_load_multiple($nids_on_message); - foreach ($possible_issues as $possible_issue) { - if (!project_issue_node_is_issue($possible_issue)) { - continue; - } - // Associate only if repository project is the same than issue - // project. - if (empty($possible_issue->field_project[LANGUAGE_NONE][0]['target_id'])) { - continue; - } - if ($possible_issue->field_project[LANGUAGE_NONE][0]['target_id'] != $project_nid) { - continue; - } + $valid_issue_nids = $this->checkValidIssues($nids_on_message); + foreach ($valid_issue_nids as $valid_issue_nid) { $operation_nid_maps[] = array( - 'nid' => $possible_issue->nid, + 'nid' => $valid_issue_nid, 'vc_op_id' => $operation->vc_op_id ); } @@ -127,10 +115,34 @@ class VersioncontrolEventProcessorGitIssueMapper implements VersioncontrolSynchr /** * Retrieve the issues from operation message. */ - function getIssuesFromMessage($message) { + public function getIssuesFromMessage($message) { if (preg_match_all($this->messagePattern, $message, $matches)) { return $matches[1]; } return array(); } + + /** + * Returns nids which can be associated. + */ + public function checkValidIssues($nids) { + $valid_nids = array(); + // Make sure we are dealing with project issues. + $possible_issues = node_load_multiple($nids); + foreach ($possible_issues as $possible_issue) { + if (!project_issue_node_is_issue($possible_issue)) { + continue; + } + // Associate only if repository project is the same than issue + // project. + if (empty($possible_issue->field_project[LANGUAGE_NONE][0]['target_id'])) { + continue; + } + if ($possible_issue->field_project[LANGUAGE_NONE][0]['target_id'] != $this->repository->project_nid) { + continue; + } + $valid_nids[] = $possible_issue->nid; + } + return $valid_nids; + } } diff --git a/versioncontrol_project_issue/versioncontrol_project_issue_git/versioncontrol_project_issue_git.drush.inc b/versioncontrol_project_issue/versioncontrol_project_issue_git/versioncontrol_project_issue_git.drush.inc new file mode 100644 index 0000000..7977ce4 --- /dev/null +++ b/versioncontrol_project_issue/versioncontrol_project_issue_git/versioncontrol_project_issue_git.drush.inc @@ -0,0 +1,127 @@ + 'Re-discover project issue/operation maps based on project repository commit messages using git_issue_mapper event processor plugin.', + 'arguments' => array( + 'type' => 'Either repositories, projects or operations.', + 'target' => 'A comma-delimited list of repository ids, project ids or operation ids corresponging with the type argument.', + ), + 'examples' => array( + 'drush vcpi-git-resync-maps repositories 1,2' => 'Re-discover issue/operation maps of the specified repositories.', + 'drush vcpi-git-resync-maps projects 1,2' => 'Re-discover issue/operation maps of the specified projects.', + 'drush vcpi-git-resync-maps operations 1,2' => 'Re-discover issue/operation maps of the specified operations.', + ), + 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL, + 'aliases' => array('vcpi-git-resync-maps'), + ); + + return $items; +} + +/** + * Implements hook_drush_help(). + */ +function versioncontrol_project_issue_git_drush_help($section) { + switch ($section) { + case 'drush:vc-project-issue-git-resync-maps': + return dt('This command will try to re-synchronize issue/operation maps associated with the parmeters passed.'); + } +} + +/** + * Drush callback for 'vc-project-issue-git-resync-maps'. + */ +function drush_versioncontrol_project_issue_git_vc_project_issue_git_resync_maps() { + list($type, $ids) = func_get_args(); + $ids = _convert_csv_to_array($ids); + $git_backend = versioncontrol_get_backends('git'); + + $default_event_processors = variable_get('versioncontrol_repository_plugin_defaults_git_event_processors'); + if (!in_array('git_issue_mapper', $default_event_processors)) { + // Nothing to do. + return; + } + ctools_include('plugins'); + $git_issue_mapper_plugin = ctools_get_plugins('versioncontrol', 'event_processor', 'git_issue_mapper'); + $git_issue_mapper_class_name = ctools_plugin_get_class($git_issue_mapper_plugin, 'handler'); + $git_issue_mapper_instace = new $git_issue_mapper_class_name(); + $default_event_processor_data = variable_get('versioncontrol_repository_plugin_defaults_git_event_processors_data', array()); + if (empty($default_event_processor_data['git_issue_mapper'])) { + $message = dt('Git issue mapper event processor is not yet configured.'); + drush_log($message, 'error'); + return drush_set_error('vcpi_git_resync_maps_unconfig_issue_mapper', $message); + } + switch ($type) { + case 'projects': + $projects = node_load_multiple($ids); + if (count($ids) != count($projects)) { + // Some projects were not loaded correctly. + $missing_ids = array_diff($ids, array_keys($projects)); + drush_log(dt('Some project ids were not loaded correctly: (!ids)', array('!ids' => implode(', ', $missing_ids))), 'warning'); + } + $ids = array(); + foreach ($projects as $project) { + $ids[] = $project->versioncontrol_project['repo']->repo_id; + } + print_r($ids); + case 'repositories': + $repositories = $git_backend->loadEntities('repo', $ids); + if (count($ids) != count($repositories)) { + // Some repositories were not loaded correctly. + $missing_ids = array_diff($ids, array_keys($repositories)); + drush_log(dt('Some repository ids were not loaded correctly: (!ids)', array('!ids' => implode(', ', $missing_ids))), 'warning'); + } + foreach ($repositories as $repository) { + if (!versioncontrol_project_repository_has_project($repository)) { + // Nothing to do. + continue; + } + // Remove old entries. + versioncontrol_project_issue_delete_issue_operation_maps($repository); + // Set up the plugin. + $git_issue_mapper_instace->setRepository($repository); + $git_issue_mapper_instace->setConfiguration($default_event_processor_data['git_issue_mapper']); + $operation_nid_maps = array(); + // Do a manual query for performance reasons. + $result = db_query('SELECT vc_op_id, message FROM versioncontrol_operations WHERE repo_id = :repo_id', array(':repo_id' => $repository->repo_id)); + while ($row = $result->fetchAssoc()) { + $nids_on_message = $git_issue_mapper_instace->getIssuesFromMessage($row['message']); + if (count($nids_on_message) < 1) { + // Nothing to do. + continue; + } + $valid_issue_nids = $git_issue_mapper_instace->checkValidIssues($nids_on_message); + foreach ($valid_issue_nids as $valid_issue_nid) { + $operation_nid_maps[] = array( + 'nid' => $valid_issue_nid, + 'vc_op_id' => $row['vc_op_id'], + ); + } + } + if (empty($operation_nid_maps)) { + // Nothing to do. + return; + } + // Insert mappings. + $insert_query = db_insert('versioncontrol_project_issue_operations')->fields(array('nid', 'vc_op_id')); + foreach ($operation_nid_maps as $operation_nid_map) { + $insert_query->values($operation_nid_map); + } + $insert_query->execute(); + } + break; + case 'operations': + // @todo Implement. + default: + $message = dt('"!type" type not yet implemented.', array('!type' => $type)); + return drush_set_error('vcpi_git_resync_maps_unimplemented_type', $message); + } +}