=== modified file 'sites/all/modules/project_dependency/project_dependency.drupal.inc'
--- sites/all/modules/project_dependency/project_dependency.drupal.inc	2012-03-01 04:01:17 +0000
+++ sites/all/modules/project_dependency/project_dependency.drupal.inc	2012-04-29 21:36:37 +0000
@@ -381,8 +381,10 @@
  * This is a recursive, accumulative function, gathering the results we need in
  * $dependency_releases.
  *
+ * @param $orig_release_nid
+ *   nid of the release node.  This parameter retains the parent release nid.
  * @param $release_nid
- *   nid of the release node.
+ *   nid of the release node. This parameter changes in the recursion.
  * @param $depending_components
  *   an array of component names, like
  *   array('views_ui', 'token', 'page_manager')
@@ -394,7 +396,7 @@
  *
  * Same as  project_dependency_info_process_dependencies($rid, $modules[$module], $dependencies);
  */
-function project_dependency_get_external_component_dependencies($release_nid, $depending_components, &$dependency_releases, $recursion_level = 0) {
+function project_dependency_get_external_component_dependencies($orig_release_nid, $release_nid, $depending_components, &$dependency_releases, $recursion_level = 0) {
   // Limit this to 4 levels for now, as we probably don't know of anything
   // that needs recursion_level > 2.
   if ($recursion_level > 4) {
@@ -440,37 +442,70 @@
     foreach ($external_dependencies as $component_info) {
       $dependency_component = $component_info['dependency'];
 
-      // Find the releases that component was shipped in.
-      // We could hope that it would only be in one package/rid,
-      // but there are probably cases (refactoring) where that is not
-      // the case.
-      $possible_dependent_releases = project_dependency_info_releases_for_component_get($dependency_component, $api_term->tid);
-      // We choose to use the project of the most recently created release
-      // node. This is not guaranteed, but is a heuristic. Is there another?
-      $first_dependent_release = reset($possible_dependent_releases);
-      $dependent_pid = $first_dependent_release['pid'];
-      $recommended_release = project_release_get_current_recommended($dependent_pid, $api_term->tid);
-
-      // If we found a recommended release for this project and that release
-      // also contains this component, accept it.
-      if (!empty($recommended_release) && !empty($possible_dependent_releases[$recommended_release->nid])) {
-        // Accept the recommended release for the project used.
-        $release = $possible_dependent_releases[$recommended_release->nid];
-      }
-      else {
-        // The recommended release does not contain the component, so just
-        // punt and accept the first release that was found.
-        $release = $first_dependent_release;
-      }
+      $possible_dependent_releases = project_dependency_info_releases_for_component_get( $dependency_component, $api_term->tid);
+      $release = project_dependency_get_release_version($orig_release_nid, $possible_dependent_releases, $api_term->tid);
       $release['component'] = $dependency_component;
+
       $dependency_releases[$dependency_component] = $release;
       // Recurse to find dependencies of the discovered dependency, but only
       // for the component which discovered the dependent release.
-      project_dependency_get_external_component_dependencies($release['release_nid'], array($dependency_component), $dependency_releases, $recursion_level + 1);
-    }
-  }
-}
-
+      project_dependency_get_external_component_dependencies($orig_release_nid, $release['release_nid'], array($dependency_component), $dependency_releases, $recursion_level + 1);
+    }
+  }
+}
+
+/*
+ * Retrieve the release version of a project.
+ *
+ * Retrieve the release version of a project by first checking for a specific
+ * override request, then looking for a recommended release and then the most
+ * recently created release.
+ *
+ * @param int $orig_release_nid
+ *   The release nid for the project being tested.
+ * @param array $possible_dependent_releases
+ *   An array of information about release nodes to be considered.
+ * @param int $tid
+ *   The term id for the release category.
+ *
+ * @return array $release
+ *   An array containing information about the selected release.
+ */
+function project_dependency_get_release_version($orig_release_nid, $possible_dependent_releases, $tid) {
+  // We choose to use the project of the most recently created release
+  // node. This is not guaranteed, but is a heuristic. Is there another?
+  $first_dependent_release = reset($possible_dependent_releases);
+  $sql = 'SELECT version FROM {pift_overrides} WHERE id=%d AND project="%s"';
+  $version = db_result(db_query($sql, $orig_release_nid,
+             $first_dependent_release['uri']));
+  if ($version) {
+    // Check for a dependency override.
+    foreach ($possible_dependent_releases as $dependent_release) {
+      if ($dependent_release['tag']==$version) {
+        $release = $dependent_release;
+        return $release;
+      }
+    }
+  }
+  if (!isset($release)) {
+    $dependent_pid = $first_dependent_release['pid'];
+    $recommended_release = project_release_get_current_recommended($dependent_pid, $tid);
+
+    // If we found a recommended release for this project and that release
+    // also contains this component, accept it.
+    if (!empty($recommended_release) && !empty($possible_dependent_releases[$recommended_release->nid])) {
+      // Accept the recommended release for the project used.
+      $release = $possible_dependent_releases[$recommended_release->nid];
+    }
+    else {
+      // The recommended release does not contain the component, so just
+      // punt and accept the first release that was found.
+      $release = $first_dependent_release;
+    }
+  }
+
+  return $release;
+}
 
 /**
  * Given a release nid and component name, find all external dependencies for

=== modified file 'sites/all/modules/project_dependency/project_dependency.module'
--- sites/all/modules/project_dependency/project_dependency.module	2012-03-01 04:01:17 +0000
+++ sites/all/modules/project_dependency/project_dependency.module	2012-04-29 21:37:44 +0000
@@ -160,7 +160,41 @@
   $excluded_dependencies = variable_get('project_dependency_excluded_dependencies', array('drupal', 'simpletest', 'leftandright'));
 
   $component_dependencies = array();
-  project_dependency_get_external_component_dependencies($depending_release_nid, $depending_components, $component_dependencies);
+  project_dependency_get_external_component_dependencies($depending_release_nid, $depending_release_nid, $depending_components, $component_dependencies);
+
+  $release_node = node_load($depending_release_nid);
+  if (!($api_term = project_dependency_info_core_api($release_node))) {
+    watchdog('project_dependency', 'ERROR: No core release API term found for release nid=%nid', array('%nid' => $depending_release_nid));
+    return;
+  }
+  $sql = 'SELECT project, components FROM {pift_overrides} WHERE id=%d';
+  $results = db_query($sql, $depending_release_nid);
+  while ($project = db_fetch_object($results)) {
+    $versions = pift_project_versions($project->project, $release_node->project_release['version']);
+    $possible_dependent_releases = array();
+    foreach ($versions as $version) {
+      $sql = 'SELECT pp.uri AS uri, prn.pid AS pid, prn.nid AS release_nid,
+          prn.version AS version, prn.tag AS tag,
+          prn.version_major AS version_major
+        FROM {project_release_nodes} prn
+        LEFT JOIN {project_projects} pp ON prn.pid=pp.nid
+        WHERE pp.uri="%s" AND prn.tag="%s"';
+      $result = db_query($sql, $project->project, $version);
+      if ($item = db_fetch_array($result)) {
+        $possible_dependent_releases[$item['release_nid']] = $item;
+      }
+    }
+    $release = project_dependency_get_release_version($depending_release_nid, $possible_dependent_releases, $api_term->tid);
+    $components = unserialize($project->components);
+    $dependencies = array();
+    project_dependency_get_external_component_dependencies($depending_release_nid, $release['release_nid'], $components, $dependencies);
+    foreach ($dependencies as $key => $dependency) {
+      if (project_dependency_missing_dependency($dependency, $component_dependencies)) {
+        $component_dependencies[$key] = $dependency;
+      }
+    }
+  }
+
   $release_dependencies = array();
   foreach ($component_dependencies as $component => $component_info) {
     if (!in_array($component_info['uri'], $excluded_dependencies)) {
@@ -171,5 +205,27 @@
       );
     }
   }
+
   return $release_dependencies;
 }
+
+/**
+ * Checks to see if the component needs to be added to the dependencies.
+ *
+ * @param $component
+ *   Name of the component.
+ * @param $release_dependencies
+ *  Array of component dependencies.
+ *
+ * @return
+ *   FALSE if the component already is included in the release dependencies;
+ *   otherwise, FALSE
+ */
+function project_dependency_missing_dependency($component, $dependencies) {
+  foreach ($dependencies as $key => $dependency) {
+    if ($component==$key) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}

=== modified file 'sites/all/modules/project_issue_file_test/pift.install'
--- sites/all/modules/project_issue_file_test/pift.install	2011-09-30 15:28:40 +0000
+++ sites/all/modules/project_issue_file_test/pift.install	2012-04-28 22:55:20 +0000
@@ -70,6 +70,39 @@
     ),
     'primary key' => array('pid'),
   );
