diff --git a/pift.admin.inc b/pift.admin.inc
index f254b66..5d188b4 100644
--- a/pift.admin.inc
+++ b/pift.admin.inc
@@ -10,7 +10,7 @@
 /**
  * PIFT settings.
  */
-function pift_admin_settings_form() {
+function pift_admin_settings_form($form, &$form_state) {
   $form = array();
 
   $form['general'] = array(
@@ -65,7 +65,7 @@ function pift_admin_settings_form() {
   $form['interface']['pift_followup_fail'] = array(
     '#type' => 'select',
     '#title' => t('Followup issue status - fail'),
-    '#description' => t('The status to set an issue to when a test result meets all of the following criteria.' . theme('item_list', $criteria)),
+    '#description' => t('The status to set an issue to when a test result meets all of the following criteria.' . theme('item_list', array('items' => $criteria))),
     '#default_value' => PIFT_FOLLOWUP_FAIL,
     '#options' => project_issue_state(),
     '#required' => TRUE,
@@ -79,24 +79,27 @@ function pift_admin_settings_form() {
     '#required' => TRUE,
   );
 
-  $project_types = array();
-  foreach (project_get_project_types() as $key => $project_type) {
-    $project_types[$key] = $project_type->name;
-  }
-  $form['results'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Results Display'),
-    '#weight' => 0,
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-  );
-  $form['results']['pift_results_display'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Project types'),
-    '#description' => t('Project types for which the "Testing Status" tab should be displayed on the project page.'),
-    '#options' => $project_types,
-    '#default_value' => variable_get('pift_results_display', array()),
-  );
+  // Removing for the D7 port, as the plan is to move the 'Automated Testing'
+  // tab interface over to the Conduit project
+  //$project_types = array();
+  //array();
+  //foreach (project_project_node_types() as $key => $project_type) {
+  //  $project_types[$project_type] = $project_type;
+  //}
+  //$form['results'] = array(
+  //  '#type' => 'fieldset',
+  //  '#title' => t('Results Display'),
+  //  '#weight' => 0,
+  //  '#collapsible' => TRUE,
+  //  '#collapsed' => TRUE,
+  //);
+  //$form['results']['pift_results_display'] = array(
+  //  '#type' => 'checkboxes',
+  //  '#title' => t('Project types'),
+  //  '#description' => t('Project types for which the "Testing Status" tab should be displayed on the project page.'),
+  //  '#options' => $project_types,
+  //  '#default_value' => variable_get('pift_results_display', array()),
+  //);
 
   $form['criteria'] = array(
     '#type' => 'fieldset',
@@ -124,7 +127,7 @@ function pift_admin_settings_form() {
     '#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' => project_release_compatibility_list(),
+    '#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.
@@ -200,10 +203,16 @@ function pift_admin_settings_form_validate($form, &$form_state) {
  * Query pid using project title.
  */
 function pift_admin_settings_form_submit($form, &$form_state) {
-  $form_state['values']['pift_pid'] = db_result(
-    db_query("SELECT nid
-              FROM {node}
-              WHERE title = '%s'
-              AND type = '%s'", $form_state['values']['pift_pid'], 'project_project')
-  );
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', 'node')
+    ->entityCondition('bundle', project_project_node_types(), 'IN')
+    ->propertyCondition('status', 1)
+    ->propertyCondition('title', $form_state['values']['pift_pid'])
+    ->range(0,1);
+  $result = $query->execute();
+
+  if (isset($result['node'])) {
+    $form_state['values']['pift_pid'] = reset(array_keys($result['node']));
+  }
 }
+
diff --git a/pift.cron.inc b/pift.cron.inc
index c3a5e11..715f271 100644
--- a/pift.cron.inc
+++ b/pift.cron.inc
@@ -21,13 +21,14 @@ function pift_cron_retest() {
 
   // Only attempt query if both values are not empty.
   if ($api_versions && $sids) {
-    $retest_time = time() - PIFT_RETEST;
+    $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) {
+      // TODO:  UPDATE THIS QUERY (Upload table doesn't exist anymore)
       db_query("UPDATE {pift_test}
-                SET status = %d
-                WHERE type = %d
+                SET status = :status
+                WHERE type = :type
                 AND id IN (
                   SELECT f.fid
                   FROM {files} f
@@ -45,15 +46,21 @@ function pift_cron_retest() {
 
                   JOIN {node} n
                     ON r.nid = n.nid
-                  JOIN {term_node} t
-                    ON (n.vid = t.vid AND t.tid IN (" . db_placeholders($api_versions, 'int') . "))
+                  JOIN {taxonomy_term_node} t
+                    ON (n.vid = t.vid AND t.tid IN (:api_versions))
 
-                  WHERE pi.sid IN (" . db_placeholders($sids, 'int') . ")
+                  WHERE pi.sid IN (:sids)
                 )
-                AND status > %d
-                AND last_tested < %d",
-                array_merge(array(PIFT_STATUS_QUEUE, PIFT_TYPE_FILE), $api_versions, $sids,
-                            array(PIFT_STATUS_SENT, $retest_time)));
+                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,
+                ));
     }
   }
 }
@@ -182,50 +189,62 @@ function pift_cron_queue_batch_build() {
  * @param array $branches Branches that must be loaded.
  */
 function pift_cron_queue_batch_build_files(array &$batch, array &$branches) {
-  // Load all files that are marked as needs testing or have never been tested.
-  $result = db_query('SELECT f.fid, f.filepath, u.nid AS u_nid, cu.nid AS c_nid, cu.cid AS c_cid
-                      FROM {pift_test} t
-                      JOIN {files} f
-                        ON (t.type = %d AND t.id = f.fid)
-                      LEFT JOIN {upload} u
-                        ON f.fid = u.fid
-                      LEFT JOIN {comment_upload} cu
-                        ON f.fid = cu.fid
-                      WHERE t.status = %d
-                      LIMIT %d', PIFT_TYPE_FILE, PIFT_STATUS_QUEUE, PIFT_XMLRPC_MAX);
-  while ($file = db_fetch_array($result)) {
-    // Load the issue related to the file, either from the comment or node.
-    $issue_nid = !empty($file['u_nid']) ? $file['u_nid'] : $file['c_nid'];
-    $item = array(
-      'client_identifier' => $file['fid'],
-      'file_url' => file_create_url($file['filepath']),
-    );
 
+  // Retrieve all file tests which are marked as needs testing.
+  $query = db_select('pift_test', 't', array('fetch' => PDO::FETCH_ASSOC))
+    ->fields('t', array('test_id', 'id'))
+    ->condition('type', 2, '=')
+    ->condition('status', 1, '=')
+    ->orderBy('id', 'DESC');
+  $result = $query->execute();
+  $tests = array();
+  foreach ($result as $record) {
+    $tests[$record['test_id']] = $record['id'];
+  }
+
+  // Retrieve the associated project_issue node for each test.
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', 'node')
+    ->entityCondition('bundle', project_issue_issue_node_types())
+    ->propertyCondition('status', 1)
+    ->fieldCondition('field_issue_files', 'fid', $tests, 'IN');
+  $result = $query->execute();
+
+  // Load the project_issue entities
+  if (isset($result['node'])) {
+    $issue_nids = array_keys($result['node']);
+    $issues = entity_load('node', $issue_nids);
+  }
 
-    $branch_info_result = db_fetch_array(db_query('SELECT prn.nid AS rid, prn.version_major, prn.tag
-                             FROM {project_issues} pi, {project_release_nodes} prn
-                             WHERE pi.nid = %d AND pi.rid = prn.nid', $issue_nid));
+  // Foreach issue, datafill the file test batch array placeholder item
+  foreach ($issues as $issue) {
+    $pid = $issue->field_project[LANGUAGE_NONE][0]['target_id'];
+    $version = $issue->field_issue_version[LANGUAGE_NONE][0]['value'];
+    $rid = project_release_exists($pid, $version);
+    $item['branch_identifier'] = $rid;
 
-    $item['branch_identifier'] = $branch_info_result['rid'];
-    // Store branch as needed to be included with data.
-    $branches[$branch_info_result['rid']] = FALSE; // Do not test unless commit found.
+    // Store the branch as required for the file test to the 'branches' array.
+    // We mark the value 'FALSE' to indicate that we do not need to test this
+    // branch, unless a commit is found on that branch later in processing.
+    $branches[$rid] = FALSE;
 
-    // Get any dependent branches and add them to the $branches array
-    $branch_dependencies = project_dependency_get_dependencies($branch_info_result['rid'], PROJECT_DEPENDENCY_DEPENDENCY_REQUIRED);
+    // Add any additional branches which this branch is dependent on
+    $branch_dependencies = project_dependency_get_dependencies($rid, PROJECT_DEPENDENCY_DEPENDENCY_REQUIRED);
     foreach ($branch_dependencies as $dep) {
       $branches[$dep['release_nid']] = FALSE;
     }
 
-    // Generate link to file issue and comment if relevant.
-    if ($file['c_cid']) {
-      $item['link'] = url('node/' . $issue_nid, array('absolute' => TRUE, 'fragment' => 'comment-' . $file['c_cid']));
-    }
-    else {
-      $item['link'] = url('node/' . $issue_nid, array('absolute' => TRUE));
+    // Add each relevant file on this issue to the batch
+    foreach ($issue->field_issue_files[LANGUAGE_NONE] as $file) {
+      if (in_array($file['fid'], $tests)) {
+        // Finish datafilling the placeholder item.
+        $item['client_identifier'] = $file['fid'];
+        $item['file_url'] = file_create_url($file['uri']);
+        $item['link'] = url('node/' . $issue->nid, array('absolute' => TRUE));
+        // Add the placeholder item to the batch.
+        $batch['files'][] = $item;
+      }
     }
-
-    // Add file to batch.
-    $batch['files'][] = $item;
   }
 }
 
@@ -235,13 +254,20 @@ function pift_cron_queue_batch_build_files(array &$batch, array &$branches) {
  * @param array $branches Branches that must be loaded.
  */
 function pift_cron_queue_batch_build_branches(array &$branches) {
-  // Load the branches that are marked as needs testing or have never been tested.
-  $result = db_query('SELECT t.id AS rid
-                      FROM {pift_test} t
-                      WHERE t.type = %d
-                      AND t.status = %d
-                      LIMIT %d', PIFT_TYPE_RELEASE, PIFT_STATUS_QUEUE, PIFT_XMLRPC_MAX);
-  while ($branch = db_fetch_array($result)) {
+  // Load branches that are marked as needs testing or have never been tested.
+  $result = db_query(
+    'SELECT t.id AS rid
+    FROM {pift_test} t
+    WHERE t.type = :type AND t.status = :status
+    LIMIT :limit',
+    array(
+      ':type' => PIFT_TYPE_RELEASE,
+      ':status' => PIFT_STATUS_QUEUE,
+      ':limit' => PIFT_XMLRPC_MAX
+    ),
+    array('fetch' => PDO::FETCH_ASSOC)
+  );
+  foreach ($result as $branch) {
     $branches[$branch['rid']] = TRUE;
   }
 }
@@ -269,29 +295,25 @@ function pift_cron_queue_batch_build_branches_process(array &$batch, array &$bra
 
     // Generate branch information.
     $item = array(
-      'project_identifier' => $branch->project_release['pid'],
+      'project_identifier' => $branch->field_release_project[LANGUAGE_NONE][0]['target_id'],
       'client_identifier' => $branch->nid,
-      'vcs_identifier' => $branch->project_release['tag'],
+      'vcs_identifier' => $branch->field_release_vcs_label[LANGUAGE_NONE][0]['value'],
       'dependency' => '',
       'plugin_argument' => array(),
       'test' => $test,
       'link' => url('node/' . $branch->nid, array('absolute' => TRUE)),
     );
 
-    // Attempt to determine the Drupal core API version.
+    // Determine the Drupal core API version.
     $api = array();
-    foreach ($branch->taxonomy as $tid => $term) {
-      if (in_array($tid, $api_versions)) {
-        $api['version'] = array_shift(explode('.', $term->name, 2));
-        $api['tid'] = $term->tid;
-        break;
-      }
+    $term = taxonomy_term_load(project_release_get_release_api_tid($branch));
+    if (in_array($term->tid, $api_versions)) {
+      $api['version'] = array_shift(exploide('.', $term->name, 2));
+      $api['tid'] = $term->tid;
     }
-
     // If the API version not found then ignore this branch.
-    if (empty($api)) {
+    else {
       watchdog('pift', 'Project release node [@nid] does not have a Drupal core API taxonomy term.', array('@nid' => $branch->nid), WATCHDOG_ERROR);
-      continue;
     }
 
     // If the project is Drupal core then add the plugin argument, otherwise
@@ -380,14 +402,16 @@ function pift_cron_queue_batch_build_projects(array &$batch, array $projects) {
  * @return array Release NIDs that match.
  */
 function pift_cron_get_release($pid, $tags) {
-  $result = db_query('SELECT nid
-                      FROM {project_release_nodes}
-                      WHERE pid = %d
-                      AND tag IN (' . db_placeholders($tags, 'varchar') . ')',
-                      array_merge(array($pid), $tags));
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', 'node')
+    ->entityCondition('bundle', 'project_release')
+    ->propertyCondition('status', 1)
+    ->fieldCondition('field_release_project', 'target_id', $pid, '=')
+    ->fieldCondition('field_release_vcs_label', 'value', $tags, 'IN');
+  $result = $query->execute();
   $rids = array();
-  while ($rid = db_result($result)) {
-    $rids[] = $rid;
+  if (isset($result['node'])) {
+    $rids = array_keys($result['node']);
   }
   return $rids;
 }
@@ -413,12 +437,14 @@ function pift_cron_retrieve_results() {
     }
     elseif (isset($response['results'])) {
       foreach ($response['results'] as $result) {
-        db_query("UPDATE {pift_test}
-                  SET status = %d,
-                  message = '%s',
-                  last_tested = %d
-                  WHERE test_id = %d",
-                  $result['pass'] ? PIFT_STATUS_PASS : PIFT_STATUS_FAIL, $result['message'], time(), $result['test_id']);
+        db_update('pift_test')
+          ->fields(array(
+            'status' => $result['pass'] ? PIFT_STATUS_PASS : PIFT_STATUS_FAIL,
+            'message' => $result['message'],
+            'last_tested' => REQUEST_TIME,
+          ))
+          ->condition('test_id', $result['test_id'])
+          ->execute();
 
         pift_cron_check_auto_followup($result);
       }
@@ -447,29 +473,19 @@ function pift_cron_check_auto_followup(array $result) {
     $test = pift_test_get($result['test_id']);
     if ($test['fid']) {
       // Get the current issue state and ensure that the test is the last one
-      // for the particular issue. Cycle through clauses to remove the need for
-      // an OR clause and thus improve performance.
+      // for the particular issue.
       $results = array();
-      foreach (array('u.nid = i.nid', 'cu.nid = i.nid') as $clause) {
-        $result = db_query('SELECT t.test_id, t.id
-                            FROM {pift_test} t
-                            LEFT JOIN {upload} u
-                              ON (t.type = %d AND t.id = u.fid)
-                            LEFT JOIN {comment_upload} cu
-                              ON (t.type = %d AND t.id = cu.fid)
-                            JOIN {project_issues} i
-                              ON ' . $clause . '
-                            WHERE u.nid = %d OR cu.nid = %d
-                            ORDER BY t.id DESC
-                            LIMIT 1', PIFT_TYPE_FILE, PIFT_TYPE_FILE, $test['nid'], $test['nid']);
-        $results[] = db_fetch_array($result);
-      }
-
-      // To simulate OR clause and descending order by 'id' select the test_id
-      // that has the highest 'id' value.
-      $test_id = $results[0]['id'] > $results[1]['id'] ? $results[0]['test_id'] : $results[1]['test_id'];
-
-      if ($test_id == $test['test_id'] && pift_test_check_criteria_issue(node_load($test['nid']))) {
+      $query = db_select('pift_test', 't', array('fetch' => PDO::FETCH_ASSOC))
+        ->fields('t', array('test_id', 'id'))
+        ->condition('t.type', PIFT_TYPE_FILE, '=');
+      $query->leftJoin('field_data_field_issue_files', 'fd', 't.id = fd.field_issue_files_fid');
+      $query->join('project_issues', 'i', 'fd.entity_id = i.nid');
+      $query->condition('fd.entity_id', $test['nid'], '=');
+      $query->orderBy('t.id', 'DESC')
+        ->range(0,1);
+      $result = $query->execute()->fetchField();
+
+      if ($result == $test['test_id'] && pift_test_check_criteria_issue(node_load($test['nid']))) {
         // Test is last one for the particular issue and still fits the criteria.
         pift_cron_auto_followup($test['nid'], $test['cid'], $test['filename']);
       }
@@ -485,11 +501,11 @@ function pift_cron_check_auto_followup(array $result) {
  * @param string $filename Name of file.
  */
 function pift_cron_auto_followup($nid, $cid, $filename) {
-  project_issue_add_auto_followup(array(
-    'nid' => $nid,
-    'sid' => PIFT_FOLLOWUP_FAIL,
-    'comment' => theme('pift_auto_followup', 'fail', $nid, $cid, $filename),
-  ));
+  $node = node_load($nid);
+  $node->field_issue_status['value'] = PIFT_FOLLOWUP_FAIL;
+  $node->nodechanges_uid = variable_get('project_issue_followup_user', drupal_anonymous_user()->uid);
+  $node->nodechanges_comment_body['value'] = theme('pift_auto_followup', array('type' => 'fail', 'nid' => $nid, 'cid' => $cid, 'filename' => $filename));
+  node_save($node);
 }
 
 /**
diff --git a/pift.css b/pift.css
index ee780db..3ec785c 100644
--- a/pift.css
+++ b/pift.css
@@ -1,14 +1,12 @@
-tr.pift-pass,
-tr.pift-pass td {
+
+tr.pift-pass {
   background-color: #99FF99 !important;
 }
 
-tr.pift-fail,
-tr.pift-fail td {
+tr.pift-fail {
   background-color: #FF9999 !important;
 }
 
-tr.pift-retest,
-tr.pift-retest td {
+tr.pift-retest {
   background-color: #FFFF77 !important;
 }
diff --git a/pift.info b/pift.info
index f2adfbe..78ee8e1 100644
--- a/pift.info
+++ b/pift.info
@@ -1,13 +1,7 @@
 name = PIFT
 description = Integrates into project to provide an automated testing hub.
 package = Project
-core = 6.x
-php = 5
-files[] = pift.admin.inc
-files[] = pift.module
-files[] = pift.pages.inc
-files[] = pift.project.inc
-files[] = pift.test.inc
+core = 7.x
 dependencies[] = project
 dependencies[] = project_dependency
 dependencies[] = project_issue
diff --git a/pift.install b/pift.install
index 330ff1b..53dd36f 100644
--- a/pift.install
+++ b/pift.install
@@ -8,44 +8,44 @@
  */
 
 /**
- * Implementation of hook_schema().
+ * Implements hook_schema().
  */
 function pift_schema() {
   $schema['pift_test'] = array(
-    'description' => t('Stores test results.'),
+    'description' => 'Stores test results.',
     'fields' => array(
       'test_id' => array(
-        'description' => t('Unique test ID.'),
+        'description' => 'Unique test ID.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => FALSE,
       ),
       'type' => array(
-        'description' => t('Type of test, PIFT_TYPE_*.'),
+        'description' => 'Type of test, PIFT_TYPE_*.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
       'id' => array(
-        'description' => t('Related test detail record ID, either rid, or fid.'),
+        'description' => 'Related test detail record ID, either rid, or fid.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
       'status' => array(
-        'description' => t('Status of the test, PIFT_STATUS_*.'),
+        'description' => 'Status of the test, PIFT_STATUS_*.',
         'type' => 'int',
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
       'message' => array(
-        'description' => t('Summary message of test result.'),
+        'description' => 'Summary message of test result.',
         'type' => 'text',
         'size' => 'big',
         'not null' => FALSE,
       ),
       'last_tested' => array(
-        'description' => t('Timestamp when test results were last recieved.'),
+        'description' => 'Timestamp when test results were last recieved.',
         'type' => 'int',
         'not null' => TRUE,
         'default' => 0,
@@ -59,10 +59,10 @@ function pift_schema() {
     ),
   );
   $schema['pift_project'] = array(
-    'description' => t('Store project testing preference.'),
+    'description' => 'Store project testing preference.',
     'fields' => array(
       'pid' => array(
-        'description' => t('Reference to project NID.'),
+        'description' => 'Reference to project NID.',
         'type' => 'serial',
         'unsigned' => TRUE,
         'not null' => TRUE,
@@ -75,43 +75,22 @@ function pift_schema() {
 }
 
 /**
- * Implementation of hook_install().
+ * Implements hook_install().
  */
 function pift_install() {
-  // Create tables.
-  drupal_install_schema('pift');
-
   // Ensure that pift runs after comment_upload.
-  db_query("UPDATE {system}
-            SET weight = 3
-            WHERE name = '%s'", 'pift');
-
-  // Check for pift_data and as such an update.
-  if (db_table_exists('pift_data')) {
-    // Set schema version just before first update to ensure that updates are
-    // triggered even though the module has been renamed.
-    register_shutdown_function('pift_install_force_update');
-  }
+  db_update('system')
+    ->fields(array(
+      'weight' => 3,
+    ))
+    ->condition('name', 'pift')
+    ->execute();
 }
 
 /**
- * Force update by reverting schema.
- *
- * The schema must be reverted after hook_install() has finished.
- */
-function pift_install_force_update() {
-  db_query("UPDATE {system}
-            SET schema_version = 6199
-            WHERE name = '%s'", 'pift');
-}
-
-/**
- * Implementation of hook_uninstall().
+ * Implements hook_uninstall().
  */
 function pift_uninstall() {
-  // Remove tables.
-  drupal_uninstall_schema('pift');
-
   $vars = array(
     'pift_frequency',
     'pift_last',
@@ -133,186 +112,3 @@ function pift_uninstall() {
     variable_del($var);
   }
 }
-
-/**
- * Remove old variables an setup drupal.org defaults.
- */
-function pift_update_6200() {
-  $ret = array();
-
-  // List of old variables.
-  $vars = array(
-    'pift_server_sites',
-    'pift_server_send_frequency',
-    'pift_server_last_sent',
-    'pift_next_test_server',
-    'pift_server_file_description',
-    'pift_send_limit',
-    'pift_batch_size',
-    'pift_file_regex',
-    'pift_resend_time',
-    'pift_retest_time',
-    'pift_test_status',
-    'pift_projects',
-    'pift_server_release_tag_regex',
-    'pift_server_debug_file_testing_link',
-    'pift_server_auto_followup_sid',
-  );
-
-  // Remove old variables.
-  foreach ($vars as $var) {
-    variable_del($var);
-  }
-
-  // List of default drupal.org values.
-  $vars = array(
-    'pift_frequency' => 0, // Per cron run.
-    'pift_server' => 'http://testing.drupal.org/',
-    'pift_description' => 'Only files ending in <em>.patch</em> or <em>.diff</em> will be sent for testing. '.
-                          'For patches that apply specifically to Drupal 5 or Drupal 6, you can prefix the extension ' .
-                          'with <em>-D5</em> or <em>-D6</em> to prevent them from being queued for testing. For example, ' .
-                          '<em>foo.patch</em> and <em>bar.diff</em> would both be queued for testing, whereas ' .
-                          '<em>foo-D5.patch</em> and <em>bar-D6.diff</em> would not be queued for testing.',
-    'pift_followup_fail' => 13, // Status: 'Needs work'.
-    'pift_followup_retest' => 8, // Status: 'Needs review'.
-    'pift_regex' => '/(?<![.\-_][Dd][56])(\.diff|\.patch)$/',
-    'pift_status' => array(8, 14), // Statuses: 'Needs review', 'reviewed & tested by the community'.
-    'pift_core' => array(7 => 7),
-    'pift_pid' => 3060, // Drupal core project NID.
-    'pift_retest' => 86400, // 1 day.
-  );
-
-  // Store each default variable value.
-  foreach ($vars as $key => $value) {
-    variable_set($key, $value);
-  }
-
-  // Enable testing for the drupal project.
-  db_query('INSERT INTO {pift_project} (pid)
-            VALUES (%d)', 3060);
-
-  return $ret;
-}
-
-/**
- * Update test records.
- */
-function pift_update_6201(&$sandbox = NULL) {
-  $ret = array();
-
-  if (!isset($sandbox['progress'])) {
-    $sandbox['progress'] = 0;
-    $sandbox['current_ftid'] = 0;
-    $sandbox['max'] = db_result(db_query('SELECT COUNT(ftid) FROM {pift_data}'));
-  }
-
-  // Map of old status to equivilent new ones.
-  $statuses = array(
-    0 => 1, // PIFT_UNTESTED => PIFT_STATUS_QUEUE
-    1 => 4, // PIFT_PASSED => PIFT_STATUS_PASS
-    2 => 3, // PIFT_FAILED => PIFT_STATUS_FAIL
-    3 => 1, // PIFT_RETEST => PIFT_STATUS_QUEUE
-    4 => 1, // PIFT_NOT_READABLE => PIFT_STATUS_QUEUE
-  );
-
-  // Read in map of ftid => test_id provided from pifr server 1.x, in a comma
-  // delimited file of the format: file_id(test_id),ftid.
-  if ($lines = file(drupal_get_path('module', 'pift') . '/pifr.file.map')) {
-    $map = array();
-    foreach ($lines as $line) {
-      $parts = explode(',', $line);
-      $map[trim($parts[1])] = trim($parts[0]);
-    }
-
-    // Update old data and insert into test table.
-    $result = db_query_range('SELECT *
-                              FROM {pift_data}
-                              WHERE ftid > %d
-                              ORDER BY ftid ASC', $sandbox['current_ftid'], 0, 5000);
-    while ($test = db_fetch_object($result)) {
-      // Only covert data that testing.drupal.org has a record of.
-      if (isset($map[$test->ftid])) {
-        // Remove link from display data.
-        $message = preg_replace('/\s+(<a|a) href.*?$/', '', $test->display_data);
-
-        db_query("INSERT INTO {pift_test} (test_id, type, id, status, message, last_tested)
-                  VALUES (%d, %d, %d, %d, '%s', %d)",
-                  $map[$test->ftid], PIFT_TYPE_FILE, $test->fid, $statuses[$test->status], $message, $test->timestamp);
-      }
-      $sandbox['progress']++;
-      $sandbox['current_ftid'] = $test->ftid;
-    }
-
-    $ret['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
-  }
-
-  return $ret;
-}
-
-/**
- * Remove old data.
- */
-function pift_update_6202() {
-  $ret = array();
-
-  $ret[] = update_sql('DROP TABLE {pift_data}');
-
-  return $ret;
-}
-
-/**
- * Convert the core API versions variable to term IDs and enable 6.x and 7.x.
- */
-function pift_update_6203() {
-  variable_set('pift_core', array(87 => 87, 103 => 103));
-
-  return array();
-}
-
-/**
- * Set the 'pift_last_retrieve' to a close approximate of what it should be.
- */
-function pift_update_6204() {
-  function pifr_server_xmlrpc_time_gmt($timestamp) {
-    $now = time();
-    $offset = $now - $timestamp;
-    return gmmktime() - $offset;
-  }
-
-  $last = db_result(db_query('SELECT MAX(last_tested) FROM {pift_test}'));
-  $last = pifr_server_xmlrpc_time_gmt($last ? $last : 1);
-  variable_set('pift_last_retrieve', $last);
-
-  return array();
-}
-
-/**
- * Remove variable 'pift_last_cid'.
- */
-function pift_update_6205() {
-  variable_del('pift_last_cid');
-  return array();
-}
-
-/**
- * Change schema to reflect that pift_test.test_id and message can be null.
- */
-function pift_update_6206() {
-  $ret = array();
-  $newattr = array(
-    'description' => t('Unique test ID.'),
-    'type' => 'int',
-    'unsigned' => TRUE,
-    'not null' => FALSE,
-  );
-  db_change_field($ret, 'pift_test', 'test_id', 'test_id', $newattr);
-
-  $newattr = array(
-    'description' => t('Summary message of test result.'),
-    'type' => 'text',
-    'size' => 'big',
-    'not null' => FALSE,
-  );
-  db_change_field($ret, 'pift_test', 'message', 'message', $newattr);
-  return $ret;
-}
\ No newline at end of file
diff --git a/pift.module b/pift.module
index f35b266..fd9287e 100644
--- a/pift.module
+++ b/pift.module
@@ -18,7 +18,7 @@ define('PIFT_DESCRIPTION', variable_get('pift_description', ''));
 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', -1));
+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_DELETE', variable_get('pift_delete', FALSE));
 define('PIFT_LAST_RETRIEVE', variable_get('pift_last_retrieve', 1));
@@ -70,7 +70,7 @@ module_load_include('project.inc', 'pift');
 module_load_include('test.inc', 'pift');
 
 /**
- * Implementation of hook_menu().
+ * Implements hook_menu().
  */
 function pift_menu() {
   $items = array();
@@ -99,17 +99,21 @@ function pift_menu() {
     'file' => 'pift.pages.inc',
     'type' => MENU_CALLBACK,
   );
-  $items['node/%node/testing-status'] = array(
+
+// TODO: The plan was to remove the testing-status tab for the D7 Port, and
+// add it back in with Conduit.  However, we need somewhere to store the
+// 'enable testing' checkbox, so leaving this in temporarily until the Conduit
+// piece is available.
+  $items['node/%node/qa-settings'] = array(
     'title' => t('Automated Testing'),
     'access callback' => 'pift_results_visibility',
     'access arguments' => array(1),
-    'page callback' => 'pift_results_project_tab',
-    'page arguments' => array(1),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('pift_pages_project_issue_settings', 1),
     'file' => 'pift.results.inc',
     'weight' => '5',
     'type' => MENU_LOCAL_TASK,
   );
-
   return $items;
 }
 
@@ -117,50 +121,52 @@ function pift_menu() {
  * Access callback to determine whether the Automated Testing tab is visible.
  */
 function pift_results_visibility($node) {
-  // Check if we have a module node which has a Git repository
-  // Do not display the tab if the project does not have any release nodes
-  // TODO: Once PIFT/PIFR has been refactored to use label_ids instead of
-  // release nids, the last condition can be changed to enable reporting
-  // of tests for any tag/branch within a project.
-
-  // Determine if node represents a valid project type for results display
-  $valid_type = array_intersect(variable_get('pift_results_display', array()), array_keys($node->taxonomy));
-  if ($node->type == 'project_project'
-    && !empty($valid_type)
-    && !empty($node->versioncontrol_project['repo']->vcs)
-    && $node->versioncontrol_project['repo']->vcs == 'git'
-    && user_access('pift access project testing tab')
-    && pift_get_releases($node, TRUE) != array()) {
-      return TRUE;
+  // Only display the tab on projects with releases
+  if (project_node_is_project($node)) {
+    if ($node->field_project_has_releases[$node->language][0]['value']) {
+      // Ensure user has access to enable testing on the node
+      if (user_access('pift enable project testing')) {
+        return TRUE;
+      }
+    }
   }
   return FALSE;
 }
 
 /**
- * Implementation of hook_perm().
+ * Implements hook_permission().
  */
-function pift_perm() {
+function pift_permission() {
   return array(
-    'pift re-test files',
-    'pift enable project testing',
-    'pift access project testing tab'
+    'pift re-test files' => array(
+      'title' => t('pift re-test files'),
+      'description' => t('Request a file to be re-tested'),
+    ),
+    'pift enable project testing' => array(
+      'title' => t('pift enable project testing'),
+      'description' => t('Enable testing on a project'),
+    ),
+    'pift access project testing tab' => array(
+      'title' => t('pift access project testing tab'),
+      'description' => t('Access the testing tab on projects'),
+    ),
   );
 }
 
 /**
- * Implementation of hook_theme().
+ * Implements hook_theme().
  */
 function pift_theme() {
   return array(
     'pift_attachments' => array(
-      'arguments' => array(
+      'variables' => array(
         'files' => array(),
         'closed' => FALSE,
       ),
       'file' => 'pift.pages.inc',
     ),
     'pift_auto_followup' => array(
-      'arguments' => array(
+      'variables' => array(
         'type' => '',
         'nid' => 0,
         'cid' => 0,
@@ -171,14 +177,14 @@ function pift_theme() {
 }
 
 /**
- * Implementation of hook_init().
+ * Implements hook_init().
  */
 function pift_init() {
   drupal_add_css(drupal_get_path('module', 'pift') . '/pift.css');
 }
 
 /**
- * Implementation of hook_cron().
+ * Implements hook_cron().
  */
 function pift_cron() {
   if (PIFT_DELETE) {
@@ -188,7 +194,7 @@ function pift_cron() {
   }
 
   // Check if sending is enabled and that the sending frequency has elapsed.
-  $time = time();
+  $time = REQUEST_TIME;
   if (PIFT_FREQUENCY != -1 && $time > PIFT_LAST + PIFT_FREQUENCY) {
     module_load_include('cron.inc', 'pift');
 
@@ -207,46 +213,7 @@ function pift_cron() {
 }
 
 /**
- * Implementation of hook_versioncontrol_git_refs_updated().
- */
-function pift_versioncontrol_git_refs_updated($repository, $refs) {
-  // Ignore commits for disabled projects.
-  if (!pift_project_enabled($repository->project_nid)) {
-    return;
-  }
-
-  module_load_include('cron.inc', 'pift');
-
-  // @TODO Decide if we want to and how to handle with tags.
-  $api_versions = pift_core_api_versions();
-  $rids = pift_cron_get_release($repository->project_nid, array_keys($refs['branches']));
-  foreach ($rids as $rid) {
-    // Ensure that one of the compatibility terms is present on the release node.
-    $release = node_load($rid);
-    $found = FALSE;
-    foreach ($api_versions as $api_version) {
-      if (array_key_exists($api_version, $release->taxonomy)) {
-        // Compatible term found, continue processing.
-        $test_id = db_result(db_query('SELECT test_id
-                                        FROM {pift_test}
-                                        WHERE type = %d
-                                        AND id = %d', PIFT_TYPE_RELEASE, $rid));
-
-        // If existing test for release, queue it, otherwise add a new test.
-        if ($test_id) {
-          pift_test_requeue($test_id);
-        }
-        else if ($test_id !== 0) {
-          pift_test_add(PIFT_TYPE_RELEASE, $rid);
-        }
-        break;
-      }
-    }
-  }
-}
-
-/**
- * Implementation of hook_versioncontrol_code_arrival().
+ * Implements hook_versioncontrol_code_arrival().
  */
 function pift_versioncontrol_code_arrival(VersioncontrolRepository $repository, VersioncontrolEvent $event) {
   // Ignore events for disabled projects and non-Git repos.
@@ -272,10 +239,10 @@ function pift_versioncontrol_code_arrival(VersioncontrolRepository $repository,
     foreach ($api_versions as $api_version) {
       if (array_key_exists($api_version, $release->taxonomy)) {
         // Compatible term found, continue processing.
-        $test_id = db_result(db_query('SELECT test_id
+        $test_id = db_query('SELECT test_id
                                           FROM {pift_test}
-                                          WHERE type = %d
-                                          AND id = %d', PIFT_TYPE_RELEASE, $rid));
+                                          WHERE type = :type
+                                          AND id = :id', array(':type' => PIFT_TYPE_RELEASE, ':id' => $rid))->fetchField();
 
         // If existing test for release, queue it, otherwise add a new test.
         if ($test_id) {
@@ -301,11 +268,11 @@ function pift_get_releases($node, $quiet = FALSE) {
   $valid = pift_valid_prefix_list();
   $branches = array();
   $topbranches = array();
-  if ($node->type == 'project_project') {
+  if (project_node_is_project($node)) {
     $result = db_query("Select b.name from {versioncontrol_release_labels} a
        join {versioncontrol_labels} b on a.label_id = b.label_id
-       where a.project_nid = %s", $node->nid);
-    while ($data = db_fetch_object($result)) {
+       where a.project_nid = :nid", array(':nid' => $node->nid));
+    foreach ($result as $data) {
       // Filter out any branches < 6 (not accepted by PIFT)
       // Move '.x' releases to the top
       if (in_array(substr($data->name, 0, 3), $valid)) {
@@ -338,7 +305,7 @@ function pift_valid_prefix_list() {
   $tids = variable_get('pift_core', array());
   foreach ($tids as $key => $value) {
     if (!empty($tids[$key])) {
-      $term = taxonomy_get_term($key);
+      $term = taxonomy_term_load($key);
       $terms[$key] = $term->name;
     }
   }
@@ -360,155 +327,190 @@ function pift_array_reverse($array) {
 
   $array_return = array();
   for ($i = 1, $size_of_array = sizeof($array_key); $i <= $size_of_array; $i++) {
-    $array_return[$array_key[$size_of_array-$i]] = $array_value[$size_of_array-$i];
+    $array_return[$array_key[$size_of_array -$i]] = $array_value[$size_of_array -$i];
   }
 
   return $array_return;
 }
 
 /**
- * Implementation of hook_form_alter(). Must use generic form_alter() due to
- * comment_upload implementation.
+ * Implements hook_form_FORM_ID_alter().
  */
-function pift_form_alter(&$form, $form_state, $form_id) {
-  if ($form_id == 'comment_form' || $form_id == 'project_issue_node_form') {
+function pift_form_project_issue_node_form_alter(&$form, $form_state, $form_id) {
     module_load_include('pages.inc', 'pift');
     pift_pages_description_add($form, $form_state, $form_id);
-  }
 }
 
 /**
- * Implementation of hook_form_alter(): project_issue_project_edit_form.
+ * Implements hook_node_view().
+ *
+ * TODO:  This approach is no longer valid after the project* changes. The
+ * new approach will be to implement a field formatter on the field_issue_files
+ * field, and add the pift testing results via this field formatter; which
+ * should be much cleaner than removing and injecting the file attachments
+ * table as was done in D6.
  */
-function pift_form_project_issue_project_edit_form_alter(&$form, $form_state) {
-  module_load_include('pages.inc', 'pift');
-  pift_pages_project_issue_settings($form, $form_state);
-}
+//function pift_node_view($node, $view_mode = 'full') {
+//  if (pift_node_is_interesting($node)) {
+//    if (!$a3 && pift_project_enabled($node->project_issue['pid'])) { // Full view.
+//      $files = pift_test_get_files_node($node->nid);
+//      $status = $node->project_issue['sid'];
+//      $node->content['pift_files'] = array(
+//        '#value' => '<div id="pift-results-' . $node->nid . '">' .
+//                        theme('pift_attachments', array('files' => $files, 'closed' => $status)) . '</div>',
+//        '#weight' => 50,
+//      );
+//      unset($node->content['files']); // Remove old attachments table.
+//    }
+//  }
+//}
 
 /**
- * Implementation of hook_nodeapi().
- */
-function pift_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
-  if ($node->type == 'project_project') {
-    // Used to maintain 'nice' url aliases for testing status pages
-    $src = 'node/' . $node->nid . '/testing-status';
-    if ($op == 'delete') {
-      db_query("DELETE FROM {url_alias} WHERE src = '%s'", $src);
-    }
-    elseif (($op == 'update' || $op == 'insert') && !empty($node->project['uri'])) {
-      $dst = 'project/' . drupal_urlencode($node->project['uri']) . '/testing-status';
-      db_query("DELETE FROM {url_alias} WHERE src = '%s'", $src);
-      db_query("INSERT INTO {url_alias} (src, dst) VALUES ('%s', '%s')", $src, $dst);
+ * Implements hook_node_insert().
+ */
+function pift_node_insert($node) {
+  if (pift_node_is_interesting($node)) {
+    if (!empty($node->field_issue_files)) {
+      if (pift_test_check_criteria_issue($node)) {
+        pift_test_add_files($node->field_issue_files);
+      }
     }
   }
-  elseif ($node->type != 'project_issue' || empty($node->files)) {
-    return;
-  }
+}
 
-  switch ($op) {
-    case 'view':
-      if (!$a3 && pift_project_enabled($node->project_issue['pid'])) { // Full view.
-        $files = pift_test_get_files_node($node->nid);
-        $status = $node->project_issue['sid'];
-        $node->content['pift_files'] = array(
-          '#value' => '<div id="pift-results-' . $node->nid . '">' .
-                      theme('pift_attachments', $files, $status) . '</div>',
-          '#weight' => 50,
-        );
-        unset($node->content['files']); // Remove old attachments table.
-      }
-      break;
-    case 'insert':
-      $proper = pift_nodeapi_clean($node);
-      if (pift_test_check_criteria_issue($proper)) {
-        $files = upload_load($proper);
-        pift_test_add_files($files);
+/**
+ * Implements hook_node_update().
+ */
+function pift_node_update($node) {
+  if (pift_node_is_interesting($node)) {
+    if ($node->field_issue_files != $node->original->field_issue_files) {
+      if (!empty($node->field_issue_files)) {
+        if (pift_test_check_criteria_issue($node)) {
+          pift_test_add_files($node->field_issue_files);
+        }
       }
-      break;
-    case 'delete':
-      variable_set('pift_delete', TRUE);
-      break;
+    }
   }
 }
 
 /**
+ * Implements hook_node_delete().
+ */
+function pift_node_delete($node) {
+  if (pift_node_is_interesting($node)) {
+    // Flag pift that a project or issue node was deleted.
+    if (project_node_is_project($node)) {
+      // Remove this project from the pift_project table
+      db_delete('pift_project')->condition('nid', $node->nid)->execute();
+    }
+    variable_set('pift_delete', TRUE);
+  }
+}
+
+/**
+ * Check if a node is a project node or issue node with file attached.
+ *
+ * Used in hook_node_*() to filter out irrelevant nodes.
+ */
+function pift_node_is_interesting($node) {
+  return project_node_is_project($node) || (project_issue_node_is_issue($node) && !empty($node->field_issue_files));
+}
+
+/**
  * Cleanup the inconsistent project_issue property placement.
  *
+ * TODO:  Confirm this approach is no longer valid after the project* changes.
+ *
  * In order to remove the need to a bunch of conditions all over PIFT, convert
  * the inconsistent node format to the one used everywhere else. The
  * inconsistent format is only found during node creation, after a node has
  * been created and hook_load() is used the properties are prefixed by
  * project_issue.
  *
+ *
+ *
  * @param object $node Node to convert.
  * @return object Properly formatted node.
  * @link http://drupal.org/node/519562
  */
-function pift_nodeapi_clean($node) {
-  $node->project_issue = array();
-
-  $fields = array('pid', 'rid', 'component', 'category', 'priority', 'assigned', 'sid');
-  foreach ($fields as $field) {
-    $node->project_issue[$field] = $node->$field;
-  }
-
-  return $node;
-}
+//function pift_nodeapi_clean($node) {
+//  $node->project_issue = array();
+//
+//  $fields = array('pid', 'rid', 'component', 'category', 'priority', 'assigned', 'sid');
+//  foreach ($fields as $field) {
+//    $node->project_issue[$field] = $node->$field;
+//  }
+//
+//  return $node;
+//}
 
 /**
- * Implementation of hook_comment().
+ * Implements hook_comment_view().
+ *
+ * TODO:  This approach is no longer valid after the project* changes. The
+ * new approach will be to implement a field formatter on the field_issue_files
+ * field and comments, and add the pift testing results via this field
+ * formatter; which should be much cleaner than removing and injecting the file
+ * attachments table as was done in D6.
  */
-function pift_comment(&$comment, $op) {
-  $node = pift_comment_load_node($comment);
-  if ($node->type != 'project_issue') {
-    return;
-  }
+//function pift_comment_view($comment) {
+//  if ($node = pift_comment_is_interesting($comment)) {
+//    if (!empty($comment->files) && pift_project_enabled($node->project_issue['pid'])) {
+//      // Remove comment_upload attachments table and generate new one.
+//      $comment->comment = preg_replace('/<table class="comment-upload-attachments">.*?<\/table>/s', '', $comment->comment);
+//      $files = pift_test_get_files_comment($comment->cid);
+//      $status = $node->project_issue['sid'];
+//      $comment->comment .= '<div id="pift-results-' . $comment->nid . '-' . $comment->cid . '">' .
+//                              theme('pift_attachments', array('files' => $files, 'closed' => $status)) . '</div>';
+//    }
+//  }
+//}
 
-  switch ($op) {
-    case 'view':
-      if (!empty($comment->files) && pift_project_enabled($node->project_issue['pid'])) {
-        // Remove comment_upload attachments table and generate new one.
-        $comment->comment = preg_replace('/<table class="comment-upload-attachments">.*?<\/table>/s', '', $comment->comment);
-        $files = pift_test_get_files_comment($comment->cid);
-        $status = $node->project_issue['sid'];
-        $comment->comment .= '<div id="pift-results-' . $comment->nid . '-' . $comment->cid . '">' .
-                             theme('pift_attachments', $files, $status) . '</div>';
-      }
-      break;
-    case 'insert':
-      if (pift_test_check_criteria_issue($node)) {
-        if (!empty($comment->files)) {
-          // Add attachments to this comment to the send queue.
-          $files = comment_upload_load_files($comment['cid']);
-          pift_test_add_files($files);
-        }
+/**
+ * Implements hook_comment_insert().
+ *
+ * TODO:  This approach is no longer valid after the project* changes. Files
+ * and patches are now attached to the node directly.
+ */
+//function pift_comment_insert($comment) {
+//  if ($node = pift_comment_is_interesting($comment)) {
+//    if (pift_test_check_criteria_issue($node)) {
+//      if (!empty($comment->files)) {
+//        // Add attachments to this comment to the send queue.
+//        $files = comment_upload_load_files($comment['cid']);
+//        pift_test_add_files($files);
+//      }
+//      // Add previously submitted files if issue state changes.
+//      pift_test_add_previous_files($comment['nid']);
+//    }
+//  }
+//}
 
-        // Add previously submitted files if issue state changes.
-        pift_test_add_previous_files($comment['nid']);
-      }
-      break;
-    case 'delete':
-      variable_set('pift_delete', TRUE);
-      break;
-  }
-}
+/**
+ * Implements hook_comment_delete().
+ *
+ * TODO:  Determine if we want to remove patches when the associated comment is
+ * deleted ... this may now be redundant, since we can simply delete the file
+ * from the field_issue_files field.
+ */
+//function pift_comment_delete($comment) {
+//  if (pift_comment_is_interesting($comment)) {
+//    variable_set('pift_delete', TRUE);
+//  }
+//}
 
 /**
- * Load the parent node for the specified comment.
+ * Check that comment is attached to a project_issue node.
  *
- * @param mixed $comment Comment information passed to hook_comment().
- * @return object Parent node.
+ * TODO:  This is only called from three functions, all of which have been
+ * commented out as part of the D7 port.
  */
-function pift_comment_load_node($comment) {
-  // Comment can be a comment object, a form, or form_values.
-  if (is_object($comment)) {
-    $nid = $comment->nid;
-  }
-  elseif (is_array($comment)) {
-    $nid = is_array($comment['nid']) ? $comment['nid']['#value'] : $comment['nid'];
-  }
-  return node_load($nid);
-}
+//function pift_comment_is_interesting($comment) {
+//  if (($node = node_load($comment->nid)) && $node->type == 'project_issue') {
+//    return $node;
+//  }
+//  return FALSE;
+//}
 
 /**
  * Theme the auto followup comments.
@@ -519,7 +521,13 @@ function pift_comment_load_node($comment) {
  * @param string $filename Name of file.
  * @return string HTML output.
  */
-function theme_pift_auto_followup($type, $nid, $cid, $filename) {
+function theme_pift_auto_followup($variables) {
+  // TODO: Validate whether these variables are still valid after the project*
+  // changes introduced with the D7 port.
+  $type = $variables['type'];
+  $nid = $variables['nid'];
+  $cid = $variables['cid'];
+  $filename = $variables['filename'];
   $args = array(
     '@id' => "pift-results-$nid",
     '@filename' => $filename,
@@ -527,7 +535,7 @@ function theme_pift_auto_followup($type, $nid, $cid, $filename) {
 
   if ($type == 'retest') {
     if ($cid) {
-      $comment = _comment_load($cid);
+      $comment = comment_load($cid);
       $args['@cid'] = $comment->cid;
       $args['@comment'] = $comment->subject;
       return t('<a href="#comment-@cid">@comment</a>: <a href="#@id">@filename</a> queued for re-testing.', $args);
@@ -559,21 +567,47 @@ function pift_core_api_versions() {
  */
 function pift_core_api_release($api_tid) {
   static $api_releases = array();
-
   if (!isset($api_branches[$api_tid])) {
-    $result = db_query('SELECT p.nid
-                        FROM {node} n
-                        JOIN {project_release_nodes} p
-                          ON p.nid = n.nid
-                        JOIN {term_node} t
-                          ON t.vid = n.vid
-                        WHERE p.pid = %d
-                        AND p.rebuild = %d
-                        AND t.tid = %d
-                        ORDER BY n.vid DESC
-                        LIMIT 1', PIFT_PID, 1, $api_tid);
-    $api_releases[$api_tid] = db_result($result);
+    $api_vocabulary = taxonomy_vocabulary_load(variable_get('project_release_api_vocabulary', ''));
+    $taxonomy_field = 'taxonomy_vocabulary_' . $api_vocabulary->machine_name;
+
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', 'node')
+      ->entityCondition('bundle', 'project_release')   // TODO: Drupal.org specific
+      ->fieldCondition('field_release_project', 'target_id', PIFT_PID, '=')
+      ->fieldCondition($taxonomy_field, 'tid', $api_tid)
+      ->propertyOrderBy('nid', 'DESC')
+      ->range(0,1);
+    $result = $query->execute();
+
+    if (isset($result['node'])) {
+      $api_releases[$api_tid] = reset(array_keys($result['node']));
+    }
   }
 
   return $api_releases[$api_tid];
 }
+
+/**
+ * Return a list of active project release compatibility terms in the system.
+ */
+function pift_compatibility_list() {
+  $compatibility_list = array();
+
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', 'taxonomy_term')
+    ->propertyCondition('vid', variable_get('project_release_api_vocabulary', -1))
+    ->fieldCondition('field_release_recommended', 'value', '1');
+  $result = $query->execute();
+
+  if (isset($result['taxonomy_term'])) {
+    $term_ids = array_keys($result['taxonomy_term']);
+    $terms = entity_load('taxonomy_term', $term_ids);
+  }
+
+  foreach ($terms as $key => $term) {
+    $compatibility_list[$key] = $term->name;
+  }
+
+  return $compatibility_list;
+}
diff --git a/pift.pages.inc b/pift.pages.inc
index 36b168e..f431100 100644
--- a/pift.pages.inc
+++ b/pift.pages.inc
@@ -8,26 +8,23 @@
  */
 
 /**
- * Add additional description to attachment form.
+ * Add additional description to file attachment form on issues.
  */
 function pift_pages_description_add(&$form, $form_state, $form_id) {
   global $user;
-
-  // Add description on uploads if it is set.
+  // Add description on field_issue_files if it is set.
   if (PIFT_DESCRIPTION) {
     // Detect project issue node ID.
     $nid = NULL;
-    if ($form_id == 'comment_form' && isset($form['original_issue'])) {
-      $node = node_load($form['nid']['#value']);
-      $nid = $node->project_issue['pid'];
-    }
-    elseif ($form_id == 'project_issue_node_form') {
-      $nid = $form['project_info']['pid']['#value'];
-    }
-
-    if (isset($form['attachments']['wrapper']['new']['upload']) && $nid && pift_project_enabled($nid)) {
-      $description = filter_xss_admin(PIFT_DESCRIPTION);
-      $form['attachments']['wrapper']['new']['upload']['#description'] .= $description;
+    // TODO: This is drupal.org specific, as any node type can be marked as an
+    // issue after the Project* D7 changes.  This code assumes a single node
+    // type of 'project_issue'.
+    if ($form_id == 'project_issue_node_form') {
+      $nid = $form['#node']->field_project['und'][0]['target_id'];
+      if (isset($form['field_issue_files'][LANGUAGE_NONE]['#file_upload_description']) && $nid && pift_project_enabled($nid)) {
+        $description = filter_xss_admin(PIFT_DESCRIPTION);
+        $form['field_issue_files'][LANGUAGE_NONE]['#file_upload_description'] .= " " . $description;
+      }
     }
   }
 }
@@ -35,15 +32,8 @@ function pift_pages_description_add(&$form, $form_state, $form_id) {
 /**
  * Add testing setting.
  */
-function pift_pages_project_issue_settings(&$form, $form_state) {
-  // We don't want to inject any of these settings the project has no releases.
-  $project_node = node_load($form['nid']['#value']);
-  if (empty($project_node->project_release['releases'])) {
-    return;
-  }
-
-  $form['issue']['#weight'] = -10;
-  $form['issue']['#email'] = -8;
+function pift_pages_project_issue_settings(&$form, $form_state, $node) {
+  $form = array();
   $form['testing'] = array(
     '#type' => 'fieldset',
     '#title' => t('Testing'),
@@ -56,7 +46,7 @@ function pift_pages_project_issue_settings(&$form, $form_state) {
   $api_versions = pift_core_api_versions();
   $versions = array();
   foreach ($api_versions as $api_version) {
-    $term = taxonomy_get_term($api_version);
+    $term = taxonomy_term_load($api_version);
     $versions[] = $term->name;
   }
   $form['testing']['pift_enable'] = array(
@@ -64,9 +54,12 @@ function pift_pages_project_issue_settings(&$form, $form_state) {
     '#title' => t('Enable automated testing'),
     '#description' => t('Enable automated testing of @versions compatible branches and patches.',
       array('@versions' => implode(', ', $versions))),
-    '#default_value' => pift_project_enabled($form['nid']['#value']),
+    '#default_value' => pift_project_enabled($node->nid),
+  );
+  $form['testing']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save Settings'),
   );
-  $form['#submit'][] = 'pift_pages_project_issue_settings_submit';
 }
 
 /**
@@ -75,12 +68,12 @@ function pift_pages_project_issue_settings(&$form, $form_state) {
 function pift_pages_project_issue_settings_submit($form, &$form_state) {
   $enabled = pift_project_enabled($form_state['values']['nid']);
   if ($form_state['values']['pift_enable'] && !$enabled) {
-    db_query('INSERT INTO {pift_project}
-              VALUES (%d)', $form_state['values']['nid']);
+    db_query('INSERT INTO {pift_project} VALUES (:nid)', array(':nid' => $form_state['values']['nid']));
   }
   else if (!$form_state['values']['pift_enable'] && $enabled) {
-    db_query('DELETE FROM {pift_project}
-              WHERE pid = %d', $form_state['values']['nid']);
+    db_delete('pift_project')
+      ->condition('pid', $form_state['values']['nid'])
+      ->execute();
   }
 }
 
@@ -89,7 +82,7 @@ function pift_pages_project_issue_settings_submit($form, &$form_state) {
  *
  * @param integer Test ID to re-test.
  */
-function pift_pages_retest_confirm_form(&$form_state, $test_id) {
+function pift_pages_retest_confirm_form($form, &$form_state, $test_id) {
   $test = pift_test_get($test_id);
 
   if ($test) {
@@ -109,7 +102,7 @@ function pift_pages_retest_confirm_form(&$form_state, $test_id) {
           'type' => PIFT_TYPE_FILE,
         ),
       );
-      $form['#redirect'] = 'node/' . $form['test']['#value']['nid'];
+      $form_state['#redirect'] = 'node/' . $form['test']['#value']['nid'];
     }
     elseif ($test['type'] == PIFT_TYPE_RELEASE) {
       // Branch test
@@ -123,13 +116,13 @@ function pift_pages_retest_confirm_form(&$form_state, $test_id) {
         ),
       );
       // Get the project id
-      $pid = db_result(db_query_range("SELECT project_nid from {versioncontrol_release_labels} where release_nid = %d", $test['id'], 0, 1));
-      $form['#redirect'] = 'node/' . $pid . '/testing-status';
+      $pid = db_query_range("SELECT project_nid from {versioncontrol_release_labels} where release_nid = %d", $test['id'])->fetchField();
+      $form_state['#redirect'] = 'node/' . $pid . '/testing-status';
     }
     return confirm_form(
       $form,
       t('Are you sure you want to request that %title be re-tested?', array('%title' => $form['test']['#value']['title'])),
-      $form['#redirect'],
+      $form_state['#redirect'],
       t('Once requested the test will be re-queued and results will be updated once the re-test has finished.'),
       t('Re-test'),
       t('Cancel')
@@ -145,33 +138,29 @@ function pift_pages_retest_confirm_form(&$form_state, $test_id) {
  */
 function pift_pages_retest_confirm_form_submit($form, &$form_state) {
   global $user;
-
   $test = $form_state['values']['test'];
-
   if ($test['status'] > PIFT_STATUS_SENT) {
     if ($test['type'] == PIFT_TYPE_FILE) {
       // Base changes to be made in followup comment.
-      $changes = array(
-        'nid' => $test['nid'],
-        'uid' => $user->uid,
-        'comment' => theme('pift_auto_followup', 'retest', $test['nid'], $test['cid'], $test['title']),
-      );
-
+      $node = node_load($test['nid']);
+      $node->nodechanges_uid = $user->uid;
+      $node->nodechanges_comment_body['value'] = theme('pift_auto_followup', array('type' => 'retest', 'nid' => $test['nid'], 'cid' => $test['cid'], 'filename' => $test['title']));
       // If node issue status is not already a valid status then set to default
       // retest status, otherwise leave status alone.
-      $node = node_load($test['nid']);
       if (!in_array($node->project_issue['sid'], variable_get('pift_status', array()))) {
-        $changes['sid'] = PIFT_FOLLOWUP_RETEST;
+        $node->field_issue_status['value'] = PIFT_FOLLOWUP_RETEST;
       }
-
       // Add followup to issue.
-      project_issue_add_auto_followup($changes);
+      node_save($node);
     }
 
     // Update test record to reflect change.
-    db_query('UPDATE {pift_test}
-              SET status = %d
-              WHERE test_id = %d', PIFT_STATUS_QUEUE, $test['test_id']);
+    db_update('pift_test')
+      ->fields(array(
+        'status' => PIFT_STATUS_QUEUE,
+      ))
+      ->condition('test_id', $test['test_id'])
+      ->execute();
 
     if (db_affected_rows()) {
       drupal_set_message(t('%title has been submitted for re-testing. Please be patient while you wait for results.',
@@ -192,7 +181,7 @@ function pift_pages_retest_confirm_form_submit($form, &$form_state) {
  *
  * @param integer Test ID to delete.
  */
-function pift_pages_delete_test_confirm_form(&$form_state, $test_id) {
+function pift_pages_delete_test_confirm_form($form, &$form_state, $test_id) {
   $test = pift_test_get($test_id);
 
   if ($test) {
@@ -205,12 +194,12 @@ function pift_pages_delete_test_confirm_form(&$form_state, $test_id) {
       ),
     );
     // Get the project id
-    $pid = db_result(db_query_range("SELECT project_nid from {versioncontrol_release_labels} where release_nid = %d", $test['id'], 0, 1));
-    $form['#redirect'] = 'node/' . $pid . '/testing-status';
+    $pid = db_query_range("SELECT project_nid from {versioncontrol_release_labels} where release_nid = %d", $test['id'])->fetchField();
+    $form_state['#redirect'] = 'node/' . $pid . '/testing-status';
     return confirm_form(
       $form,
       t('Are you sure you want to delete %title?', array('%title' => $form['test']['#value']['title'])),
-      $form['#redirect'],
+      $form_state['#redirect'],
       t('This will remove any existing results from the site, and reset the test status.') . '<br />' . t('This can help free up a branch test which is stuck in a "sent" state for long periods of time.'),
       t('Delete Test'),
       t('Cancel')
@@ -227,7 +216,9 @@ function pift_pages_delete_test_confirm_form(&$form_state, $test_id) {
 function pift_pages_delete_test_confirm_form_submit($form, &$form_state) {
   $test_id = $form_state['values']['test']['test_id'];
   if (!empty($test_id)) {
-    db_query('DELETE FROM {pift_test} WHERE test_id = %d', $test_id);
+    db_delete('pift_test')
+      ->condition('test_id', $test_id)
+      ->execute();
   }
 }
 
@@ -238,7 +229,11 @@ function pift_pages_delete_test_confirm_form_submit($form, &$form_state) {
  * @param boolean $status Issue status.
  * @return string HTML output.
  */
-function theme_pift_attachments(array $files, $status) {
+function theme_pift_attachments($variables) {
+  // TODO: Validate whether these variables are still valid after the project*
+  // changes introduced with the D7 port.
+  $files = $variables['files'];
+  $status = $variables['status'];
   $header = array(t('Attachment'), t('Size'), t('Status'), t('Test result'), t('Operations'));
   $rows = array();
   foreach ($files as $file) {
@@ -280,9 +275,12 @@ function theme_pift_attachments(array $files, $status) {
     }
     $row[] = ($operations ? implode(' | ', $operations) : '<em>' . t('None') . '</em>');
 
-    $rows[] = array('class' => $class, 'data' => $row);
+    $rows[] = array(
+      'class' => $class,
+      'data' => $row,
+    );
   }
-  return theme('table', $header, $rows);
+  return theme('table', array('header' => $header, 'rows' => $rows));
 }
 
 /**
diff --git a/pift.project.inc b/pift.project.inc
index ff0ca95..c477521 100644
--- a/pift.project.inc
+++ b/pift.project.inc
@@ -17,9 +17,10 @@ function pift_project_enabled($pid) {
   static $statuses = array();
 
   if (!isset($statuses[$pid])) {
-    $nid = db_result(db_query('SELECT pid
-                               FROM {pift_project}
-                               WHERE pid = %d', $pid));
+    $nid = db_query('SELECT pid FROM {pift_project} WHERE pid = :pid',
+        array(':pid' => $pid)
+      )
+      ->fetchField();
     $statuses[$pid] = ($nid !== FALSE);
   }
   return $statuses[$pid];
diff --git a/pift.results.inc b/pift.results.inc
deleted file mode 100644
index 3629bd7..0000000
--- a/pift.results.inc
+++ /dev/null
@@ -1,301 +0,0 @@
-<?php
-
-/**
- * @file
- * Provide the Automated Testing tab and UI functions.
- */
-
-/**
- * Produce html code for the Automated Testing tab.
- */
-function pift_results_project_tab($node, $version = NULL) {
-  // Load array of release branches in this projects repo.
-  $versions = pift_get_releases($node);
-
-  if (empty($version) && !empty($versions)) {
-    $version = current($versions);
-  }
-
-  // Retrieve project test results for the current branch/tag from {PIFT_TEST}
-  $tests = pift_results_testresult_load($node, $versions);
-
-  // Determine list of releases without tests
-  $noresults = $versions;
-
-  if (!empty($tests)) {
-    foreach ($tests as $testdata) {
-      foreach ($testdata as $test) {
-        unset($noresults[$test['version']]);
-      }
-    }
-    // Format test results
-    $statusoutput = pift_results_format_testresult_table($tests);
-  }
-  else {
-    $statusoutput = pift_results_empty_text();
-  }
-
-  // Okay we have the variable data let's build the page.
-  $content = array();
-  $content[] = '<p>' . t('This page provides information regarding automated testing status for this project\'s releases.') . '</p>';
-
-  // Add the 'Testing Status' table
-  $content[] = '<h3>' . t('Branch Test Results') . '</h3>';
-  $content[] =  $statusoutput;
-
-  // If there are any untested branches, provide a form which can be
-  // used to initiate an 'on-demand' branch test.
-  if (!empty($noresults)) {
-    $content[] = '<br /><br />' . drupal_get_form('pift_results_test_branch_form', $node, $noresults);
-  }
-
-  // TODO:  (Future development) If test has been queued or sent for too
-  // long, provide a form which will allow the user to reset the test (by
-  // updating status for tests with id = branch_nid in the pift_test table)
-
-  return implode("\n", $content);
-}
-
-/**
- * Prepare a form API array to mark a specific module version for testing
- *
- * @param $form_state
- * @param $project object The project node object
- * @param versions array List of versions
- * @return array
- */
-function pift_results_test_branch_form(&$form_state, $project, $versions = array()) {
-  $form = array(
-    '#prefix' => '<div class="container-inline">',
-    '#suffix' => '</div>',
-  );
-
-  $description = '<strong>' . t('Note: Automated tests are typically run on ".x" branches.') . '</strong><br />';
-  $description .= t('Core examples: 6.x, 7.x, 8.x') . '<br />';
-  $description .= t('Contrib examples: 6.x-1.x, 7.x-2.x, 8.x-1.x') . '<br />';
-  $description = t('Marking a branch for testing will add it to the list of branch/patch requests sent to the automated testing infrastructure. ');
-  $description .= t('Once the tests complete, the results will be passed back to drupal.org and reflected on this page. ');
-  $description .= '<br />';
-
-  $form['nid'] = array(
-    '#type' => 'value',
-    '#value' => $project->nid,
-  );
-
-  $form['additional'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Test Additional Branches'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-    '#prefix' => '<div>',
-    '#suffix' => '</div>',
-    '#description' => $description,
-  );
-
-  $form['additional']['version'] = array(
-    '#type' => 'select',
-    '#title' => t('Select a branch/tag to queue for testing'),
-    '#options' => $versions,
-    '#required' => TRUE,
-  );
-
-  $form['additional'][] = array(
-    '#type' => 'submit',
-    '#value' => t('Queue Test'),
-  );
-
-  return $form;
-}
-
-/**
- * Validate the submitted pift_results_test_branch_form form
- *
- * @param $form form to validate
- * @param $form_state A keyed array containing the current state of the form.
- */
-function pift_results_test_branch_form_validate($form, &$form_state) {
-  // Ensure required values have been passed
-  if (!$form_state['values']['nid'] || !$form_state['values']['version']) {
-    form_set_error('form', t('Error: Unable to determine correct project tag/branch.'));
-  }
-}
-
-/**
- * Process the submitted pift_results_test_branch_form form
- *
- * @param $form form to submit
- * @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']);
-}
-
-/**
- * Queues a particular project branch/tag/release for testing
- *
- * @param $nid The node id for the given project to be tested
- * @param $version A label representing a particular project branch/tag/release
- */
-function pift_results_test_add($nid, $version) {
-
-  // Get the repo_id for the project
-  $repo_id = db_result(db_query("SELECT repo_id FROM {versioncontrol_project_projects} WHERE nid = %d", $nid));
-
-  // Get the label_id for the passed version
-  $label_id = db_result(db_query("SELECT label_id FROM {versioncontrol_labels} WHERE repo_id = %d AND name = '%s'", $repo_id, $version));
-
-  /********************* Version Control Label ID code ********************
-  // For use if/when PIFT/PIFR are refactored to use label_id instead of release_nid.
-  if ($label_id) {
-    db_query('INSERT INTO {pift_test} (type, id, status) VALUES (%d, %d, %d)', PIFT_TYPE_RELEASE, $label_id, PIFT_STATUS_QUEUE);
-    drupal_set_message(t("This project branch/tag has been queued for testing."));
-  }
-  else {
-    drupal_set_message("Unable to queue this project branch/tag for testing, due to an error in resolving the corresponding label ID.", 'error');
-  }
-  */
-  /********************* 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) {
-    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.");
-  }
-  else {
-    drupal_set_message("This branch does not have an associated release node.  Unable to queue branch for testing.", 'error');
-  }
-}
-
-/**
- * Retrieves recent testing status for a given project branch/tag/release
- *
- * @param $node The node id for the given project
- * @param $versions An array of project branch/tag/release labels
- *
- * @return $status Array of test results, or FALSE if no results available
- */
-function pift_results_testresult_load($node, $versions) {
-  // Ensure we've been passed an actual project node
-  if ($node->type != 'project_project') {
-    return FALSE;
-  }
-  // Initialize placeholder for test results return value
-  $tests = array();
-
-  // Get the repo_id for the project
-  $repo_id = db_result(db_query("SELECT repo_id FROM {versioncontrol_project_projects} WHERE nid = %d", $node->nid));
-
-  // Get the label_ids for the passed versions
-  $label_ids = array();
-  $result = db_query("SELECT label_id, name FROM {versioncontrol_labels}
-          WHERE repo_id = %d AND name IN (" . db_placeholders($versions, 'text') . ")",
-          array_merge( (array) $repo_id, $versions));
-  while ($data = db_fetch_object($result)) {
-    $label_ids[$data->name] = $data->label_id;
-  }
-
-  /********************* Version Control Label ID code ********************
-  // Get the branch test results for this label_id
-  $sql = "Select * from {pift_test} where type = 1 and id IN (" . db_placeholders($label_ids, 'int') . ")";
-  $result = db_query($sql, $label_ids);
-  */
-  /********************* Release Nid code ********************/
-  // Retrieve corresponding release nids for the requested labels
-  $release_nids = array();
-  $result = db_query("SELECT release_nid, label_id FROM {versioncontrol_release_labels}
-          WHERE project_nid = %d AND label_id IN (" . db_placeholders($label_ids, 'int') . ")",
-          array_merge( (array) $node->nid, $label_ids));
-  while ($data = db_fetch_object($result)) {
-    $release_nids[$data->label_id] = $data->release_nid;
-  }
-
-  // Obtain the actual test results
-  $sql = "SELECT test_id, status, message, id, last_tested FROM {pift_test}
-          WHERE type = 1 AND id IN (" . db_placeholders($release_nids, 'int') . ")
-          ORDER BY last_tested DESC";
-  $result = db_query($sql, $release_nids);
-  while ($data = db_fetch_array($result)) {
-    $data['version'] = array_search(array_search($data['id'], $release_nids), $label_ids);
-    unset($data['id']);
-    $tests[$data['version']][] = $data;
-  }
-  if (!empty($tests)) {
-    // Re-order tests array
-    $sorted = array();
-    foreach ($versions as $version) {
-      if (array_key_exists($version, $tests)) {
-        $sorted[] = $tests[$version];
-      }
-    }
-    return $sorted;
-  }
-  return FALSE;
-}
-
-/**
- * Formats the testing results table for output
- *
- * @param $tests An array of test statuses to be rendered
- *
- * @return Themed table containing the testing status for the given branch
- */
-function pift_results_format_testresult_table($tests = array()) {
-  if (!empty($tests)) {
-    $header = array('Version', 'Status', 'Result', 'Last Tested', 'Operations');
-    foreach ($tests as $testdata) {
-      foreach ($testdata as $test) {
-        $rows[] = pift_results_build_testresult_row($test);
-      }
-    }
-  }
-  return theme('table', $header, $rows);
-}
-
-/**
- * Formats a row of the testing results table for output
- *
- * @param $test An array of test status information to render
- *
- * @return Themed table containing the testing status for the given branch
- */
-function pift_results_build_testresult_row($test = array()) {
-  if (!empty($test)) {
-    $options = array('1' => 'Queued', '2' => 'Sent', '3' => 'Failed', '4' => 'Passed');
-    $rowclass = array('1' => 'pift-retest', '2' => 'pift-retest', '3' => 'pift-fail', '4' => 'pift-pass');
-    $operations = array();
-    // A first-time queued test will not have a test_id, so hide links
-    if ($test['test_id'] > 0) {
-      $operations = array(
-        l('View Test', variable_get('pift_server', 'http://qa.drupal.org/') . 'pifr/test/' . $test['test_id']),
-      );
-      if (user_access('pift re-test files') && $test['status'] > PIFT_STATUS_SENT) {
-        $operations[] = l('Re-test', 'pift/retest/' . $test['test_id']);
-      }
-      if (user_access('pift re-test files') && $test['status'] == PIFT_STATUS_SENT) {
-        $operations[] = l('Remove Test', 'pift/delete/' . $test['test_id']);
-      }
-    }
-    // Hide old results if new test queued/sent
-    if ($test['status'] <= PIFT_STATUS_SENT) {
-      $test['message'] = t('Waiting for results.');
-    }
-    // Format 'Last Tested' value
-    $test['last_tested'] = $test['last_tested'] > 0 ? format_date($test['last_tested'], 'small') : 'never';
-    $row = array(
-      'data' => array($test['version'], $options[$test['status']], $test['message'], $test['last_tested'], implode(" | ", $operations)),
-      'class' => $rowclass[$test['status']],
-    );
-    return $row;
-  }
-  return array();
-}
-
-/**
- * Returns the default 'no test results available' text
- */
-function pift_results_empty_text() {
-  $default = <<<EOT
-<p>No Test Results Available.</p>
-<p>Please use the 'queue test' form below to trigger a new test.</p>
-EOT;
-  return $default;
-}
diff --git a/pift.test b/pift.test
index b5acd85..ec6fc54 100644
--- a/pift.test
+++ b/pift.test
@@ -104,7 +104,7 @@ class PIFTTestCase extends DrupalWebTestCase {
       'name' => 'Release type',
       'nodes[project_release]' => TRUE,
     );
-    $this->drupalPost('admin/content/taxonomy/add/vocabulary', $edit, t('Save'));
+    $this->drupalPost('admin/structure/taxonomy/add/vocabulary', $edit, t('Save'));
 
     $this->setUpTaxonomyTerms(2, array('Bug fixes', 'New features', 'Security release'));
 
@@ -114,9 +114,14 @@ class PIFTTestCase extends DrupalWebTestCase {
       'nodes[project_release]' => TRUE,
       'required' => TRUE,
     );
-    $this->drupalPost('admin/content/taxonomy/add/vocabulary', $edit, t('Save'));
+    $this->drupalPost('admin/structure/taxonomy/add/vocabulary', $edit, t('Save'));
 
-    db_query("UPDATE {vocabulary} SET module = '%s' WHERE vid = %d", 'project_release', 3);
+    db_update('taxonomy_vocabulary')
+      ->fields(array(
+        'module' => 'project_release',
+      ))
+      ->condition('vid', 3)
+      ->execute();
 
     // Set the variable to ensure that _project_release_get_api_vid() works.
     variable_set('project_release_api_vocabulary', 3);
@@ -132,7 +137,7 @@ class PIFTTestCase extends DrupalWebTestCase {
    */
   protected function setUpTaxonomyTerms($vid, array $terms) {
     // Visit taxonomy page ahead of time to remove all get requests from loop.
-    $this->drupalGet('admin/content/taxonomy/' . $vid . '/add/term');
+    $this->drupalGet('admin/structure/taxonomy/' . $vid . '/add/term');
 
     foreach ($terms as $term) {
       $edit = array(
@@ -208,7 +213,7 @@ class PIFTTestCase extends DrupalWebTestCase {
     $edit = array(
       'upload_extensions_default' => 'txt patch diff',
     );
-    $this->drupalPost('admin/settings/uploads', $edit, t('Save configuration'));
+    $this->drupalPost('admin/config/uploads', $edit, t('Save configuration'));
     $this->assertText(t('The configuration options have been saved.'));
 
     // Setup Drupal core and contrib projects.
@@ -227,7 +232,8 @@ class PIFTTestCase extends DrupalWebTestCase {
         'cvs[directory]' => $core ? '/' : '/modules/' . $project . '/',
       );
       $this->drupalPost('node/add/project-project', $edit, t('Save'));
-      $this->projects[$project] = node_load(array('title' => $edit['title']));
+      // TODO node_load_multiple returns an array of nodes, rather than a single node
+      $this->projects[$project] = node_load_multiple(array('title' => $edit['title']));
 
       // Drupal core requires a special version format string.
       if ($core) {
@@ -259,7 +265,8 @@ class PIFTTestCase extends DrupalWebTestCase {
         'body' => $this->randomString(32),
       );
       $this->drupalPost(NULL, $edit, t('Save'));
-      $this->releases[$project] = node_load(array('title' => $this->projects[$project]->title . ' 7.x' . ($core ? '' : '-1.x') . '-dev'));
+      // TODO node_load_multiple returns an array of nodes, rather than a single node
+      $this->releases[$project] = node_load_multiple(array('title' => $this->projects[$project]->title . ' 7.x' . ($core ? '' : '-1.x') . '-dev'));
 
       // Add project_info information, firstly module list.
       $info = array(
@@ -347,7 +354,7 @@ class PIFTTestCase extends DrupalWebTestCase {
   protected function addCommit($project, $branch = 'HEAD') {
     $commit = array(
       'rid' => $this->releases[$project]->nid,
-      'created' => time(),
+      'created' => REQUEST_TIME,
       'cvs_user' => $this->admin->name,
       'message' => $this->randomString(64),
     );
@@ -390,7 +397,8 @@ class PIFTTestCase extends DrupalWebTestCase {
 
     $this->drupalPost('node/add/project-issue/' . $this->projects[$project]->project['uri'], $edit, t('Save'));
     $this->assertRaw(t('@type %title has been created', array('@type' => 'Issue', '%title' => $edit['title'])));
-    return node_load(array('title' => $edit['title']));
+    // TODO node_load_multiple returns an array of nodes, rather than a single node
+    return node_load_multiple(array('title' => $edit['title']));
   }
 
   /**
@@ -437,11 +445,11 @@ class PIFTTestCase extends DrupalWebTestCase {
   protected function assertTest($test_id, $type, $id, $status) {
     $result = db_query('SELECT test_id
                         FROM {pift_test}
-                        WHERE test_id = %d
-                        AND type = %d
-                        AND id = %d
-                        AND status = %d', $test_id, $type, $id, $status);
-    return $this->assertTrue(db_result($result) !== FALSE, "Test found {test_id:$test_id, type:$type, id:$id, status:$status}");
+                        WHERE test_id = :test_id
+                        AND type = :type
+                        AND id = :id
+                        AND status = :status', array(':test_id' => $test_id, ':type' => $type, ':id' => $id, ':status' => $status));
+    return $this->assertTrue($result->fetchField() !== FALSE, "Test found {test_id:$test_id, type:$type, id:$id, status:$status}");
   }
 
   /**
@@ -456,11 +464,11 @@ class PIFTTestCase extends DrupalWebTestCase {
   protected function assertNoTest($test_id, $type, $id, $status) {
     $result = db_query('SELECT test_id
                         FROM {pift_test}
-                        WHERE test_id = %d
-                        AND type = %d
-                        AND id = %d
-                        AND status = %d', $test_id, $type, $id, $status);
-    return $this->assertFalse(db_result($result) !== FALSE, "Test not found {test_id:$test_id, type:$type, id:$id, status:$status}");
+                        WHERE test_id = :test_id
+                        AND type = :type
+                        AND id = :id
+                        AND status = :status', array(':test_id' => $test_id, ':type' => $type, ':id' => $id, ':status' => $status));
+    return $this->assertFalse($result->fetchField() !== FALSE, "Test not found {test_id:$test_id, type:$type, id:$id, status:$status}");
   }
 
   /**
@@ -511,6 +519,7 @@ class PIFTTestCase extends DrupalWebTestCase {
     $this->assertEqual($file['branch_identifier'], $this->releases[$key]->nid, 'Branch identifier matches');
     $this->assertEqual($file['client_identifier'], $fid, 'Client identifier matches');
     $this->assertEqual($file['file_url'], $file_url, 'File URL matches');
+    // TODO The second parameter to this function call should be an array.
     $this->assertEqual($file['link'], url('node/' . $nid, $options), 'File link matches');
   }
 
@@ -585,10 +594,10 @@ class PIFTTestCase extends DrupalWebTestCase {
   protected function loadLastComment($nid) {
     $result = db_query('SELECT cid
                         FROM {comments}
-                        WHERE nid = %d
+                        WHERE nid = :nid
                         ORDER BY cid DESC
-                        LIMIT 1', $nid);
-    return _comment_load(db_result($result));
+                        LIMIT 1', array(':nid' => $nid));
+    return comment_load($result->fetchField());
   }
 
   /**
diff --git a/pift.test.inc b/pift.test.inc
index 0bc5444..38cfafb 100644
--- a/pift.test.inc
+++ b/pift.test.inc
@@ -14,96 +14,113 @@
  * @return array Test data.
  */
 function pift_test_get($test_id) {
-  return db_fetch_array(db_query('SELECT t.*, f.fid, f.filename, f.filepath, f.filesize,
-                                     IF(u.nid IS NULL, cu.nid, u.nid) AS nid, cu.cid
-                                   FROM {pift_test} t
-                                   LEFT JOIN {files} f
-                                     ON (t.type = %d AND t.id = f.fid)
-                                   LEFT JOIN {upload} u
-                                     ON f.fid = u.fid
-                                   LEFT JOIN {comment_upload} cu
-                                     ON f.fid = cu.fid
-                                   WHERE t.test_id = %d', PIFT_TYPE_FILE, $test_id));
+  // Get test and files
+  $query = db_query('SELECT t.*, f.fid, f.filename, f.filepath, f.filesize,
+      FROM {pift_test} t
+      LEFT JOIN {file_managed} f
+        ON (t.type = :type AND t.id = f.fid)
+      WHERE t.test_id = :test_id',
+    array(':type' => PIFT_TYPE_FILE, ':test_id' => $test_id),
+    array('fetch' => PDO::FETCH_ASSOC)
+  );
+  $test = $query->execute()->fetchAssoc();
+
+  // Retrieve the associated project_issue node for each test.
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', 'node')
+    ->entityCondition('bundle', project_issue_issue_node_types())
+    ->propertyCondition('status', 1)
+    ->fieldCondition('field_issue_files', 'fid', $test['fid'], '=');
+  $result = $query->execute();
+  // Load the project_issue entities
+  if (isset($result['node'])) {
+    $test['nid'] = reset(array_keys($result['node']));
+    $issue = entity_load('node', $test['nid']);
+    // TODO: Determine how to add "cid" to the test item.
+  }
+  return $test;
 }
 
 /**
  * Get the files and test data for the specified comment ID.
  *
+ * TODO:  Confirm this is no longer required after the Project* changes during
+ * the port to D7.  This is only called from pift_comment_view(), which should
+ * no longer be required.
+ *
  * @param integer $cid Comment ID.
  * @return array List of files and test data.
  */
-function pift_test_get_files_comment($cid) {
-  $result = db_query('SELECT f.fid, f.filename, f.filepath, f.filesize, cu.nid, cu.cid, t.*
-                      FROM {files} f
-                      INNER JOIN {comment_upload} cu
-                        ON f.fid = cu.fid
-                      LEFT JOIN {pift_test} t
-                        ON (t.type = %d AND f.fid = t.id)
-                      WHERE cu.cid = %d
-                      ORDER BY cu.weight, f.fid', PIFT_TYPE_FILE, $cid);
-  $files = array();
-  while ($file = db_fetch_array($result)) {
-    $files[] = $file;
-  }
-  return $files;
-}
+//function pift_test_get_files_comment($cid) {
+//  return db_query('SELECT f.fid, f.filename, f.filepath, f.filesize, cu.nid, cu.cid, t.*
+//                      FROM {files} f
+//                      INNER JOIN {comment_upload} cu
+//                        ON f.fid = cu.fid
+//                      LEFT JOIN {pift_test} t
+//                        ON (t.type = :type AND f.fid = t.id)
+//                      WHERE cu.cid = :cid
+//                      ORDER BY cu.weight, f.fid', array(':type' => PIFT_TYPE_FILE, ':cid' => $cid), array('fetch' => PDO::FETCH_ASSOC));
+//}
 
 /**
  * Get the files and test data on comments for the specified node ID.
  *
+ * TODO:  Confirm this is no longer required after the Project* changes during
+ * the port to D7.  Because all files are now attached to the node itself, we
+ * should no longer need to concern ourselves with comments.
+ *
  * @param integer $nid Node ID.
  * @return array List of files and test data.
  */
-function pift_test_get_files_comment_all($nid) {
-  $result = db_query('SELECT f.fid, f.filename, f.filepath, f.filesize, cu.nid, cu.cid, t.*
-                      FROM {files} f
-                      INNER JOIN {comment_upload} cu
-                        ON f.fid = cu.fid
-                      LEFT JOIN {pift_test} t
-                        ON (t.type = %d AND f.fid = t.id)
-                      WHERE cu.nid = %d
-                      ORDER BY cu.weight, f.fid', PIFT_TYPE_FILE, $nid);
-  $files = array();
-  while ($file = db_fetch_array($result)) {
-    $files[] = $file;
-  }
-  return $files;
-}
-
+//function pift_test_get_files_comment_all($nid) {
+//  return db_query('SELECT f.fid, f.filename, f.filepath, f.filesize, cu.nid, cu.cid, t.*
+//                      FROM {files} f
+//                      INNER JOIN {comment_upload} cu
+//                        ON f.fid = cu.fid
+//                      LEFT JOIN {pift_test} t
+//                        ON (t.type = :type AND f.fid = t.id)
+//                      WHERE cu.nid = :nid
+//                      ORDER BY cu.weight, f.fid', array(':type' => PIFT_TYPE_FILE, ':nid' => $nid), array('fetch' => PDO::FETCH_ASSOC));
+//}
 
 /**
  * Get the files and test data for the specified node ID.
  *
+ * TODO: Confirm this is no longer needed after the Project* changes during the
+ * port to D7.  This is only called from pift_test_get_files_node_all, which is
+ * only called from pift_test_add_previous_files(), which in turn is only
+ * called from pift_comment_insert(); which does not apply now that all files
+ * are attached to a node directly.
+ *
  * @param integer $nid Node ID.
  * @return array List of files and test data.
  */
-function pift_test_get_files_node($nid) {
-  $node = node_load($nid);
-  $result = db_query('SELECT f.fid, f.filename, f.filepath, f.filesize, u.nid, t.*
-                      FROM {files} f
-                      INNER JOIN {upload} u
-                        ON f.fid = u.fid
-                      LEFT JOIN {pift_test} t
-                        ON (t.type = %d AND f.fid = t.id)
-                      WHERE u.nid = %d AND u.vid = %d
-                      ORDER BY u.weight, f.fid', PIFT_TYPE_FILE, $node->nid, $node->vid);
-  $files = array();
-  while ($file = db_fetch_array($result)) {
-    $files[] = $file;
-  }
-  return $files;
-}
+//function pift_test_get_files_node($nid) {
+//  return db_query('SELECT f.fid, f.filename, f.filepath, f.filesize, u.nid, t.*
+//                      FROM {files} f
+//                      INNER JOIN {upload} u
+//                        ON f.fid = u.fid
+//                      LEFT JOIN {pift_test} t
+//                        ON (t.type = :type AND f.fid = t.id)
+//                      WHERE u.nid = :nid AND u.vid = :vid
+//                      ORDER BY u.weight, f.fid', array(':type' => PIFT_TYPE_FILE, 'nid' => $node->nid, ':vid' => $node->vid), array('fetch' => PDO::FETCH_ASSOC));
+//}
 
 
 /**
  * Get the files and test data for the specified node ID and its comments.
  *
+ * TODO: Confirm this is no longer needed after the Project* changes during the
+ * port to D7.  This is only called from pift_test_add_previous_files(), which
+ * in turn is only called from pift_comment_insert(); which does not apply now
+ * that all files are attached to a node directly.
+ *
  * @param integer $nid Node ID.
  * @return array List of files and test data.
  */
-function pift_test_get_files_node_all($nid) {
-  return array_merge(pift_test_get_files_node($nid), pift_test_get_files_comment_all($nid));
-}
+//function pift_test_get_files_node_all($nid) {
+//  return array_merge(pift_test_get_files_node($nid), pift_test_get_files_comment_all($nid));
+//}
 
 /**
  * Check the criteria for the specified issue.
@@ -114,25 +131,29 @@ function pift_test_get_files_node_all($nid) {
  * @return boolean Passed criteria.
  */
 function pift_test_check_criteria_issue($node) {
-  // Ensure that the issue is in one of the acceptable statuses.
-  if (!in_array($node->project_issue['sid'], variable_get('pift_status', array()))) {
+  // Ensure we are passed an issue node
+  if (!project_issue_node_is_issue()) {
+    return FALSE;
+  }
+  // Ensure the issue has a valid 'testing' status
+  if (!in_array($node->field_issue_status[LANGUAGE_NONE][0]['value'], variable_get('pift_status', array()))) {
     return FALSE;
   }
-
   // Ensure that the project has testing enabled.
-  if (!pift_project_enabled($node->project_issue['pid'])) {
+  $pid = $node->field_project[LANGUAGE_NONE][0]['target_id'];
+  if (!pift_project_enabled($pid)) {
     return FALSE;
   }
-
   // Ensure that one of the compatibility terms is present on the release node.
-  $release = node_load($node->project_issue['rid']);
-  $api_versions = pift_core_api_versions();
-  foreach ($api_versions as $api_version) {
-    if (array_key_exists($api_version, $release->taxonomy)) {
-      return TRUE;
-    }
+  $version = $node->field_issue_version[LANGUAGE_NONE][0]['value'];
+  if (!($rid = project_release_exists($pid, $version))) {
+    return FALSE;
+  }
+  $release_node = node_load($rid);
+  $release_api = project_release_get_release_api_tid($release_node);
+  if (array_key_exists($release_api, pift_core_api_versions())) {
+    return TRUE;
   }
-
   return FALSE;
 }
 
@@ -155,8 +176,7 @@ function pift_test_check_criteria_file(array $file) {
  * @param array $files Files to add.
  */
 function pift_test_add_files(array $files) {
-  foreach ($files as $file) {
-    $file = (array) $file;
+  foreach ($files[LANGUAGE_NONE] as $file) {
     if (pift_test_check_criteria_file($file)) {
       pift_test_add(PIFT_TYPE_FILE, $file['fid']);
     }
@@ -170,16 +190,27 @@ function pift_test_add_files(array $files) {
  * @param integer $id Related test detail record ID, either rid, or fid.
  */
 function pift_test_add($type, $id) {
-  db_query('INSERT INTO {pift_test} (type, id, status)
-            VALUES (%d, %d, %d)', $type, $id, PIFT_STATUS_QUEUE);
+  $id = db_insert('pift_test')
+    ->fields(array(
+      'type' => $type,
+      'id' => $id,
+      'status' => PIFT_STATUS_QUEUE,
+    ))
+    ->execute();
 }
 
+/**
+ * Mark a test as sent.
+ */
 function pift_test_sent($test_id, $type, $id) {
-  db_query('UPDATE {pift_test}
-            SET test_id = %d,
-            status = %d
-            WHERE type = %d
-            AND id = %d', $test_id, PIFT_STATUS_SENT, $type, $id);
+  db_update('pift_test')
+    ->fields(array(
+      'test_id' => $test_id,
+      'status' => PIFT_STATUS_SENT,
+    ))
+    ->condition('type', $type)
+    ->condition('id', $id)
+    ->execute();
 }
 
 /**
@@ -188,9 +219,12 @@ function pift_test_sent($test_id, $type, $id) {
  * @param integer $test_id Test ID.
  */
 function pift_test_requeue($test_id) {
-  db_query('UPDATE {pift_test}
-            SET status = %d
-            WHERE test_id = %d', PIFT_STATUS_QUEUE, $test_id);
+  db_update('pift_test')
+    ->fields(array(
+      'status' => PIFT_STATUS_QUEUE,
+    ))
+    ->condition('test_id', $test_id)
+    ->execute();
 }
 
 /**
@@ -199,24 +233,28 @@ function pift_test_requeue($test_id) {
  */
 function pift_test_delete_files() {
   db_query('DELETE FROM {pift_test}
-            WHERE type = %d
-            AND id NOT IN (
-              SELECT fid
-              FROM {files}
-            )', PIFT_TYPE_FILE);
+    WHERE type = :type
+    AND id NOT IN (
+      SELECT fid
+      FROM {file_managed}
+    )', array(':type' => PIFT_TYPE_FILE));
 }
 
 /**
  * Add previously submitted files once the node meets the criteria.
  *
+ * TODO:  Confirm this is no longer required after the Project* changes during
+ * the port to D7.  This is only called from pift_comment_insert(), which is
+ * irrelevant when files are attached directly to a node.
+ *
  * @param integer $nid Node ID.
  */
-function pift_test_add_previous_files($nid) {
-  $files = pift_test_get_files_node_all($nid);
-  foreach ($files as $file) {
-    $file = (array) $file;
-    if ($file['test_id'] === NULL && pift_test_check_criteria_file($file)) {
-      pift_test_add(PIFT_TYPE_FILE, $file['fid']);
-    }
-  }
-}
+//function pift_test_add_previous_files($nid) {
+//  $files = pift_test_get_files_node_all($nid);
+//  foreach ($files as $file) {
+//    $file = (array) $file;
+//    if ($file['test_id'] === NULL && pift_test_check_criteria_file($file)) {
+//      pift_test_add(PIFT_TYPE_FILE, $file['fid']);
+//    }
+//  }
+//}
diff --git a/tests/pifr_xmlrpc/pifr_xmlrpc.info b/tests/pifr_xmlrpc/pifr_xmlrpc.info
index bd9617e..7e6e517 100644
--- a/tests/pifr_xmlrpc/pifr_xmlrpc.info
+++ b/tests/pifr_xmlrpc/pifr_xmlrpc.info
@@ -1,8 +1,7 @@
 name = PIFR XML-RPC
 description = Provides a dummy implementation of PIFR XML-RPC API for testing.
 package = Project
-core = 6.x
-php = 5
+core = 7.x
 hidden = TRUE
-files[] = pifr_xmlrpc.module
+
 dependencies[] = pift
diff --git a/tests/pifr_xmlrpc/pifr_xmlrpc.module b/tests/pifr_xmlrpc/pifr_xmlrpc.module
index 983cc4d..7db4247 100644
--- a/tests/pifr_xmlrpc/pifr_xmlrpc.module
+++ b/tests/pifr_xmlrpc/pifr_xmlrpc.module
@@ -13,17 +13,29 @@
 define('PROJECT_NOMAIL', 17);
 
 /**
- * Implementation of hook_xmlrpc().
+ * Implements hook_xmlrpc().
  */
 function pifr_xmlrpc_xmlrpc() {
   return array(
-    array('pifr.queue', 'pifr_xmlrpc_queue', array('int', 'string', 'struct'),
-           t('Queue a batch of files for testing. (Called by PIFT)')),
-    array('pifr.retrieve', 'pifr_xmlrpc_retrieve', array('struct', 'string', 'int'),
-           t('Retrieve test results. (Called by PIFT)')),
+    array(
+      'pifr.queue',
+      'pifr_xmlrpc_queue',
+      array('int', 'string', 'struct'),
+      t('Queue a batch of files for testing. (Called by PIFT)'),
+    ),
+    array(
+      'pifr.retrieve',
+      'pifr_xmlrpc_retrieve',
+      array('struct', 'string', 'int'),
+      t('Retrieve test results. (Called by PIFT)'),
+    ),
   );
 }
 
+/**
+ * @todo Please document this function.
+ * @see http://drupal.org/node/1354
+ */
 function pifr_xmlrpc_queue($client_key, $batch) {
   $response = array(
     'branches' => array(),
@@ -40,6 +52,10 @@ function pifr_xmlrpc_queue($client_key, $batch) {
   return $response;
 }
 
+/**
+ * @todo Please document this function.
+ * @see http://drupal.org/node/1354
+ */
 function pifr_xmlrpc_retrieve() {
   if (!($response = variable_get('pifr_xmlrpc_response', FALSE))) {
     $response = array(
