diff --git a/pift.admin.inc b/pift.admin.inc index 091ae1c..087300a 100644 --- a/pift.admin.inc +++ b/pift.admin.inc @@ -119,6 +119,20 @@ function pift_admin_settings_form($form, &$form_state) { '#default_value' => PIFT_REGEX, '#required' => TRUE, ); + // Defines the core compatibility criteria. + $form['criteria']['pift_core'] = array( + '#type' => 'checkboxes', + '#title' => t('Core branches'), + '#description' => t('Drupal core branches that are to be tested. Issues pertaining to them will have files tested.'), + '#options' => pift_compatibility_list(), + '#default_value' => variable_get('pift_core', array()), + ); + // Release must be compatible with Drupal 6 or later in order to be tested. + foreach ($form['criteria']['pift_core']['#options'] as $key => $option) { + if ($option[0] < 6) { + unset($form['criteria']['pift_core']['#options'][$key]); + } + } // Defines project_issue issue status criteria. $form['criteria']['pift_status'] = array( '#type' => 'select', @@ -129,20 +143,6 @@ function pift_admin_settings_form($form, &$form_state) { '#options' => list_allowed_values($field), '#required' => TRUE, ); - // Defines the core compatibility criteria. - $form['criteria']['pift_core'] = array( - '#type' => 'checkboxes', - '#title' => t('Core branches'), - '#description' => t('Drupal core branches that are to be tested. Issues pertaining to them will have files tested.'), - '#options' => pift_compatibility_list(), - '#default_value' => variable_get('pift_core', array()), - ); - // Release must be compatible with Drupal 6 or later in order to be tested. - foreach ($form['criteria']['pift_core']['#options'] as $key => $option) { - if ($option[0] < 6) { - unset($form['criteria']['pift_core']['#options'][$key]); - } - } // Advanced settings container. $form['advanced'] = array( '#type' => 'fieldset', @@ -160,34 +160,62 @@ function pift_admin_settings_form($form, &$form_state) { '#default_value' => ($project ? $project->title : ''), '#required' => TRUE, ); - /* - // Defines file result expiry (i.e. retest interval). Currently disabled. + // Defines the base URL location for the git repositories. + $form['advanced']['pift_git_base_url'] = array( + '#type' => 'textfield', + '#title' => t('PIFT Git Base URL'), + '#description' => t('Base URL for Git repositories, like git://git.drupal.org/project/'), + '#default_value' => variable_get('pift_git_base_url', 'git://git.drupal.org/project/'), + '#required' => TRUE, + ); + // Defines file result expiry (i.e. retest interval). $form['advanced']['pift_retest'] = array( '#type' => 'select', '#title' => t('Re-test interval'), '#description' => t('Number of days to wait before re-testing a previously passed file.'), '#options' => array( -1, - 24 * 60 * 60, - 48 * 60 * 60, - 72 * 60 * 60, - 96 * 60 * 60, + 1 * 24 * 60 * 60, + 2 * 24 * 60 * 60, + 3 * 24 * 60 * 60, + 4 * 24 * 60 * 60, + 5 * 24 * 60 * 60, + 7 * 24 * 60 * 60, + 14 * 24 * 60 * 60, ), '#default_value' => PIFT_RETEST, '#required' => TRUE, ); $form['advanced']['pift_retest']['#options'] = drupal_map_assoc($form['advanced']['pift_retest']['#options'], 'format_interval'); $form['advanced']['pift_retest']['#options'][-1] = t('Disabled'); - */ - // Defines the base URL location for the git repositories. - $form['advanced']['pift_git_base_url'] = array( + // Defines project_issue retest issue status criteria. + $form['advanced']['pift_retest_status'] = array( + '#type' => 'select', + '#multiple' => TRUE, + '#title' => t('Issue statuses'), + '#description' => t('List of issue statuses that an issue must belong to in order to re-test a previously passed file.'), + '#default_value' => variable_get('pift_retest_status', array()), + '#options' => list_allowed_values($field), + ); + // Defines whether to retest all projects or only core + $form['advanced']['pift_retest_projects'] = array( + '#type' => 'select', + '#title' => t('Projects'), + '#description' => t('Projects for which to allow re-testing of previously tested patches.'), + '#default_value' => variable_get('pift_retest_projects', 'core'), + '#options' => array( + 'core' => t('Core project only'), + 'all' => t('All projects')), + '#required' => TRUE, + ); + // Defines the maximum number of tests to re-test + $form['advanced']['pift_retest_quantity'] = array( '#type' => 'textfield', - '#title' => t('PIFT Git Base URL'), - '#description' => t('Base URL for Git repositories, like git://git.drupal.org/project/'), - '#default_value' => variable_get('pift_git_base_url', 'git://git.drupal.org/project/'), + '#title' => t('Number of tests'), + '#description' => t('Maximum number of previously passed files to re-test on each run.'), + '#default_value' => variable_get('pift_retest_quantity', '1'), '#required' => TRUE, ); - $form['#submit'] = array('pift_admin_settings_form_submit'); return system_settings_form($form); } diff --git a/pift.cron.inc b/pift.cron.inc index b60e88a..1d9aa7a 100644 --- a/pift.cron.inc +++ b/pift.cron.inc @@ -10,66 +10,89 @@ * * Mark files for re-testing if they still meet all the criteria and the * re-test interval has passed. - * - * TODO: Update the retest query, since the upload table doesn't exist in - * Drupal 7 anymore. - * TODO: Update for the id => nid data move within pift_data */ -/* -function pift_cron_retest() { - if (PIFT_RETEST == -1) { - return; - } + +function pift_cron_retest($quantity = NULL, $count_only_flag = FALSE, $projects = array()) { $api_versions = pift_core_api_versions(); - $sids = variable_get('pift_status', array()); + $sids = variable_get('pift_retest_status', array()); + + $retest_interval = variable_get('pift_retest', -1); + if ($retest_interval == -1) { + $retest_interval = 86400; + } // Only attempt query if both values are not empty. - if ($api_versions && $sids) { - $retest_time = REQUEST_TIME - PIFT_RETEST; - - // Loop over 'ON' clause to remove an 'OR' which should be more efficient. - foreach (array('u.nid = pi.nid', 'cu.nid = pi.nid') as $clause) { - - db_query("UPDATE {pift_data} - SET status = :status - WHERE type = :type - AND id IN ( - SELECT f.fid - FROM {files} f - LEFT JOIN {upload} u - ON f.fid = u.fid - LEFT JOIN {comment_upload} cu - ON f.fid = cu.fid - - JOIN {project_issues} pi - ON " . $clause . " - JOIN {pift_project} p - ON pi.pid = p.pid - JOIN {project_release_nodes} r - ON pi.rid = r.nid - - JOIN {node} n - ON r.nid = n.nid - JOIN {taxonomy_term_node} t - ON (n.vid = t.vid AND t.tid IN (:api_versions)) - - WHERE pi.sid IN (:sids) - ) - AND status > :status2 - AND last_tested < :last_tested", - array( - ':status' => PIFT_STATUS_QUEUE, - ':type' => PIFT_TYPE_FILE, - ':api_versions' => $api_versions, - ':sids' => $sids, - ':status2' => PIFT_STATUS_SENT, - ':last_tested' => $retest_time, - )); + if (!empty($api_versions) && !empty($sids)) { + $retest_time = time() - $retest_interval; + + // Retrieve last test for each issue + $query = db_select('pift_data', 'pd'); + + // Add required table joins + $query->join('node', 'n', 'pd.nid = n.nid'); + $query->join('field_data_field_issue_status', 'fdfis', 'n.nid = fdfis.entity_id AND n.type = fdfis.bundle'); + $query->join('field_data_field_project', 'fdfp', 'n.nid = fdfp.entity_id AND n.type = fdfp.bundle'); + + // Restrict to the last test in any given issue + $query->addExpression('MAX(test_id)', 'max_id'); + $query->groupBy('pd.nid'); + + // Restrict to $quantity recent file tests which have passed and not been + // tested in the retest interval, ordered by oldest first. + if (empty($quantity)) { + $quantity = (int) variable_get('pift_retest_quantity', 1); } + $query->condition('pd.type', PIFT_TYPE_FILE, '=') + ->condition('pd.status', PIFT_STATUS_PASS, '=') + ->condition('pd.last_tested', $retest_time, '<') + ->orderBy('pd.last_tested', 'ASC') + ->range(0, $quantity); + + // Restrict to issue node types with the right status + $project_issue_types = project_issue_issue_node_types(); + $query->condition('fdfis.entity_type', 'node', '=') + ->condition('fdfis.bundle', $project_issue_types, 'IN') + ->condition('fdfis.field_issue_status_value', $sids, 'IN'); + + // Determine projects + if (!empty($projects)) { + $query->condition('fdfp.field_project_target_id', $projects, 'IN'); + } + elseif (variable_get('pift_retest_project', 'core') == 'core') { + $query->condition('fdfp.field_project_target_id', PIFT_PID, '='); + } + + // Execute query + $result = $query->execute(); + + $retest_candidates = array(); + + foreach ($result as $record) { + $retest_candidates[] = $record->max_id; + // TODO: Ensure test matches a valid API term + } + + if ($count_only_flag) { + drupal_set_message("Test Count: " . count($retest_candidates)); + return; + } + + // Update status for tests with final results (Passed or Failed) + // and which have not been tested in the retest period. + $updated = db_update('pift_data') + ->fields(array( + 'status' => PIFT_STATUS_QUEUE, + )) + ->condition('status', PIFT_STATUS_SENT, '>') + ->condition('last_tested', $retest_time, '<') + ->condition('test_id', $retest_candidates, 'IN') + ->range(0, $quantity) + ->execute(); + + drupal_set_message("Re-Tests Queued: " . $updated); } } -*/ /** * Create test batch and send it to the PIFR testing server. diff --git a/pift.drush.inc b/pift.drush.inc index 23f5f79..4bc94f3 100644 --- a/pift.drush.inc +++ b/pift.drush.inc @@ -11,14 +11,28 @@ function pift_drush_command() { $items = array(); $items['pift-cron'] = array( - 'description' => 'Requeue expired test results, test out batch, and retrieve results.', + 'description' => 'Send batch for testing, and retrieve results.', + ); + + $items['pift-cron-retest'] = array( + 'description' => 'Requeue expired test results.', + 'arguments' => array( + 'quantity' => 'Maximum number of tests to requeue. (Defaults to "3").', + ), + 'options' => array( + 'project' => array( + 'description' => 'Comma delimited list of project ids to include.', + 'value' => 'required', + ), + 'count' => 'Return the number of tests meeting the retest criteria, without queuing tests.', + ), ); return $items; } /** - * Requeue expired test results, test the batch, and retrieve results. + * Send batch for testing, and retrieve results. */ function drush_pift_cron() { module_load_include('cron.inc', 'pift'); @@ -32,3 +46,22 @@ function drush_pift_cron() { // Retrieve any results that have occured since last cron run. pift_cron_retrieve_results(); } + +/** + * Requeue expired test results + */ +function drush_pift_cron_retest($quantity = 3) { + module_load_include('cron.inc', 'pift'); + + // Requeue all tests that have passed the re-test interval + $projects = array(); + + $count_only_flag = drush_get_option('count'); + + if ($projects = drush_get_option('project')) { + pift_cron_retest($quantity, $count_only_flag, explode(',', $projects)); + } + else { + pift_cron_retest($quantity, $count_only_flag); + } +} \ No newline at end of file diff --git a/pift.module b/pift.module index 673bb0c..61690c0 100644 --- a/pift.module +++ b/pift.module @@ -17,7 +17,7 @@ define('PIFT_FOLLOWUP_FAIL', variable_get('pift_followup_fail', 0)); define('PIFT_FOLLOWUP_RETEST', variable_get('pift_followup_retest', 0)); define('PIFT_REGEX', variable_get('pift_regex', '/(\.diff|\.patch)$/')); define('PIFT_PID', variable_get('pift_pid', 3060)); // TODO: Drupal.org specific, to expediate the D7 port -//define('PIFT_RETEST', variable_get('pift_retest', 24 * 60 * 60)); +define('PIFT_RETEST', variable_get('pift_retest', -1)); define('PIFT_LAST_RETRIEVE', variable_get('pift_last_retrieve', 1)); /** @@ -173,8 +173,11 @@ function pift_cron() { if (PIFT_FREQUENCY != -1 && $time > PIFT_LAST + PIFT_FREQUENCY) { module_load_include('cron.inc', 'pift'); - // Requeue all tests that have passed the re-test interval. - // pift_cron_retest(); TODO fix query. + // Check whether retesting is enabled + if (PIFT_RETEST != -1) { + // Requeue all tests that have passed the re-test interval. + // pift_cron_retest(); TODO fix query. + } // Send a batch of queued tests. pift_cron_queue_batch();