+  $schema['pift_dependencies'] = array(
+    'description' => t('Stores test project dependency overrides.'),
+    'fields' => array(
+      'id' => array(
+        'description' => t('Related test detail record ID, either rid, or fid.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'project' => array(
+        'description' => t('Dependent project name.'),
+        'type' => 'varchar',
+	'length' => 60,
+	'default' => '',
+        'not null' => TRUE,
+      ),
+      'version' => array(
+        'description' => t('Requested version for this test.'),
+        'type' => 'varchar',
+	'length' => 60,
+	'default' => '',
+        'not null' => TRUE,
+      ),
+      'components' => array(
+        'description' => t('Dependent components.'),
+        'type' => 'text',
+        'size' => 'normal',
+	'default' => '',
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('id', 'project'),
+  );
 
   return $schema;
 }
@@ -315,4 +348,46 @@
   );
   db_change_field($ret, 'pift_test', 'message', 'message', $newattr);
   return $ret;
-}
\ No newline at end of file
+}
+
+/**
+ * Add table for dependency overrides.
+ */
+function pift_update_6207() {
+  $ret = array();
+  $schema['pift_overrides'] = array(
+    'description' => t('Stores test project dependency overrides.'),
+    'fields' => array(
+      'id' => array(
+        'description' => t('Related test detail record ID, either rid, or fid.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'project' => array(
+        'description' => t('Dependent project name.'),
+        'type' => 'varchar',
+	'length' => 60,
+	'default' => '',
+        'not null' => TRUE,
+      ),
+      'version' => array(
+        'description' => t('Requested version for this test.'),
+        'type' => 'varchar',
+	'length' => 60,
+	'default' => '',
+        'not null' => TRUE,
+      ),
+      'components' => array(
+        'description' => t('Dependent components.'),
+        'type' => 'text',
+        'size' => 'normal',
+        'default' => '',
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('id', 'project'),
+  );
+  db_create_table($ret, 'pift_overrides', $schema['pift_overrides']);
+  return $ret;
+}

=== modified file 'sites/all/modules/project_issue_file_test/pift.module'
--- sites/all/modules/project_issue_file_test/pift.module	2011-11-14 20:13:12 +0000
+++ sites/all/modules/project_issue_file_test/pift.module	2012-04-29 02:26:36 +0000
@@ -109,6 +109,17 @@
     'weight' => '5',
     'type' => MENU_LOCAL_TASK,
   );
+  $items['pift/projects'] = array(
+    'type' => MENU_CALLBACK,
+    'page callback' => 'pift_projects',
+    'access callback' => TRUE,
+  );
+  $items['pift/%/versions/%'] = array(
+    'type' => MENU_CALLBACK,
+    'page callback' => 'pift_versions',
+    'page arguments' => array(1, 3),
+    'access callback' => TRUE,
+  );
 
   return $items;
 }
@@ -531,3 +542,66 @@
 
   return $api_releases[$api_tid];
 }
