/[drupal]/contributions/modules/project_issue_file_test/pift.module
ViewVC logotype

Contents of /contributions/modules/project_issue_file_test/pift.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.31 - (show annotations) (download) (as text)
Fri Oct 23 21:01:51 2009 UTC (5 weeks ago) by boombatower
Branch: MAIN
Branch point for: DRUPAL-7--1
Changes since 1.30: +25 -1 lines
File MIME type: text/x-php
Abstract core API version term ID location.
1 <?php
2 // $Id: pift.module,v 1.30 2009/10/23 03:06:02 boombatower Exp $
3
4 /**
5 * @file
6 * Integrates into project to provide an automated testing hub.
7 *
8 * Copyright 2008-2009 by Jimmy Berry ("boombatower", http://drupal.org/user/214218)
9 */
10
11 /*
12 * Variables loaded as constants.
13 */
14 define('PIFT_FREQUENCY', variable_get('pift_frequency', -1));
15 define('PIFT_LAST', variable_get('pift_last', 0));
16 define('PIFT_KEY', variable_get('pift_key', ''));
17 define('PIFT_SERVER', variable_get('pift_server', ''));
18 define('PIFT_DESCRIPTION', variable_get('pift_description', ''));
19 define('PIFT_FOLLOWUP_FAIL', variable_get('pift_followup_fail', 0));
20 define('PIFT_FOLLOWUP_RETEST', variable_get('pift_followup_retest', 0));
21 define('PIFT_REGEX', variable_get('pift_regex', '/(\.diff|\.patch)$/'));
22 define('PIFT_PID', variable_get('pift_pid', -1));
23 define('PIFT_RETEST', variable_get('pift_retest', 24 * 60 * 60));
24 define('PIFT_DELETE', variable_get('pift_delete', FALSE));
25 define('PIFT_LAST_CID', variable_get('pift_last_cid', 0));
26
27 /**
28 * Maximum number of items of the same type to transfer in a single XML-RPC
29 * request.
30 */
31 define('PIFT_XMLRPC_MAX', 50);
32
33 /**
34 * Maximum number of batches to send during a single cron run.
35 */
36 define('PIFT_XMLRPC_MAX_BATCHES', 3);
37
38 /**
39 * Maximum number of commits to process in a single cron run.
40 */
41 define('PIFT_COMMIT_MAX', 100);
42
43 /*
44 * Test type codes.
45 */
46 define('PIFT_TYPE_RELEASE', 1);
47 define('PIFT_TYPE_FILE', 2);
48
49 /*
50 * Test status codes.
51 */
52 define('PIFT_STATUS_QUEUE', 1);
53 define('PIFT_STATUS_SENT', 2);
54 define('PIFT_STATUS_FAIL', 3);
55 define('PIFT_STATUS_PASS', 4);
56
57 if (!defined('PIFR_RESPONSE_ACCEPTED')) {
58 /*
59 * PIFR XML-RPC response codes.
60 */
61 define('PIFR_RESPONSE_ACCEPTED', 1);
62 define('PIFR_RESPONSE_INVALID_SERVER', 2);
63 define('PIFR_RESPONSE_DENIED', 3);
64
65 /*
66 * Project type codes.
67 */
68 define('PIFR_SERVER_PROJECT_TYPE_CORE', 1);
69 define('PIFR_SERVER_PROJECT_TYPE_MODULE', 2);
70 }
71
72 /*
73 * Load required includes.
74 */
75 module_load_include('project.inc', 'pift');
76 module_load_include('test.inc', 'pift');
77
78 /**
79 * Implementation of hook_menu().
80 */
81 function pift_menu() {
82 $items = array();
83
84 $items['admin/project/pift'] = array(
85 'title' => 'PIFT settings',
86 'description' => 'Configure PIFT.',
87 'page callback' => 'drupal_get_form',
88 'page arguments' => array('pift_admin_settings_form'),
89 'access arguments' => array('administer projects'),
90 'file' => 'pift.admin.inc',
91 );
92 $items['pift/retest/%'] = array(
93 'title' => 'Request to re-test a file',
94 'page callback' => 'drupal_get_form',
95 'page arguments' => array('pift_pages_retest_confirm_form', 2),
96 'access arguments' => array('pift re-test files'),
97 'file' => 'pift.pages.inc',
98 'type' => MENU_CALLBACK,
99 );
100
101 return $items;
102 }
103
104 /**
105 * Implementation of hook_perm().
106 */
107 function pift_perm() {
108 return array(
109 'pift re-test files',
110 'pift enable project testing',
111 );
112 }
113
114 /**
115 * Implementation of hook_theme().
116 */
117 function pift_theme() {
118 return array(
119 'pift_attachments' => array(
120 'arguments' => array(
121 'files' => array(),
122 ),
123 'file' => 'pift.pages.inc',
124 ),
125 'pift_auto_followup' => array(
126 'arguments' => array(
127 'message' => '',
128 'nid' => 0,
129 'cid' => 0,
130 ),
131 ),
132 );
133 }
134
135 /**
136 * Implementation of hook_init().
137 */
138 function pift_init() {
139 drupal_add_css(drupal_get_path('module', 'pift') . '/pift.css');
140 }
141
142 /**
143 * Implementation of hook_cron().
144 */
145 function pift_cron() {
146 if (PIFT_DELETE) {
147 // An issue comment or node has been deleted, remove related test entries.
148 pift_test_delete_files();
149 variable_set('pift_delete', FALSE);
150 }
151
152 // Check if sending is enabled and that the sending frequency has elapsed.
153 $time = time();
154 if (PIFT_FREQUENCY != -1 && $time > PIFT_LAST + PIFT_FREQUENCY) {
155 module_load_include('cron.inc', 'pift');
156
157 // Requeue all tests that have passed the re-test interval.
158 pift_cron_retest();
159
160 // Queue all tests related to any commits that have occured.
161 $cid = db_result(db_query('SELECT MAX(cid) FROM {cvs_messages}'));
162 $cid = min($cid, PIFT_LAST_CID + PIFT_COMMIT_MAX);
163 if ($cid > PIFT_LAST_CID) {
164 pift_cron_test_release(PIFT_LAST_CID + 1, $cid);
165 variable_set('pift_last_cid', $cid);
166 }
167
168 // Send a batch of queued tests.
169 pift_cron_queue_batch();
170
171 // Retreive any results that have occured since last cron run.
172 pift_cron_retreive_results();
173
174 // Store current time as last run.
175 variable_set('pift_last', $time);
176 }
177 }
178
179 /**
180 * Implementation of hook_form_alter(). Must use generic form_alter() due to
181 * comment_upload implementation.
182 */
183 function pift_form_alter(&$form, $form_state, $form_id) {
184 if ($form_id == 'comment_form' || $form_id == 'project_issue_node_form') {
185 module_load_include('pages.inc', 'pift');
186 pift_pages_description_add($form, $form_state, $form_id);
187 }
188 }
189
190 /**
191 * Implementation of hook_form_alter(): project_issue_project_edit_form.
192 */
193 function pift_form_project_issue_project_edit_form_alter(&$form, $form_state) {
194 module_load_include('pages.inc', 'pift');
195 pift_pages_project_issue_settings($form, $form_state);
196 }
197
198 /**
199 * Implementation of hook_nodeapi().
200 */
201 function pift_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
202 if ($node->type != 'project_issue' || empty($node->files)) {
203 return;
204 }
205
206 switch ($op) {
207 case 'view':
208 if (!$a3 && pift_project_enabled($node->project_issue['pid'])) { // Full view.
209 $files = pift_test_get_files_node($node->nid);
210 $node->content['pift_files'] = array(
211 '#value' => '<div id="pift-results-' . $node->nid . '">' .
212 theme('pift_attachments', $files) . '</div>',
213 '#weight' => 50,
214 );
215 unset($node->content['files']); // Remove old attachments table.
216 }
217 break;
218 case 'insert':
219 $proper = pift_nodeapi_clean($node);
220 if (pift_test_check_criteria_issue($proper)) {
221 $files = upload_load($proper);
222 pift_test_add_files($files);
223 }
224 break;
225 case 'delete':
226 variable_set('pift_delete', TRUE);
227 break;
228 }
229 }
230
231 /**
232 * Cleanup the inconsistent project_issue property placement.
233 *
234 * In order to remove the need to a bunch of conditions all over PIFT, convert
235 * the inconsistent node format to the one used everywhere else. The
236 * inconsistent format is only found during node creation, after a node has
237 * been created and hook_load() is used the properties are prefixed by
238 * project_issue.
239 *
240 * @param object $node Node to convert.
241 * @return object Properly formatted node.
242 * @link http://drupal.org/node/519562
243 */
244 function pift_nodeapi_clean($node) {
245 $node->project_issue = array();
246
247 $fields = array('pid', 'rid', 'component', 'category', 'priority', 'assigned', 'sid');
248 foreach ($fields as $field) {
249 $node->project_issue[$field] = $node->$field;
250 }
251
252 return $node;
253 }
254
255 /**
256 * Implementation of hook_comment().
257 */
258 function pift_comment(&$comment, $op) {
259 $node = pift_comment_load_node($comment);
260 if ($node->type != 'project_issue') {
261 return;
262 }
263
264 switch ($op) {
265 case 'view':
266 if (!empty($comment->files) && pift_project_enabled($node->project_issue['pid'])) {
267 // Remove comment_upload attachments table and generate new one.
268 $comment->comment = preg_replace('/<table class="comment-upload-attachments">.*?<\/table>/s', '', $comment->comment);
269 $files = pift_test_get_files_comment($comment->cid);
270 $comment->comment .= '<div id="pift-results-' . $comment->nid . '-' . $comment->cid . '">' .
271 theme('pift_attachments', $files) . '</div>';
272 }
273 break;
274 case 'insert':
275 if (pift_test_check_criteria_issue($node)) {
276 if (!empty($comment->files)) {
277 // Add attachments to this comment to the send queue.
278 $files = comment_upload_load_files($comment['cid']);
279 pift_test_add_files($files);
280 }
281
282 // Add previously submitted files if issue state changes.
283 pift_test_add_previous_files($comment['nid']);
284 }
285 break;
286 case 'delete':
287 variable_set('pift_delete', TRUE);
288 break;
289 }
290 }
291
292 /**
293 * Load the parent node for the specified comment.
294 *
295 * @param mixed $comment Comment information passed to hook_comment().
296 * @return object Parent node.
297 */
298 function pift_comment_load_node($comment) {
299 // Comment can be a comment object, a form, or form_values.
300 if (is_object($comment)) {
301 $nid = $comment->nid;
302 }
303 elseif (is_array($comment)) {
304 $nid = is_array($comment['nid']) ? $comment['nid']['#value'] : $comment['nid'];
305 }
306 return node_load($nid);
307 }
308
309 /**
310 * Theme the auto followup comments.
311 *
312 * @param string $message Comment message.
313 * @param integer $nid Node ID containting the failed test.
314 * @param integer $cid Comment ID, if applicable, containing the failed test.
315 * @return string HTML output.
316 */
317 function theme_pift_auto_followup($type, $nid, $cid) {
318 global $user;
319 if ($type == 'retest') {
320 return t('!user requested that <a href="#@id">failed test</a> be re-tested.',
321 array('!user' => theme('username', $user), '@id' => "pift-results-$nid" . ($cid ? "-$cid" : '')));
322 }
323 elseif ($type == 'fail') {
324 return t('The last submitted patch <a href="#@id">failed testing</a>.',
325 array('@id' => "pift-results-$nid" . ($cid ? "-$cid" : '')));
326 }
327 return '';
328 }
329
330 /**
331 * Attempt to determine the Drupal core API version.
332 *
333 * @param object $node Node object.
334 * @return array Core API version information in the format
335 * array($api_version, $api_tid).
336 */
337 function pift_core_api($node) {
338 if (!empty($node->taxonomy)) {
339 // Relase API version vocabulary.
340 $api_vid = _project_release_get_api_vid();
341
342 foreach ($node->taxonomy as $tid => $term) {
343 if ($term->vid == $api_vid) {
344 $api_version = array_shift(explode('.', $term->name, 2));
345 $api_tid = $term->tid;
346
347 return array($api_version, $api_tid);
348 }
349 }
350 }
351 return array(NULL, NULL);
352 }
353
354 /**
355 * Load the core release for the given API term ID.
356 *
357 * @param integer $api_tid Drupal core API compatibility term ID, of the
358 * vocabulary defined by _project_release_get_api_vid.
359 * @return Drupal core release NID.
360 * @see _project_release_get_api_vid()
361 */
362 function pift_core_api_release($api_tid) {
363 static $api_releases = array();
364
365 if (!isset($api_branches[$api_tid])) {
366 $result = db_query('SELECT p.nid
367 FROM {node} n
368 JOIN {project_release_nodes} p
369 ON p.nid = n.nid
370 JOIN {term_node} t
371 ON t.vid = n.vid
372 WHERE p.pid = %d
373 AND p.rebuild = %d
374 AND t.tid = %d
375 ORDER BY n.vid DESC
376 LIMIT 1', PIFT_PID, 1, $api_tid);
377 $api_releases[$api_tid] = db_result($result);
378 }
379
380 return $api_releases[$api_tid];
381 }

  ViewVC Help
Powered by ViewVC 1.1.2