Indefero

Indefero Git Source Tree

Root/src/IDF/Commit.php

1<?php
2/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3/*
4# ***** BEGIN LICENSE BLOCK *****
5# This file is part of InDefero, an open source project management application.
6# Copyright (C) 2008 Céondo Ltd and contributors.
7#
8# InDefero is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# InDefero is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16n# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21#
22# ***** END LICENSE BLOCK ***** */
23
24Pluf::loadFunction('Pluf_HTTP_URL_urlForView');
25Pluf::loadFunction('Pluf_Template_dateAgo');
26
27/**
28 * Base definition of a commit.
29 *
30 * By having a reference in the database for each commit, one can
31 * easily generate a timeline or use the search engine. Commit details
32 * are normally always taken from the underlining SCM.
33 */
34class IDF_Commit extends Pluf_Model
35{
36 public $_model = __CLASS__;
37 public $extra = null; /**< Extra data as IDF_Gconf object */
38
39 function init()
40 {
41 $this->_a['table'] = 'idf_commits';
42 $this->_a['model'] = __CLASS__;
43 $this->_a['cols'] = array(
44 // It is mandatory to have an "id" column.
45 'id' =>
46 array(
47 'type' => 'Pluf_DB_Field_Sequence',
48 'blank' => true,
49 ),
50 'project' =>
51 array(
52 'type' => 'Pluf_DB_Field_Foreignkey',
53 'model' => 'IDF_Project',
54 'blank' => false,
55 'verbose' => __('project'),
56 'relate_name' => 'commits',
57 ),
58 'author' =>
59 array(
60 'type' => 'Pluf_DB_Field_Foreignkey',
61 'model' => 'Pluf_User',
62 'is_null' => true,
63 'verbose' => __('submitter'),
64 'relate_name' => 'submitted_commit',
65 'help_text' => 'This will allow us to list the latest commits of a user in its profile.',
66 ),
67 'origauthor' =>
68 array(
69 'type' => 'Pluf_DB_Field_Varchar',
70 'blank' => false,
71 'size' => 150,
72 'help_text' => 'As we do not necessary have the mapping between the author in the database and the scm, we store the scm author commit information here. That way we can update the author info later in the process.',
73 ),
74 'scm_id' =>
75 array(
76 'type' => 'Pluf_DB_Field_Varchar',
77 'blank' => false,
78 'size' => 50,
79 'index' => true,
80 'help_text' => 'The id of the commit. For git, it will be the SHA1 hash, for subversion it will be the revision id.',
81 ),
82 'summary' =>
83 array(
84 'type' => 'Pluf_DB_Field_Varchar',
85 'blank' => false,
86 'size' => 250,
87 'verbose' => __('summary'),
88 ),
89 'fullmessage' =>
90 array(
91 'type' => 'Pluf_DB_Field_Text',
92 'blank' => true,
93 'verbose' => __('changelog'),
94 'help_text' => 'This is the full message of the commit.',
95 ),
96 'creation_dtime' =>
97 array(
98 'type' => 'Pluf_DB_Field_Datetime',
99 'blank' => true,
100 'verbose' => __('creation date'),
101 'index' => true,
102 'help_text' => 'Date of creation by the scm',
103 ),
104 );
105 }
106
107 function __toString()
108 {
109 return $this->summary.' - ('.$this->scm_id.')';
110 }
111
112 function _toIndex()
113 {
114 $str = str_repeat($this->summary.' ', 4).' '.$this->fullmessage;
115 return Pluf_Text::cleanString(html_entity_decode($str, ENT_QUOTES, 'UTF-8'));
116 }
117
118 function postSave($create=false)
119 {
120 IDF_Search::index($this);
121 if ($create) {
122 IDF_Timeline::insert($this, $this->get_project(),
123 $this->get_author(), $this->creation_dtime);
124 }
125 }
126
127 function preDelete()
128 {
129 IDF_Timeline::remove($this);
130 IDF_Search::remove($this);
131 IDF_Gconf::dropForModel($this);
132 }
133
134 /**
135 * Create a commit from a simple class commit info of a changelog.
136 *
137 * @param stdClass Commit info
138 * @param IDF_Project Current project
139 * @return IDF_Commit
140 */
141 public static function getOrAdd($change, $project)
142 {
143 $sql = new Pluf_SQL('project=%s AND scm_id=%s',
144 array($project->id, $change->commit));
145 $r = Pluf::factory('IDF_Commit')->getList(array('filter'=>$sql->gen()));
146 if ($r->count() > 0) {
147 $r[0]->extra = new IDF_Gconf();
148 $r[0]->extra->serialize = true;
149 $r[0]->extra->setModel($r[0]);
150 $r[0]->extra->initCache();
151 return $r[0];
152 }
153 if (!isset($change->full_message)) {
154 $change->full_message = '';
155 }
156 $scm = IDF_Scm::get($project);
157 $commit = new IDF_Commit();
158 $commit->project = $project;
159 $commit->scm_id = $change->commit;
160 $commit->summary = self::toUTF8($change->title);
161 $commit->fullmessage = self::toUTF8($change->full_message);
162 $commit->author = $scm->findAuthor($change->author);
163 $commit->origauthor = self::toUTF8($change->author);
164 $commit->creation_dtime = $change->date;
165 $commit->create();
166 $extra = $scm->getExtraProperties($change);
167 $commit->extra = new IDF_Gconf();
168 $commit->extra->serialize = true; // As we can store arrays
169 $commit->extra->setModel($commit);
170 foreach ($extra as $key => $val) {
171 $commit->extra->setVal($key, $val);
172 }
173 $commit->notify($project->getConf());
174 return $commit;
175 }
176
177 /**
178 * Convert encoding to UTF8.
179 *
180 * If an array is given, the encoding is detected only on the
181 * first value and then used to convert all the strings.
182 *
183 * @param mixed String or array of string to be converted
184 * @param bool Returns the encoding together with the converted text (false)
185 * @return mixed String or array of string or array of res + encoding
186 */
187 public static function toUTF8($text, $get_encoding=False)
188 {
189 $enc = 'ASCII, UTF-8, ISO-8859-1, JIS, EUC-JP, SJIS';
190 $ref = $text;
191 if (is_array($text)) {
192 $ref = $text[0];
193 }
194 if (Pluf_Text_UTF8::check($ref)) {
195 return (!$get_encoding) ? $text : array($text, 'UTF-8');
196 }
197 $encoding = mb_detect_encoding($ref, $enc, true);
198 if ($encoding == false) {
199 $encoding = Pluf_Text_UTF8::detect_cyr_charset($ref);
200 }
201 if (is_array($text)) {
202 foreach ($text as $t) {
203 $res[] = mb_convert_encoding($t, 'UTF-8', $encoding);
204 }
205 return (!$get_encoding) ? $res : array($res, $encoding);
206 } else {
207 $res = mb_convert_encoding($text, 'UTF-8', $encoding);
208 return (!$get_encoding) ? $res : array($res, $encoding);
209 }
210 }
211
212 /**
213 * Returns the timeline fragment for the commit.
214 *
215 *
216 * @param Pluf_HTTP_Request
217 * @return Pluf_Template_SafeString
218 */
219 public function timelineFragment($request)
220 {
221 $url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit',
222 array($request->project->shortname,
223 $this->scm_id));
224 $out = '<tr class="log"><td><a href="'.$url.'">'.
225 Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')).
226 '</a></td><td>';
227 $stag = new IDF_Template_ShowUser();
228 $user = $stag->start($this->get_author(), $request, $this->origauthor, false);
229 $tag = new IDF_Template_IssueComment();
230 $out .= $tag->start($this->summary, $request, false);
231 if (0 && $this->fullmessage) {
232 $out .= '<br /><br />'.$tag->start($this->fullmessage, $request, false);
233 }
234 $out .= '</td>
235</tr>
236<tr class="extra">
237<td colspan="2">
238<div class="helptext right">'.sprintf(__('Commit&nbsp;%s, by %s'), '<a href="'.$url.'" class="mono">'.$this->scm_id.'</a>', $user).'</div></td></tr>';
239 return Pluf_Template::markSafe($out);
240 }
241
242 /**
243 * Returns the feed fragment for the commit.
244 *
245 * @param Pluf_HTTP_Request
246 * @return Pluf_Template_SafeString
247 */
248 public function feedFragment($request)
249 {
250 $url = Pluf::f('url_base')
251 .Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit',
252 array($request->project->shortname,
253 $this->scm_id));
254 $date = Pluf_Date::gmDateToGmString($this->creation_dtime);
255 $author = ($this->get_author()) ?
256 $this->get_author() : $this->origauthor;
257 $cproject = $this->get_project();
258 $context = new Pluf_Template_Context_Request(
259 $request,
260 array(
261 'c' => $this,
262 'cproject' => $cproject,
263 'url' => $url,
264 'date' => $date,
265 'author' => $author,
266 )
267 );
268 $tmpl = new Pluf_Template('idf/source/feedfragment.xml');
269 return $tmpl->render($context);
270 }
271
272 /**
273 * Notification of change of the object.
274 *
275 * @param IDF_Conf Current configuration
276 * @param bool Creation (true)
277 */
278 public function notify($conf, $create=true)
279 {
280 // Now we add to the queue, soon we will push everything in
281 // the queue, including email notifications and indexing.
282 // Even if the url is empty, we add to the queue as some
283 // plugins may want to do something with this information in
284 // an asynchronous way.
285 $project = $this->get_project();
286 $scm = $project->getConf()->getVal('scm', 'git');
287 $url = str_replace(array('%p', '%r'),
288 array($project->shortname, $this->scm_id),
289 $conf->getVal('webhook_url', ''));
290 $payload = array('to_send' => array(
291 'project' => $project->shortname,
292 'rev' => $this->scm_id,
293 'scm' => $scm,
294 'summary' => $this->summary,
295 'fullmessage' => $this->fullmessage,
296 'author' => $this->origauthor,
297 'creation_date' => $this->creation_dtime,
298 ),
299 'project_id' => $project->id,
300 'authkey' => $project->getPostCommitHookKey(),
301 'url' => $url,
302 );
303 $item = new IDF_Queue();
304 $item->type = 'new_commit';
305 $item->payload = $payload;
306 $item->create();
307
308 if ('' == $conf->getVal('source_notification_email', '')) {
309 return;
310 }
311
312 $current_locale = Pluf_Translation::getLocale();
313 $langs = Pluf::f('languages', array('en'));
314 Pluf_Translation::loadSetLocale($langs[0]);
315
316 $context = new Pluf_Template_Context(
317 array(
318 'c' => $this,
319 'project' => $this->get_project(),
320 'url_base' => Pluf::f('url_base'),
321 )
322 );
323 $tmpl = new Pluf_Template('idf/source/commit-created-email.txt');
324 $text_email = $tmpl->render($context);
325 $addresses = explode(',', $conf->getVal('source_notification_email'));
326 foreach ($addresses as $address) {
327 $email = new Pluf_Mail(Pluf::f('from_email'),
328 $address,
329 sprintf(__('New Commit %s - %s (%s)'),
330 $this->scm_id, $this->summary,
331 $this->get_project()->shortname));
332 $email->addTextMessage($text_email);
333 $email->sendMail();
334 }
335 Pluf_Translation::loadSetLocale($current_locale);
336 }
337}
338

Archive Download this file