+
+/**
+ * Retrieve the projects starting with the search string.
+ *
+ * @param string $search
+ *   The beginning characters of a project.
+ * @return array of project objects.
+ */
+function pift_projects($search='') {
+  $sql = 'SELECT uri FROM {project_projects} WHERE uri LIKE "%s%"';
+  $result = db_query($sql, $search);
+  $matches = array();
+  while ($item = db_fetch_object($result)) {
+    $matches[$item->uri] = $item->uri;
+  }
+  drupal_json($matches);
+}
+
+/**
+ * Retrieve the versions of a project.
+ *
+ * @param string $project
+ *   The project name.
+ * @param int $item
+ *   The index from the Automated Testing branch form.
+ * @return array of available versions.
+ */
+function pift_versions($project, $item) {
+  $sql = 'SELECT nid FROM {project_projects} WHERE uri="%s"';
+  $nid = db_result(db_query($sql, $project));
+  $node = node_load($nid);
+  $versions = pift_get_releases($node, TRUE);
+  $versions['item'] = $item;
+  drupal_json($versions);
+}
+
+/**
+ * Retrieve the versions of a project compatible with a project being tested.
+ *
+ * Finds all the available versions that match the project being tested.
+ *
+ * @param string $project
+ *   The project name.
+ * @param string $version
+ *   The version of the project being tested.
+ * @param array $results
+ *   The results array if the versions are to be added to it.
+ * @return array of available versions along with the elements passed in.
+ */
+function pift_project_versions($project, $version, $results=array()) {
+  $sql = 'SELECT nid FROM {project_projects} WHERE uri="%s"';
+  $nid = db_result(db_query($sql, $project));
+  $node = node_load($nid);
+  $major = explode('-', $version);
+  $versions = pift_get_releases($node, TRUE);
+  foreach ($versions as $item) {
+    $item_major = explode('-', $item);
+    if ($major[0] == $item_major[0]) {
+      $results[$item] = $item;
+    }
+  }
+  return $results;
+}

=== modified file 'sites/all/modules/project_issue_file_test/pift.results.inc'
--- sites/all/modules/project_issue_file_test/pift.results.inc	2011-11-14 20:13:12 +0000
+++ sites/all/modules/project_issue_file_test/pift.results.inc	2012-04-29 21:28:15 +0000
@@ -86,28 +86,149 @@
     '#type' => 'fieldset',
     '#title' => t('Test Additional Branches'),
     '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
     '#prefix' => '<div>',
     '#suffix' => '</div>',
     '#description' => $description,
   );
+  if (isset($form_state['storage']['number'])) {
+    $form['additional']['#collapsed'] =  FALSE;
+  }
+  else {
+    $form['additional']['#collapsed'] =  TRUE;
+  }
 
+  if (!empty($form_state['values']['version'])) {
+    $version = $form_state['values']['version'];
+  }
+  else {
+    reset($versions);
+    $temp = each($versions);
+    $version = $temp['value'];
+  }
   $form['additional']['version'] = array(
     '#type' => 'select',
     '#title' => t('Select a branch/tag to queue for testing'),
     '#options' => $versions,
+    '#default_value' => $version,
     '#required' => TRUE,
   );
 
+  $form['additional']['overrides'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Override project dependencies'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+  );
+
+  $number = (isset($form_state['storage']['number'])) ?
+              $form_state['storage']['number'] : 1;
+
+  for ($i=1; $i<=$number; $i++) {
+    $form['additional']['overrides']['dependency-' . $i] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Project #') . $i,
+      '#collapsible' => TRUE,
+      '#collapsed' => FALSE,
+    );
+    
+    $project = !empty($form_state['values']['project-' . $i]) ? $form_state['values']['project-' . $i] : '';
+    $form['additional']['overrides']['dependency-' . $i]['project-' . $i] = array(
+      '#type' => 'textfield',
+      '#title' => t('Project'),
+      '#attributes' => array('class' => 'dependent-project'),
+      '#default_value' => $project,
+      '#autocomplete_path' => 'pift/projects',
+    );
+
+    $options = array('' => 'Default');
+    if ($project!='') {
+      $options = pift_project_versions($project, $version, $options);
+    }
+    $form['additional']['overrides']['dependency-' . $i]['project-version-' . $i] = array(
+      '#title' => t('Version'),
+      '#type' => 'select',
+      '#options' => $options,
+      '#default_value' => !empty($form_state['values']['project-version-' . $i]) ? $form_state['values']['project-version-' . $i] : '',
+    );
+
+    $components = !empty($form_state['values']['components-' . $i]) ? $form_state['values']['components-' . $i] : '';
+    $form['additional']['overrides']['dependency-' . $i]['components-' . $i] = array(
+      '#type' => 'textfield',
+      '#title' => '<br />' . t('Components'),
+      '#default_value' => $components,
+      '#description' => t('Some projects have multiple component modules.  List required components separated by commas for the project; leave blank to include dependencies for all component modules.'),
+    );
+  }
+
   $form['additional'][] = array(
     '#type' => 'submit',
     '#value' => t('Queue Test'),
   );
+  $form['additional']['clear'] = array(
+    '#type' => 'submit',
+    '#value' => 'Reset form',
+    '#validate' => array('pift_results_test_branch_clear'),
+  );
+  $form['additional']['add_project'] = array(
+    '#type' => 'submit',
+    '#value' => 'Add another project',
+    '#validate' => array('pift_results_test_branch_add_project'),
+  );
+  $form['additional']['retrieve_versions'] = array(
+    '#type' => 'submit',
+    '#value' => 'Retrieve versions',
+    '#validate' => array('pift_results_test_branch_retrieve_versions'),
+  );
+
+  drupal_add_js(drupal_get_path('module', 'pift') . '/dependency_overrides.js');
 
   return $form;
 }
 
 /**
+ * Function for incrementing the number of projects in the
+ * pift_results_test_branch_form.
+ */
+function pift_results_test_branch_add_project($form, &$form_state) {
+  if (!isset($form_state['storage']['number'])) {
+    $form_state['storage']['number'] = 2;
+  }
+  else {
+    $form_state['storage']['number'] += 1;
+  }
+  // Setting $form_state['rebuild'] = TRUE causes the default submit
+  // function to be skipped and the form to be rebuilt.
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Function for retrieving versions of projects in the
+ * pift_results_test_branch_form.
+ */
+function pift_results_test_branch_retrieve_versions($form, &$form_state) {
+  if (!isset($form_state['storage']['number'])) {
+    $form_state['storage']['number'] = 1;
+  }
+  // Setting $form_state['rebuild'] = TRUE causes the default submit
+  // function to be skipped and the form to be rebuilt.
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Function for resetting the pift_results_test_branch_form.
+ */
+function pift_results_test_branch_clear($form, &$form_state) {
+  // Ensures fields are blank after the reset button is clicked.
+  unset($form_state['values']);
+  // Ensures the reset button removes the add_project button.
+  unset($form_state['storage']);
+  // Setting $form_state['rebuild'] = TRUE causes the default submit
+  // function to be skipped and the form to be rebuilt.
+
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
  * Validate the submitted pift_results_test_branch_form form
  *
  * @param $form form to validate
@@ -127,7 +248,38 @@
  * @param $form_state A keyed array containing the current state of the form.
  */
 function pift_results_test_branch_form_submit($form, &$form_state) {
-  pift_results_test_add($form_state['values']['nid'], $form_state['values']['version']);
+  $overrides = array();
+  foreach ($form_state['values'] as $key => $value) {
+    $project = explode('-', $key);
+    if ($project[0]=='project') {
+      if ($project[1]=='version') {
+        $overrides[$project[2]]['version'] = $value;
+      }
+      else {
+        $overrides[$project[1]]['project'] = $value;
+      }
+    }
+    else if ($project[0]=='components') {
+      if ($value!='') {
+        $components = explode(',', $value);
+        foreach ($components as &$component) {
+          $component = trim($component);
+        }
+        $overrides[$project[1]]['components'] = $components;
+      }
+      else {
+        $overrides[$project[1]]['components'] = array();
+      }
+    }
+  }
+  // Remove blank projects.
+  foreach ($overrides as $key => $value) {
+    if ($value['project'] == '') {
+      unset($overrides[$key]);
+    }
+  }
+  pift_results_test_add($form_state['values']['nid'],
+    $form_state['values']['version'], $overrides);
 }
 
 /**
@@ -135,8 +287,9 @@
  *
  * @param $nid The node id for the given project to be tested
  * @param $version A label representing a particular project branch/tag/release
+ * @param $overrides Array of dependency overrides.
  */
-function pift_results_test_add($nid, $version) {
+function pift_results_test_add($nid, $version, $overrides = array()) {
 
   // Get the repo_id for the project
   $repo_id = db_result(db_query("SELECT repo_id FROM {versioncontrol_project_projects} WHERE nid = %d", $nid));
@@ -157,8 +310,15 @@
   /********************* Release Nid code ********************/
   $release_nid = db_result(db_query("SELECT release_nid FROM {versioncontrol_release_labels} WHERE label_id = %d AND project_nid = %d", $label_id, $nid));
   if ($release_nid) {
+    // Remove any existing overrides.
+    db_query('DELETE FROM {pift_overrides} WHERE id=%d', $release_nid);
+    foreach ($overrides as $override) {
+      $sql = 'INSERT INTO {pift_overrides} VALUES (%d, "%s", "%s", "%s")';
+      db_query($sql, $release_nid, $override['project'], $override['version'],
+               serialize($override['components']));
+    }
     db_query('INSERT INTO {pift_test} (type, id, status) VALUES (%d, %d, %d)', PIFT_TYPE_RELEASE, $release_nid, PIFT_STATUS_QUEUE);
-    drupal_set_message("This project branch/tag has been queued for testing.");
+     drupal_set_message("This project branch/tag has been queued for testing.");
   }
   else {
     drupal_set_message("This branch does not have an associated release node.  Unable to queue branch for testing.", 'error');

