Compare commits
87 Commits
bake
...
blender-tw
| Author | SHA1 | Date | |
|---|---|---|---|
| 81827bee9a | |||
|
|
c041cfa1bd | ||
| e53bf0655e | |||
| 114b2b9f1b | |||
| 883046f69f | |||
| 1810f1dda9 | |||
| 14aa6a671b | |||
|
|
34082efb02 | ||
|
|
bf8707d3a9 | ||
|
|
ae5a38f334 | ||
|
|
c04147328f | ||
|
|
671986592b | ||
|
|
bc4f86d279 | ||
|
|
b2e96df3a3 | ||
|
|
2b8bbae5fb | ||
|
|
058d2489e7 | ||
|
|
1f7c736f9a | ||
|
|
0f27cd46cc | ||
|
|
0f0e94ca71 | ||
|
|
a5f20f7106 | ||
|
|
58d3f6145a | ||
|
|
f21a00a315 | ||
|
|
a754c694de | ||
|
|
969587f7b0 | ||
|
|
2a83df5786 | ||
|
|
6f78e2a91c | ||
|
|
737e7c8541 | ||
|
|
93ef902ffa | ||
|
|
a39c590442 | ||
|
|
cebde34425 | ||
|
|
e454c3dafe | ||
|
|
7d6874d9f0 | ||
|
|
3a80efa440 | ||
|
|
f6238f9d9b | ||
|
|
a9506097ea | ||
|
|
a745055813 | ||
|
|
367cd28927 | ||
|
|
3dfa89dd5d | ||
|
|
6e1b5da112 | ||
|
|
7daaaa8463 | ||
|
|
0854425d19 | ||
|
|
72f149bf39 | ||
|
|
429543b637 | ||
|
|
0b64092d25 | ||
|
|
49af92e903 | ||
|
|
57f9450bcf | ||
|
|
8aec3f916b | ||
|
|
36dac46ff2 | ||
|
|
57ee6649aa | ||
|
|
2b0632b442 | ||
|
|
7087c0439a | ||
|
|
cd09ba5e19 | ||
|
|
9fa2525384 | ||
|
|
46695c76eb | ||
|
|
c6de7c66a3 | ||
|
|
9afc5c6287 | ||
|
|
c8a279957d | ||
|
|
60e9f64190 | ||
|
|
7fd6bf26a9 | ||
|
|
81e4e5b7f9 | ||
|
|
5454175973 | ||
|
|
79375c6c53 | ||
|
|
ce0dc9a2ba | ||
|
|
dbdfac1e07 | ||
|
|
2db1955159 | ||
|
|
98e0440d45 | ||
|
|
c1eeacd850 | ||
|
|
017ef1927c | ||
|
|
a27c83757d | ||
|
|
78d1b62bb8 | ||
|
|
5f0535934d | ||
|
|
fcb75d0503 | ||
|
|
8f9ba48528 | ||
|
|
0ed5569e9f | ||
|
|
37ffb71c4d | ||
|
|
1d4d860cb5 | ||
|
|
6e85b521fe | ||
|
|
b21b73b8dd | ||
|
|
73c4240415 | ||
|
|
56838c0e3d | ||
|
|
205657ac76 | ||
|
|
7d496f2c6d | ||
|
|
a7b3ba5a6f | ||
|
|
22de618d3b | ||
|
|
d91abf50f7 | ||
|
|
9ce1271805 | ||
|
|
8c7f114b4d |
722
externals/amazon-ses/ses.php
vendored
722
externals/amazon-ses/ses.php
vendored
@@ -1,722 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* Copyright (c) 2011, Dan Myers.
|
||||
* Parts copyright (c) 2008, Donovan Schonknecht.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This is a modified BSD license (the third clause has been removed).
|
||||
* The BSD license may be found here:
|
||||
* http://www.opensource.org/licenses/bsd-license.php
|
||||
*
|
||||
* Amazon Simple Email Service is a trademark of Amazon.com, Inc. or its affiliates.
|
||||
*
|
||||
* SimpleEmailService is based on Donovan Schonknecht's Amazon S3 PHP class, found here:
|
||||
* http://undesigned.org.za/2007/10/22/amazon-s3-php-class
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Amazon SimpleEmailService PHP class
|
||||
*
|
||||
* @link http://sourceforge.net/projects/php-aws-ses/
|
||||
* version 0.8.1
|
||||
*
|
||||
*/
|
||||
class SimpleEmailService
|
||||
{
|
||||
protected $__accessKey; // AWS Access key
|
||||
protected $__secretKey; // AWS Secret key
|
||||
protected $__host;
|
||||
|
||||
public function getAccessKey() { return $this->__accessKey; }
|
||||
public function getSecretKey() { return $this->__secretKey; }
|
||||
public function getHost() { return $this->__host; }
|
||||
|
||||
protected $__verifyHost = 1;
|
||||
protected $__verifyPeer = 1;
|
||||
|
||||
// verifyHost and verifyPeer determine whether curl verifies ssl certificates.
|
||||
// It may be necessary to disable these checks on certain systems.
|
||||
// These only have an effect if SSL is enabled.
|
||||
public function verifyHost() { return $this->__verifyHost; }
|
||||
public function enableVerifyHost($enable = true) { $this->__verifyHost = $enable; }
|
||||
|
||||
public function verifyPeer() { return $this->__verifyPeer; }
|
||||
public function enableVerifyPeer($enable = true) { $this->__verifyPeer = $enable; }
|
||||
|
||||
// If you use exceptions, errors will be communicated by throwing a
|
||||
// SimpleEmailServiceException. By default, they will be trigger_error()'d.
|
||||
protected $__useExceptions = 0;
|
||||
public function useExceptions() { return $this->__useExceptions; }
|
||||
public function enableUseExceptions($enable = true) { $this->__useExceptions = $enable; }
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $accessKey Access key
|
||||
* @param string $secretKey Secret key
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($accessKey = null, $secretKey = null, $host = 'email.us-east-1.amazonaws.com') {
|
||||
if (!function_exists('simplexml_load_string')) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'The PHP SimpleXML extension is not available, but this '.
|
||||
'extension is required to send mail via Amazon SES, because '.
|
||||
'Amazon SES returns API responses in XML format. Install or '.
|
||||
'enable the SimpleXML extension.'));
|
||||
}
|
||||
|
||||
// Catch mistakes with reading the wrong column out of the SES
|
||||
// documentation. See T10728.
|
||||
if (preg_match('(-smtp)', $host)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Amazon SES is not configured correctly: the configured SES '.
|
||||
'endpoint ("%s") is an SMTP endpoint. Instead, use an API (HTTPS) '.
|
||||
'endpoint.',
|
||||
$host));
|
||||
}
|
||||
|
||||
if ($accessKey !== null && $secretKey !== null) {
|
||||
$this->setAuth($accessKey, $secretKey);
|
||||
}
|
||||
|
||||
$this->__host = $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set AWS access key and secret key
|
||||
*
|
||||
* @param string $accessKey Access key
|
||||
* @param string $secretKey Secret key
|
||||
* @return void
|
||||
*/
|
||||
public function setAuth($accessKey, $secretKey) {
|
||||
$this->__accessKey = $accessKey;
|
||||
$this->__secretKey = $secretKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the email addresses that have been verified and can be used as the 'From' address
|
||||
*
|
||||
* @return An array containing two items: a list of verified email addresses, and the request id.
|
||||
*/
|
||||
public function listVerifiedEmailAddresses() {
|
||||
$rest = new SimpleEmailServiceRequest($this, 'GET');
|
||||
$rest->setParameter('Action', 'ListVerifiedEmailAddresses');
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
|
||||
$response = array();
|
||||
if(!isset($rest->body)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$addresses = array();
|
||||
foreach($rest->body->ListVerifiedEmailAddressesResult->VerifiedEmailAddresses->member as $address) {
|
||||
$addresses[] = (string)$address;
|
||||
}
|
||||
|
||||
$response['Addresses'] = $addresses;
|
||||
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests verification of the provided email address, so it can be used
|
||||
* as the 'From' address when sending emails through SimpleEmailService.
|
||||
*
|
||||
* After submitting this request, you should receive a verification email
|
||||
* from Amazon at the specified address containing instructions to follow.
|
||||
*
|
||||
* @param string email The email address to get verified
|
||||
* @return The request id for this request.
|
||||
*/
|
||||
public function verifyEmailAddress($email) {
|
||||
$rest = new SimpleEmailServiceRequest($this, 'POST');
|
||||
$rest->setParameter('Action', 'VerifyEmailAddress');
|
||||
$rest->setParameter('EmailAddress', $email);
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
|
||||
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified email address from the list of verified addresses.
|
||||
*
|
||||
* @param string email The email address to remove
|
||||
* @return The request id for this request.
|
||||
*/
|
||||
public function deleteVerifiedEmailAddress($email) {
|
||||
$rest = new SimpleEmailServiceRequest($this, 'DELETE');
|
||||
$rest->setParameter('Action', 'DeleteVerifiedEmailAddress');
|
||||
$rest->setParameter('EmailAddress', $email);
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
|
||||
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information on the current activity limits for this account.
|
||||
* See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendQuota.html
|
||||
*
|
||||
* @return An array containing information on this account's activity limits.
|
||||
*/
|
||||
public function getSendQuota() {
|
||||
$rest = new SimpleEmailServiceRequest($this, 'GET');
|
||||
$rest->setParameter('Action', 'GetSendQuota');
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
|
||||
$response = array();
|
||||
if(!isset($rest->body)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response['Max24HourSend'] = (string)$rest->body->GetSendQuotaResult->Max24HourSend;
|
||||
$response['MaxSendRate'] = (string)$rest->body->GetSendQuotaResult->MaxSendRate;
|
||||
$response['SentLast24Hours'] = (string)$rest->body->GetSendQuotaResult->SentLast24Hours;
|
||||
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves statistics for the last two weeks of activity on this account.
|
||||
* See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendStatistics.html
|
||||
*
|
||||
* @return An array of activity statistics. Each array item covers a 15-minute period.
|
||||
*/
|
||||
public function getSendStatistics() {
|
||||
$rest = new SimpleEmailServiceRequest($this, 'GET');
|
||||
$rest->setParameter('Action', 'GetSendStatistics');
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
|
||||
$response = array();
|
||||
if(!isset($rest->body)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$datapoints = array();
|
||||
foreach($rest->body->GetSendStatisticsResult->SendDataPoints->member as $datapoint) {
|
||||
$p = array();
|
||||
$p['Bounces'] = (string)$datapoint->Bounces;
|
||||
$p['Complaints'] = (string)$datapoint->Complaints;
|
||||
$p['DeliveryAttempts'] = (string)$datapoint->DeliveryAttempts;
|
||||
$p['Rejects'] = (string)$datapoint->Rejects;
|
||||
$p['Timestamp'] = (string)$datapoint->Timestamp;
|
||||
|
||||
$datapoints[] = $p;
|
||||
}
|
||||
|
||||
$response['SendDataPoints'] = $datapoints;
|
||||
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
public function sendRawEmail($raw) {
|
||||
$rest = new SimpleEmailServiceRequest($this, 'POST');
|
||||
$rest->setParameter('Action', 'SendRawEmail');
|
||||
$rest->setParameter('RawMessage.Data', base64_encode($raw));
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
|
||||
$response['MessageId'] = (string)$rest->body->SendEmailResult->MessageId;
|
||||
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a SimpleEmailServiceMessage object, submits the message to the service for sending.
|
||||
*
|
||||
* @return An array containing the unique identifier for this message and a separate request id.
|
||||
* Returns false if the provided message is missing any required fields.
|
||||
*/
|
||||
public function sendEmail($sesMessage) {
|
||||
if(!$sesMessage->validate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rest = new SimpleEmailServiceRequest($this, 'POST');
|
||||
$rest->setParameter('Action', 'SendEmail');
|
||||
|
||||
$i = 1;
|
||||
foreach($sesMessage->to as $to) {
|
||||
$rest->setParameter('Destination.ToAddresses.member.'.$i, $to);
|
||||
$i++;
|
||||
}
|
||||
|
||||
if(is_array($sesMessage->cc)) {
|
||||
$i = 1;
|
||||
foreach($sesMessage->cc as $cc) {
|
||||
$rest->setParameter('Destination.CcAddresses.member.'.$i, $cc);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
if(is_array($sesMessage->bcc)) {
|
||||
$i = 1;
|
||||
foreach($sesMessage->bcc as $bcc) {
|
||||
$rest->setParameter('Destination.BccAddresses.member.'.$i, $bcc);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
if(is_array($sesMessage->replyto)) {
|
||||
$i = 1;
|
||||
foreach($sesMessage->replyto as $replyto) {
|
||||
$rest->setParameter('ReplyToAddresses.member.'.$i, $replyto);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$rest->setParameter('Source', $sesMessage->from);
|
||||
|
||||
if($sesMessage->returnpath != null) {
|
||||
$rest->setParameter('ReturnPath', $sesMessage->returnpath);
|
||||
}
|
||||
|
||||
if($sesMessage->subject != null && strlen($sesMessage->subject) > 0) {
|
||||
$rest->setParameter('Message.Subject.Data', $sesMessage->subject);
|
||||
if($sesMessage->subjectCharset != null && strlen($sesMessage->subjectCharset) > 0) {
|
||||
$rest->setParameter('Message.Subject.Charset', $sesMessage->subjectCharset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if($sesMessage->messagetext != null && strlen($sesMessage->messagetext) > 0) {
|
||||
$rest->setParameter('Message.Body.Text.Data', $sesMessage->messagetext);
|
||||
if($sesMessage->messageTextCharset != null && strlen($sesMessage->messageTextCharset) > 0) {
|
||||
$rest->setParameter('Message.Body.Text.Charset', $sesMessage->messageTextCharset);
|
||||
}
|
||||
}
|
||||
|
||||
if($sesMessage->messagehtml != null && strlen($sesMessage->messagehtml) > 0) {
|
||||
$rest->setParameter('Message.Body.Html.Data', $sesMessage->messagehtml);
|
||||
if($sesMessage->messageHtmlCharset != null && strlen($sesMessage->messageHtmlCharset) > 0) {
|
||||
$rest->setParameter('Message.Body.Html.Charset', $sesMessage->messageHtmlCharset);
|
||||
}
|
||||
}
|
||||
|
||||
$rest = $rest->getResponse();
|
||||
|
||||
$response['MessageId'] = (string)$rest->body->SendEmailResult->MessageId;
|
||||
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger an error message
|
||||
*
|
||||
* @internal Used by member functions to output errors
|
||||
* @param array $error Array containing error information
|
||||
* @return string
|
||||
*/
|
||||
public function __triggerError($functionname, $error)
|
||||
{
|
||||
if($error == false) {
|
||||
$message = sprintf("SimpleEmailService::%s(): Encountered an error, but no description given", $functionname);
|
||||
}
|
||||
else if(isset($error['curl']) && $error['curl'])
|
||||
{
|
||||
$message = sprintf("SimpleEmailService::%s(): %s %s", $functionname, $error['code'], $error['message']);
|
||||
}
|
||||
else if(isset($error['Error']))
|
||||
{
|
||||
$e = $error['Error'];
|
||||
$message = sprintf("SimpleEmailService::%s(): %s - %s: %s\nRequest Id: %s\n", $functionname, $e['Type'], $e['Code'], $e['Message'], $error['RequestId']);
|
||||
}
|
||||
|
||||
if ($this->useExceptions()) {
|
||||
throw new SimpleEmailServiceException($message);
|
||||
} else {
|
||||
trigger_error($message, E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback handler for 503 retries.
|
||||
*
|
||||
* @internal Used by SimpleDBRequest to call the user-specified callback, if set
|
||||
* @param $attempt The number of failed attempts so far
|
||||
* @return The retry delay in microseconds, or 0 to stop retrying.
|
||||
*/
|
||||
public function __executeServiceTemporarilyUnavailableRetryDelay($attempt)
|
||||
{
|
||||
if(is_callable($this->__serviceUnavailableRetryDelayCallback)) {
|
||||
$callback = $this->__serviceUnavailableRetryDelayCallback;
|
||||
return $callback($attempt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
final class SimpleEmailServiceRequest
|
||||
{
|
||||
private $ses, $verb, $parameters = array();
|
||||
public $response;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $ses The SimpleEmailService object making this request
|
||||
* @param string $action action
|
||||
* @param string $verb HTTP verb
|
||||
* @return mixed
|
||||
*/
|
||||
function __construct($ses, $verb) {
|
||||
$this->ses = $ses;
|
||||
$this->verb = $verb;
|
||||
$this->response = new STDClass;
|
||||
$this->response->error = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set request parameter
|
||||
*
|
||||
* @param string $key Key
|
||||
* @param string $value Value
|
||||
* @param boolean $replace Whether to replace the key if it already exists (default true)
|
||||
* @return void
|
||||
*/
|
||||
public function setParameter($key, $value, $replace = true) {
|
||||
if(!$replace && isset($this->parameters[$key]))
|
||||
{
|
||||
$temp = (array)($this->parameters[$key]);
|
||||
$temp[] = $value;
|
||||
$this->parameters[$key] = $temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->parameters[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response
|
||||
*
|
||||
* @return object | false
|
||||
*/
|
||||
public function getResponse() {
|
||||
|
||||
$params = array();
|
||||
foreach ($this->parameters as $var => $value)
|
||||
{
|
||||
if(is_array($value))
|
||||
{
|
||||
foreach($value as $v)
|
||||
{
|
||||
$params[] = $var.'='.$this->__customUrlEncode($v);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$params[] = $var.'='.$this->__customUrlEncode($value);
|
||||
}
|
||||
}
|
||||
|
||||
sort($params, SORT_STRING);
|
||||
|
||||
// must be in format 'Sun, 06 Nov 1994 08:49:37 GMT'
|
||||
$date = gmdate('D, d M Y H:i:s e');
|
||||
|
||||
$query = implode('&', $params);
|
||||
|
||||
$headers = array();
|
||||
$headers[] = 'Date: '.$date;
|
||||
$headers[] = 'Host: '.$this->ses->getHost();
|
||||
|
||||
$auth = 'AWS3-HTTPS AWSAccessKeyId='.$this->ses->getAccessKey();
|
||||
$auth .= ',Algorithm=HmacSHA256,Signature='.$this->__getSignature($date);
|
||||
$headers[] = 'X-Amzn-Authorization: '.$auth;
|
||||
|
||||
$url = 'https://'.$this->ses->getHost().'/';
|
||||
|
||||
// Basic setup
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, 'SimpleEmailService/php');
|
||||
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, ($this->ses->verifyHost() ? 2 : 0));
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, ($this->ses->verifyPeer() ? 1 : 0));
|
||||
|
||||
// Request types
|
||||
switch ($this->verb) {
|
||||
case 'GET':
|
||||
$url .= '?'.$query;
|
||||
break;
|
||||
case 'POST':
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $query);
|
||||
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
|
||||
break;
|
||||
case 'DELETE':
|
||||
$url .= '?'.$query;
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
||||
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
|
||||
curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
|
||||
// Execute, grab errors
|
||||
if (!curl_exec($curl)) {
|
||||
throw new SimpleEmailServiceException(
|
||||
pht(
|
||||
'Encountered an error while making an HTTP request to Amazon SES '.
|
||||
'(cURL Error #%d): %s',
|
||||
curl_errno($curl),
|
||||
curl_error($curl)));
|
||||
}
|
||||
|
||||
$this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
if ($this->response->code != 200) {
|
||||
throw new SimpleEmailServiceException(
|
||||
pht(
|
||||
'Unexpected HTTP status while making request to Amazon SES: '.
|
||||
'expected 200, got %s.',
|
||||
$this->response->code));
|
||||
}
|
||||
|
||||
@curl_close($curl);
|
||||
|
||||
// Parse body into XML
|
||||
if ($this->response->error === false && isset($this->response->body)) {
|
||||
$this->response->body = simplexml_load_string($this->response->body);
|
||||
|
||||
// Grab SES errors
|
||||
if (!in_array($this->response->code, array(200, 201, 202, 204))
|
||||
&& isset($this->response->body->Error)) {
|
||||
$error = $this->response->body->Error;
|
||||
$output = array();
|
||||
$output['curl'] = false;
|
||||
$output['Error'] = array();
|
||||
$output['Error']['Type'] = (string)$error->Type;
|
||||
$output['Error']['Code'] = (string)$error->Code;
|
||||
$output['Error']['Message'] = (string)$error->Message;
|
||||
$output['RequestId'] = (string)$this->response->body->RequestId;
|
||||
|
||||
$this->response->error = $output;
|
||||
unset($this->response->body);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* CURL write callback
|
||||
*
|
||||
* @param resource &$curl CURL resource
|
||||
* @param string &$data Data
|
||||
* @return integer
|
||||
*/
|
||||
private function __responseWriteCallback(&$curl, &$data) {
|
||||
if(!isset($this->response->body)) $this->response->body = '';
|
||||
$this->response->body .= $data;
|
||||
return strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Contributed by afx114
|
||||
* URL encode the parameters as per http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html
|
||||
* PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde (~), so convert it back after rawurlencode
|
||||
* See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php
|
||||
*
|
||||
* @param string $var String to encode
|
||||
* @return string
|
||||
*/
|
||||
private function __customUrlEncode($var) {
|
||||
return str_replace('%7E', '~', rawurlencode($var));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the auth string using Hmac-SHA256
|
||||
*
|
||||
* @internal Used by SimpleDBRequest::getResponse()
|
||||
* @param string $string String to sign
|
||||
* @return string
|
||||
*/
|
||||
private function __getSignature($string) {
|
||||
return base64_encode(hash_hmac('sha256', $string, $this->ses->getSecretKey(), true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final class SimpleEmailServiceMessage {
|
||||
|
||||
// these are public for convenience only
|
||||
// these are not to be used outside of the SimpleEmailService class!
|
||||
public $to, $cc, $bcc, $replyto;
|
||||
public $from, $returnpath;
|
||||
public $subject, $messagetext, $messagehtml;
|
||||
public $subjectCharset, $messageTextCharset, $messageHtmlCharset;
|
||||
|
||||
function __construct() {
|
||||
$to = array();
|
||||
$cc = array();
|
||||
$bcc = array();
|
||||
$replyto = array();
|
||||
|
||||
$from = null;
|
||||
$returnpath = null;
|
||||
|
||||
$subject = null;
|
||||
$messagetext = null;
|
||||
$messagehtml = null;
|
||||
|
||||
$subjectCharset = null;
|
||||
$messageTextCharset = null;
|
||||
$messageHtmlCharset = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* addTo, addCC, addBCC, and addReplyTo have the following behavior:
|
||||
* If a single address is passed, it is appended to the current list of addresses.
|
||||
* If an array of addresses is passed, that array is merged into the current list.
|
||||
*/
|
||||
function addTo($to) {
|
||||
if(!is_array($to)) {
|
||||
$this->to[] = $to;
|
||||
}
|
||||
else {
|
||||
$this->to = array_merge($this->to, $to);
|
||||
}
|
||||
}
|
||||
|
||||
function addCC($cc) {
|
||||
if(!is_array($cc)) {
|
||||
$this->cc[] = $cc;
|
||||
}
|
||||
else {
|
||||
$this->cc = array_merge($this->cc, $cc);
|
||||
}
|
||||
}
|
||||
|
||||
function addBCC($bcc) {
|
||||
if(!is_array($bcc)) {
|
||||
$this->bcc[] = $bcc;
|
||||
}
|
||||
else {
|
||||
$this->bcc = array_merge($this->bcc, $bcc);
|
||||
}
|
||||
}
|
||||
|
||||
function addReplyTo($replyto) {
|
||||
if(!is_array($replyto)) {
|
||||
$this->replyto[] = $replyto;
|
||||
}
|
||||
else {
|
||||
$this->replyto = array_merge($this->replyto, $replyto);
|
||||
}
|
||||
}
|
||||
|
||||
function setFrom($from) {
|
||||
$this->from = $from;
|
||||
}
|
||||
|
||||
function setReturnPath($returnpath) {
|
||||
$this->returnpath = $returnpath;
|
||||
}
|
||||
|
||||
function setSubject($subject) {
|
||||
$this->subject = $subject;
|
||||
}
|
||||
|
||||
function setSubjectCharset($charset) {
|
||||
$this->subjectCharset = $charset;
|
||||
}
|
||||
|
||||
function setMessageFromString($text, $html = null) {
|
||||
$this->messagetext = $text;
|
||||
$this->messagehtml = $html;
|
||||
}
|
||||
|
||||
function setMessageFromFile($textfile, $htmlfile = null) {
|
||||
if(file_exists($textfile) && is_file($textfile) && is_readable($textfile)) {
|
||||
$this->messagetext = file_get_contents($textfile);
|
||||
}
|
||||
if(file_exists($htmlfile) && is_file($htmlfile) && is_readable($htmlfile)) {
|
||||
$this->messagehtml = file_get_contents($htmlfile);
|
||||
}
|
||||
}
|
||||
|
||||
function setMessageFromURL($texturl, $htmlurl = null) {
|
||||
$this->messagetext = file_get_contents($texturl);
|
||||
if($htmlurl !== null) {
|
||||
$this->messagehtml = file_get_contents($htmlurl);
|
||||
}
|
||||
}
|
||||
|
||||
function setMessageCharset($textCharset, $htmlCharset = null) {
|
||||
$this->messageTextCharset = $textCharset;
|
||||
$this->messageHtmlCharset = $htmlCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates whether the message object has sufficient information to submit a request to SES.
|
||||
* This does not guarantee the message will arrive, nor that the request will succeed;
|
||||
* instead, it makes sure that no required fields are missing.
|
||||
*
|
||||
* This is used internally before attempting a SendEmail or SendRawEmail request,
|
||||
* but it can be used outside of this file if verification is desired.
|
||||
* May be useful if e.g. the data is being populated from a form; developers can generally
|
||||
* use this function to verify completeness instead of writing custom logic.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function validate() {
|
||||
if(count($this->to) == 0)
|
||||
return false;
|
||||
if($this->from == null || strlen($this->from) == 0)
|
||||
return false;
|
||||
if($this->messagetext == null)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown by SimpleEmailService when errors occur if you call
|
||||
* enableUseExceptions(true).
|
||||
*/
|
||||
final class SimpleEmailServiceException extends Exception {
|
||||
|
||||
}
|
||||
@@ -9,13 +9,13 @@ return array(
|
||||
'names' => array(
|
||||
'conpherence.pkg.css' => '0e3cf785',
|
||||
'conpherence.pkg.js' => '020aebcf',
|
||||
'core.pkg.css' => 'f784f26b',
|
||||
'core.pkg.js' => '74ad315f',
|
||||
'core.pkg.css' => '704ac9c8',
|
||||
'core.pkg.js' => '0c06d967',
|
||||
'dark-console.pkg.js' => '187792c2',
|
||||
'differential.pkg.css' => '32879ab6',
|
||||
'differential.pkg.js' => '218fda21',
|
||||
'differential.pkg.css' => '5c459f92',
|
||||
'differential.pkg.js' => '5080baf4',
|
||||
'diffusion.pkg.css' => '42c75c37',
|
||||
'diffusion.pkg.js' => 'a98c0bf7',
|
||||
'diffusion.pkg.js' => '78c9885d',
|
||||
'maniphest.pkg.css' => '35995d6d',
|
||||
'maniphest.pkg.js' => 'c9308721',
|
||||
'rsrc/audio/basic/alert.mp3' => '17889334',
|
||||
@@ -67,13 +67,13 @@ return array(
|
||||
'rsrc/css/application/differential/core.css' => '7300a73e',
|
||||
'rsrc/css/application/differential/phui-inline-comment.css' => '9863a85e',
|
||||
'rsrc/css/application/differential/revision-comment.css' => '7dbc8d1d',
|
||||
'rsrc/css/application/differential/revision-history.css' => '04edcc29',
|
||||
'rsrc/css/application/differential/revision-history.css' => '8aa3eac5',
|
||||
'rsrc/css/application/differential/revision-list.css' => '93d2df7d',
|
||||
'rsrc/css/application/differential/table-of-contents.css' => 'bba788b9',
|
||||
'rsrc/css/application/diffusion/diffusion-icons.css' => '23b31a1b',
|
||||
'rsrc/css/application/diffusion/diffusion-readme.css' => 'b68a76e4',
|
||||
'rsrc/css/application/diffusion/diffusion-repository.css' => 'b89e8c6c',
|
||||
'rsrc/css/application/diffusion/diffusion.css' => 'b54c77b0',
|
||||
'rsrc/css/application/diffusion/diffusion.css' => 'e46232d6',
|
||||
'rsrc/css/application/feed/feed.css' => 'd8b6e3f8',
|
||||
'rsrc/css/application/files/global-drag-and-drop.css' => '1d2713a4',
|
||||
'rsrc/css/application/flag/flag.css' => '2b77be8d',
|
||||
@@ -113,14 +113,18 @@ return array(
|
||||
'rsrc/css/application/slowvote/slowvote.css' => '1694baed',
|
||||
'rsrc/css/application/tokens/tokens.css' => 'ce5a50bd',
|
||||
'rsrc/css/application/uiexample/example.css' => 'b4795059',
|
||||
'rsrc/css/core/core.css' => '1b29ed61',
|
||||
'rsrc/css/core/remarkup.css' => 'c286eaef',
|
||||
'rsrc/css/core/core.css' => 'b3ebd90d',
|
||||
'rsrc/css/core/remarkup.css' => '24d48a73',
|
||||
'rsrc/css/core/syntax.css' => '548567f6',
|
||||
'rsrc/css/core/z-index.css' => 'ac3bfcd4',
|
||||
'rsrc/css/diviner/diviner-shared.css' => '4bd263b0',
|
||||
'rsrc/css/font/font-awesome.css' => '3883938a',
|
||||
'rsrc/css/font/font-lato.css' => '23631304',
|
||||
'rsrc/css/font/phui-font-icon-base.css' => '303c9b87',
|
||||
'rsrc/css/fuel/fuel-grid.css' => '66697240',
|
||||
'rsrc/css/fuel/fuel-handle-list.css' => '2c4cbeca',
|
||||
'rsrc/css/fuel/fuel-map.css' => 'd6e31510',
|
||||
'rsrc/css/fuel/fuel-menu.css' => '21f5d199',
|
||||
'rsrc/css/layout/phabricator-source-code-view.css' => '03d7ac28',
|
||||
'rsrc/css/phui/button/phui-button-bar.css' => 'a4aa75c4',
|
||||
'rsrc/css/phui/button/phui-button-simple.css' => '1ff278aa',
|
||||
@@ -133,7 +137,7 @@ return array(
|
||||
'rsrc/css/phui/object-item/phui-oi-color.css' => 'b517bfa0',
|
||||
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'da15d3dc',
|
||||
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e',
|
||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'd7723ecc',
|
||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'af98a277',
|
||||
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46',
|
||||
'rsrc/css/phui/phui-action-list.css' => '1b0085b2',
|
||||
'rsrc/css/phui/phui-action-panel.css' => '6c386cbf',
|
||||
@@ -147,7 +151,7 @@ return array(
|
||||
'rsrc/css/phui/phui-comment-form.css' => '68a2d99a',
|
||||
'rsrc/css/phui/phui-comment-panel.css' => 'ec4e31c0',
|
||||
'rsrc/css/phui/phui-crumbs-view.css' => '614f43cf',
|
||||
'rsrc/css/phui/phui-curtain-object-ref-view.css' => 'b43b7307',
|
||||
'rsrc/css/phui/phui-curtain-object-ref-view.css' => '12404744',
|
||||
'rsrc/css/phui/phui-curtain-view.css' => '68c5efb6',
|
||||
'rsrc/css/phui/phui-document-pro.css' => 'b9613a10',
|
||||
'rsrc/css/phui/phui-document-summary.css' => 'b068eed1',
|
||||
@@ -389,7 +393,7 @@ return array(
|
||||
'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be',
|
||||
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9',
|
||||
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8',
|
||||
'rsrc/js/application/diff/DiffChangeset.js' => '39dcf2c3',
|
||||
'rsrc/js/application/diff/DiffChangeset.js' => '3b6e1fde',
|
||||
'rsrc/js/application/diff/DiffChangesetList.js' => 'cc2c5de5',
|
||||
'rsrc/js/application/diff/DiffInline.js' => '511a1315',
|
||||
'rsrc/js/application/diff/DiffPathView.js' => '8207abf9',
|
||||
@@ -400,7 +404,7 @@ return array(
|
||||
'rsrc/js/application/diffusion/ExternalEditorLinkEngine.js' => '48a8641f',
|
||||
'rsrc/js/application/diffusion/behavior-audit-preview.js' => 'b7b73831',
|
||||
'rsrc/js/application/diffusion/behavior-commit-branches.js' => '4b671572',
|
||||
'rsrc/js/application/diffusion/behavior-commit-graph.js' => 'ef836bf2',
|
||||
'rsrc/js/application/diffusion/behavior-commit-graph.js' => 'ac10c917',
|
||||
'rsrc/js/application/diffusion/behavior-locate-file.js' => '87428eb2',
|
||||
'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'c715c123',
|
||||
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '6a85bc5a',
|
||||
@@ -483,7 +487,7 @@ return array(
|
||||
'rsrc/js/core/behavior-choose-control.js' => '04f8a1e3',
|
||||
'rsrc/js/core/behavior-copy.js' => 'cf32921f',
|
||||
'rsrc/js/core/behavior-detect-timezone.js' => '78bc5d94',
|
||||
'rsrc/js/core/behavior-device.js' => '0cf79f45',
|
||||
'rsrc/js/core/behavior-device.js' => 'ac2b1e01',
|
||||
'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '7ad020a5',
|
||||
'rsrc/js/core/behavior-fancy-datepicker.js' => '956f3eeb',
|
||||
'rsrc/js/core/behavior-form.js' => '55d7b788',
|
||||
@@ -574,16 +578,20 @@ return array(
|
||||
'differential-core-view-css' => '7300a73e',
|
||||
'differential-revision-add-comment-css' => '7e5900d9',
|
||||
'differential-revision-comment-css' => '7dbc8d1d',
|
||||
'differential-revision-history-css' => '04edcc29',
|
||||
'differential-revision-history-css' => '8aa3eac5',
|
||||
'differential-revision-list-css' => '93d2df7d',
|
||||
'differential-table-of-contents-css' => 'bba788b9',
|
||||
'diffusion-css' => 'b54c77b0',
|
||||
'diffusion-css' => 'e46232d6',
|
||||
'diffusion-icons-css' => '23b31a1b',
|
||||
'diffusion-readme-css' => 'b68a76e4',
|
||||
'diffusion-repository-css' => 'b89e8c6c',
|
||||
'diviner-shared-css' => '4bd263b0',
|
||||
'font-fontawesome' => '3883938a',
|
||||
'font-lato' => '23631304',
|
||||
'fuel-grid-css' => '66697240',
|
||||
'fuel-handle-list-css' => '2c4cbeca',
|
||||
'fuel-map-css' => 'd6e31510',
|
||||
'fuel-menu-css' => '21f5d199',
|
||||
'global-drag-and-drop-css' => '1d2713a4',
|
||||
'harbormaster-css' => '8dfe16b2',
|
||||
'herald-css' => '648d39e2',
|
||||
@@ -621,11 +629,11 @@ return array(
|
||||
'javelin-behavior-day-view' => '727a5a61',
|
||||
'javelin-behavior-desktop-notifications-control' => '070679fe',
|
||||
'javelin-behavior-detect-timezone' => '78bc5d94',
|
||||
'javelin-behavior-device' => '0cf79f45',
|
||||
'javelin-behavior-device' => 'ac2b1e01',
|
||||
'javelin-behavior-differential-diff-radios' => '925fe8cd',
|
||||
'javelin-behavior-differential-populate' => 'b86ef6c2',
|
||||
'javelin-behavior-diffusion-commit-branches' => '4b671572',
|
||||
'javelin-behavior-diffusion-commit-graph' => 'ef836bf2',
|
||||
'javelin-behavior-diffusion-commit-graph' => 'ac10c917',
|
||||
'javelin-behavior-diffusion-locate-file' => '87428eb2',
|
||||
'javelin-behavior-diffusion-pull-lastmodified' => 'c715c123',
|
||||
'javelin-behavior-document-engine' => '243d6c22',
|
||||
@@ -781,12 +789,12 @@ return array(
|
||||
'phabricator-busy' => '5202e831',
|
||||
'phabricator-chatlog-css' => 'abdc76ee',
|
||||
'phabricator-content-source-view-css' => 'cdf0d579',
|
||||
'phabricator-core-css' => '1b29ed61',
|
||||
'phabricator-core-css' => 'b3ebd90d',
|
||||
'phabricator-countdown-css' => 'bff8012f',
|
||||
'phabricator-darklog' => '3b869402',
|
||||
'phabricator-darkmessage' => '26cd4b73',
|
||||
'phabricator-dashboard-css' => '5a205b9d',
|
||||
'phabricator-diff-changeset' => '39dcf2c3',
|
||||
'phabricator-diff-changeset' => '3b6e1fde',
|
||||
'phabricator-diff-changeset-list' => 'cc2c5de5',
|
||||
'phabricator-diff-inline' => '511a1315',
|
||||
'phabricator-diff-path-view' => '8207abf9',
|
||||
@@ -808,7 +816,7 @@ return array(
|
||||
'phabricator-object-selector-css' => 'ee77366f',
|
||||
'phabricator-phtize' => '2f1db1ed',
|
||||
'phabricator-prefab' => '5793d835',
|
||||
'phabricator-remarkup-css' => 'c286eaef',
|
||||
'phabricator-remarkup-css' => '24d48a73',
|
||||
'phabricator-search-results-css' => '9ea70ace',
|
||||
'phabricator-shaped-request' => '995f5102',
|
||||
'phabricator-slowvote-css' => '1694baed',
|
||||
@@ -848,7 +856,7 @@ return array(
|
||||
'phui-comment-form-css' => '68a2d99a',
|
||||
'phui-comment-panel-css' => 'ec4e31c0',
|
||||
'phui-crumbs-view-css' => '614f43cf',
|
||||
'phui-curtain-object-ref-view-css' => 'b43b7307',
|
||||
'phui-curtain-object-ref-view-css' => '12404744',
|
||||
'phui-curtain-view-css' => '68c5efb6',
|
||||
'phui-document-summary-view-css' => 'b068eed1',
|
||||
'phui-document-view-css' => '52b748a5',
|
||||
@@ -877,7 +885,7 @@ return array(
|
||||
'phui-oi-color-css' => 'b517bfa0',
|
||||
'phui-oi-drag-ui-css' => 'da15d3dc',
|
||||
'phui-oi-flush-ui-css' => '490e2e2e',
|
||||
'phui-oi-list-view-css' => 'd7723ecc',
|
||||
'phui-oi-list-view-css' => 'af98a277',
|
||||
'phui-oi-simple-ui-css' => '6a30fa46',
|
||||
'phui-pager-css' => 'd022c7ad',
|
||||
'phui-pinboard-view-css' => '1f08f5d8',
|
||||
@@ -1013,13 +1021,6 @@ return array(
|
||||
'javelin-dom',
|
||||
'phabricator-draggable-list',
|
||||
),
|
||||
'0cf79f45' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
'javelin-install',
|
||||
),
|
||||
'0d2490ce' => array(
|
||||
'javelin-install',
|
||||
),
|
||||
@@ -1239,7 +1240,14 @@ return array(
|
||||
'trigger-rule',
|
||||
'trigger-rule-type',
|
||||
),
|
||||
'39dcf2c3' => array(
|
||||
'3ae89b20' => array(
|
||||
'phui-workcard-view-css',
|
||||
),
|
||||
'3b4899b0' => array(
|
||||
'javelin-behavior',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
'3b6e1fde' => array(
|
||||
'javelin-dom',
|
||||
'javelin-util',
|
||||
'javelin-stratcom',
|
||||
@@ -1253,13 +1261,6 @@ return array(
|
||||
'phuix-button-view',
|
||||
'javelin-external-editor-link-engine',
|
||||
),
|
||||
'3ae89b20' => array(
|
||||
'phui-workcard-view-css',
|
||||
),
|
||||
'3b4899b0' => array(
|
||||
'javelin-behavior',
|
||||
'phabricator-prefab',
|
||||
),
|
||||
'3dc5ad43' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
@@ -1932,6 +1933,18 @@ return array(
|
||||
'javelin-dom',
|
||||
'phabricator-notification',
|
||||
),
|
||||
'ac10c917' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'ac2b1e01' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-dom',
|
||||
'javelin-vector',
|
||||
'javelin-install',
|
||||
),
|
||||
'ad258e28' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
@@ -2184,11 +2197,6 @@ return array(
|
||||
'ee77366f' => array(
|
||||
'aphront-dialog-view-css',
|
||||
),
|
||||
'ef836bf2' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
'javelin-stratcom',
|
||||
),
|
||||
'f340a484' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
|
||||
@@ -40,7 +40,8 @@ foreach ($lists as $list) {
|
||||
if (!$username_okay) {
|
||||
echo pht(
|
||||
'Failed to migrate mailing list "%s": unable to generate a unique '.
|
||||
'username for it.')."\n";
|
||||
'username for it.',
|
||||
$name)."\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,576 +0,0 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Bootstrap.
|
||||
|
||||
$PHABRICATOR_ROOT = dirname(dirname(dirname(__FILE__)));
|
||||
require_once $PHABRICATOR_ROOT.'/scripts/__init_script__.php';
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Command line.
|
||||
|
||||
$argc = count($argv);
|
||||
if ($argc < 3 || $argc > 4) {
|
||||
print("Usage: $argv[0] <conduit_token_file> <output_directory> [timestamp]\n");
|
||||
die;
|
||||
}
|
||||
|
||||
$CONDUIT_TOKEN_FILE = $argv[1];
|
||||
$OUTPUT_DIR = $argv[2];
|
||||
$TIMESTAMP = ($argc == 4) ? (int)$argv[3] : 0;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Global configuration.
|
||||
|
||||
$HOST = 'phabricator.local';
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Utilities.
|
||||
|
||||
// Create an instance of the AphrontApplicationConfiguration configured with all
|
||||
// invariant settings (settings which do not change between handlers of different
|
||||
// revisions).
|
||||
function CreateApplicationConfiguration() {
|
||||
global $HOST;
|
||||
|
||||
$application_configuration = new AphrontApplicationConfiguration();
|
||||
$application_configuration->setHost($HOST);
|
||||
return $application_configuration;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Global state.
|
||||
|
||||
$site = id(new PhabricatorPlatformSite());
|
||||
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$application_configuration = CreateApplicationConfiguration();
|
||||
|
||||
$differential_application = id(new PhabricatorDifferentialApplication());
|
||||
$revision_controller = id(new DifferentialRevisionViewController())
|
||||
->setCurrentApplication($differential_application);
|
||||
|
||||
$maniphest_application = id(new PhabricatorManiphestApplication());
|
||||
$maniphest_controller = id(new ManiphestTaskDetailController())
|
||||
->setCurrentApplication($maniphest_application);
|
||||
|
||||
$differential_routing_map = id(new AphrontRoutingMap())
|
||||
->setSite($site)
|
||||
->setApplication($differential_application)
|
||||
->setRoutes($differential_application->getRoutes());
|
||||
|
||||
$maniphest_routing_map = id(new AphrontRoutingMap())
|
||||
->setSite($site)
|
||||
->setApplication($maniphest_application)
|
||||
->setRoutes($maniphest_application->getRoutes());
|
||||
|
||||
$conduit = id(new ConduitClient('https://developer.blender.org/api/'))
|
||||
->setConduitToken(trim(file_get_contents($CONDUIT_TOKEN_FILE)));
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Baking utilities.
|
||||
|
||||
function EnsureDirectoryOrDie($dir) {
|
||||
if (!is_dir($dir)) {
|
||||
if (!mkdir($dir, 0777, true)) {
|
||||
print("Error creating output durectory $dir\n");
|
||||
die;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function RenderElement($element) {
|
||||
if (is_array($element)) {
|
||||
$html = '';
|
||||
foreach ($element as $child) {
|
||||
$html .= RenderElement($child);
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
return $element->render();
|
||||
}
|
||||
|
||||
function RenderResponseToHTML($response) {
|
||||
$html = '';
|
||||
|
||||
$crumbs = $response->getCrumbs();
|
||||
if ($crumbs) {
|
||||
$html .= $crumbs->render();
|
||||
}
|
||||
|
||||
foreach ($response->renderChildren() as $child) {
|
||||
$html .= RenderElement($child);
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Revision baking.
|
||||
|
||||
class RevisionInfo {
|
||||
public $title = '';
|
||||
public $page_title = '';
|
||||
|
||||
public $last_diff_id = 0;
|
||||
|
||||
public $hash = '';
|
||||
|
||||
public static function ReadFromFile($file_name) {
|
||||
$info = new RevisionInfo();
|
||||
|
||||
if (!file_exists($file_name)) {
|
||||
return $info;
|
||||
}
|
||||
|
||||
$json = json_decode(file_get_contents($file_name));
|
||||
foreach ($json as $key => $value) {
|
||||
$info->{$key} = $value;
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function SaveToFile($file_name) {
|
||||
$json_str = json_encode(get_object_vars($this));
|
||||
file_put_contents($file_name, $json_str);
|
||||
}
|
||||
};
|
||||
|
||||
function GetRevisionOutputDirectory($revision) {
|
||||
global $OUTPUT_DIR;
|
||||
|
||||
$id = $revision->getID();
|
||||
|
||||
return PathJoin(array($OUTPUT_DIR, 'differential', SubpathFromId($id)));
|
||||
}
|
||||
|
||||
function EnsureRevisionOutputDirectory($revision) {
|
||||
$dir = GetRevisionOutputDirectory($revision);
|
||||
|
||||
EnsureDirectoryOrDie($dir);
|
||||
EnsureDirectoryOrDie(PathJoin(array($dir, 'raw_diff')));
|
||||
|
||||
return $dir;
|
||||
}
|
||||
|
||||
function GetRevisionInfoFilename($revision) {
|
||||
$revision_dir = GetRevisionOutputDirectory($revision);
|
||||
return PathJoin(array($revision_dir, 'info.json'));
|
||||
}
|
||||
|
||||
function GetRevisionHTMLFilename($revision, $diff_id) {
|
||||
$revision_id = $revision->getID();
|
||||
$revision_dir = GetRevisionOutputDirectory($revision);
|
||||
|
||||
$file_name = "D{$revision_id}.id{$diff_id}.html";
|
||||
|
||||
return PathJoin(array($revision_dir, $file_name));
|
||||
}
|
||||
|
||||
function GetRevisionRawDiffFilename($revision, $diff_id) {
|
||||
$revision_id = $revision->getID();
|
||||
$revision_dir = GetRevisionOutputDirectory($revision);
|
||||
|
||||
$file_name = "D{$revision_id}.id{$diff_id}.diff";
|
||||
|
||||
return PathJoin(array($revision_dir, 'raw_diff', $file_name));
|
||||
}
|
||||
|
||||
function RenderDifferentialToResponse($revision, $diff_id) {
|
||||
global $application_configuration;
|
||||
global $revision_controller;
|
||||
global $differential_routing_map;
|
||||
global $viewer;
|
||||
|
||||
$revision_id = $revision->getID();
|
||||
|
||||
$path = '/D' . $revision_id;
|
||||
|
||||
$route_result = $differential_routing_map->routePath($path);
|
||||
$uri_data = $route_result->getURIData();
|
||||
|
||||
$application_configuration->setPath($path);
|
||||
|
||||
$request_data = array(
|
||||
'id' => $diff_id,
|
||||
);
|
||||
|
||||
$request = $application_configuration->buildRequest()
|
||||
->setUser($viewer)
|
||||
->setRequestData($request_data)
|
||||
->setURIMap($uri_data);
|
||||
|
||||
$response = id($revision_controller)
|
||||
->setRequest($request)
|
||||
->handleRequest($request);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function StoreRawDiff($revision, $diff_id) {
|
||||
global $viewer;
|
||||
global $conduit;
|
||||
|
||||
$diff = id(new DifferentialDiffQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($diff_id))
|
||||
->needChangesets(true)
|
||||
->executeOne();
|
||||
|
||||
$raw_changes = $diff->buildChangesList();
|
||||
|
||||
$changes = array();
|
||||
foreach ($raw_changes as $changedict) {
|
||||
$changes[] = ArcanistDiffChange::newFromDictionary($changedict);
|
||||
}
|
||||
|
||||
$bundle = ArcanistBundle::newFromChanges($changes);
|
||||
$bundle->setConduit($conduit);
|
||||
$raw_diff = $bundle->toGitPatch();
|
||||
|
||||
$output_file = GetRevisionRawDiffFilename($revision, $diff_id);
|
||||
file_put_contents($output_file, $raw_diff);
|
||||
}
|
||||
|
||||
function GetRevisionHash($revision) {
|
||||
global $viewer;
|
||||
|
||||
$xaction = id(new DifferentialTransactionQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($revision->getPHID()))
|
||||
->setOrder('updated')
|
||||
->setLimit(1)
|
||||
->executeOne();
|
||||
|
||||
$digest = '';
|
||||
|
||||
$digest .= $revision->getDateModified();
|
||||
|
||||
if ($xaction) {
|
||||
$digest .= '_' . $xaction->getPHID();
|
||||
$digest .= '_' . $xaction->getDateModified();
|
||||
}
|
||||
|
||||
return $digest;
|
||||
}
|
||||
|
||||
function NeedBakeRevision($info, $revision, $diff_id) {
|
||||
if (!file_exists(GetRevisionHTMLFilename($revision, $diff_id))) {
|
||||
return true;
|
||||
}
|
||||
if (!file_exists(GetRevisionRawDiffFilename($revision, $diff_id))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($info->last_diff_id < $diff_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($revision->getTitle() != $info->title) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetRevisionHash($revision) != $info->hash) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function BakeRevision($revision, $diff_id) {
|
||||
$revision_id = $revision->getID();
|
||||
|
||||
printf('Baking D' . $revision_id . '?id=' . $diff_id . ' ...' . "\n");
|
||||
|
||||
$info_file_name = GetRevisionInfoFilename($revision);
|
||||
|
||||
$info = RevisionInfo::ReadFromFile($info_file_name);
|
||||
|
||||
if (!NeedBakeRevision($info, $revision, $diff_id)) {
|
||||
print(' ... ignoring: up to date' . "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
$response = RenderDifferentialToResponse($revision, $diff_id);
|
||||
|
||||
$html = RenderResponseToHTML($response);
|
||||
$html_file_name = GetRevisionHTMLFIlename($revision, $diff_id);
|
||||
file_put_contents($html_file_name, $html);
|
||||
|
||||
StoreRawDiff($revision, $diff_id);
|
||||
|
||||
$info->title = $revision->getTitle();
|
||||
$info->page_title = $response->getTitle();
|
||||
$info->hash = GetRevisionHash($revision);
|
||||
$info->last_diff_id = max($info->last_diff_id, $diff_id);
|
||||
|
||||
$info->SaveToFile($info_file_name);
|
||||
}
|
||||
|
||||
function GetAllRevisions() {
|
||||
global $viewer;
|
||||
|
||||
return id(new DifferentialRevisionQuery())
|
||||
->setViewer($viewer)
|
||||
->needDiffIDs(true)
|
||||
->setOrder('oldest')
|
||||
->execute();
|
||||
}
|
||||
|
||||
|
||||
function GetModifiedRevisionsSince($timestamp) {
|
||||
if (!$timestamp) {
|
||||
return GetAllRevisions();
|
||||
}
|
||||
|
||||
global $viewer;
|
||||
|
||||
$xactions = id(new DifferentialTransactionQuery())
|
||||
->setViewer($viewer)
|
||||
->setOrder('oldest')
|
||||
->withUpdatedEpochAfter($timestamp)
|
||||
->execute();
|
||||
|
||||
$revision_ids_set = array();
|
||||
|
||||
foreach ($xactions as $xaction_id => $xaction) {
|
||||
$revision = $xaction->getObject();
|
||||
$revision_id = $revision->getID();
|
||||
|
||||
$revision_ids_set[$revision_id] = 1;
|
||||
}
|
||||
|
||||
$updated_revision_ids = array_keys($revision_ids_set);
|
||||
|
||||
return id(new DifferentialRevisionQuery())
|
||||
->setViewer($viewer)
|
||||
->needDiffIDs(true)
|
||||
->setOrder('oldest')
|
||||
->withIDs($updated_revision_ids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Task baking.
|
||||
|
||||
class TaskInfo {
|
||||
public $title = '';
|
||||
public $page_title = '';
|
||||
|
||||
public $hash = '';
|
||||
|
||||
public static function ReadFromFile($file_name) {
|
||||
$info = new TaskInfo();
|
||||
|
||||
if (!file_exists($file_name)) {
|
||||
return $info;
|
||||
}
|
||||
|
||||
$json = json_decode(file_get_contents($file_name));
|
||||
foreach ($json as $key => $value) {
|
||||
$info->{$key} = $value;
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function SaveToFile($file_name) {
|
||||
$json_str = json_encode(get_object_vars($this));
|
||||
file_put_contents($file_name, $json_str);
|
||||
}
|
||||
};
|
||||
|
||||
function GetTaskOutputDirectory($task) {
|
||||
global $OUTPUT_DIR;
|
||||
|
||||
$id = $task->getID();
|
||||
|
||||
return PathJoin(array($OUTPUT_DIR, 'maniphest', SubpathFromId($id)));
|
||||
}
|
||||
|
||||
function EnsureTaskOutputDirectory($task) {
|
||||
$dir = GetTaskOutputDirectory($task);
|
||||
|
||||
EnsureDirectoryOrDie($dir);
|
||||
|
||||
return $dir;
|
||||
}
|
||||
|
||||
function GetTaskInfoFilename($task) {
|
||||
$task_dir = GetTaskOutputDirectory($task);
|
||||
return PathJoin(array($task_dir, 'info.json'));
|
||||
}
|
||||
|
||||
function GetTaskHTMLFilename($task) {
|
||||
$task_id = $task->getID();
|
||||
$task_dir = GetTaskOutputDirectory($task);
|
||||
|
||||
$file_name = "index.html";
|
||||
|
||||
return PathJoin(array($task_dir, $file_name));
|
||||
}
|
||||
|
||||
function RenderTaskToResponse($task) {
|
||||
global $application_configuration;
|
||||
global $maniphest_routing_map;
|
||||
global $viewer;
|
||||
global $maniphest_controller;
|
||||
|
||||
$task_id = $task->getID();
|
||||
|
||||
$path = '/T' . $task_id;
|
||||
|
||||
$route_result = $maniphest_routing_map->routePath($path);
|
||||
$uri_data = $route_result->getURIData();
|
||||
|
||||
$application_configuration->setPath($path);
|
||||
|
||||
$request_data = array(
|
||||
);
|
||||
|
||||
$request = $application_configuration->buildRequest()
|
||||
->setUser($viewer)
|
||||
->setRequestData($request_data)
|
||||
->setURIMap($uri_data);
|
||||
|
||||
$response = id($maniphest_controller)
|
||||
->setRequest($request)
|
||||
->handleRequest($request);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function GetTaskHash($task) {
|
||||
global $viewer;
|
||||
|
||||
$xaction = id(new ManiphestTransactionQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($task->getPHID()))
|
||||
->setOrder('updated')
|
||||
->setLimit(1)
|
||||
->executeOne();
|
||||
|
||||
$digest = '';
|
||||
|
||||
$digest .= $task->getDateModified();
|
||||
|
||||
if ($xaction) {
|
||||
$digest .= '_' . $xaction->getPHID();
|
||||
$digest .= '_' . $xaction->getDateModified();
|
||||
}
|
||||
|
||||
return $digest;
|
||||
}
|
||||
|
||||
function NeedBakeTask($info, $task) {
|
||||
if (!file_exists(GetTaskHTMLFilename($task))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($task->getTitle() != $info->title) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetTaskHash($task) != $info->hash) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function BakeTask($task) {
|
||||
$task_id = $task->getID();
|
||||
|
||||
printf('Baking T' . $task_id . ' ...' . "\n");
|
||||
|
||||
$info_file_name = GetTaskInfoFilename($task);
|
||||
|
||||
$info = TaskInfo::ReadFromFile($info_file_name);
|
||||
|
||||
if (!NeedBakeTask($info, $task)) {
|
||||
print(' ... ignoring: up to date' . "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
$response = RenderTaskToResponse($task);
|
||||
|
||||
$html = RenderResponseToHTML($response);
|
||||
|
||||
$html_file_name = GetTaskHTMLFIlename($task);
|
||||
file_put_contents($html_file_name, $html);
|
||||
|
||||
$info->title = $task->getTitle();
|
||||
$info->page_title = $response->getTitle();
|
||||
$info->hash = GetTaskHash($task);
|
||||
|
||||
$info->SaveToFile($info_file_name);
|
||||
}
|
||||
|
||||
function GetAllTasks() {
|
||||
global $viewer;
|
||||
|
||||
return id(new ManiphestTaskQuery())
|
||||
->setViewer($viewer)
|
||||
->setOrder('oldest')
|
||||
->execute();
|
||||
}
|
||||
|
||||
function GetModifiedTasksSinze($timestamp) {
|
||||
if (!$timestamp) {
|
||||
return GetAllTasks();
|
||||
}
|
||||
|
||||
global $viewer;
|
||||
|
||||
$xactions = id(new ManiphestTransactionQuery())
|
||||
->setViewer($viewer)
|
||||
->setOrder('updated')
|
||||
->withUpdatedEpochAfter($timestamp)
|
||||
->execute();
|
||||
|
||||
$task_ids_set = array();
|
||||
|
||||
foreach ($xactions as $xaction_id => $xaction) {
|
||||
$task = $xaction->getObject();
|
||||
$task_id = $task->getID();
|
||||
|
||||
$task_ids_set[$task_id] = 1;
|
||||
}
|
||||
|
||||
$updated_task_ids = array_keys($task_ids_set);
|
||||
|
||||
return id(new ManiphestTaskQuery())
|
||||
->setViewer($viewer)
|
||||
->setOrder('oldest')
|
||||
->withIDs($updated_task_ids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Baking main loop.
|
||||
|
||||
print('Querying differential revisions from the database ... ' . "\n");
|
||||
$revisions = GetModifiedRevisionsSince($TIMESTAMP);
|
||||
|
||||
foreach ($revisions as $revision_id => $revision) {
|
||||
EnsureRevisionOutputDirectory($revision);
|
||||
|
||||
foreach ($revision->getDiffIDs() as $diff_id) {
|
||||
BakeRevision($revision, $diff_id);
|
||||
}
|
||||
}
|
||||
|
||||
print("\n");
|
||||
print('Querying maniphest tasks from the database ... ' . "\n");
|
||||
$tasks = GetModifiedTasksSinze($TIMESTAMP);
|
||||
|
||||
foreach ($tasks as $task_id => $task) {
|
||||
EnsureTaskOutputDirectory($task);
|
||||
BakeTask($task);
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
$PHABRICATOR_ROOT = dirname(dirname(dirname(__FILE__)));
|
||||
require_once $PHABRICATOR_ROOT.'/scripts/__init_script__.php';
|
||||
|
||||
if (count($argv) != 2) {
|
||||
print("Usage: $argv[0] timestamp\n");
|
||||
die;
|
||||
}
|
||||
|
||||
$TIMESTAMP = $argv[1];
|
||||
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
$xactions = id(new ManiphestTransactionQuery())
|
||||
->setViewer($viewer)
|
||||
->setOrder('updated')
|
||||
->withUpdatedEpochAfter($TIMESTAMP)
|
||||
->execute();
|
||||
|
||||
$tasks = array();
|
||||
|
||||
foreach ($xactions as $xaction_id => $xaction) {
|
||||
$task = $xaction->getObject();
|
||||
$task_id = $task->getID();
|
||||
|
||||
$tasks[$task_id] = 1;
|
||||
}
|
||||
|
||||
$task_ids = array_keys($tasks);
|
||||
sort($task_ids);
|
||||
|
||||
$handle = fopen("tasks.json", "w");
|
||||
fwrite($handle, "[\n");
|
||||
|
||||
$is_first = true;
|
||||
foreach ($task_ids as $task_id ) {
|
||||
if (!$is_first) {
|
||||
fwrite($handle, ",\n");
|
||||
}
|
||||
fwrite($handle, " {$task_id}");
|
||||
$is_first = false;
|
||||
}
|
||||
|
||||
fwrite($handle, "\n]\n");
|
||||
fclose($handle);
|
||||
|
||||
?>
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
$PHABRICATOR_ROOT = dirname(dirname(dirname(__FILE__)));
|
||||
require_once $PHABRICATOR_ROOT.'/scripts/__init_script__.php';
|
||||
|
||||
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||
|
||||
# print("Querying all files...\n");
|
||||
$files = id(new PhabricatorFileQuery())
|
||||
->setViewer($viewer)
|
||||
->setOrder('oldest')
|
||||
->execute();
|
||||
|
||||
# print("Looping over the files\n");
|
||||
print("ids = (\n");
|
||||
foreach ($files as $file_id => $file) {
|
||||
$authorPHID = $file->getAuthorPHID();
|
||||
|
||||
if (!$authorPHID) {
|
||||
$name = $file->getName();
|
||||
if (substr($name, 0, 8) != 'preview-') {
|
||||
$prev_file = $file;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
print($file->getID() . ",\n");
|
||||
}
|
||||
print(")\n");
|
||||
|
||||
?>
|
||||
@@ -343,7 +343,7 @@ function handleCustomPolicy($config, $policy) {
|
||||
|
||||
$policy_config_user_names = array();
|
||||
$rule_type = $rule['rule'];
|
||||
if ($rule_type == 'PhabricatorPolicyRuleUsers') {
|
||||
if ($rule_type == 'PhabricatorUsersPolicyRule') {
|
||||
$policy_config_user_names =
|
||||
handleUsersPolicyRule($config, $rule);
|
||||
} else if ($rule_type == 'PhabricatorProjectsPolicyRule') {
|
||||
|
||||
@@ -211,21 +211,29 @@ try {
|
||||
->setUniqueMethod('getName')
|
||||
->execute();
|
||||
|
||||
$command_list = array_keys($workflows);
|
||||
$command_list = implode(', ', $command_list);
|
||||
|
||||
$error_lines = array();
|
||||
$error_lines[] = pht('Welcome to Phabricator.');
|
||||
$error_lines[] = pht(
|
||||
'You are logged in as %s.',
|
||||
$user_name);
|
||||
|
||||
if (!$original_argv) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"Welcome to Phabricator.\n\n".
|
||||
"You are logged in as %s.\n\n".
|
||||
"You haven't specified a command to run. This means you're requesting ".
|
||||
"an interactive shell, but Phabricator does not provide an ".
|
||||
"interactive shell over SSH.\n\n".
|
||||
"Usually, you should run a command like `%s` or `%s` ".
|
||||
"rather than connecting directly with SSH.\n\n".
|
||||
"Supported commands are: %s.",
|
||||
$user_name,
|
||||
'git clone',
|
||||
'hg push',
|
||||
implode(', ', array_keys($workflows))));
|
||||
$error_lines[] = pht(
|
||||
'You have not specified a command to run. This means you are requesting '.
|
||||
'an interactive shell, but Phabricator does not provide interactive '.
|
||||
'shells over SSH.');
|
||||
$error_lines[] = pht(
|
||||
'(Usually, you should run a command like "git clone" or "hg push" '.
|
||||
'instead of connecting directly with SSH.)');
|
||||
$error_lines[] = pht(
|
||||
'Supported commands are: %s.',
|
||||
$command_list);
|
||||
|
||||
$error_lines = implode("\n\n", $error_lines);
|
||||
throw new PhutilArgumentUsageException($error_lines);
|
||||
}
|
||||
|
||||
$log_argv = implode(' ', $original_argv);
|
||||
@@ -247,7 +255,20 @@ try {
|
||||
$parsed_args = new PhutilArgumentParser($parseable_argv);
|
||||
|
||||
if (empty($workflows[$command])) {
|
||||
throw new Exception(pht('Invalid command.'));
|
||||
$error_lines[] = pht(
|
||||
'You have specified the command "%s", but that command is not '.
|
||||
'supported by Phabricator. As received by Phabricator, your entire '.
|
||||
'argument list was:',
|
||||
$command);
|
||||
|
||||
$error_lines[] = csprintf(' $ ssh ... -- %Ls', $parseable_argv);
|
||||
|
||||
$error_lines[] = pht(
|
||||
'Supported commands are: %s.',
|
||||
$command_list);
|
||||
|
||||
$error_lines = implode("\n\n", $error_lines);
|
||||
throw new PhutilArgumentUsageException($error_lines);
|
||||
}
|
||||
|
||||
$workflow = $parsed_args->parseWorkflows($workflows);
|
||||
|
||||
@@ -770,6 +770,7 @@ phutil_register_library_map(array(
|
||||
'DiffusionCommitEditEngine' => 'applications/diffusion/editor/DiffusionCommitEditEngine.php',
|
||||
'DiffusionCommitFerretEngine' => 'applications/repository/search/DiffusionCommitFerretEngine.php',
|
||||
'DiffusionCommitFulltextEngine' => 'applications/repository/search/DiffusionCommitFulltextEngine.php',
|
||||
'DiffusionCommitGraphView' => 'applications/diffusion/view/DiffusionCommitGraphView.php',
|
||||
'DiffusionCommitHasPackageEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasPackageEdgeType.php',
|
||||
'DiffusionCommitHasRevisionEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasRevisionEdgeType.php',
|
||||
'DiffusionCommitHasRevisionRelationship' => 'applications/diffusion/relationships/DiffusionCommitHasRevisionRelationship.php',
|
||||
@@ -782,7 +783,6 @@ phutil_register_library_map(array(
|
||||
'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php',
|
||||
'DiffusionCommitHookRejectException' => 'applications/diffusion/exception/DiffusionCommitHookRejectException.php',
|
||||
'DiffusionCommitListController' => 'applications/diffusion/controller/DiffusionCommitListController.php',
|
||||
'DiffusionCommitListView' => 'applications/diffusion/view/DiffusionCommitListView.php',
|
||||
'DiffusionCommitMergeHeraldField' => 'applications/diffusion/herald/DiffusionCommitMergeHeraldField.php',
|
||||
'DiffusionCommitMessageHeraldField' => 'applications/diffusion/herald/DiffusionCommitMessageHeraldField.php',
|
||||
'DiffusionCommitPackageAuditHeraldField' => 'applications/diffusion/herald/DiffusionCommitPackageAuditHeraldField.php',
|
||||
@@ -861,12 +861,8 @@ phutil_register_library_map(array(
|
||||
'DiffusionGitWireProtocolCapabilities' => 'applications/diffusion/protocol/DiffusionGitWireProtocolCapabilities.php',
|
||||
'DiffusionGitWireProtocolRef' => 'applications/diffusion/protocol/DiffusionGitWireProtocolRef.php',
|
||||
'DiffusionGitWireProtocolRefList' => 'applications/diffusion/protocol/DiffusionGitWireProtocolRefList.php',
|
||||
'DiffusionGraphController' => 'applications/diffusion/controller/DiffusionGraphController.php',
|
||||
'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php',
|
||||
'DiffusionHistoryListView' => 'applications/diffusion/view/DiffusionHistoryListView.php',
|
||||
'DiffusionHistoryQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php',
|
||||
'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php',
|
||||
'DiffusionHistoryView' => 'applications/diffusion/view/DiffusionHistoryView.php',
|
||||
'DiffusionHovercardEngineExtension' => 'applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php',
|
||||
'DiffusionIdentityAssigneeDatasource' => 'applications/diffusion/typeahead/DiffusionIdentityAssigneeDatasource.php',
|
||||
'DiffusionIdentityAssigneeEditField' => 'applications/diffusion/editfield/DiffusionIdentityAssigneeEditField.php',
|
||||
@@ -877,6 +873,8 @@ phutil_register_library_map(array(
|
||||
'DiffusionIdentityViewController' => 'applications/diffusion/controller/DiffusionIdentityViewController.php',
|
||||
'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php',
|
||||
'DiffusionInternalAncestorsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionInternalAncestorsConduitAPIMethod.php',
|
||||
'DiffusionInternalCommitSearchConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionInternalCommitSearchConduitAPIMethod.php',
|
||||
'DiffusionInternalCommitSearchEngine' => 'applications/audit/query/DiffusionInternalCommitSearchEngine.php',
|
||||
'DiffusionInternalGitRawDiffQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php',
|
||||
'DiffusionLastModifiedController' => 'applications/diffusion/controller/DiffusionLastModifiedController.php',
|
||||
'DiffusionLastModifiedQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php',
|
||||
@@ -1063,7 +1061,6 @@ phutil_register_library_map(array(
|
||||
'DiffusionSyncLogSearchEngine' => 'applications/diffusion/query/DiffusionSyncLogSearchEngine.php',
|
||||
'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php',
|
||||
'DiffusionTagListView' => 'applications/diffusion/view/DiffusionTagListView.php',
|
||||
'DiffusionTagTableView' => 'applications/diffusion/view/DiffusionTagTableView.php',
|
||||
'DiffusionTaggedRepositoriesFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionTaggedRepositoriesFunctionDatasource.php',
|
||||
'DiffusionTagsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionTagsQueryConduitAPIMethod.php',
|
||||
'DiffusionURIEditConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionURIEditConduitAPIMethod.php',
|
||||
@@ -1310,6 +1307,17 @@ phutil_register_library_map(array(
|
||||
'FlagDeleteConduitAPIMethod' => 'applications/flag/conduit/FlagDeleteConduitAPIMethod.php',
|
||||
'FlagEditConduitAPIMethod' => 'applications/flag/conduit/FlagEditConduitAPIMethod.php',
|
||||
'FlagQueryConduitAPIMethod' => 'applications/flag/conduit/FlagQueryConduitAPIMethod.php',
|
||||
'FuelComponentView' => 'view/fuel/FuelComponentView.php',
|
||||
'FuelGridCellView' => 'view/fuel/FuelGridCellView.php',
|
||||
'FuelGridRowView' => 'view/fuel/FuelGridRowView.php',
|
||||
'FuelGridView' => 'view/fuel/FuelGridView.php',
|
||||
'FuelHandleListItemView' => 'view/fuel/FuelHandleListItemView.php',
|
||||
'FuelHandleListView' => 'view/fuel/FuelHandleListView.php',
|
||||
'FuelMapItemView' => 'view/fuel/FuelMapItemView.php',
|
||||
'FuelMapView' => 'view/fuel/FuelMapView.php',
|
||||
'FuelMenuItemView' => 'view/fuel/FuelMenuItemView.php',
|
||||
'FuelMenuView' => 'view/fuel/FuelMenuView.php',
|
||||
'FuelView' => 'view/fuel/FuelView.php',
|
||||
'FundBacker' => 'applications/fund/storage/FundBacker.php',
|
||||
'FundBackerCart' => 'applications/fund/phortune/FundBackerCart.php',
|
||||
'FundBackerEditor' => 'applications/fund/editor/FundBackerEditor.php',
|
||||
@@ -1422,12 +1430,16 @@ phutil_register_library_map(array(
|
||||
'HarbormasterBuildStep' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStep.php',
|
||||
'HarbormasterBuildStepCoreCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php',
|
||||
'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php',
|
||||
'HarbormasterBuildStepEditAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildStepEditAPIMethod.php',
|
||||
'HarbormasterBuildStepEditEngine' => 'applications/harbormaster/editor/HarbormasterBuildStepEditEngine.php',
|
||||
'HarbormasterBuildStepEditor' => 'applications/harbormaster/editor/HarbormasterBuildStepEditor.php',
|
||||
'HarbormasterBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterBuildStepGroup.php',
|
||||
'HarbormasterBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterBuildStepImplementation.php',
|
||||
'HarbormasterBuildStepImplementationTestCase' => 'applications/harbormaster/step/__tests__/HarbormasterBuildStepImplementationTestCase.php',
|
||||
'HarbormasterBuildStepPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php',
|
||||
'HarbormasterBuildStepQuery' => 'applications/harbormaster/query/HarbormasterBuildStepQuery.php',
|
||||
'HarbormasterBuildStepSearchAPIMethod' => 'applications/harbormaster/conduit/HarbormasterBuildStepSearchAPIMethod.php',
|
||||
'HarbormasterBuildStepSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildStepSearchEngine.php',
|
||||
'HarbormasterBuildStepTransaction' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php',
|
||||
'HarbormasterBuildStepTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildStepTransactionQuery.php',
|
||||
'HarbormasterBuildTarget' => 'applications/harbormaster/storage/build/HarbormasterBuildTarget.php',
|
||||
@@ -1549,6 +1561,7 @@ phutil_register_library_map(array(
|
||||
'HeraldBuildableState' => 'applications/herald/state/HeraldBuildableState.php',
|
||||
'HeraldCallWebhookAction' => 'applications/herald/action/HeraldCallWebhookAction.php',
|
||||
'HeraldCommentAction' => 'applications/herald/action/HeraldCommentAction.php',
|
||||
'HeraldCommentContentField' => 'applications/herald/field/HeraldCommentContentField.php',
|
||||
'HeraldCommitAdapter' => 'applications/diffusion/herald/HeraldCommitAdapter.php',
|
||||
'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php',
|
||||
'HeraldConditionTranscript' => 'applications/herald/storage/transcript/HeraldConditionTranscript.php',
|
||||
@@ -2173,6 +2186,7 @@ phutil_register_library_map(array(
|
||||
'PeopleUserLogGarbageCollector' => 'applications/people/garbagecollector/PeopleUserLogGarbageCollector.php',
|
||||
'Phabricator404Controller' => 'applications/base/controller/Phabricator404Controller.php',
|
||||
'PhabricatorAWSConfigOptions' => 'applications/config/option/PhabricatorAWSConfigOptions.php',
|
||||
'PhabricatorAWSSESFuture' => 'applications/metamta/future/PhabricatorAWSSESFuture.php',
|
||||
'PhabricatorAccessControlTestCase' => 'applications/base/controller/__tests__/PhabricatorAccessControlTestCase.php',
|
||||
'PhabricatorAccessLog' => 'infrastructure/log/PhabricatorAccessLog.php',
|
||||
'PhabricatorAccessLogConfigOptions' => 'applications/config/option/PhabricatorAccessLogConfigOptions.php',
|
||||
@@ -2282,7 +2296,6 @@ phutil_register_library_map(array(
|
||||
'PhabricatorAuditController' => 'applications/audit/controller/PhabricatorAuditController.php',
|
||||
'PhabricatorAuditEditor' => 'applications/audit/editor/PhabricatorAuditEditor.php',
|
||||
'PhabricatorAuditInlineComment' => 'applications/audit/storage/PhabricatorAuditInlineComment.php',
|
||||
'PhabricatorAuditListView' => 'applications/audit/view/PhabricatorAuditListView.php',
|
||||
'PhabricatorAuditMailReceiver' => 'applications/audit/mail/PhabricatorAuditMailReceiver.php',
|
||||
'PhabricatorAuditManagementDeleteWorkflow' => 'applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php',
|
||||
'PhabricatorAuditManagementWorkflow' => 'applications/audit/management/PhabricatorAuditManagementWorkflow.php',
|
||||
@@ -4584,7 +4597,6 @@ phutil_register_library_map(array(
|
||||
'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php',
|
||||
'PhabricatorRepositoryManagementListPathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListPathsWorkflow.php',
|
||||
'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php',
|
||||
'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementLookupUsersWorkflow.php',
|
||||
'PhabricatorRepositoryManagementMaintenanceWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMaintenanceWorkflow.php',
|
||||
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php',
|
||||
'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkReachableWorkflow.php',
|
||||
@@ -4657,8 +4669,6 @@ phutil_register_library_map(array(
|
||||
'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php',
|
||||
'PhabricatorRepositoryURI' => 'applications/repository/storage/PhabricatorRepositoryURI.php',
|
||||
'PhabricatorRepositoryURIIndex' => 'applications/repository/storage/PhabricatorRepositoryURIIndex.php',
|
||||
'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php',
|
||||
'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php',
|
||||
'PhabricatorRepositoryURIPHIDType' => 'applications/repository/phid/PhabricatorRepositoryURIPHIDType.php',
|
||||
'PhabricatorRepositoryURIQuery' => 'applications/repository/query/PhabricatorRepositoryURIQuery.php',
|
||||
'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php',
|
||||
@@ -5958,16 +5968,15 @@ phutil_register_library_map(array(
|
||||
'UserWhoAmIConduitAPIMethod' => 'applications/people/conduit/UserWhoAmIConduitAPIMethod.php',
|
||||
),
|
||||
'function' => array(
|
||||
'MakeFilemameSafe' => 'infrastructure/util/PhabricatorID.php',
|
||||
'PathJoin' => 'infrastructure/util/PhabricatorID.php',
|
||||
'SubpathFromId' => 'infrastructure/util/PhabricatorID.php',
|
||||
'celerity_generate_unique_node_id' => 'applications/celerity/api.php',
|
||||
'celerity_get_resource_uri' => 'applications/celerity/api.php',
|
||||
'hsprintf' => 'infrastructure/markup/render.php',
|
||||
'javelin_tag' => 'infrastructure/javelin/markup.php',
|
||||
'phabricator_absolute_datetime' => 'view/viewutils.php',
|
||||
'phabricator_date' => 'view/viewutils.php',
|
||||
'phabricator_datetime' => 'view/viewutils.php',
|
||||
'phabricator_datetimezone' => 'view/viewutils.php',
|
||||
'phabricator_dual_datetime' => 'view/viewutils.php',
|
||||
'phabricator_form' => 'infrastructure/javelin/markup.php',
|
||||
'phabricator_format_local_time' => 'view/viewutils.php',
|
||||
'phabricator_relative_date' => 'view/viewutils.php',
|
||||
@@ -6873,6 +6882,7 @@ phutil_register_library_map(array(
|
||||
'DiffusionCommitEditEngine' => 'PhabricatorEditEngine',
|
||||
'DiffusionCommitFerretEngine' => 'PhabricatorFerretEngine',
|
||||
'DiffusionCommitFulltextEngine' => 'PhabricatorFulltextEngine',
|
||||
'DiffusionCommitGraphView' => 'DiffusionView',
|
||||
'DiffusionCommitHasPackageEdgeType' => 'PhabricatorEdgeType',
|
||||
'DiffusionCommitHasRevisionEdgeType' => 'PhabricatorEdgeType',
|
||||
'DiffusionCommitHasRevisionRelationship' => 'DiffusionCommitRelationship',
|
||||
@@ -6885,7 +6895,6 @@ phutil_register_library_map(array(
|
||||
'DiffusionCommitHookEngine' => 'Phobject',
|
||||
'DiffusionCommitHookRejectException' => 'Exception',
|
||||
'DiffusionCommitListController' => 'DiffusionController',
|
||||
'DiffusionCommitListView' => 'AphrontView',
|
||||
'DiffusionCommitMergeHeraldField' => 'DiffusionCommitHeraldField',
|
||||
'DiffusionCommitMessageHeraldField' => 'DiffusionCommitHeraldField',
|
||||
'DiffusionCommitPackageAuditHeraldField' => 'DiffusionCommitHeraldField',
|
||||
@@ -6967,12 +6976,8 @@ phutil_register_library_map(array(
|
||||
'DiffusionGitWireProtocolCapabilities' => 'Phobject',
|
||||
'DiffusionGitWireProtocolRef' => 'Phobject',
|
||||
'DiffusionGitWireProtocolRefList' => 'Phobject',
|
||||
'DiffusionGraphController' => 'DiffusionController',
|
||||
'DiffusionHistoryController' => 'DiffusionController',
|
||||
'DiffusionHistoryListView' => 'DiffusionHistoryView',
|
||||
'DiffusionHistoryQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||
'DiffusionHistoryTableView' => 'DiffusionHistoryView',
|
||||
'DiffusionHistoryView' => 'DiffusionView',
|
||||
'DiffusionHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
||||
'DiffusionIdentityAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'DiffusionIdentityAssigneeEditField' => 'PhabricatorTokenizerEditField',
|
||||
@@ -6983,6 +6988,8 @@ phutil_register_library_map(array(
|
||||
'DiffusionIdentityViewController' => 'DiffusionController',
|
||||
'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController',
|
||||
'DiffusionInternalAncestorsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||
'DiffusionInternalCommitSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||
'DiffusionInternalCommitSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'DiffusionInternalGitRawDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||
'DiffusionLastModifiedController' => 'DiffusionController',
|
||||
'DiffusionLastModifiedQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||
@@ -7168,7 +7175,6 @@ phutil_register_library_map(array(
|
||||
'DiffusionSyncLogSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'DiffusionTagListController' => 'DiffusionController',
|
||||
'DiffusionTagListView' => 'DiffusionView',
|
||||
'DiffusionTagTableView' => 'DiffusionView',
|
||||
'DiffusionTaggedRepositoriesFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
|
||||
'DiffusionTagsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
|
||||
'DiffusionURIEditConduitAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||
@@ -7461,6 +7467,17 @@ phutil_register_library_map(array(
|
||||
'FlagDeleteConduitAPIMethod' => 'FlagConduitAPIMethod',
|
||||
'FlagEditConduitAPIMethod' => 'FlagConduitAPIMethod',
|
||||
'FlagQueryConduitAPIMethod' => 'FlagConduitAPIMethod',
|
||||
'FuelComponentView' => 'FuelView',
|
||||
'FuelGridCellView' => 'FuelComponentView',
|
||||
'FuelGridRowView' => 'FuelView',
|
||||
'FuelGridView' => 'FuelComponentView',
|
||||
'FuelHandleListItemView' => 'FuelView',
|
||||
'FuelHandleListView' => 'FuelComponentView',
|
||||
'FuelMapItemView' => 'AphrontView',
|
||||
'FuelMapView' => 'FuelComponentView',
|
||||
'FuelMenuItemView' => 'FuelView',
|
||||
'FuelMenuView' => 'FuelComponentView',
|
||||
'FuelView' => 'AphrontView',
|
||||
'FundBacker' => array(
|
||||
'FundDAO',
|
||||
'PhabricatorPolicyInterface',
|
||||
@@ -7620,18 +7637,23 @@ phutil_register_library_map(array(
|
||||
'PhabricatorApplicationTransactionInterface',
|
||||
'PhabricatorPolicyInterface',
|
||||
'PhabricatorCustomFieldInterface',
|
||||
'PhabricatorConduitResultInterface',
|
||||
),
|
||||
'HarbormasterBuildStepCoreCustomField' => array(
|
||||
'HarbormasterBuildStepCustomField',
|
||||
'PhabricatorStandardCustomFieldInterface',
|
||||
),
|
||||
'HarbormasterBuildStepCustomField' => 'PhabricatorCustomField',
|
||||
'HarbormasterBuildStepEditAPIMethod' => 'PhabricatorEditEngineAPIMethod',
|
||||
'HarbormasterBuildStepEditEngine' => 'PhabricatorEditEngine',
|
||||
'HarbormasterBuildStepEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'HarbormasterBuildStepGroup' => 'Phobject',
|
||||
'HarbormasterBuildStepImplementation' => 'Phobject',
|
||||
'HarbormasterBuildStepImplementationTestCase' => 'PhabricatorTestCase',
|
||||
'HarbormasterBuildStepPHIDType' => 'PhabricatorPHIDType',
|
||||
'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'HarbormasterBuildStepSearchAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
|
||||
'HarbormasterBuildStepSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||
'HarbormasterBuildStepTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'HarbormasterBuildStepTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'HarbormasterBuildTarget' => array(
|
||||
@@ -7764,6 +7786,7 @@ phutil_register_library_map(array(
|
||||
'HeraldBuildableState' => 'HeraldState',
|
||||
'HeraldCallWebhookAction' => 'HeraldAction',
|
||||
'HeraldCommentAction' => 'HeraldAction',
|
||||
'HeraldCommentContentField' => 'HeraldField',
|
||||
'HeraldCommitAdapter' => array(
|
||||
'HeraldAdapter',
|
||||
'HarbormasterBuildableAdapterInterface',
|
||||
@@ -8486,6 +8509,7 @@ phutil_register_library_map(array(
|
||||
'PeopleUserLogGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||
'Phabricator404Controller' => 'PhabricatorController',
|
||||
'PhabricatorAWSConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorAWSSESFuture' => 'PhutilAWSFuture',
|
||||
'PhabricatorAccessControlTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorAccessLog' => 'Phobject',
|
||||
'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
@@ -8610,7 +8634,6 @@ phutil_register_library_map(array(
|
||||
'PhabricatorAuditController' => 'PhabricatorController',
|
||||
'PhabricatorAuditEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorAuditInlineComment' => 'PhabricatorInlineComment',
|
||||
'PhabricatorAuditListView' => 'AphrontView',
|
||||
'PhabricatorAuditMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||
'PhabricatorAuditManagementDeleteWorkflow' => 'PhabricatorAuditManagementWorkflow',
|
||||
'PhabricatorAuditManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
@@ -11323,7 +11346,6 @@ phutil_register_library_map(array(
|
||||
'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementListPathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementMaintenanceWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
'PhabricatorRepositoryManagementMarkReachableWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
|
||||
@@ -11420,8 +11442,6 @@ phutil_register_library_map(array(
|
||||
'PhabricatorConduitResultInterface',
|
||||
),
|
||||
'PhabricatorRepositoryURIIndex' => 'PhabricatorRepositoryDAO',
|
||||
'PhabricatorRepositoryURINormalizer' => 'Phobject',
|
||||
'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorRepositoryURIPHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorRepositoryURIQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase',
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionInternalCommitSearchEngine
|
||||
extends PhabricatorApplicationSearchEngine {
|
||||
|
||||
public function getResultTypeDescription() {
|
||||
return pht('Diffusion Raw Commits');
|
||||
}
|
||||
|
||||
public function getApplicationClassName() {
|
||||
return 'PhabricatorDiffusionApplication';
|
||||
}
|
||||
|
||||
public function newQuery() {
|
||||
return new DiffusionCommitQuery();
|
||||
}
|
||||
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
if ($map['repositoryPHIDs']) {
|
||||
$query->withRepositoryPHIDs($map['repositoryPHIDs']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function buildCustomSearchFields() {
|
||||
return array(
|
||||
id(new PhabricatorSearchDatasourceField())
|
||||
->setLabel(pht('Repositories'))
|
||||
->setKey('repositoryPHIDs')
|
||||
->setDatasource(new DiffusionRepositoryFunctionDatasource())
|
||||
->setDescription(pht('Find commits in particular repositories.')),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function renderResultList(
|
||||
array $commits,
|
||||
PhabricatorSavedQuery $query,
|
||||
array $handles) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getObjectWireFieldsForConduit(
|
||||
$object,
|
||||
array $field_extensions,
|
||||
array $extension_data) {
|
||||
|
||||
$commit = $object;
|
||||
$viewer = $this->requireViewer();
|
||||
|
||||
$repository = $commit->getRepository();
|
||||
$identifier = $commit->getCommitIdentifier();
|
||||
|
||||
id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->synchronizeWorkingCopyBeforeRead();
|
||||
|
||||
$ref = id(new DiffusionLowLevelCommitQuery())
|
||||
->setRepository($repository)
|
||||
->withIdentifier($identifier)
|
||||
->execute();
|
||||
|
||||
return array(
|
||||
'ref' => $ref->newDictionary(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -221,9 +221,9 @@ final class PhabricatorCommitSearchEngine
|
||||
|
||||
$bucket = $this->getResultBucket($query);
|
||||
|
||||
$template = id(new PhabricatorAuditListView())
|
||||
$template = id(new DiffusionCommitGraphView())
|
||||
->setViewer($viewer)
|
||||
->setShowDrafts(true);
|
||||
->setShowAuditors(true);
|
||||
|
||||
$views = array();
|
||||
if ($bucket) {
|
||||
@@ -235,37 +235,31 @@ final class PhabricatorCommitSearchEngine
|
||||
foreach ($groups as $group) {
|
||||
// Don't show groups in Dashboard Panels
|
||||
if ($group->getObjects() || !$this->isPanelContext()) {
|
||||
$views[] = id(clone $template)
|
||||
$item_list = id(clone $template)
|
||||
->setCommits($group->getObjects())
|
||||
->newObjectItemListView();
|
||||
|
||||
$views[] = $item_list
|
||||
->setHeader($group->getName())
|
||||
->setNoDataString($group->getNoDataString())
|
||||
->setCommits($group->getObjects());
|
||||
->setNoDataString($group->getNoDataString());
|
||||
}
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
$this->addError($ex->getMessage());
|
||||
}
|
||||
} else {
|
||||
$views[] = id(clone $template)
|
||||
->setCommits($commits)
|
||||
->setNoDataString(pht('No commits found.'));
|
||||
}
|
||||
|
||||
if (!$views) {
|
||||
$views[] = id(new PhabricatorAuditListView())
|
||||
->setViewer($viewer)
|
||||
$item_list = id(clone $template)
|
||||
->setCommits($commits)
|
||||
->newObjectItemListView();
|
||||
|
||||
$views[] = $item_list
|
||||
->setNoDataString(pht('No commits found.'));
|
||||
}
|
||||
|
||||
if (count($views) == 1) {
|
||||
$list = head($views)->buildList();
|
||||
} else {
|
||||
$list = $views;
|
||||
}
|
||||
|
||||
$result = new PhabricatorApplicationSearchResultView();
|
||||
$result->setContent($list);
|
||||
|
||||
return $result;
|
||||
return id(new PhabricatorApplicationSearchResultView())
|
||||
->setContent($views);
|
||||
}
|
||||
|
||||
protected function getNewUserBody() {
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
<?php
|
||||
|
||||
final class PhabricatorAuditListView extends AphrontView {
|
||||
|
||||
private $commits = array();
|
||||
private $header;
|
||||
private $showDrafts;
|
||||
private $noDataString;
|
||||
private $highlightedAudits;
|
||||
|
||||
public function setNoDataString($no_data_string) {
|
||||
$this->noDataString = $no_data_string;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNoDataString() {
|
||||
return $this->noDataString;
|
||||
}
|
||||
|
||||
public function setHeader($header) {
|
||||
$this->header = $header;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHeader() {
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
public function setShowDrafts($show_drafts) {
|
||||
$this->showDrafts = $show_drafts;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getShowDrafts() {
|
||||
return $this->showDrafts;
|
||||
}
|
||||
|
||||
/**
|
||||
* These commits should have both commit data and audit requests attached.
|
||||
*/
|
||||
public function setCommits(array $commits) {
|
||||
assert_instances_of($commits, 'PhabricatorRepositoryCommit');
|
||||
$this->commits = mpull($commits, null, 'getPHID');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCommits() {
|
||||
return $this->commits;
|
||||
}
|
||||
|
||||
private function getCommitDescription($phid) {
|
||||
if ($this->commits === null) {
|
||||
return pht('(Unknown Commit)');
|
||||
}
|
||||
|
||||
$commit = idx($this->commits, $phid);
|
||||
if (!$commit) {
|
||||
return pht('(Unknown Commit)');
|
||||
}
|
||||
|
||||
$summary = $commit->getCommitData()->getSummary();
|
||||
if (strlen($summary)) {
|
||||
return $summary;
|
||||
}
|
||||
|
||||
// No summary, so either this is still importing or just has an empty
|
||||
// commit message.
|
||||
|
||||
if (!$commit->isImported()) {
|
||||
return pht('(Importing Commit...)');
|
||||
} else {
|
||||
return pht('(Untitled Commit)');
|
||||
}
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$list = $this->buildList();
|
||||
$list->setFlush(true);
|
||||
return $list->render();
|
||||
}
|
||||
|
||||
public function buildList() {
|
||||
$viewer = $this->getViewer();
|
||||
$rowc = array();
|
||||
|
||||
$phids = array();
|
||||
foreach ($this->getCommits() as $commit) {
|
||||
$phids[] = $commit->getPHID();
|
||||
|
||||
foreach ($commit->getAudits() as $audit) {
|
||||
$phids[] = $audit->getAuditorPHID();
|
||||
}
|
||||
|
||||
$author_phid = $commit->getAuthorPHID();
|
||||
if ($author_phid) {
|
||||
$phids[] = $author_phid;
|
||||
}
|
||||
}
|
||||
|
||||
$handles = $viewer->loadHandles($phids);
|
||||
|
||||
$show_drafts = $this->getShowDrafts();
|
||||
|
||||
$draft_icon = id(new PHUIIconView())
|
||||
->setIcon('fa-comment yellow')
|
||||
->addSigil('has-tooltip')
|
||||
->setMetadata(
|
||||
array(
|
||||
'tip' => pht('Unsubmitted Comments'),
|
||||
));
|
||||
|
||||
$list = new PHUIObjectItemListView();
|
||||
foreach ($this->commits as $commit) {
|
||||
$commit_phid = $commit->getPHID();
|
||||
$commit_handle = $handles[$commit_phid];
|
||||
$committed = null;
|
||||
|
||||
$commit_name = $commit_handle->getName();
|
||||
$commit_link = $commit_handle->getURI();
|
||||
$commit_desc = $this->getCommitDescription($commit_phid);
|
||||
$committed = phabricator_datetime($commit->getEpoch(), $viewer);
|
||||
|
||||
$status = $commit->getAuditStatusObject();
|
||||
|
||||
$status_text = $status->getName();
|
||||
$status_color = $status->getColor();
|
||||
$status_icon = $status->getIcon();
|
||||
|
||||
$author_phid = $commit->getAuthorPHID();
|
||||
if ($author_phid) {
|
||||
$author_name = $handles[$author_phid]->renderLink();
|
||||
} else {
|
||||
$author_name = $commit->getCommitData()->getAuthorName();
|
||||
}
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setObjectName($commit_name)
|
||||
->setHeader($commit_desc)
|
||||
->setHref($commit_link)
|
||||
->setDisabled($commit->isUnreachable())
|
||||
->addByline(pht('Author: %s', $author_name))
|
||||
->addIcon('none', $committed);
|
||||
|
||||
if ($show_drafts) {
|
||||
if ($commit->getHasDraft($viewer)) {
|
||||
$item->addAttribute($draft_icon);
|
||||
}
|
||||
}
|
||||
|
||||
$audits = $commit->getAudits();
|
||||
$auditor_phids = mpull($audits, 'getAuditorPHID');
|
||||
if ($auditor_phids) {
|
||||
$auditor_list = $handles->newSublist($auditor_phids)
|
||||
->renderList()
|
||||
->setAsInline(true);
|
||||
} else {
|
||||
$auditor_list = phutil_tag('em', array(), pht('None'));
|
||||
}
|
||||
$item->addAttribute(pht('Auditors: %s', $auditor_list));
|
||||
|
||||
if ($status_color) {
|
||||
$item->setStatusIcon($status_icon.' '.$status_color, $status_text);
|
||||
}
|
||||
|
||||
$list->addItem($item);
|
||||
}
|
||||
|
||||
if ($this->noDataString) {
|
||||
$list->setNoDataString($this->noDataString);
|
||||
}
|
||||
|
||||
if ($this->header) {
|
||||
$list->setHeader($this->header);
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -181,6 +181,12 @@ final class PhabricatorAuthPasswordEngine
|
||||
$normal_password = phutil_utf8_strtolower($raw_password);
|
||||
if (strlen($normal_password) >= $minimum_similarity) {
|
||||
foreach ($normal_map as $term => $source) {
|
||||
|
||||
// See T2312. This may be required if the term list includes numeric
|
||||
// strings like "12345", which will be cast to integers when used as
|
||||
// array keys.
|
||||
$term = phutil_string_cast($term);
|
||||
|
||||
if (strpos($term, $normal_password) === false &&
|
||||
strpos($normal_password, $term) === false) {
|
||||
continue;
|
||||
|
||||
@@ -334,7 +334,7 @@ abstract class PhabricatorController extends AphrontController {
|
||||
}
|
||||
|
||||
$crumbs[] = id(new PHUICrumbView())
|
||||
// ->setHref($this->getApplicationURI())
|
||||
->setHref($this->getApplicationURI())
|
||||
->setName($application->getName())
|
||||
->setIcon($icon);
|
||||
}
|
||||
|
||||
@@ -100,9 +100,17 @@ final class PhabricatorConduitAPIController
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
$result = null;
|
||||
$error_code = ($ex instanceof ConduitException
|
||||
? 'ERR-CONDUIT-CALL'
|
||||
: 'ERR-CONDUIT-CORE');
|
||||
|
||||
if ($ex instanceof ConduitException) {
|
||||
$error_code = 'ERR-CONDUIT-CALL';
|
||||
} else {
|
||||
$error_code = 'ERR-CONDUIT-CORE';
|
||||
|
||||
// See T13581. When a Conduit method raises an uncaught exception
|
||||
// other than a "ConduitException", log it.
|
||||
phlog($ex);
|
||||
}
|
||||
|
||||
$error_info = $ex->getMessage();
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,8 @@ abstract class PhabricatorConduitController extends PhabricatorController {
|
||||
$parts[] = '--conduit-token ';
|
||||
$parts[] = phutil_tag('strong', array(), '<conduit-token>');
|
||||
$parts[] = ' ';
|
||||
$parts[] = '--';
|
||||
$parts[] = ' ';
|
||||
|
||||
$parts[] = $method->getAPIMethodName();
|
||||
|
||||
|
||||
@@ -120,9 +120,21 @@ abstract class ConduitAPIMethod
|
||||
public function executeMethod(ConduitAPIRequest $request) {
|
||||
$this->setViewer($request->getUser());
|
||||
|
||||
$client = $this->newConduitCallProxyClient($request);
|
||||
if ($client) {
|
||||
// We're proxying, so just make an intracluster call.
|
||||
return $client->callMethodSynchronous(
|
||||
$this->getAPIMethodName(),
|
||||
$request->getAllParameters());
|
||||
}
|
||||
|
||||
return $this->execute($request);
|
||||
}
|
||||
|
||||
protected function newConduitCallProxyClient(ConduitAPIRequest $request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract public function getAPIMethodName();
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,10 @@ final class ConduitAPIRequest extends Phobject {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->getUser();
|
||||
}
|
||||
|
||||
public function setOAuthToken(
|
||||
PhabricatorOAuthServerAccessToken $oauth_token) {
|
||||
$this->oauthToken = $oauth_token;
|
||||
|
||||
@@ -8,14 +8,21 @@ final class PhabricatorDaemonsSetupCheck extends PhabricatorSetupCheck {
|
||||
|
||||
protected function executeChecks() {
|
||||
|
||||
$task_daemon = id(new PhabricatorDaemonLogQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
|
||||
->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))
|
||||
->setLimit(1)
|
||||
->execute();
|
||||
try {
|
||||
$task_daemons = id(new PhabricatorDaemonLogQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
|
||||
->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))
|
||||
->setLimit(1)
|
||||
->execute();
|
||||
|
||||
if (!$task_daemon) {
|
||||
$no_daemons = !$task_daemons;
|
||||
} catch (Exception $ex) {
|
||||
// Just skip this warning if the query fails for some reason.
|
||||
$no_daemons = false;
|
||||
}
|
||||
|
||||
if ($no_daemons) {
|
||||
$doc_href = PhabricatorEnv::getDoclink('Managing Daemons with phd');
|
||||
|
||||
$summary = pht(
|
||||
|
||||
@@ -322,6 +322,9 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
||||
'directly supported. Prefixes and other strings may be customized with '.
|
||||
'"translation.override".');
|
||||
|
||||
$phd_reason = pht(
|
||||
'Use "bin/phd debug ..." to get a detailed daemon execution log.');
|
||||
|
||||
$ancient_config += array(
|
||||
'phid.external-loaders' =>
|
||||
pht(
|
||||
@@ -539,6 +542,9 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
||||
|
||||
'phd.pid-directory' => pht(
|
||||
'Phabricator daemons no longer use PID files.'),
|
||||
|
||||
'phd.trace' => $phd_reason,
|
||||
'phd.verbose' => $phd_reason,
|
||||
);
|
||||
|
||||
return $ancient_config;
|
||||
|
||||
@@ -43,22 +43,6 @@ final class PhabricatorPHDConfigOptions
|
||||
"configuration changes are picked up by the daemons ".
|
||||
"automatically, but pool sizes can not be changed without a ".
|
||||
"restart.")),
|
||||
$this->newOption('phd.verbose', 'bool', false)
|
||||
->setLocked(true)
|
||||
->setBoolOptions(
|
||||
array(
|
||||
pht('Verbose mode'),
|
||||
pht('Normal mode'),
|
||||
))
|
||||
->setSummary(pht("Launch daemons in 'verbose' mode by default."))
|
||||
->setDescription(
|
||||
pht(
|
||||
"Launch daemons in 'verbose' mode by default. This creates a lot ".
|
||||
"of output, but can help debug issues. Daemons launched in debug ".
|
||||
"mode with '%s' are always launched in verbose mode. ".
|
||||
"See also '%s'.",
|
||||
'phd debug',
|
||||
'phd.trace')),
|
||||
$this->newOption('phd.user', 'string', null)
|
||||
->setLocked(true)
|
||||
->setSummary(pht('System user to run daemons as.'))
|
||||
@@ -68,22 +52,6 @@ final class PhabricatorPHDConfigOptions
|
||||
'user will own the working copies of any repositories that '.
|
||||
'Phabricator imports or manages. This option is new and '.
|
||||
'experimental.')),
|
||||
$this->newOption('phd.trace', 'bool', false)
|
||||
->setLocked(true)
|
||||
->setBoolOptions(
|
||||
array(
|
||||
pht('Trace mode'),
|
||||
pht('Normal mode'),
|
||||
))
|
||||
->setSummary(pht("Launch daemons in 'trace' mode by default."))
|
||||
->setDescription(
|
||||
pht(
|
||||
"Launch daemons in 'trace' mode by default. This creates an ".
|
||||
"ENORMOUS amount of output, but can help debug issues. Daemons ".
|
||||
"launched in debug mode with '%s' are always launched in ".
|
||||
"trace mode. See also '%s'.",
|
||||
'phd debug',
|
||||
'phd.verbose')),
|
||||
$this->newOption('phd.garbage-collection', 'wild', array())
|
||||
->setLocked(true)
|
||||
->setLockedMessage(
|
||||
|
||||
@@ -116,11 +116,11 @@ abstract class PhabricatorDaemonManagementWorkflow
|
||||
$trace = PhutilArgumentParser::isTraceModeEnabled();
|
||||
|
||||
$flags = array();
|
||||
if ($trace || PhabricatorEnv::getEnvConfig('phd.trace')) {
|
||||
if ($trace) {
|
||||
$flags[] = '--trace';
|
||||
}
|
||||
|
||||
if ($debug || PhabricatorEnv::getEnvConfig('phd.verbose')) {
|
||||
if ($debug) {
|
||||
$flags[] = '--verbose';
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ final class DifferentialRevisionViewController
|
||||
|
||||
$request_uri = $request->getRequestURI();
|
||||
|
||||
$large = $request->getStr('large') && true;
|
||||
$large = $request->getStr('large');
|
||||
|
||||
$large_warning =
|
||||
($this->isLargeDiff()) &&
|
||||
@@ -310,7 +310,7 @@ final class DifferentialRevisionViewController
|
||||
$header = $this->buildHeader($revision);
|
||||
$subheader = $this->buildSubheaderView($revision);
|
||||
$details = $this->buildDetails($revision, $field_list);
|
||||
$curtain = $this->buildCurtain($revision, $target_id);
|
||||
$curtain = $this->buildCurtain($revision);
|
||||
|
||||
$repository = $revision->getRepository();
|
||||
if ($repository) {
|
||||
@@ -510,6 +510,11 @@ final class DifferentialRevisionViewController
|
||||
->setLoadEntireGraph(true)
|
||||
->loadGraph();
|
||||
if (!$stack_graph->isEmpty()) {
|
||||
// See PHI1900. The graph UI element now tries to figure out the correct
|
||||
// height automatically, but currently can't in this case because the
|
||||
// element is not visible when the page loads. Set an explicit height.
|
||||
$stack_graph->setHeight(34);
|
||||
|
||||
$stack_table = $stack_graph->newGraphTable();
|
||||
|
||||
$parent_type = DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST;
|
||||
@@ -553,8 +558,7 @@ final class DifferentialRevisionViewController
|
||||
|
||||
$tab_header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Revision Contents'))
|
||||
// ->addActionLink($view_button)
|
||||
;
|
||||
->addActionLink($view_button);
|
||||
|
||||
$tab_view = id(new PHUIObjectBoxView())
|
||||
->setHeader($tab_header)
|
||||
@@ -664,7 +668,7 @@ final class DifferentialRevisionViewController
|
||||
$view = id(new PHUIHeaderView())
|
||||
->setHeader($revision->getTitle($revision))
|
||||
->setUser($this->getViewer())
|
||||
// ->setPolicyObject($revision)
|
||||
->setPolicyObject($revision)
|
||||
->setHeaderIcon('fa-cog');
|
||||
|
||||
$status_tag = id(new PHUITagView())
|
||||
@@ -711,7 +715,7 @@ final class DifferentialRevisionViewController
|
||||
|
||||
return id(new PHUIHeadThingView())
|
||||
->setImage($image_uri)
|
||||
// ->setImageHref($image_href)
|
||||
->setImageHref($image_href)
|
||||
->setContent($content);
|
||||
}
|
||||
|
||||
@@ -738,7 +742,7 @@ final class DifferentialRevisionViewController
|
||||
->appendChild($properties);
|
||||
}
|
||||
|
||||
private function buildCurtain(DifferentialRevision $revision, $diff_id) {
|
||||
private function buildCurtain(DifferentialRevision $revision) {
|
||||
$viewer = $this->getViewer();
|
||||
$revision_id = $revision->getID();
|
||||
$revision_phid = $revision->getPHID();
|
||||
@@ -749,48 +753,48 @@ final class DifferentialRevisionViewController
|
||||
$revision,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
// $curtain->addAction(
|
||||
// id(new PhabricatorActionView())
|
||||
// ->setIcon('fa-pencil')
|
||||
// ->setHref("/differential/revision/edit/{$revision_id}/")
|
||||
// ->setName(pht('Edit Revision'))
|
||||
// ->setDisabled(!$can_edit)
|
||||
// ->setWorkflow(!$can_edit));
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-pencil')
|
||||
->setHref("/differential/revision/edit/{$revision_id}/")
|
||||
->setName(pht('Edit Revision'))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
// $curtain->addAction(
|
||||
// id(new PhabricatorActionView())
|
||||
// ->setIcon('fa-upload')
|
||||
// ->setHref("/differential/revision/update/{$revision_id}/")
|
||||
// ->setName(pht('Update Diff'))
|
||||
// ->setDisabled(!$can_edit)
|
||||
// ->setWorkflow(!$can_edit));
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-upload')
|
||||
->setHref("/differential/revision/update/{$revision_id}/")
|
||||
->setName(pht('Update Diff'))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$request_uri = $this->getRequest()->getRequestURI();
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setIcon('fa-download')
|
||||
->setName(pht('Download Raw Diff'))
|
||||
->setHref('raw_diff/D' . $revision_id . '.id' . $diff_id . '.diff'));
|
||||
->setHref($request_uri->alter('download', 'true')));
|
||||
|
||||
$relationship_list = PhabricatorObjectRelationshipList::newForObject(
|
||||
$viewer,
|
||||
$revision);
|
||||
|
||||
// $revision_actions = array(
|
||||
// DifferentialRevisionHasParentRelationship::RELATIONSHIPKEY,
|
||||
// DifferentialRevisionHasChildRelationship::RELATIONSHIPKEY,
|
||||
// );
|
||||
//
|
||||
// $revision_submenu = $relationship_list->newActionSubmenu($revision_actions)
|
||||
// ->setName(pht('Edit Related Revisions...'))
|
||||
// ->setIcon('fa-cog');
|
||||
//
|
||||
// $curtain->addAction($revision_submenu);
|
||||
//
|
||||
// $relationship_submenu = $relationship_list->newActionMenu();
|
||||
// if ($relationship_submenu) {
|
||||
// $curtain->addAction($relationship_submenu);
|
||||
// }
|
||||
$revision_actions = array(
|
||||
DifferentialRevisionHasParentRelationship::RELATIONSHIPKEY,
|
||||
DifferentialRevisionHasChildRelationship::RELATIONSHIPKEY,
|
||||
);
|
||||
|
||||
$revision_submenu = $relationship_list->newActionSubmenu($revision_actions)
|
||||
->setName(pht('Edit Related Revisions...'))
|
||||
->setIcon('fa-cog');
|
||||
|
||||
$curtain->addAction($revision_submenu);
|
||||
|
||||
$relationship_submenu = $relationship_list->newActionMenu();
|
||||
if ($relationship_submenu) {
|
||||
$curtain->addAction($relationship_submenu);
|
||||
}
|
||||
|
||||
$repository = $revision->getRepository();
|
||||
if ($repository && $repository->canPerformAutomation()) {
|
||||
@@ -871,7 +875,6 @@ final class DifferentialRevisionViewController
|
||||
$raw_changesets = id(new DifferentialChangesetQuery())
|
||||
->setViewer($viewer)
|
||||
->withDiffs($load_diffs)
|
||||
->needHunks(true)
|
||||
->execute();
|
||||
$changeset_groups = mgroup($raw_changesets, 'getDiffID');
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ final class PhabricatorDifferentialRebuildChangesetsWorkflow
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Object "%s" specified by "--revision" must be a Differential '.
|
||||
'revision.'));
|
||||
'revision.',
|
||||
$revision_identifier));
|
||||
}
|
||||
} else {
|
||||
$revision = id(new DifferentialRevisionQuery())
|
||||
|
||||
@@ -1053,14 +1053,30 @@ final class DifferentialChangesetParser extends Phobject {
|
||||
$this->comments = id(new PHUIDiffInlineThreader())
|
||||
->reorderAndThreadCommments($this->comments);
|
||||
|
||||
$old_max_display = 1;
|
||||
foreach ($this->old as $old) {
|
||||
if (isset($old['line'])) {
|
||||
$old_max_display = $old['line'];
|
||||
}
|
||||
}
|
||||
|
||||
$new_max_display = 1;
|
||||
foreach ($this->new as $new) {
|
||||
if (isset($new['line'])) {
|
||||
$new_max_display = $new['line'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->comments as $comment) {
|
||||
$final = $comment->getLineNumber() +
|
||||
$comment->getLineLength();
|
||||
$final = max(1, $final);
|
||||
$display_line = $comment->getLineNumber() + $comment->getLineLength();
|
||||
$display_line = max(1, $display_line);
|
||||
|
||||
if ($this->isCommentOnRightSideWhenDisplayed($comment)) {
|
||||
$new_comments[$final][] = $comment;
|
||||
$display_line = min($new_max_display, $display_line);
|
||||
$new_comments[$display_line][] = $comment;
|
||||
} else {
|
||||
$old_comments[$final][] = $comment;
|
||||
$display_line = min($old_max_display, $display_line);
|
||||
$old_comments[$display_line][] = $comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1327,6 +1343,10 @@ final class DifferentialChangesetParser extends Phobject {
|
||||
$not_covered = 0;
|
||||
|
||||
foreach ($this->new as $k => $new) {
|
||||
if ($new === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$new['line']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -33,14 +33,9 @@ final class DifferentialDiffPHIDType extends PhabricatorPHIDType {
|
||||
$diff = $objects[$phid];
|
||||
|
||||
$id = $diff->getID();
|
||||
$revision_id = $diff->getRevisionID();
|
||||
|
||||
$handle->setName(pht('Diff %d', $id));
|
||||
|
||||
$subpath = SubpathFromId($revision_id);
|
||||
$uri = '../../../differential/' . $subpath . '/' . "D{$revision_id}.id{$id}.html";
|
||||
|
||||
$handle->setURI("$uri");
|
||||
$handle->setURI("/differential/diff/{$id}/");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -778,12 +778,19 @@ final class DifferentialRevisionQuery
|
||||
*/
|
||||
protected function shouldGroupQueryResultRows() {
|
||||
|
||||
$join_triggers = array_merge(
|
||||
$this->pathIDs,
|
||||
$this->ccs,
|
||||
$this->reviewers);
|
||||
if (count($this->pathIDs) > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (count($join_triggers) > 1) {
|
||||
if (count($this->ccs) > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (count($this->reviewers) > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (count($this->commitHashes) > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,29 +3,8 @@
|
||||
final class DifferentialTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
private $updatedEpochAfter;
|
||||
|
||||
public function getTemplateApplicationTransaction() {
|
||||
return new DifferentialTransaction();
|
||||
}
|
||||
|
||||
public function withUpdatedEpochAfter($epoch) {
|
||||
$this->updatedEpochAfter = $epoch;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
|
||||
$where = array();
|
||||
|
||||
if ($this->updatedEpochAfter !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'x.dateModified >= %d',
|
||||
$this->updatedEpochAfter);
|
||||
}
|
||||
|
||||
$where[] = $this->buildWhereClauseParts($conn);
|
||||
|
||||
return $this->formatWhereClause($conn, $where);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -589,15 +589,15 @@ abstract class DifferentialChangesetHTMLRenderer
|
||||
$reference = $this->getRenderingReference();
|
||||
|
||||
return javelin_tag(
|
||||
'span',
|
||||
'a',
|
||||
array(
|
||||
// 'href' => '#',
|
||||
// 'mustcapture' => true,
|
||||
// 'sigil' => 'show-more',
|
||||
// 'meta' => array(
|
||||
// 'type' => ($is_all ? 'all' : null),
|
||||
// 'range' => $range,
|
||||
// ),
|
||||
'href' => '#',
|
||||
'mustcapture' => true,
|
||||
'sigil' => 'show-more',
|
||||
'meta' => array(
|
||||
'type' => ($is_all ? 'all' : null),
|
||||
'range' => $range,
|
||||
),
|
||||
),
|
||||
$text);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,9 @@ final class DifferentialChangesetOneUpRenderer
|
||||
$cells = array();
|
||||
if ($is_old) {
|
||||
if ($p['htype']) {
|
||||
if (empty($p['oline'])) {
|
||||
if ($p['htype'] === '\\') {
|
||||
$class = 'comment';
|
||||
} else if (empty($p['oline'])) {
|
||||
$class = 'left old old-full';
|
||||
} else {
|
||||
$class = 'left old';
|
||||
@@ -129,7 +131,9 @@ final class DifferentialChangesetOneUpRenderer
|
||||
$cells[] = $no_coverage;
|
||||
} else {
|
||||
if ($p['htype']) {
|
||||
if (empty($p['oline'])) {
|
||||
if ($p['htype'] === '\\') {
|
||||
$class = 'comment';
|
||||
} else if (empty($p['oline'])) {
|
||||
$class = 'right new new-full';
|
||||
} else {
|
||||
$class = 'right new';
|
||||
|
||||
@@ -505,6 +505,8 @@ abstract class DifferentialChangesetRenderer extends Phobject {
|
||||
$ospec['htype'] = $old[$ii]['type'];
|
||||
if (isset($old_render[$ii])) {
|
||||
$ospec['render'] = $old_render[$ii];
|
||||
} else if ($ospec['htype'] === '\\') {
|
||||
$ospec['render'] = $old[$ii]['text'];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,6 +516,8 @@ abstract class DifferentialChangesetRenderer extends Phobject {
|
||||
$nspec['htype'] = $new[$ii]['type'];
|
||||
if (isset($new_render[$ii])) {
|
||||
$nspec['render'] = $new_render[$ii];
|
||||
} else if ($nspec['htype'] === '\\') {
|
||||
$nspec['render'] = $new[$ii]['text'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -747,9 +747,10 @@ final class DifferentialDiff
|
||||
$prop->delete();
|
||||
}
|
||||
|
||||
$viewstates = id(new DifferentialViewStateQuery())
|
||||
$viewstate_query = id(new DifferentialViewStateQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($this->getPHID()));
|
||||
$viewstates = new PhabricatorQueryIterator($viewstate_query);
|
||||
foreach ($viewstates as $viewstate) {
|
||||
$viewstate->delete();
|
||||
}
|
||||
|
||||
@@ -147,8 +147,7 @@ final class DifferentialRevision extends DifferentialDAO
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
$subpath = SubpathFromId($this->getID());
|
||||
return '../../../differential/' . $subpath . '/index.html';
|
||||
return '/'.$this->getMonogram();
|
||||
}
|
||||
|
||||
public function getCommitPHIDs() {
|
||||
@@ -1034,9 +1033,10 @@ final class DifferentialRevision extends DifferentialDAO
|
||||
$dummy_path->getTableName(),
|
||||
$this->getID());
|
||||
|
||||
$viewstates = id(new DifferentialViewStateQuery())
|
||||
$viewstate_query = id(new DifferentialViewStateQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($this->getPHID()));
|
||||
$viewstates = new PhabricatorQueryIterator($viewstate_query);
|
||||
foreach ($viewstates as $viewstate) {
|
||||
$viewstate->delete();
|
||||
}
|
||||
|
||||
@@ -68,8 +68,6 @@ final class DifferentialTransactionComment
|
||||
}
|
||||
|
||||
public function shouldUseMarkupCache($field) {
|
||||
return false;
|
||||
|
||||
// Only cache submitted comments.
|
||||
return ($this->getTransactionPHID() != null);
|
||||
}
|
||||
|
||||
@@ -187,13 +187,13 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||
$uniq_id = 'diff-'.$changeset->getAnchorName();
|
||||
$detail->setID($uniq_id);
|
||||
|
||||
// $view_options = $this->renderViewOptionsDropdown(
|
||||
// $detail,
|
||||
// $ref,
|
||||
// $changeset);
|
||||
$view_options = $this->renderViewOptionsDropdown(
|
||||
$detail,
|
||||
$ref,
|
||||
$changeset);
|
||||
|
||||
$detail->setChangeset($changeset);
|
||||
// $detail->addButton($view_options);
|
||||
$detail->addButton($view_options);
|
||||
$detail->setSymbolIndex(idx($this->symbolIndexes, $key));
|
||||
$detail->setVsChangesetID(idx($this->vsMap, $changeset->getID()));
|
||||
$detail->setEditable(true);
|
||||
@@ -202,107 +202,7 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||
|
||||
$detail->setRenderURI($this->renderURI);
|
||||
|
||||
// $parser = $this->getParser();
|
||||
|
||||
$revision_id = $diff->getRevisionID();
|
||||
$revision = id(new DifferentialRevisionQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($revision_id))
|
||||
->executeOne();
|
||||
|
||||
$old = array();
|
||||
$new = array();
|
||||
|
||||
$right = $changeset;
|
||||
$left = null;
|
||||
|
||||
$right_source = $right->getID();
|
||||
$right_new = true;
|
||||
$left_source = $right->getID();
|
||||
$left_new = false;
|
||||
|
||||
$render_cache_key = $right->getID();
|
||||
|
||||
$old[] = $changeset;
|
||||
$new[] = $changeset;
|
||||
|
||||
$parser = id(new DifferentialChangesetParser())
|
||||
->setViewer($viewer)
|
||||
->setViewState(new PhabricatorChangesetViewState())
|
||||
// ->setCoverage($coverage)
|
||||
->setChangeset($changeset)
|
||||
->setRenderingReference($ref)
|
||||
->setRenderCacheKey($render_cache_key)
|
||||
->setRightSideCommentMapping($right_source, $right_new)
|
||||
->setLeftSideCommentMapping($left_source, $left_new)
|
||||
->setMask(array())
|
||||
;
|
||||
|
||||
if ($left && $right) {
|
||||
$parser->setOriginals($left, $right);
|
||||
}
|
||||
|
||||
if ($revision) {
|
||||
$inlines = id(new DifferentialDiffInlineCommentQuery())
|
||||
->setViewer($viewer)
|
||||
->withRevisionPHIDs(array($revision->getPHID()))
|
||||
->withPublishableComments(true)
|
||||
->withPublishedComments(true)
|
||||
->needHidden(true)
|
||||
->needInlineContext(true)
|
||||
->execute();
|
||||
|
||||
$inlines = mpull($inlines, 'newInlineCommentObject');
|
||||
|
||||
$inlines = id(new PhabricatorInlineCommentAdjustmentEngine())
|
||||
->setViewer($viewer)
|
||||
->setRevision($revision)
|
||||
->setOldChangesets($old)
|
||||
->setNewChangesets($new)
|
||||
->setInlines($inlines)
|
||||
->execute();
|
||||
} else {
|
||||
$inlines = array();
|
||||
}
|
||||
|
||||
if ($left_new) {
|
||||
$inlines = array_merge(
|
||||
$inlines,
|
||||
$this->buildLintInlineComments($left));
|
||||
}
|
||||
|
||||
if ($right_new) {
|
||||
$inlines = array_merge(
|
||||
$inlines,
|
||||
$this->buildLintInlineComments($right));
|
||||
}
|
||||
|
||||
$phids = array();
|
||||
foreach ($inlines as $inline) {
|
||||
$parser->parseInlineComment($inline);
|
||||
if ($inline->getAuthorPHID()) {
|
||||
$phids[$inline->getAuthorPHID()] = true;
|
||||
}
|
||||
}
|
||||
$phids = array_keys($phids);
|
||||
|
||||
$handles = $this->loadViewerHandles($phids);
|
||||
$parser->setHandles($handles);
|
||||
|
||||
$engine = new PhabricatorMarkupEngine();
|
||||
$engine->setViewer($viewer);
|
||||
|
||||
foreach ($inlines as $inline) {
|
||||
$engine->addObject(
|
||||
$inline,
|
||||
PhabricatorInlineComment::MARKUP_FIELD_BODY);
|
||||
}
|
||||
|
||||
$engine->process();
|
||||
|
||||
$parser
|
||||
->setMarkupEngine($engine);
|
||||
|
||||
$parser = $this->getParser();
|
||||
if ($parser) {
|
||||
$response = $parser->newChangesetResponse();
|
||||
$detail->setChangesetResponse($response);
|
||||
@@ -571,92 +471,4 @@ final class DifferentialChangesetListView extends AphrontView {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
private function buildLintInlineComments($changeset) {
|
||||
$diff = $changeset->getDiff();
|
||||
|
||||
$target_phids = $diff->getBuildTargetPHIDs();
|
||||
if (!$target_phids) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$messages = id(new HarbormasterBuildLintMessage())->loadAllWhere(
|
||||
'buildTargetPHID IN (%Ls) AND path = %s',
|
||||
$target_phids,
|
||||
$changeset->getFilename());
|
||||
|
||||
if (!$messages) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$change_type = $changeset->getChangeType();
|
||||
if (DifferentialChangeType::isDeleteChangeType($change_type)) {
|
||||
// If this is a lint message on a deleted file, show it on the left
|
||||
// side of the UI because there are no source code lines on the right
|
||||
// side of the UI so inlines don't have anywhere to render. See PHI416.
|
||||
$is_new = 0;
|
||||
} else {
|
||||
$is_new = 1;
|
||||
}
|
||||
|
||||
$template = id(new DifferentialInlineComment())
|
||||
->setChangesetID($changeset->getID())
|
||||
->setIsNewFile($is_new)
|
||||
->setLineLength(0);
|
||||
|
||||
$inlines = array();
|
||||
foreach ($messages as $message) {
|
||||
$description = $message->getProperty('description');
|
||||
|
||||
$inlines[] = id(clone $template)
|
||||
->setSyntheticAuthor(pht('Lint: %s', $message->getName()))
|
||||
->setLineNumber($message->getLine())
|
||||
->setContent($description);
|
||||
}
|
||||
|
||||
return $inlines;
|
||||
}
|
||||
|
||||
private function loadCoverage(DifferentialChangeset $changeset) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$target_phids = $changeset->getDiff()->getBuildTargetPHIDs();
|
||||
if (!$target_phids) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$unit = id(new HarbormasterBuildUnitMessageQuery())
|
||||
->setViewer($viewer)
|
||||
->withBuildTargetPHIDs($target_phids)
|
||||
->execute();
|
||||
if (!$unit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$coverage = array();
|
||||
foreach ($unit as $message) {
|
||||
$test_coverage = $message->getProperty('coverage');
|
||||
if ($test_coverage === null) {
|
||||
continue;
|
||||
}
|
||||
$coverage_data = idx($test_coverage, $changeset->getFileName());
|
||||
if (!strlen($coverage_data)) {
|
||||
continue;
|
||||
}
|
||||
$coverage[] = $coverage_data;
|
||||
}
|
||||
|
||||
if (!$coverage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ArcanistUnitTestResult::mergeCoverage($coverage);
|
||||
}
|
||||
|
||||
protected function loadViewerHandles(array $phids) {
|
||||
return id(new PhabricatorHandleQuery())
|
||||
->setViewer($this->getViewer())
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ final class DifferentialLocalCommitsView extends AphrontView {
|
||||
$view->setSome($summary);
|
||||
|
||||
if ($message && (trim($summary) != trim($message))) {
|
||||
// $view->setMore(phutil_escape_html_newlines($message));
|
||||
$view->setMore(phutil_escape_html_newlines($message));
|
||||
}
|
||||
|
||||
$row[] = $view->render();
|
||||
@@ -137,9 +137,9 @@ final class DifferentialLocalCommitsView extends AphrontView {
|
||||
$commit_hash = self::formatCommit($hash);
|
||||
if ($commit_for_link) {
|
||||
$link = phutil_tag(
|
||||
'span',
|
||||
'a',
|
||||
array(
|
||||
// 'href' => $commit_for_link->getURI(),
|
||||
'href' => $commit_for_link->getURI(),
|
||||
),
|
||||
$commit_hash);
|
||||
} else {
|
||||
|
||||
@@ -178,7 +178,7 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
$id_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => 'D'.$revision_id.'.id'.$id.'.html',
|
||||
'href' => '/D'.$revision_id.'?id='.$id,
|
||||
),
|
||||
$id);
|
||||
} else {
|
||||
@@ -196,27 +196,19 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
$base,
|
||||
$desc,
|
||||
$age,
|
||||
// $lint,
|
||||
// $unit,
|
||||
// $old,
|
||||
// $new,
|
||||
$lint,
|
||||
$unit,
|
||||
$old,
|
||||
$new,
|
||||
);
|
||||
|
||||
$classes = array();
|
||||
|
||||
/*
|
||||
if ($old_class) {
|
||||
$classes[] = 'differential-update-history-old-now';
|
||||
}
|
||||
if ($new_class) {
|
||||
$classes[] = 'differential-update-history-new-now';
|
||||
}
|
||||
*/
|
||||
|
||||
if ($id && $this->selectedDiffID == $id) {
|
||||
$classes[] = 'differential-update-history-current';
|
||||
}
|
||||
|
||||
$rowc[] = nonempty(implode(' ', $classes), null);
|
||||
}
|
||||
|
||||
@@ -234,10 +226,10 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
pht('Base'),
|
||||
pht('Description'),
|
||||
pht('Created'),
|
||||
// pht('Lint'),
|
||||
// pht('Unit'),
|
||||
// '',
|
||||
// '',
|
||||
pht('Lint'),
|
||||
pht('Unit'),
|
||||
'',
|
||||
'',
|
||||
));
|
||||
$table->setColumnClasses(
|
||||
array(
|
||||
@@ -246,8 +238,8 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
'',
|
||||
'wide',
|
||||
'date',
|
||||
// 'center',
|
||||
// 'center',
|
||||
'center',
|
||||
'center',
|
||||
'center differential-update-history-old',
|
||||
'center differential-update-history-new',
|
||||
));
|
||||
@@ -259,8 +251,8 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
// false,
|
||||
// false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
));
|
||||
@@ -284,7 +276,7 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
),
|
||||
array(
|
||||
$table,
|
||||
// $show_diff,
|
||||
$show_diff,
|
||||
));
|
||||
|
||||
return $content;
|
||||
@@ -400,10 +392,8 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
$diff->getSourceControlBaseRevision());
|
||||
if ($commit_for_link) {
|
||||
$link = phutil_tag(
|
||||
'span',
|
||||
array(
|
||||
'href' => $commit_for_link->getURI()
|
||||
),
|
||||
'a',
|
||||
array('href' => $commit_for_link->getURI()),
|
||||
$label);
|
||||
} else {
|
||||
$link = $label;
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionAbandonTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.abandon';
|
||||
const ACTIONKEY = 'abandon';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Abandon Revision');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('This revision will be abandoned and closed.');
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionAcceptTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.accept';
|
||||
const ACTIONKEY = 'accept';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Accept Revision');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('These changes will be approved.');
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ abstract class DifferentialRevisionActionTransaction
|
||||
}
|
||||
|
||||
abstract protected function validateAction($object, PhabricatorUser $viewer);
|
||||
abstract protected function getRevisionActionLabel();
|
||||
abstract protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer);
|
||||
|
||||
protected function validateOptionValue($object, $actor, array $value) {
|
||||
return null;
|
||||
@@ -53,15 +55,23 @@ abstract class DifferentialRevisionActionTransaction
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getRevisionActionSubmitButtonText(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getRevisionActionMetadata(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return array();
|
||||
}
|
||||
|
||||
public static function loadAllActions() {
|
||||
return id(new PhutilClassMapQuery())
|
||||
->setAncestorClass(__CLASS__)
|
||||
@@ -105,17 +115,19 @@ abstract class DifferentialRevisionActionTransaction
|
||||
->setValue(true);
|
||||
|
||||
if ($this->isActionAvailable($revision, $viewer)) {
|
||||
$label = $this->getRevisionActionLabel();
|
||||
$label = $this->getRevisionActionLabel($revision, $viewer);
|
||||
if ($label !== null) {
|
||||
$field->setCommentActionLabel($label);
|
||||
|
||||
$description = $this->getRevisionActionDescription($revision);
|
||||
$description = $this->getRevisionActionDescription($revision, $viewer);
|
||||
$field->setActionDescription($description);
|
||||
|
||||
$group_key = $this->getRevisionActionGroupKey();
|
||||
$field->setCommentActionGroupKey($group_key);
|
||||
|
||||
$button_text = $this->getRevisionActionSubmitButtonText($revision);
|
||||
$button_text = $this->getRevisionActionSubmitButtonText(
|
||||
$revision,
|
||||
$viewer);
|
||||
$field->setActionSubmitButtonText($button_text);
|
||||
|
||||
// Currently, every revision action conflicts with every other
|
||||
@@ -144,6 +156,11 @@ abstract class DifferentialRevisionActionTransaction
|
||||
$field->setOptions($options);
|
||||
$field->setValue($value);
|
||||
}
|
||||
|
||||
$metadata = $this->getRevisionActionMetadata($revision, $viewer);
|
||||
foreach ($metadata as $metadata_key => $metadata_value) {
|
||||
$field->setMetadataValue($metadata_key, $metadata_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionCloseTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.close';
|
||||
const ACTIONKEY = 'close';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Close Revision');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('This revision will be closed.');
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionCommandeerTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.commandeer';
|
||||
const ACTIONKEY = 'commandeer';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Commandeer Revision');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('You will take control of this revision and become its author.');
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionPlanChangesTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.plan';
|
||||
const ACTIONKEY = 'plan-changes';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Plan Changes');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht(
|
||||
'This revision will be removed from review queues until it is revised.');
|
||||
}
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionReclaimTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.reclaim';
|
||||
const ACTIONKEY = 'reclaim';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Reclaim Revision');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('This revision will be reclaimed and reopened.');
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionRejectTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.reject';
|
||||
const ACTIONKEY = 'reject';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Request Changes');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('This revision will be returned to the author for updates.');
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionReopenTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.reopen';
|
||||
const ACTIONKEY = 'reopen';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Reopen Revision');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('This revision will be reopened for review.');
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,8 @@ final class DifferentialRevisionRepositoryTransaction
|
||||
$errors[] = $this->newInvalidError(
|
||||
pht(
|
||||
'Repository "%s" is not a valid repository, or you do not have '.
|
||||
'permission to view it.'),
|
||||
'permission to view it.',
|
||||
$new_value),
|
||||
$xaction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,21 +6,63 @@ final class DifferentialRevisionRequestReviewTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.request';
|
||||
const ACTIONKEY = 'request-review';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
const SOURCE_HARBORMASTER = 'harbormaster';
|
||||
const SOURCE_AUTHOR = 'author';
|
||||
const SOURCE_VIEWER = 'viewer';
|
||||
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
|
||||
// See PHI1810. Allow non-authors to "Request Review" on draft revisions
|
||||
// to promote them out of the draft state. This smoothes over the workflow
|
||||
// where an author asks for review of an urgent change but has not used
|
||||
// "Request Review" to skip builds.
|
||||
|
||||
if ($revision->isDraft()) {
|
||||
if (!$this->isViewerRevisionAuthor($revision, $viewer)) {
|
||||
return pht('Begin Review Now');
|
||||
}
|
||||
}
|
||||
|
||||
return pht('Request Review');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
if ($revision->isDraft()) {
|
||||
return pht('This revision will be submitted to reviewers for feedback.');
|
||||
if (!$this->isViewerRevisionAuthor($revision, $viewer)) {
|
||||
return pht(
|
||||
'This revision will be moved out of the draft state so you can '.
|
||||
'review it immediately.');
|
||||
} else {
|
||||
return pht(
|
||||
'This revision will be submitted to reviewers for feedback.');
|
||||
}
|
||||
} else {
|
||||
return pht('This revision will be returned to reviewers for feedback.');
|
||||
}
|
||||
}
|
||||
|
||||
protected function getRevisionActionMetadata(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
$map = array();
|
||||
|
||||
if ($revision->isDraft()) {
|
||||
$action_source = $this->getActorSourceType(
|
||||
$revision,
|
||||
$viewer);
|
||||
$map['promotion.source'] = $action_source;
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
protected function getRevisionActionSubmitButtonText(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
|
||||
// See PHI975. When the action stack will promote the revision out of
|
||||
// draft, change the button text from "Submit Quietly".
|
||||
@@ -72,29 +114,43 @@ final class DifferentialRevisionRequestReviewTransaction
|
||||
'revisions.'));
|
||||
}
|
||||
|
||||
// When revisions automatically promote out of "Draft" after builds finish,
|
||||
// the viewer may be acting as the Harbormaster application.
|
||||
if (!$viewer->isOmnipotent()) {
|
||||
if (!$this->isViewerRevisionAuthor($object, $viewer)) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'You can not request review of this revision because you are not '.
|
||||
'the author of the revision.'));
|
||||
}
|
||||
}
|
||||
$this->getActorSourceType($object, $viewer);
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
return pht(
|
||||
'%s requested review of this revision.',
|
||||
$this->renderAuthor());
|
||||
$source = $this->getDraftPromotionSource();
|
||||
|
||||
switch ($source) {
|
||||
case self::SOURCE_HARBORMASTER:
|
||||
case self::SOURCE_VIEWER:
|
||||
case self::SOURCE_AUTHOR:
|
||||
return pht(
|
||||
'%s published this revision for review.',
|
||||
$this->renderAuthor());
|
||||
default:
|
||||
return pht(
|
||||
'%s requested review of this revision.',
|
||||
$this->renderAuthor());
|
||||
}
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
return pht(
|
||||
'%s requested review of %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject());
|
||||
$source = $this->getDraftPromotionSource();
|
||||
|
||||
switch ($source) {
|
||||
case self::SOURCE_HARBORMASTER:
|
||||
case self::SOURCE_VIEWER:
|
||||
case self::SOURCE_AUTHOR:
|
||||
return pht(
|
||||
'%s published %s for review.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject());
|
||||
default:
|
||||
return pht(
|
||||
'%s requested review of %s.',
|
||||
$this->renderAuthor(),
|
||||
$this->renderObject());
|
||||
}
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
@@ -105,4 +161,36 @@ final class DifferentialRevisionRequestReviewTransaction
|
||||
return array();
|
||||
}
|
||||
|
||||
private function getDraftPromotionSource() {
|
||||
return $this->getMetadataValue('promotion.source');
|
||||
}
|
||||
|
||||
private function getActorSourceType(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
|
||||
$is_harbormaster = $viewer->isOmnipotent();
|
||||
$is_author = $this->isViewerRevisionAuthor($revision, $viewer);
|
||||
$is_draft = $revision->isDraft();
|
||||
|
||||
if ($is_harbormaster) {
|
||||
// When revisions automatically promote out of "Draft" after builds
|
||||
// finish, the viewer may be acting as the Harbormaster application.
|
||||
$source = self::SOURCE_HARBORMASTER;
|
||||
} else if ($is_author) {
|
||||
$source = self::SOURCE_AUTHOR;
|
||||
} else if ($is_draft) {
|
||||
// Non-authors are allowed to "Request Review" on draft revisions, to
|
||||
// force them into review immediately.
|
||||
$source = self::SOURCE_VIEWER;
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'You can not request review of this revision because you are not '.
|
||||
'the author of the revision and it is not currently a draft.'));
|
||||
}
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,12 +6,15 @@ final class DifferentialRevisionResignTransaction
|
||||
const TRANSACTIONTYPE = 'differential.revision.resign';
|
||||
const ACTIONKEY = 'resign';
|
||||
|
||||
protected function getRevisionActionLabel() {
|
||||
protected function getRevisionActionLabel(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('Resign as Reviewer');
|
||||
}
|
||||
|
||||
protected function getRevisionActionDescription(
|
||||
DifferentialRevision $revision) {
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $viewer) {
|
||||
return pht('You will resign as a reviewer for this change.');
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,6 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
|
||||
'change/(?P<dblob>.*)' => 'DiffusionChangeController',
|
||||
'clone/' => 'DiffusionCloneController',
|
||||
'history/(?P<dblob>.*)' => 'DiffusionHistoryController',
|
||||
'graph/(?P<dblob>.*)' => 'DiffusionGraphController',
|
||||
'browse/(?P<dblob>.*)' => 'DiffusionBrowseController',
|
||||
'document/(?P<dblob>.*)'
|
||||
=> 'DiffusionDocumentController',
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionInternalCommitSearchConduitAPIMethod
|
||||
extends PhabricatorSearchEngineAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'internal.commit.search';
|
||||
}
|
||||
|
||||
public function newSearchEngine() {
|
||||
return new DiffusionInternalCommitSearchEngine();
|
||||
}
|
||||
|
||||
public function getMethodSummary() {
|
||||
return pht('Read raw information about commits.');
|
||||
}
|
||||
|
||||
protected function newConduitCallProxyClient(ConduitAPIRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$constraints = $request->getValue('constraints');
|
||||
if (is_array($constraints)) {
|
||||
$repository_phids = idx($constraints, 'repositoryPHIDs');
|
||||
} else {
|
||||
$repository_phids = array();
|
||||
}
|
||||
|
||||
$repository_phid = null;
|
||||
if (is_array($repository_phids)) {
|
||||
if (phutil_is_natural_list($repository_phids)) {
|
||||
if (count($repository_phids) === 1) {
|
||||
$value = head($repository_phids);
|
||||
if (is_string($value)) {
|
||||
$repository_phid = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($repository_phid === null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'This internal method must be invoked with a "repositoryPHIDs" '.
|
||||
'constraint with exactly one value.'));
|
||||
}
|
||||
|
||||
$repository = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withPHIDs(array($repository_phid))
|
||||
->executeOne();
|
||||
if (!$repository) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $repository->newConduitClientForRequest($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,7 +38,6 @@ final class DiffusionQueryCommitsConduitAPIMethod
|
||||
|
||||
protected function execute(ConduitAPIRequest $request) {
|
||||
$need_messages = $request->getValue('needMessages');
|
||||
$bypass_cache = $request->getValue('bypassCache');
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$query = id(new DiffusionCommitQuery())
|
||||
@@ -53,12 +52,6 @@ final class DiffusionQueryCommitsConduitAPIMethod
|
||||
->executeOne();
|
||||
if ($repository) {
|
||||
$query->withRepository($repository);
|
||||
if ($bypass_cache) {
|
||||
id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->synchronizeWorkingCopyBeforeRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,48 +89,22 @@ final class DiffusionQueryCommitsConduitAPIMethod
|
||||
'repositoryPHID' => $commit->getRepository()->getPHID(),
|
||||
'identifier' => $commit->getCommitIdentifier(),
|
||||
'epoch' => $commit->getEpoch(),
|
||||
'authorEpoch' => $commit_data->getCommitDetail('authorEpoch'),
|
||||
'authorEpoch' => $commit_data->getAuthorEpoch(),
|
||||
'uri' => $uri,
|
||||
'isImporting' => !$commit->isImported(),
|
||||
'summary' => $commit->getSummary(),
|
||||
'authorPHID' => $commit->getAuthorPHID(),
|
||||
'committerPHID' => $commit_data->getCommitDetail('committerPHID'),
|
||||
'author' => $commit_data->getAuthorName(),
|
||||
'authorName' => $commit_data->getCommitDetail('authorName'),
|
||||
'authorEmail' => $commit_data->getCommitDetail('authorEmail'),
|
||||
'committer' => $commit_data->getCommitDetail('committer'),
|
||||
'committerName' => $commit_data->getCommitDetail('committerName'),
|
||||
'committerEmail' => $commit_data->getCommitDetail('committerEmail'),
|
||||
'author' => $commit_data->getAuthorString(),
|
||||
'authorName' => $commit_data->getAuthorDisplayName(),
|
||||
'authorEmail' => $commit_data->getAuthorEmail(),
|
||||
'committer' => $commit_data->getCommitterString(),
|
||||
'committerName' => $commit_data->getCommitterDisplayName(),
|
||||
'committerEmail' => $commit_data->getCommitterEmail(),
|
||||
'hashes' => array(),
|
||||
);
|
||||
|
||||
if ($bypass_cache) {
|
||||
$lowlevel_commitref = id(new DiffusionLowLevelCommitQuery())
|
||||
->setRepository($commit->getRepository())
|
||||
->withIdentifier($commit->getCommitIdentifier())
|
||||
->execute();
|
||||
|
||||
$dict['authorEpoch'] = $lowlevel_commitref->getAuthorEpoch();
|
||||
$dict['author'] = $lowlevel_commitref->getAuthor();
|
||||
$dict['authorName'] = $lowlevel_commitref->getAuthorName();
|
||||
$dict['authorEmail'] = $lowlevel_commitref->getAuthorEmail();
|
||||
$dict['committer'] = $lowlevel_commitref->getCommitter();
|
||||
$dict['committerName'] = $lowlevel_commitref->getCommitterName();
|
||||
$dict['committerEmail'] = $lowlevel_commitref->getCommitterEmail();
|
||||
|
||||
if ($need_messages) {
|
||||
$dict['message'] = $lowlevel_commitref->getMessage();
|
||||
}
|
||||
|
||||
foreach ($lowlevel_commitref->getHashes() as $hash) {
|
||||
$dict['hashes'][] = array(
|
||||
'type' => $hash->getHashType(),
|
||||
'value' => $hash->getHashValue(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($need_messages && !$bypass_cache) {
|
||||
if ($need_messages) {
|
||||
$dict['message'] = $commit_data->getCommitMessage();
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,35 @@ abstract class DiffusionQueryConduitAPIMethod
|
||||
* should occur after @{method:getResult}, like formatting a timestamp.
|
||||
*/
|
||||
final protected function execute(ConduitAPIRequest $request) {
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
|
||||
// We pass this flag on to prevent proxying of any other Conduit calls
|
||||
// which we need to make in order to respond to this one. Although we
|
||||
// could safely proxy them, we take a big performance hit in the common
|
||||
// case, and doing more proxying wouldn't exercise any additional code so
|
||||
// we wouldn't gain a testability/predictability benefit.
|
||||
$is_cluster_request = $request->getIsClusterRequest();
|
||||
$drequest->setIsClusterRequest($is_cluster_request);
|
||||
|
||||
$viewer = $request->getViewer();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
// TODO: Allow web UI queries opt out of this if they don't care about
|
||||
// fetching the most up-to-date data? Synchronization can be slow, and a
|
||||
// lot of web reads are probably fine if they're a few seconds out of
|
||||
// date.
|
||||
id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->synchronizeWorkingCopyBeforeRead();
|
||||
|
||||
return $this->getResult($request);
|
||||
}
|
||||
|
||||
|
||||
protected function newConduitCallProxyClient(ConduitAPIRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
|
||||
$identifier = $request->getValue('repository');
|
||||
if ($identifier === null) {
|
||||
$identifier = $request->getValue('callsign');
|
||||
@@ -92,7 +121,7 @@ abstract class DiffusionQueryConduitAPIMethod
|
||||
|
||||
$drequest = DiffusionRequest::newFromDictionary(
|
||||
array(
|
||||
'user' => $request->getUser(),
|
||||
'user' => $viewer,
|
||||
'repository' => $identifier,
|
||||
'branch' => $request->getValue('branch'),
|
||||
'path' => $request->getValue('path'),
|
||||
@@ -106,46 +135,16 @@ abstract class DiffusionQueryConduitAPIMethod
|
||||
$identifier));
|
||||
}
|
||||
|
||||
// Figure out whether we're going to handle this request on this device,
|
||||
// or proxy it to another node in the cluster.
|
||||
|
||||
// If this is a cluster request and we need to proxy, we'll explode here
|
||||
// to prevent infinite recursion.
|
||||
|
||||
$is_cluster_request = $request->getIsClusterRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$repository = $drequest->getRepository();
|
||||
$client = $repository->newConduitClient(
|
||||
$viewer,
|
||||
$is_cluster_request);
|
||||
|
||||
$client = $repository->newConduitClientForRequest($request);
|
||||
if ($client) {
|
||||
// We're proxying, so just make an intracluster call.
|
||||
return $client->callMethodSynchronous(
|
||||
$this->getAPIMethodName(),
|
||||
$request->getAllParameters());
|
||||
} else {
|
||||
|
||||
// We pass this flag on to prevent proxying of any other Conduit calls
|
||||
// which we need to make in order to respond to this one. Although we
|
||||
// could safely proxy them, we take a big performance hit in the common
|
||||
// case, and doing more proxying wouldn't exercise any additional code so
|
||||
// we wouldn't gain a testability/predictability benefit.
|
||||
$drequest->setIsClusterRequest($is_cluster_request);
|
||||
|
||||
$this->setDiffusionRequest($drequest);
|
||||
|
||||
// TODO: Allow web UI queries opt out of this if they don't care about
|
||||
// fetching the most up-to-date data? Synchronization can be slow, and a
|
||||
// lot of web reads are probably fine if they're a few seconds out of
|
||||
// date.
|
||||
id(new DiffusionRepositoryClusterEngine())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->synchronizeWorkingCopyBeforeRead();
|
||||
|
||||
return $this->getResult($request);
|
||||
return $client;
|
||||
}
|
||||
|
||||
$this->setDiffusionRequest($drequest);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getResult(ConduitAPIRequest $request) {
|
||||
|
||||
@@ -292,7 +292,6 @@ final class DiffusionBrowseController extends DiffusionController {
|
||||
|
||||
$empty_result = null;
|
||||
$browse_panel = null;
|
||||
$branch_panel = null;
|
||||
if (!$results->isValidResults()) {
|
||||
$empty_result = new DiffusionEmptyResultView();
|
||||
$empty_result->setDiffusionRequest($drequest);
|
||||
@@ -328,12 +327,6 @@ final class DiffusionBrowseController extends DiffusionController {
|
||||
->setTable($browse_table)
|
||||
->addClass('diffusion-mobile-view')
|
||||
->setPager($pager);
|
||||
|
||||
$path = $drequest->getPath();
|
||||
$is_branch = (!strlen($path) && $repository->supportsBranchComparison());
|
||||
if ($is_branch) {
|
||||
$branch_panel = $this->buildBranchTable();
|
||||
}
|
||||
}
|
||||
|
||||
$open_revisions = $this->buildOpenRevisions();
|
||||
@@ -359,7 +352,6 @@ final class DiffusionBrowseController extends DiffusionController {
|
||||
->setFooter(
|
||||
array(
|
||||
$bar,
|
||||
$branch_panel,
|
||||
$empty_result,
|
||||
$browse_panel,
|
||||
$open_revisions,
|
||||
@@ -1074,59 +1066,4 @@ final class DiffusionBrowseController extends DiffusionController {
|
||||
return $file;
|
||||
}
|
||||
|
||||
private function buildBranchTable() {
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$branch = $drequest->getBranch();
|
||||
$default_branch = $repository->getDefaultBranch();
|
||||
|
||||
if ($branch === $default_branch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$pager = id(new PHUIPagerView())
|
||||
->setPageSize(10);
|
||||
|
||||
try {
|
||||
$results = $this->callConduitWithDiffusionRequest(
|
||||
'diffusion.historyquery',
|
||||
array(
|
||||
'commit' => $branch,
|
||||
'against' => $default_branch,
|
||||
'path' => $drequest->getPath(),
|
||||
'offset' => $pager->getOffset(),
|
||||
'limit' => $pager->getPageSize() + 1,
|
||||
));
|
||||
} catch (Exception $ex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$history = DiffusionPathChange::newFromConduit($results['pathChanges']);
|
||||
$history = $pager->sliceResults($history);
|
||||
|
||||
if (!$history) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$history_table = id(new DiffusionHistoryTableView())
|
||||
->setViewer($viewer)
|
||||
->setDiffusionRequest($drequest)
|
||||
->setHistory($history)
|
||||
->setParents($results['parents'])
|
||||
->setFilterParents(true)
|
||||
->setIsHead(true)
|
||||
->setIsTail(!$pager->getHasMorePages());
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('%s vs %s', $branch, $default_branch));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->addClass('diffusion-mobile-view')
|
||||
->setTable($history_table);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -90,10 +90,9 @@ final class DiffusionCommitController extends DiffusionController {
|
||||
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
|
||||
->appendChild($warning_message);
|
||||
|
||||
$list = id(new DiffusionCommitListView())
|
||||
$list = id(new DiffusionCommitGraphView())
|
||||
->setViewer($viewer)
|
||||
->setCommits($commits)
|
||||
->setNoDataString(pht('No recent commits.'));
|
||||
->setCommits($commits);
|
||||
|
||||
$crumbs->addTextCrumb(pht('Ambiguous Commit'));
|
||||
|
||||
@@ -183,7 +182,6 @@ final class DiffusionCommitController extends DiffusionController {
|
||||
}
|
||||
|
||||
$curtain = $this->buildCurtain($commit, $repository);
|
||||
$subheader = $this->buildSubheaderView($commit, $commit_data);
|
||||
$details = $this->buildPropertyListView(
|
||||
$commit,
|
||||
$commit_data,
|
||||
@@ -483,7 +481,6 @@ final class DiffusionCommitController extends DiffusionController {
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setSubheader($subheader)
|
||||
->setCurtain($curtain)
|
||||
->setMainColumn(
|
||||
array(
|
||||
@@ -625,33 +622,50 @@ final class DiffusionCommitController extends DiffusionController {
|
||||
}
|
||||
}
|
||||
|
||||
$author_epoch = $data->getCommitDetail('authorEpoch');
|
||||
$provenance_list = new PHUIStatusListView();
|
||||
|
||||
$committed_info = id(new PHUIStatusItemView())
|
||||
->setNote(phabricator_datetime($commit->getEpoch(), $viewer))
|
||||
->setTarget($commit->renderAnyCommitter($viewer, $handles));
|
||||
$author_view = $commit->newCommitAuthorView($viewer);
|
||||
if ($author_view) {
|
||||
$author_date = $data->getAuthorEpoch();
|
||||
$author_date = phabricator_datetime($author_date, $viewer);
|
||||
|
||||
$committed_list = new PHUIStatusListView();
|
||||
$committed_list->addItem($committed_info);
|
||||
$view->addProperty(
|
||||
pht('Committed'),
|
||||
$committed_list);
|
||||
$provenance_list->addItem(
|
||||
id(new PHUIStatusItemView())
|
||||
->setTarget($author_view)
|
||||
->setNote(pht('Authored on %s', $author_date)));
|
||||
}
|
||||
|
||||
if (!$commit->isAuthorSameAsCommitter()) {
|
||||
$committer_view = $commit->newCommitCommitterView($viewer);
|
||||
if ($committer_view) {
|
||||
$committer_date = $commit->getEpoch();
|
||||
$committer_date = phabricator_datetime($committer_date, $viewer);
|
||||
|
||||
$provenance_list->addItem(
|
||||
id(new PHUIStatusItemView())
|
||||
->setTarget($committer_view)
|
||||
->setNote(pht('Committed on %s', $committer_date)));
|
||||
}
|
||||
}
|
||||
|
||||
if ($push_logs) {
|
||||
$pushed_list = new PHUIStatusListView();
|
||||
|
||||
foreach ($push_logs as $push_log) {
|
||||
$pushed_item = id(new PHUIStatusItemView())
|
||||
->setTarget($handles[$push_log->getPusherPHID()]->renderLink())
|
||||
->setNote(phabricator_datetime($push_log->getEpoch(), $viewer));
|
||||
$pushed_list->addItem($pushed_item);
|
||||
}
|
||||
$pusher_date = $push_log->getEpoch();
|
||||
$pusher_date = phabricator_datetime($pusher_date, $viewer);
|
||||
|
||||
$view->addProperty(
|
||||
pht('Pushed'),
|
||||
$pushed_list);
|
||||
$pusher_view = $handles[$push_log->getPusherPHID()]->renderLink();
|
||||
|
||||
$provenance_list->addItem(
|
||||
id(new PHUIStatusItemView())
|
||||
->setTarget($pusher_view)
|
||||
->setNote(pht('Pushed on %s', $pusher_date)));
|
||||
}
|
||||
}
|
||||
|
||||
$view->addProperty(pht('Provenance'), $provenance_list);
|
||||
|
||||
$reviewer_phid = $data->getCommitDetail('reviewerPHID');
|
||||
if ($reviewer_phid) {
|
||||
$view->addProperty(
|
||||
@@ -743,52 +757,6 @@ final class DiffusionCommitController extends DiffusionController {
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function buildSubheaderView(
|
||||
PhabricatorRepositoryCommit $commit,
|
||||
PhabricatorRepositoryCommitData $data) {
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
if ($repository->isSVN()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$author_phid = $commit->getAuthorDisplayPHID();
|
||||
$author_name = $data->getAuthorName();
|
||||
$author_epoch = $data->getCommitDetail('authorEpoch');
|
||||
$date = null;
|
||||
if ($author_epoch !== null) {
|
||||
$date = phabricator_datetime($author_epoch, $viewer);
|
||||
}
|
||||
|
||||
if ($author_phid) {
|
||||
$handles = $viewer->loadHandles(array($author_phid));
|
||||
$image_uri = $handles[$author_phid]->getImageURI();
|
||||
$image_href = $handles[$author_phid]->getURI();
|
||||
$author = $handles[$author_phid]->renderLink();
|
||||
} else if (strlen($author_name)) {
|
||||
$author = $author_name;
|
||||
$image_uri = null;
|
||||
$image_href = null;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
$author = phutil_tag('strong', array(), $author);
|
||||
if ($date) {
|
||||
$content = pht('Authored by %s on %s.', $author, $date);
|
||||
} else {
|
||||
$content = pht('Authored by %s.', $author);
|
||||
}
|
||||
|
||||
return id(new PHUIHeadThingView())
|
||||
->setImage($image_uri)
|
||||
->setImageHref($image_href)
|
||||
->setContent($content);
|
||||
}
|
||||
|
||||
private function buildComments(PhabricatorRepositoryCommit $commit) {
|
||||
$timeline = $this->buildTransactionTimeline(
|
||||
$commit,
|
||||
@@ -843,15 +811,15 @@ final class DiffusionCommitController extends DiffusionController {
|
||||
new PhutilNumber($limit)));
|
||||
}
|
||||
|
||||
$history_table = id(new DiffusionHistoryTableView())
|
||||
->setUser($viewer)
|
||||
$commit_list = id(new DiffusionCommitGraphView())
|
||||
->setViewer($viewer)
|
||||
->setDiffusionRequest($drequest)
|
||||
->setHistory($merges);
|
||||
|
||||
$panel = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Merged Changes'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($history_table);
|
||||
->setObjectList($commit_list->newObjectItemListView());
|
||||
if ($caption) {
|
||||
$panel->setInfoView($caption);
|
||||
}
|
||||
|
||||
@@ -285,7 +285,6 @@ final class DiffusionCompareController extends DiffusionController {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
if (!$history) {
|
||||
return $this->renderStatusMessage(
|
||||
@@ -296,8 +295,8 @@ final class DiffusionCompareController extends DiffusionController {
|
||||
phutil_tag('strong', array(), $against_ref)));
|
||||
}
|
||||
|
||||
$history_table = id(new DiffusionHistoryTableView())
|
||||
->setUser($viewer)
|
||||
$history_view = id(new DiffusionCommitGraphView())
|
||||
->setViewer($viewer)
|
||||
->setDiffusionRequest($drequest)
|
||||
->setHistory($history)
|
||||
->setParents($results['parents'])
|
||||
@@ -305,15 +304,6 @@ final class DiffusionCompareController extends DiffusionController {
|
||||
->setIsHead(!$pager->getOffset())
|
||||
->setIsTail(!$pager->getHasMorePages());
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Commits'));
|
||||
|
||||
return id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($history_table)
|
||||
->addClass('diffusion-mobile-view')
|
||||
->setPager($pager);
|
||||
|
||||
return $history_view;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,9 +210,6 @@ abstract class DiffusionController extends PhabricatorController {
|
||||
case 'history':
|
||||
$view_name = pht('History');
|
||||
break;
|
||||
case 'graph':
|
||||
$view_name = pht('Graph');
|
||||
break;
|
||||
case 'browse':
|
||||
$view_name = pht('Browse');
|
||||
break;
|
||||
@@ -553,17 +550,6 @@ abstract class DiffusionController extends PhabricatorController {
|
||||
)))
|
||||
->setSelected($key == 'history'));
|
||||
|
||||
$view->addMenuItem(
|
||||
id(new PHUIListItemView())
|
||||
->setKey('graph')
|
||||
->setName(pht('Graph'))
|
||||
->setIcon('fa-code-fork')
|
||||
->setHref($drequest->generateURI(
|
||||
array(
|
||||
'action' => 'graph',
|
||||
)))
|
||||
->setSelected($key == 'graph'));
|
||||
|
||||
return $view;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionGraphController extends DiffusionController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$response = $this->loadDiffusionContext();
|
||||
if ($response) {
|
||||
return $response;
|
||||
}
|
||||
require_celerity_resource('diffusion-css');
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$pager = id(new PHUIPagerView())
|
||||
->readFromRequest($request);
|
||||
|
||||
$params = array(
|
||||
'commit' => $drequest->getCommit(),
|
||||
'path' => $drequest->getPath(),
|
||||
'offset' => $pager->getOffset(),
|
||||
'limit' => $pager->getPageSize() + 1,
|
||||
);
|
||||
|
||||
$history_results = $this->callConduitWithDiffusionRequest(
|
||||
'diffusion.historyquery',
|
||||
$params);
|
||||
$history = DiffusionPathChange::newFromConduit(
|
||||
$history_results['pathChanges']);
|
||||
|
||||
$history = $pager->sliceResults($history);
|
||||
|
||||
$graph = id(new DiffusionHistoryTableView())
|
||||
->setViewer($viewer)
|
||||
->setDiffusionRequest($drequest)
|
||||
->setHistory($history);
|
||||
|
||||
$show_graph = !strlen($drequest->getPath());
|
||||
if ($show_graph) {
|
||||
$graph->setParents($history_results['parents']);
|
||||
$graph->setIsHead(!$pager->getOffset());
|
||||
$graph->setIsTail(!$pager->getHasMorePages());
|
||||
}
|
||||
|
||||
$header = $this->buildHeader($drequest);
|
||||
|
||||
$crumbs = $this->buildCrumbs(
|
||||
array(
|
||||
'branch' => true,
|
||||
'path' => true,
|
||||
'view' => 'graph',
|
||||
));
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$title = array(
|
||||
pht('Graph'),
|
||||
$repository->getDisplayName(),
|
||||
);
|
||||
|
||||
$graph_view = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('History Graph'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setTable($graph)
|
||||
->addClass('diffusion-mobile-view')
|
||||
->setPager($pager);
|
||||
|
||||
$tabs = $this->buildTabsView('graph');
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setTabs($tabs)
|
||||
->setFooter($graph_view);
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
}
|
||||
|
||||
private function buildHeader(DiffusionRequest $drequest) {
|
||||
$viewer = $this->getViewer();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
$no_path = !strlen($drequest->getPath());
|
||||
if ($no_path) {
|
||||
$header_text = pht('Graph');
|
||||
} else {
|
||||
$header_text = $this->renderPathLinks($drequest, $mode = 'history');
|
||||
}
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setUser($viewer)
|
||||
->setHeader($header_text)
|
||||
->setHeaderIcon('fa-code-fork');
|
||||
|
||||
if (!$repository->isSVN()) {
|
||||
$branch_tag = $this->renderBranchTag($drequest);
|
||||
$header->addTag($branch_tag);
|
||||
}
|
||||
|
||||
return $header;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,11 +35,29 @@ final class DiffusionHistoryController extends DiffusionController {
|
||||
|
||||
$history = $pager->sliceResults($history);
|
||||
|
||||
$history_list = id(new DiffusionHistoryListView())
|
||||
$history_list = id(new DiffusionCommitGraphView())
|
||||
->setViewer($viewer)
|
||||
->setDiffusionRequest($drequest)
|
||||
->setHistory($history);
|
||||
|
||||
// NOTE: If we have a path (like "src/"), many nodes in the graph are
|
||||
// likely to be missing (since the path wasn't touched by those commits).
|
||||
|
||||
// If we draw the graph, commits will often appear to be unrelated because
|
||||
// intermediate nodes are omitted. Just drop the graph.
|
||||
|
||||
// The ideal behavior would be to load the entire graph and then connect
|
||||
// ancestors appropriately, but this would currrently be prohibitively
|
||||
// expensive in the general case.
|
||||
|
||||
$show_graph = !strlen($drequest->getPath());
|
||||
if ($show_graph) {
|
||||
$history_list
|
||||
->setParents($history_results['parents'])
|
||||
->setIsHead(!$pager->getOffset())
|
||||
->setIsTail(!$pager->getHasMorePages());
|
||||
}
|
||||
|
||||
$header = $this->buildHeader($drequest);
|
||||
|
||||
$crumbs = $this->buildCrumbs(
|
||||
|
||||
@@ -53,14 +53,6 @@ final class DiffusionLastModifiedController extends DiffusionController {
|
||||
}
|
||||
}
|
||||
|
||||
$phids = array();
|
||||
foreach ($commits as $commit) {
|
||||
$phids[] = $commit->getCommitterDisplayPHID();
|
||||
$phids[] = $commit->getAuthorDisplayPHID();
|
||||
}
|
||||
$phids = array_filter($phids);
|
||||
$handles = $this->loadViewerHandles($phids);
|
||||
|
||||
$branch = $drequest->loadBranch();
|
||||
if ($branch && $commits) {
|
||||
$lint_query = id(new DiffusionLintCountQuery())
|
||||
@@ -83,7 +75,6 @@ final class DiffusionLastModifiedController extends DiffusionController {
|
||||
|
||||
$output[$path] = $this->renderColumns(
|
||||
$prequest,
|
||||
$handles,
|
||||
$commit,
|
||||
idx($lint, $path));
|
||||
}
|
||||
@@ -93,11 +84,9 @@ final class DiffusionLastModifiedController extends DiffusionController {
|
||||
|
||||
private function renderColumns(
|
||||
DiffusionRequest $drequest,
|
||||
array $handles,
|
||||
PhabricatorRepositoryCommit $commit = null,
|
||||
$lint = null) {
|
||||
assert_instances_of($handles, 'PhabricatorObjectHandle');
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
if ($commit) {
|
||||
$epoch = $commit->getEpoch();
|
||||
@@ -110,13 +99,6 @@ final class DiffusionLastModifiedController extends DiffusionController {
|
||||
$date = '';
|
||||
}
|
||||
|
||||
$author = $commit->renderAuthor($viewer, $handles);
|
||||
$committer = $commit->renderCommitter($viewer, $handles);
|
||||
|
||||
if ($author != $committer) {
|
||||
$author = hsprintf('%s/%s', $author, $committer);
|
||||
}
|
||||
|
||||
$data = $commit->getCommitData();
|
||||
$details = DiffusionView::linkDetail(
|
||||
$drequest->getRepository(),
|
||||
@@ -124,11 +106,9 @@ final class DiffusionLastModifiedController extends DiffusionController {
|
||||
$data->getSummary());
|
||||
$details = AphrontTableView::renderSingleDisplayLine($details);
|
||||
|
||||
|
||||
$return = array(
|
||||
'commit' => $modified,
|
||||
'date' => $date,
|
||||
'author' => $author,
|
||||
'details' => $details,
|
||||
);
|
||||
|
||||
|
||||
@@ -299,16 +299,10 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||
$handles,
|
||||
$browse_pager);
|
||||
|
||||
$content[] = $this->buildHistoryTable(
|
||||
$history_results,
|
||||
$history,
|
||||
$history_exception);
|
||||
|
||||
if ($readme) {
|
||||
$content[] = $readme;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
$branch_button = $this->buildBranchList($drequest);
|
||||
$this->branchButton = $branch_button;
|
||||
@@ -428,51 +422,6 @@ final class DiffusionRepositoryController extends DiffusionController {
|
||||
return null;
|
||||
}
|
||||
|
||||
private function buildHistoryTable(
|
||||
$history_results,
|
||||
$history,
|
||||
$history_exception) {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
if ($history_exception) {
|
||||
if ($repository->isImporting()) {
|
||||
return $this->renderStatusMessage(
|
||||
pht('Still Importing...'),
|
||||
pht(
|
||||
'This repository is still importing. History is not yet '.
|
||||
'available.'));
|
||||
} else {
|
||||
return $this->renderStatusMessage(
|
||||
pht('Unable to Retrieve History'),
|
||||
$history_exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$history_table = id(new DiffusionHistoryTableView())
|
||||
->setUser($viewer)
|
||||
->setDiffusionRequest($drequest)
|
||||
->setHistory($history)
|
||||
->setIsHead(true);
|
||||
|
||||
if ($history_results) {
|
||||
$history_table->setParents($history_results['parents']);
|
||||
}
|
||||
|
||||
$panel = id(new PHUIObjectBoxView())
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->addClass('diffusion-mobile-view');
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader(pht('Recent Commits'));
|
||||
$panel->setHeader($header);
|
||||
$panel->setTable($history_table);
|
||||
|
||||
return $panel;
|
||||
}
|
||||
|
||||
private function buildBranchList(DiffusionRequest $drequest) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
||||
@@ -922,18 +922,26 @@ final class DiffusionServeController extends DiffusionController {
|
||||
// This is a pretty funky fix: it would be nice to more precisely detect
|
||||
// that a request is a `--depth N` clone request, but we don't have any code
|
||||
// to decode protocol frames yet. Instead, look for reasonable evidence
|
||||
// in the error and output that we're looking at a `--depth` clone.
|
||||
// in the output that we're looking at a `--depth` clone.
|
||||
|
||||
// For evidence this isn't completely crazy, see:
|
||||
// https://github.com/schacon/grack/pull/7
|
||||
// A valid x-git-upload-pack-result response during packfile negotiation
|
||||
// should end with a flush packet ("0000"). As long as that packet
|
||||
// terminates the response body in the response, we'll assume the response
|
||||
// is correct and complete.
|
||||
|
||||
// See https://git-scm.com/docs/pack-protocol#_packfile_negotiation
|
||||
|
||||
$stdout_regexp = '(^Content-Type: application/x-git-upload-pack-result)m';
|
||||
$stderr_regexp = '(The remote end hung up unexpectedly)';
|
||||
|
||||
$has_pack = preg_match($stdout_regexp, $stdout);
|
||||
$is_hangup = preg_match($stderr_regexp, $stderr);
|
||||
|
||||
return $has_pack && $is_hangup;
|
||||
if (strlen($stdout) >= 4) {
|
||||
$has_flush_packet = (substr($stdout, -4) === "0000");
|
||||
} else {
|
||||
$has_flush_packet = false;
|
||||
}
|
||||
|
||||
return ($has_pack && $has_flush_packet);
|
||||
}
|
||||
|
||||
private function getCommonEnvironment(PhabricatorUser $viewer) {
|
||||
|
||||
@@ -34,4 +34,21 @@ final class DiffusionCommitHash extends Phobject {
|
||||
}
|
||||
return $hash_objects;
|
||||
}
|
||||
|
||||
public static function newFromDictionary(array $map) {
|
||||
$hash_type = idx($map, 'type');
|
||||
$hash_value = idx($map, 'value');
|
||||
|
||||
return id(new self())
|
||||
->setHashType($hash_type)
|
||||
->setHashValue($hash_value);
|
||||
}
|
||||
|
||||
public function newDictionary() {
|
||||
return array(
|
||||
'type' => $this->hashType,
|
||||
'value' => $this->hashValue,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,28 +10,48 @@ final class DiffusionCommitRef extends Phobject {
|
||||
private $committerEmail;
|
||||
private $hashes = array();
|
||||
|
||||
public static function newFromConduitResult(array $result) {
|
||||
$ref = id(new DiffusionCommitRef())
|
||||
->setAuthorEpoch(idx($result, 'authorEpoch'))
|
||||
->setCommitterEmail(idx($result, 'committerEmail'))
|
||||
->setCommitterName(idx($result, 'committerName'))
|
||||
->setAuthorEmail(idx($result, 'authorEmail'))
|
||||
->setAuthorName(idx($result, 'authorName'))
|
||||
->setMessage(idx($result, 'message'));
|
||||
public function newDictionary() {
|
||||
$hashes = $this->getHashes();
|
||||
$hashes = mpull($hashes, 'newDictionary');
|
||||
$hashes = array_values($hashes);
|
||||
|
||||
$hashes = array();
|
||||
foreach (idx($result, 'hashes', array()) as $hash_result) {
|
||||
$hashes[] = id(new DiffusionCommitHash())
|
||||
->setHashType(idx($hash_result, 'type'))
|
||||
->setHashValue(idx($hash_result, 'value'));
|
||||
return array(
|
||||
'authorEpoch' => $this->authorEpoch,
|
||||
'authorName' => $this->authorName,
|
||||
'authorEmail' => $this->authorEmail,
|
||||
'committerName' => $this->committerName,
|
||||
'committerEmail' => $this->committerEmail,
|
||||
'message' => $this->message,
|
||||
'hashes' => $hashes,
|
||||
);
|
||||
}
|
||||
|
||||
public static function newFromDictionary(array $map) {
|
||||
$hashes = idx($map, 'hashes', array());
|
||||
foreach ($hashes as $key => $hash_map) {
|
||||
$hashes[$key] = DiffusionCommitHash::newFromDictionary($hash_map);
|
||||
}
|
||||
$hashes = array_values($hashes);
|
||||
|
||||
$ref->setHashes($hashes);
|
||||
$author_epoch = idx($map, 'authorEpoch');
|
||||
$author_name = idx($map, 'authorName');
|
||||
$author_email = idx($map, 'authorEmail');
|
||||
$committer_name = idx($map, 'committerName');
|
||||
$committer_email = idx($map, 'committerEmail');
|
||||
$message = idx($map, 'message');
|
||||
|
||||
return $ref;
|
||||
return id(new self())
|
||||
->setAuthorEpoch($author_epoch)
|
||||
->setAuthorName($author_name)
|
||||
->setAuthorEmail($author_email)
|
||||
->setCommitterName($committer_name)
|
||||
->setCommitterEmail($committer_email)
|
||||
->setMessage($message)
|
||||
->setHashes($hashes);
|
||||
}
|
||||
|
||||
public function setHashes(array $hashes) {
|
||||
assert_instances_of($hashes, 'DiffusionCommitHash');
|
||||
$this->hashes = $hashes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ final class DiffusionPathChange extends Phobject {
|
||||
|
||||
public function getAuthorName() {
|
||||
if ($this->getCommitData()) {
|
||||
return $this->getCommitData()->getAuthorName();
|
||||
return $this->getCommitData()->getAuthorString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -68,10 +68,15 @@ final class DiffusionMercurialCommandEngine
|
||||
// http://selenic.com/pipermail/mercurial-devel/2011-February/028541.html
|
||||
//
|
||||
// After Jan 2015, it may also fail to write to a revision branch cache.
|
||||
//
|
||||
// Separately, it may fail to write to a different branch cache, and may
|
||||
// encounter issues reading the branch cache.
|
||||
|
||||
$ignore = array(
|
||||
'ignoring untrusted configuration option',
|
||||
"couldn't write revision branch cache:",
|
||||
"couldn't write branch cache:",
|
||||
'invalid branchheads cache',
|
||||
);
|
||||
|
||||
foreach ($ignore as $key => $pattern) {
|
||||
|
||||
@@ -73,17 +73,11 @@ abstract class DiffusionQuery extends PhabricatorQuery {
|
||||
|
||||
$params = $params + $core_params;
|
||||
|
||||
$client = $repository->newConduitClient(
|
||||
$future = $repository->newConduitFuture(
|
||||
$user,
|
||||
$method,
|
||||
$params,
|
||||
$drequest->getIsClusterRequest());
|
||||
if (!$client) {
|
||||
$result = id(new ConduitCall($method, $params))
|
||||
->setUser($user)
|
||||
->execute();
|
||||
$future = new ImmediateFuture($result);
|
||||
} else {
|
||||
$future = $client->callMethod($method, $params);
|
||||
}
|
||||
|
||||
if (!$return_future) {
|
||||
return $future->resolve();
|
||||
|
||||
@@ -76,7 +76,6 @@ final class DiffusionBrowseTableView extends DiffusionView {
|
||||
$dict = array(
|
||||
'lint' => celerity_generate_unique_node_id(),
|
||||
'date' => celerity_generate_unique_node_id(),
|
||||
'author' => celerity_generate_unique_node_id(),
|
||||
'details' => celerity_generate_unique_node_id(),
|
||||
);
|
||||
|
||||
|
||||
642
src/applications/diffusion/view/DiffusionCommitGraphView.php
Normal file
642
src/applications/diffusion/view/DiffusionCommitGraphView.php
Normal file
@@ -0,0 +1,642 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionCommitGraphView
|
||||
extends DiffusionView {
|
||||
|
||||
private $history;
|
||||
private $commits;
|
||||
private $isHead;
|
||||
private $isTail;
|
||||
private $parents;
|
||||
private $filterParents;
|
||||
|
||||
private $commitMap;
|
||||
private $buildableMap;
|
||||
private $revisionMap;
|
||||
|
||||
private $showAuditors;
|
||||
|
||||
public function setHistory(array $history) {
|
||||
assert_instances_of($history, 'DiffusionPathChange');
|
||||
$this->history = $history;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHistory() {
|
||||
return $this->history;
|
||||
}
|
||||
|
||||
public function setCommits(array $commits) {
|
||||
assert_instances_of($commits, 'PhabricatorRepositoryCommit');
|
||||
$this->commits = $commits;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCommits() {
|
||||
return $this->commits;
|
||||
}
|
||||
|
||||
public function setShowAuditors($show_auditors) {
|
||||
$this->showAuditors = $show_auditors;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getShowAuditors() {
|
||||
return $this->showAuditors;
|
||||
}
|
||||
|
||||
public function setParents(array $parents) {
|
||||
$this->parents = $parents;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getParents() {
|
||||
return $this->parents;
|
||||
}
|
||||
|
||||
public function setIsHead($is_head) {
|
||||
$this->isHead = $is_head;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsHead() {
|
||||
return $this->isHead;
|
||||
}
|
||||
|
||||
public function setIsTail($is_tail) {
|
||||
$this->isTail = $is_tail;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsTail() {
|
||||
return $this->isTail;
|
||||
}
|
||||
|
||||
public function setFilterParents($filter_parents) {
|
||||
$this->filterParents = $filter_parents;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilterParents() {
|
||||
return $this->filterParents;
|
||||
}
|
||||
|
||||
private function getRepository() {
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
|
||||
if (!$drequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $drequest->getRepository();
|
||||
}
|
||||
|
||||
public function newObjectItemListView() {
|
||||
$list_view = id(new PHUIObjectItemListView());
|
||||
|
||||
$item_views = $this->newObjectItemViews();
|
||||
foreach ($item_views as $item_view) {
|
||||
$list_view->addItem($item_view);
|
||||
}
|
||||
|
||||
return $list_view;
|
||||
}
|
||||
|
||||
private function newObjectItemViews() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
require_celerity_resource('diffusion-css');
|
||||
|
||||
$show_builds = $this->shouldShowBuilds();
|
||||
$show_revisions = $this->shouldShowRevisions();
|
||||
$show_auditors = $this->shouldShowAuditors();
|
||||
|
||||
$phids = array();
|
||||
|
||||
if ($show_revisions) {
|
||||
$revision_map = $this->getRevisionMap();
|
||||
foreach ($revision_map as $revisions) {
|
||||
foreach ($revisions as $revision) {
|
||||
$phids[] = $revision->getPHID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$commits = $this->getCommitMap();
|
||||
|
||||
foreach ($commits as $commit) {
|
||||
$author_phid = $commit->getAuthorDisplayPHID();
|
||||
if ($author_phid !== null) {
|
||||
$phids[] = $author_phid;
|
||||
}
|
||||
}
|
||||
|
||||
if ($show_auditors) {
|
||||
foreach ($commits as $commit) {
|
||||
$audits = $commit->getAudits();
|
||||
foreach ($audits as $auditor) {
|
||||
$phids[] = $auditor->getAuditorPHID();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$handles = $viewer->loadHandles($phids);
|
||||
|
||||
$views = array();
|
||||
|
||||
$items = $this->newHistoryItems();
|
||||
foreach ($items as $hash => $item) {
|
||||
$content = array();
|
||||
|
||||
$commit = $item['commit'];
|
||||
|
||||
$commit_description = $this->getCommitDescription($commit);
|
||||
$commit_link = $this->getCommitURI($hash);
|
||||
|
||||
$short_hash = $this->getCommitObjectName($hash);
|
||||
$is_disabled = $this->getCommitIsDisabled($commit);
|
||||
|
||||
$item_view = id(new PHUIObjectItemView())
|
||||
->setViewer($viewer)
|
||||
->setHeader($commit_description)
|
||||
->setObjectName($short_hash)
|
||||
->setHref($commit_link)
|
||||
->setDisabled($is_disabled);
|
||||
|
||||
$this->addBrowseAction($item_view, $hash);
|
||||
|
||||
if ($show_builds) {
|
||||
$this->addBuildAction($item_view, $hash);
|
||||
}
|
||||
|
||||
$this->addAuditAction($item_view, $hash);
|
||||
|
||||
if ($show_auditors) {
|
||||
$auditor_list = $item_view->newMapView();
|
||||
if ($commit) {
|
||||
$auditors = $this->newAuditorList($commit, $handles);
|
||||
$auditor_list->newItem()
|
||||
->setName(pht('Auditors'))
|
||||
->setValue($auditors);
|
||||
}
|
||||
}
|
||||
|
||||
$property_list = $item_view->newMapView();
|
||||
|
||||
if ($commit) {
|
||||
$author_view = $this->getCommitAuthorView($commit);
|
||||
if ($author_view) {
|
||||
$property_list->newItem()
|
||||
->setName(pht('Author'))
|
||||
->setValue($author_view);
|
||||
}
|
||||
}
|
||||
|
||||
if ($show_revisions) {
|
||||
if ($commit) {
|
||||
$revisions = $this->getRevisions($commit);
|
||||
if ($revisions) {
|
||||
$list_view = $handles->newSublist(mpull($revisions, 'getPHID'))
|
||||
->newListView();
|
||||
|
||||
$property_list->newItem()
|
||||
->setName(pht('Revisions'))
|
||||
->setValue($list_view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$views[$hash] = $item_view;
|
||||
}
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
||||
private function newObjectItemRows() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$items = $this->newHistoryItems();
|
||||
$views = $this->newObjectItemViews();
|
||||
|
||||
$last_date = null;
|
||||
$rows = array();
|
||||
foreach ($items as $hash => $item) {
|
||||
$item_epoch = $item['epoch'];
|
||||
$item_date = phabricator_date($item_epoch, $viewer);
|
||||
if ($item_date !== $last_date) {
|
||||
$last_date = $item_date;
|
||||
$header = $item_date;
|
||||
} else {
|
||||
$header = null;
|
||||
}
|
||||
|
||||
$item_view = $views[$hash];
|
||||
|
||||
$list_view = id(new PHUIObjectItemListView())
|
||||
->setViewer($viewer)
|
||||
->setFlush(true)
|
||||
->addItem($item_view);
|
||||
|
||||
if ($header !== null) {
|
||||
$list_view->setHeader($header);
|
||||
}
|
||||
|
||||
$rows[] = $list_view;
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$rows = $this->newObjectItemRows();
|
||||
|
||||
$graph = $this->newGraphView();
|
||||
foreach ($rows as $idx => $row) {
|
||||
$cells = array();
|
||||
|
||||
if ($graph) {
|
||||
$cells[] = phutil_tag(
|
||||
'td',
|
||||
array(
|
||||
'class' => 'diffusion-commit-graph-path-cell',
|
||||
),
|
||||
$graph[$idx]);
|
||||
}
|
||||
|
||||
$cells[] = phutil_tag(
|
||||
'td',
|
||||
array(
|
||||
'class' => 'diffusion-commit-graph-content-cell',
|
||||
),
|
||||
$row);
|
||||
|
||||
$rows[$idx] = phutil_tag('tr', array(), $cells);
|
||||
}
|
||||
|
||||
$table = phutil_tag(
|
||||
'table',
|
||||
array(
|
||||
'class' => 'diffusion-commit-graph-table',
|
||||
),
|
||||
$rows);
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function newGraphView() {
|
||||
if (!$this->getParents()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parents = $this->getParents();
|
||||
|
||||
// If we're filtering parents, remove relationships which point to
|
||||
// commits that are not part of the visible graph. Otherwise, we get
|
||||
// a big tree of nonsense when viewing release branches like "stable"
|
||||
// versus "master".
|
||||
if ($this->getFilterParents()) {
|
||||
foreach ($parents as $key => $nodes) {
|
||||
foreach ($nodes as $nkey => $node) {
|
||||
if (empty($parents[$node])) {
|
||||
unset($parents[$key][$nkey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return id(new PHUIDiffGraphView())
|
||||
->setIsHead($this->getIsHead())
|
||||
->setIsTail($this->getIsTail())
|
||||
->renderGraph($parents);
|
||||
}
|
||||
|
||||
private function shouldShowBuilds() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$show_builds = PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorHarbormasterApplication',
|
||||
$this->getUser());
|
||||
|
||||
return $show_builds;
|
||||
}
|
||||
|
||||
private function shouldShowRevisions() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$show_revisions = PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorDifferentialApplication',
|
||||
$viewer);
|
||||
|
||||
return $show_revisions;
|
||||
}
|
||||
|
||||
private function shouldShowAuditors() {
|
||||
return $this->getShowAuditors();
|
||||
}
|
||||
|
||||
private function newHistoryItems() {
|
||||
$items = array();
|
||||
|
||||
$history = $this->getHistory();
|
||||
if ($history !== null) {
|
||||
foreach ($history as $history_item) {
|
||||
$commit_hash = $history_item->getCommitIdentifier();
|
||||
|
||||
$items[$commit_hash] = array(
|
||||
'epoch' => $history_item->getEpoch(),
|
||||
'hash' => $commit_hash,
|
||||
'commit' => $this->getCommit($commit_hash),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$commits = $this->getCommitMap();
|
||||
foreach ($commits as $commit) {
|
||||
$commit_hash = $commit->getCommitIdentifier();
|
||||
|
||||
$items[$commit_hash] = array(
|
||||
'epoch' => $commit->getEpoch(),
|
||||
'hash' => $commit_hash,
|
||||
'commit' => $commit,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function getCommitDescription($commit) {
|
||||
if (!$commit) {
|
||||
return phutil_tag('em', array(), pht("Discovering\xE2\x80\xA6"));
|
||||
}
|
||||
|
||||
// We can show details once the message and change have been imported.
|
||||
$partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE |
|
||||
PhabricatorRepositoryCommit::IMPORTED_CHANGE;
|
||||
if (!$commit->isPartiallyImported($partial_import)) {
|
||||
return phutil_tag('em', array(), pht("Importing\xE2\x80\xA6"));
|
||||
}
|
||||
|
||||
return $commit->getCommitData()->getSummary();
|
||||
}
|
||||
|
||||
private function getCommitURI($hash) {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
if ($repository) {
|
||||
return $repository->getCommitURI($hash);
|
||||
}
|
||||
|
||||
$commit = $this->getCommit($hash);
|
||||
if ($commit) {
|
||||
return $commit->getURI();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getCommitObjectName($hash) {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
if ($repository) {
|
||||
return $repository->formatCommitName(
|
||||
$hash,
|
||||
$is_local = true);
|
||||
}
|
||||
|
||||
$commit = $this->getCommit($hash);
|
||||
if ($commit) {
|
||||
return $commit->getDisplayName();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getCommitIsDisabled($commit) {
|
||||
if (!$commit) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($commit->isUnreachable()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getCommitAuthorView($commit) {
|
||||
if (!$commit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$author_phid = $commit->getAuthorDisplayPHID();
|
||||
if ($author_phid) {
|
||||
return $viewer->loadHandles(array($author_phid))
|
||||
->newListView();
|
||||
}
|
||||
|
||||
return $commit->newCommitAuthorView($viewer);
|
||||
}
|
||||
|
||||
private function getCommit($hash) {
|
||||
$commit_map = $this->getCommitMap();
|
||||
return idx($commit_map, $hash);
|
||||
}
|
||||
|
||||
private function getCommitMap() {
|
||||
if ($this->commitMap === null) {
|
||||
$commit_list = $this->newCommitList();
|
||||
$this->commitMap = mpull($commit_list, null, 'getCommitIdentifier');
|
||||
}
|
||||
|
||||
return $this->commitMap;
|
||||
}
|
||||
|
||||
private function addBrowseAction(PHUIObjectItemView $item, $hash) {
|
||||
$repository = $this->getRepository();
|
||||
|
||||
if (!$repository) {
|
||||
return;
|
||||
}
|
||||
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$path = $drequest->getPath();
|
||||
|
||||
$uri = $drequest->generateURI(
|
||||
array(
|
||||
'action' => 'browse',
|
||||
'path' => $path,
|
||||
'commit' => $hash,
|
||||
));
|
||||
|
||||
$menu_item = $item->newMenuItem()
|
||||
->setName(pht('Browse Repository'))
|
||||
->setURI($uri);
|
||||
|
||||
$menu_item->newIcon()
|
||||
->setIcon('fa-folder-open-o')
|
||||
->setColor('bluegrey');
|
||||
}
|
||||
|
||||
private function addBuildAction(PHUIObjectItemView $item, $hash) {
|
||||
$is_disabled = true;
|
||||
|
||||
$buildable = null;
|
||||
|
||||
$commit = $this->getCommit($hash);
|
||||
if ($commit) {
|
||||
$buildable = $this->getBuildable($commit);
|
||||
}
|
||||
|
||||
if ($buildable) {
|
||||
$icon = $buildable->getStatusIcon();
|
||||
$color = $buildable->getStatusColor();
|
||||
$name = $buildable->getStatusDisplayName();
|
||||
$uri = $buildable->getURI();
|
||||
} else {
|
||||
$icon = 'fa-times';
|
||||
$color = 'grey';
|
||||
$name = pht('No Builds');
|
||||
$uri = null;
|
||||
}
|
||||
|
||||
$menu_item = $item->newMenuItem()
|
||||
->setName($name)
|
||||
->setURI($uri)
|
||||
->setDisabled(($uri === null));
|
||||
|
||||
$menu_item->newIcon()
|
||||
->setIcon($icon)
|
||||
->setColor($color);
|
||||
}
|
||||
|
||||
private function addAuditAction(PHUIObjectItemView $item_view, $hash) {
|
||||
$commit = $this->getCommit($hash);
|
||||
|
||||
if ($commit) {
|
||||
$status = $commit->getAuditStatusObject();
|
||||
|
||||
$text = $status->getName();
|
||||
$icon = $status->getIcon();
|
||||
|
||||
$is_disabled = $status->isNoAudit();
|
||||
if ($is_disabled) {
|
||||
$uri = null;
|
||||
$color = 'grey';
|
||||
} else {
|
||||
$color = $status->getColor();
|
||||
$uri = $commit->getURI();
|
||||
}
|
||||
} else {
|
||||
$text = pht('No Audit');
|
||||
$color = 'grey';
|
||||
$icon = 'fa-times';
|
||||
$uri = null;
|
||||
|
||||
$is_disabled = true;
|
||||
}
|
||||
|
||||
$menu_item = $item_view->newMenuItem()
|
||||
->setName($text)
|
||||
->setURI($uri)
|
||||
->setBackgroundColor($color)
|
||||
->setDisabled($is_disabled);
|
||||
|
||||
$menu_item->newIcon()
|
||||
->setIcon($icon)
|
||||
->setColor($color);
|
||||
}
|
||||
|
||||
private function getBuildable(PhabricatorRepositoryCommit $commit) {
|
||||
$buildable_map = $this->getBuildableMap();
|
||||
return idx($buildable_map, $commit->getPHID());
|
||||
}
|
||||
|
||||
private function getBuildableMap() {
|
||||
if ($this->buildableMap === null) {
|
||||
$commits = $this->getCommitMap();
|
||||
$buildables = $this->loadBuildables($commits);
|
||||
$this->buildableMap = $buildables;
|
||||
}
|
||||
|
||||
return $this->buildableMap;
|
||||
}
|
||||
|
||||
private function getRevisions(PhabricatorRepositoryCommit $commit) {
|
||||
$revision_map = $this->getRevisionMap();
|
||||
return idx($revision_map, $commit->getPHID(), array());
|
||||
}
|
||||
|
||||
private function getRevisionMap() {
|
||||
if ($this->revisionMap === null) {
|
||||
$this->revisionMap = $this->newRevisionMap();
|
||||
}
|
||||
|
||||
return $this->revisionMap;
|
||||
}
|
||||
|
||||
private function newRevisionMap() {
|
||||
$viewer = $this->getViewer();
|
||||
$commits = $this->getCommitMap();
|
||||
|
||||
return DiffusionCommitRevisionQuery::loadRevisionMapForCommits(
|
||||
$viewer,
|
||||
$commits);
|
||||
}
|
||||
|
||||
private function newCommitList() {
|
||||
$commits = $this->getCommits();
|
||||
if ($commits !== null) {
|
||||
return $commits;
|
||||
}
|
||||
|
||||
$repository = $this->getRepository();
|
||||
if (!$repository) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$history = $this->getHistory();
|
||||
if ($history === null) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$identifiers = array();
|
||||
foreach ($history as $item) {
|
||||
$identifiers[] = $item->getCommitIdentifier();
|
||||
}
|
||||
|
||||
if (!$identifiers) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$commits = id(new DiffusionCommitQuery())
|
||||
->setViewer($viewer)
|
||||
->withRepository($repository)
|
||||
->withIdentifiers($identifiers)
|
||||
->needCommitData(true)
|
||||
->needIdentities(true)
|
||||
->execute();
|
||||
|
||||
return $commits;
|
||||
}
|
||||
|
||||
private function newAuditorList(
|
||||
PhabricatorRepositoryCommit $commit,
|
||||
$handles) {
|
||||
|
||||
$auditors = $commit->getAudits();
|
||||
if (!$auditors) {
|
||||
return phutil_tag('em', array(), pht('None'));
|
||||
}
|
||||
|
||||
$auditor_phids = mpull($auditors, 'getAuditorPHID');
|
||||
$auditor_list = $handles->newSublist($auditor_phids)
|
||||
->newListView();
|
||||
|
||||
return $auditor_list;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionCommitListView extends AphrontView {
|
||||
|
||||
private $commits = array();
|
||||
private $noDataString;
|
||||
|
||||
public function setNoDataString($no_data_string) {
|
||||
$this->noDataString = $no_data_string;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHeader($header) {
|
||||
$this->header = $header;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCommits(array $commits) {
|
||||
assert_instances_of($commits, 'PhabricatorRepositoryCommit');
|
||||
$this->commits = mpull($commits, null, 'getPHID');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCommits() {
|
||||
return $this->commits;
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
assert_instances_of($handles, 'PhabricatorObjectHandle');
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function getRequiredHandlePHIDs() {
|
||||
$phids = array();
|
||||
foreach ($this->history as $item) {
|
||||
$data = $item->getCommitData();
|
||||
if ($data) {
|
||||
if ($data->getCommitDetail('authorPHID')) {
|
||||
$phids[$data->getCommitDetail('authorPHID')] = true;
|
||||
}
|
||||
if ($data->getCommitDetail('committerPHID')) {
|
||||
$phids[$data->getCommitDetail('committerPHID')] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_keys($phids);
|
||||
}
|
||||
|
||||
private function getCommitDescription($phid) {
|
||||
if ($this->commits === null) {
|
||||
return pht('(Unknown Commit)');
|
||||
}
|
||||
|
||||
$commit = idx($this->commits, $phid);
|
||||
if (!$commit) {
|
||||
return pht('(Unknown Commit)');
|
||||
}
|
||||
|
||||
$summary = $commit->getCommitData()->getSummary();
|
||||
if (strlen($summary)) {
|
||||
return $summary;
|
||||
}
|
||||
|
||||
// No summary, so either this is still importing or just has an empty
|
||||
// commit message.
|
||||
|
||||
if (!$commit->isImported()) {
|
||||
return pht('(Importing Commit...)');
|
||||
} else {
|
||||
return pht('(Untitled Commit)');
|
||||
}
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('diffusion-css');
|
||||
return $this->buildList();
|
||||
}
|
||||
|
||||
public function buildList() {
|
||||
$viewer = $this->getViewer();
|
||||
$rowc = array();
|
||||
|
||||
$phids = array();
|
||||
foreach ($this->getCommits() as $commit) {
|
||||
$phids[] = $commit->getPHID();
|
||||
|
||||
$author_phid = $commit->getAuthorPHID();
|
||||
if ($author_phid) {
|
||||
$phids[] = $author_phid;
|
||||
}
|
||||
}
|
||||
|
||||
$handles = $viewer->loadHandles($phids);
|
||||
|
||||
$cur_date = 0;
|
||||
$view = array();
|
||||
foreach ($this->commits as $commit) {
|
||||
$new_date = phabricator_date($commit->getEpoch(), $viewer);
|
||||
if ($cur_date !== $new_date) {
|
||||
$date = ucfirst(
|
||||
phabricator_relative_date($commit->getEpoch(), $viewer));
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($date);
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setFlush(true)
|
||||
->addClass('diffusion-history-list');
|
||||
|
||||
$view[] = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setObjectList($list);
|
||||
}
|
||||
|
||||
$commit_phid = $commit->getPHID();
|
||||
$commit_handle = $handles[$commit_phid];
|
||||
$committed = null;
|
||||
|
||||
$commit_name = $commit_handle->getName();
|
||||
$commit_link = $commit_handle->getURI();
|
||||
$commit_desc = $this->getCommitDescription($commit_phid);
|
||||
$committed = phabricator_datetime($commit->getEpoch(), $viewer);
|
||||
|
||||
$engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
|
||||
$engine->setConfig('viewer', $viewer);
|
||||
$commit_data = $commit->getCommitData();
|
||||
$message = $commit_data->getCommitMessage();
|
||||
$message = $engine->markupText($message);
|
||||
$message = phutil_tag_div(
|
||||
'diffusion-history-message phabricator-remarkup', $message);
|
||||
|
||||
$author_phid = $commit->getAuthorPHID();
|
||||
if ($author_phid) {
|
||||
$author_name = $handles[$author_phid]->renderLink();
|
||||
$author_image_uri = $handles[$author_phid]->getImageURI();
|
||||
} else {
|
||||
$author_name = $commit->getCommitData()->getAuthorName();
|
||||
$author_image_uri =
|
||||
celerity_get_resource_uri('/rsrc/image/people/user0.png');
|
||||
}
|
||||
|
||||
$commit_tag = id(new PHUITagView())
|
||||
->setName($commit_name)
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setColor(PHUITagView::COLOR_INDIGO)
|
||||
->setBorder(PHUITagView::BORDER_NONE)
|
||||
->setSlimShady(true);
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($commit_desc)
|
||||
->setHref($commit_link)
|
||||
->setDisabled($commit->isUnreachable())
|
||||
->setDescription($message)
|
||||
->setImageURI($author_image_uri)
|
||||
->addByline(pht('Author: %s', $author_name))
|
||||
->addIcon('none', $committed)
|
||||
->addAttribute($commit_tag);
|
||||
|
||||
$list->addItem($item);
|
||||
$cur_date = $new_date;
|
||||
}
|
||||
|
||||
if (!$view) {
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setFlush(true)
|
||||
->setNoDataString($this->noDataString);
|
||||
|
||||
$view = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Recent Commits'))
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->setObjectList($list);
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionHistoryListView extends DiffusionHistoryView {
|
||||
|
||||
public function render() {
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$viewer = $this->getUser();
|
||||
$repository = $drequest->getRepository();
|
||||
|
||||
require_celerity_resource('diffusion-css');
|
||||
Javelin::initBehavior('phabricator-tooltips');
|
||||
|
||||
$buildables = $this->loadBuildables(
|
||||
mpull($this->getHistory(), 'getCommit'));
|
||||
|
||||
$show_revisions = PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorDifferentialApplication',
|
||||
$viewer);
|
||||
|
||||
$handles = $viewer->loadHandles($this->getRequiredHandlePHIDs());
|
||||
|
||||
$show_builds = PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorHarbormasterApplication',
|
||||
$this->getUser());
|
||||
|
||||
$cur_date = null;
|
||||
$view = array();
|
||||
foreach ($this->getHistory() as $history) {
|
||||
$epoch = $history->getEpoch();
|
||||
$new_date = phabricator_date($history->getEpoch(), $viewer);
|
||||
if ($cur_date !== $new_date) {
|
||||
$date = ucfirst(
|
||||
phabricator_relative_date($history->getEpoch(), $viewer));
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($date);
|
||||
$list = id(new PHUIObjectItemListView())
|
||||
->setFlush(true)
|
||||
->addClass('diffusion-history-list');
|
||||
|
||||
$view[] = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->addClass('diffusion-mobile-view')
|
||||
->setObjectList($list);
|
||||
}
|
||||
|
||||
if ($epoch) {
|
||||
$committed = $viewer->formatShortDateTime($epoch);
|
||||
} else {
|
||||
$committed = null;
|
||||
}
|
||||
|
||||
$data = $history->getCommitData();
|
||||
$author_phid = $committer = $committer_phid = null;
|
||||
if ($data) {
|
||||
$author_phid = $data->getCommitDetail('authorPHID');
|
||||
$committer_phid = $data->getCommitDetail('committerPHID');
|
||||
$committer = $data->getCommitDetail('committer');
|
||||
}
|
||||
|
||||
if ($author_phid && isset($handles[$author_phid])) {
|
||||
$author_name = $handles[$author_phid]->renderLink();
|
||||
$author_image = $handles[$author_phid]->getImageURI();
|
||||
} else {
|
||||
$author_name = self::renderName($history->getAuthorName());
|
||||
$author_image =
|
||||
celerity_get_resource_uri('/rsrc/image/people/user0.png');
|
||||
}
|
||||
|
||||
$different_committer = false;
|
||||
if ($committer_phid) {
|
||||
$different_committer = ($committer_phid != $author_phid);
|
||||
} else if ($committer != '') {
|
||||
$different_committer = ($committer != $history->getAuthorName());
|
||||
}
|
||||
if ($different_committer) {
|
||||
if ($committer_phid && isset($handles[$committer_phid])) {
|
||||
$committer = $handles[$committer_phid]->renderLink();
|
||||
} else {
|
||||
$committer = self::renderName($committer);
|
||||
}
|
||||
$author_name = hsprintf('%s / %s', $author_name, $committer);
|
||||
}
|
||||
|
||||
// We can show details once the message and change have been imported.
|
||||
$partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE |
|
||||
PhabricatorRepositoryCommit::IMPORTED_CHANGE;
|
||||
|
||||
$commit = $history->getCommit();
|
||||
if ($commit && $commit->isPartiallyImported($partial_import) && $data) {
|
||||
$commit_desc = $history->getSummary();
|
||||
} else {
|
||||
$commit_desc = phutil_tag('em', array(), pht("Importing\xE2\x80\xA6"));
|
||||
}
|
||||
|
||||
$browse_button = $this->linkBrowse(
|
||||
$history->getPath(),
|
||||
array(
|
||||
'commit' => $history->getCommitIdentifier(),
|
||||
'branch' => $drequest->getBranch(),
|
||||
'type' => $history->getFileType(),
|
||||
),
|
||||
true);
|
||||
|
||||
$diff_tag = null;
|
||||
if ($show_revisions && $commit) {
|
||||
$revisions = $this->getRevisionsForCommit($commit);
|
||||
if ($revisions) {
|
||||
$revision = head($revisions);
|
||||
$diff_tag = id(new PHUITagView())
|
||||
->setName($revision->getMonogram())
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setColor(PHUITagView::COLOR_BLUE)
|
||||
->setHref($revision->getURI())
|
||||
->setBorder(PHUITagView::BORDER_NONE)
|
||||
->setSlimShady(true);
|
||||
}
|
||||
}
|
||||
|
||||
$build_view = null;
|
||||
if ($show_builds) {
|
||||
$buildable = idx($buildables, $commit->getPHID());
|
||||
if ($buildable !== null) {
|
||||
$build_view = $this->renderBuildable($buildable, 'button');
|
||||
}
|
||||
}
|
||||
|
||||
$message = null;
|
||||
$commit_link = $repository->getCommitURI(
|
||||
$history->getCommitIdentifier());
|
||||
|
||||
$commit_name = $repository->formatCommitName(
|
||||
$history->getCommitIdentifier(), $local = true);
|
||||
|
||||
$committed = phabricator_datetime($commit->getEpoch(), $viewer);
|
||||
$author_name = phutil_tag(
|
||||
'strong',
|
||||
array(
|
||||
'class' => 'diffusion-history-author-name',
|
||||
),
|
||||
$author_name);
|
||||
$authored = pht('%s on %s.', $author_name, $committed);
|
||||
|
||||
$commit_tag = id(new PHUITagView())
|
||||
->setName($commit_name)
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setColor(PHUITagView::COLOR_INDIGO)
|
||||
->setBorder(PHUITagView::BORDER_NONE)
|
||||
->setSlimShady(true);
|
||||
|
||||
$item = id(new PHUIObjectItemView())
|
||||
->setHeader($commit_desc)
|
||||
->setHref($commit_link)
|
||||
->setDisabled($commit->isUnreachable())
|
||||
->setDescription($message)
|
||||
->setImageURI($author_image)
|
||||
->addAttribute(array($commit_tag, ' ', $diff_tag)) // For Copy Pasta
|
||||
->addAttribute($authored)
|
||||
->setSideColumn(array(
|
||||
$build_view,
|
||||
$browse_button,
|
||||
));
|
||||
|
||||
$list->addItem($item);
|
||||
$cur_date = $new_date;
|
||||
}
|
||||
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionHistoryTableView extends DiffusionHistoryView {
|
||||
|
||||
public function render() {
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
|
||||
$viewer = $this->getUser();
|
||||
|
||||
$buildables = $this->loadBuildables(
|
||||
mpull($this->getHistory(), 'getCommit'));
|
||||
$has_any_build = false;
|
||||
|
||||
$show_revisions = PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorDifferentialApplication',
|
||||
$viewer);
|
||||
|
||||
$handles = $viewer->loadHandles($this->getRequiredHandlePHIDs());
|
||||
|
||||
$graph = null;
|
||||
if ($this->getParents()) {
|
||||
$parents = $this->getParents();
|
||||
|
||||
// If we're filtering parents, remove relationships which point to
|
||||
// commits that are not part of the visible graph. Otherwise, we get
|
||||
// a big tree of nonsense when viewing release branches like "stable"
|
||||
// versus "master".
|
||||
if ($this->getFilterParents()) {
|
||||
foreach ($parents as $key => $nodes) {
|
||||
foreach ($nodes as $nkey => $node) {
|
||||
if (empty($parents[$node])) {
|
||||
unset($parents[$key][$nkey]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$graph = id(new PHUIDiffGraphView())
|
||||
->setIsHead($this->getIsHead())
|
||||
->setIsTail($this->getIsTail())
|
||||
->renderGraph($parents);
|
||||
}
|
||||
|
||||
$show_builds = PhabricatorApplication::isClassInstalledForViewer(
|
||||
'PhabricatorHarbormasterApplication',
|
||||
$this->getUser());
|
||||
|
||||
$rows = array();
|
||||
$ii = 0;
|
||||
foreach ($this->getHistory() as $history) {
|
||||
$epoch = $history->getEpoch();
|
||||
|
||||
if ($epoch) {
|
||||
$committed = $viewer->formatShortDateTime($epoch);
|
||||
} else {
|
||||
$committed = null;
|
||||
}
|
||||
|
||||
$data = $history->getCommitData();
|
||||
$author_phid = $committer = $committer_phid = null;
|
||||
if ($data) {
|
||||
$author_phid = $data->getCommitDetail('authorPHID');
|
||||
$committer_phid = $data->getCommitDetail('committerPHID');
|
||||
$committer = $data->getCommitDetail('committer');
|
||||
}
|
||||
|
||||
if ($author_phid && isset($handles[$author_phid])) {
|
||||
$author = $handles[$author_phid]->renderLink();
|
||||
} else {
|
||||
$author = self::renderName($history->getAuthorName());
|
||||
}
|
||||
|
||||
$different_committer = false;
|
||||
if ($committer_phid) {
|
||||
$different_committer = ($committer_phid != $author_phid);
|
||||
} else if ($committer != '') {
|
||||
$different_committer = ($committer != $history->getAuthorName());
|
||||
}
|
||||
if ($different_committer) {
|
||||
if ($committer_phid && isset($handles[$committer_phid])) {
|
||||
$committer = $handles[$committer_phid]->renderLink();
|
||||
} else {
|
||||
$committer = self::renderName($committer);
|
||||
}
|
||||
$author = hsprintf('%s/%s', $author, $committer);
|
||||
}
|
||||
|
||||
// We can show details once the message and change have been imported.
|
||||
$partial_import = PhabricatorRepositoryCommit::IMPORTED_MESSAGE |
|
||||
PhabricatorRepositoryCommit::IMPORTED_CHANGE;
|
||||
|
||||
$commit = $history->getCommit();
|
||||
if ($commit && $commit->isPartiallyImported($partial_import) && $data) {
|
||||
$summary = AphrontTableView::renderSingleDisplayLine(
|
||||
$history->getSummary());
|
||||
} else {
|
||||
$summary = phutil_tag('em', array(), pht("Importing\xE2\x80\xA6"));
|
||||
}
|
||||
|
||||
$build = null;
|
||||
if ($show_builds) {
|
||||
$buildable = idx($buildables, $commit->getPHID());
|
||||
if ($buildable !== null) {
|
||||
$build = $this->renderBuildable($buildable);
|
||||
$has_any_build = true;
|
||||
}
|
||||
}
|
||||
|
||||
$browse = $this->linkBrowse(
|
||||
$history->getPath(),
|
||||
array(
|
||||
'commit' => $history->getCommitIdentifier(),
|
||||
'branch' => $drequest->getBranch(),
|
||||
'type' => $history->getFileType(),
|
||||
));
|
||||
|
||||
$status = $commit->getAuditStatusObject();
|
||||
$icon = $status->getIcon();
|
||||
$color = $status->getColor();
|
||||
$name = $status->getName();
|
||||
|
||||
$audit_view = id(new PHUIIconView())
|
||||
->setIcon($icon, $color)
|
||||
->addSigil('has-tooltip')
|
||||
->setMetadata(
|
||||
array(
|
||||
'tip' => $name,
|
||||
));
|
||||
|
||||
$revision_link = null;
|
||||
if ($commit) {
|
||||
$revisions = $this->getRevisionsForCommit($commit);
|
||||
if ($revisions) {
|
||||
$revision = head($revisions);
|
||||
$revision_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $revision->getURI(),
|
||||
),
|
||||
$revision->getMonogram());
|
||||
}
|
||||
}
|
||||
|
||||
$rows[] = array(
|
||||
$graph ? $graph[$ii++] : null,
|
||||
$browse,
|
||||
self::linkCommit(
|
||||
$drequest->getRepository(),
|
||||
$history->getCommitIdentifier()),
|
||||
$build,
|
||||
$audit_view,
|
||||
$revision_link,
|
||||
$author,
|
||||
$summary,
|
||||
$committed,
|
||||
);
|
||||
}
|
||||
|
||||
$view = new AphrontTableView($rows);
|
||||
$view->setHeaders(
|
||||
array(
|
||||
null,
|
||||
null,
|
||||
pht('Commit'),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
pht('Author'),
|
||||
pht('Details'),
|
||||
pht('Committed'),
|
||||
));
|
||||
$view->setColumnClasses(
|
||||
array(
|
||||
'threads',
|
||||
'nudgeright',
|
||||
'',
|
||||
'icon',
|
||||
'icon',
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
'right',
|
||||
));
|
||||
$view->setColumnVisibility(
|
||||
array(
|
||||
$graph ? true : false,
|
||||
true,
|
||||
true,
|
||||
$has_any_build,
|
||||
true,
|
||||
$show_revisions,
|
||||
));
|
||||
$view->setDeviceVisibility(
|
||||
array(
|
||||
$graph ? true : false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
));
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
<?php
|
||||
|
||||
abstract class DiffusionHistoryView extends DiffusionView {
|
||||
|
||||
private $history;
|
||||
private $revisions = array();
|
||||
private $handles = array();
|
||||
private $isHead;
|
||||
private $isTail;
|
||||
private $parents;
|
||||
private $filterParents;
|
||||
private $revisionMap;
|
||||
|
||||
public function setHistory(array $history) {
|
||||
assert_instances_of($history, 'DiffusionPathChange');
|
||||
$this->history = $history;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHistory() {
|
||||
return $this->history;
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
assert_instances_of($handles, 'PhabricatorObjectHandle');
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$phids = array();
|
||||
foreach ($this->history as $item) {
|
||||
$data = $item->getCommitData();
|
||||
if ($data) {
|
||||
if ($data->getCommitDetail('authorPHID')) {
|
||||
$phids[$data->getCommitDetail('authorPHID')] = true;
|
||||
}
|
||||
if ($data->getCommitDetail('committerPHID')) {
|
||||
$phids[$data->getCommitDetail('committerPHID')] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_keys($phids);
|
||||
}
|
||||
|
||||
public function setParents(array $parents) {
|
||||
$this->parents = $parents;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getParents() {
|
||||
return $this->parents;
|
||||
}
|
||||
|
||||
public function setIsHead($is_head) {
|
||||
$this->isHead = $is_head;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsHead() {
|
||||
return $this->isHead;
|
||||
}
|
||||
|
||||
public function setIsTail($is_tail) {
|
||||
$this->isTail = $is_tail;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIsTail() {
|
||||
return $this->isTail;
|
||||
}
|
||||
|
||||
public function setFilterParents($filter_parents) {
|
||||
$this->filterParents = $filter_parents;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getFilterParents() {
|
||||
return $this->filterParents;
|
||||
}
|
||||
|
||||
public function render() {}
|
||||
|
||||
final protected function getRevisionsForCommit(
|
||||
PhabricatorRepositoryCommit $commit) {
|
||||
|
||||
if ($this->revisionMap === null) {
|
||||
$this->revisionMap = $this->newRevisionMap();
|
||||
}
|
||||
|
||||
return idx($this->revisionMap, $commit->getPHID(), array());
|
||||
}
|
||||
|
||||
private function newRevisionMap() {
|
||||
$history = $this->history;
|
||||
|
||||
$commits = array();
|
||||
foreach ($history as $item) {
|
||||
$commit = $item->getCommit();
|
||||
if ($commit) {
|
||||
|
||||
// NOTE: The "commit" objects in the history list may be undiscovered,
|
||||
// and thus not yet have PHIDs. Only load data for commits with PHIDs.
|
||||
if (!$commit->getPHID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$commits[] = $commit;
|
||||
}
|
||||
}
|
||||
|
||||
return DiffusionCommitRevisionQuery::loadRevisionMapForCommits(
|
||||
$this->getViewer(),
|
||||
$commits);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -150,7 +150,7 @@ final class DiffusionTagListView extends DiffusionView {
|
||||
if ($commit->getAuthorPHID()) {
|
||||
$author = $this->handles[$commit->getAuthorPHID()]->renderLink();
|
||||
} else if ($commit->getCommitData()) {
|
||||
$author = self::renderName($commit->getCommitData()->getAuthorName());
|
||||
$author = self::renderName($commit->getCommitData()->getAuthorString());
|
||||
} else {
|
||||
$author = self::renderName($tag->getAuthor());
|
||||
}
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionTagTableView extends DiffusionView {
|
||||
|
||||
private $tags;
|
||||
private $commits = array();
|
||||
private $handles = array();
|
||||
|
||||
public function setTags($tags) {
|
||||
$this->tags = $tags;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCommits(array $commits) {
|
||||
$this->commits = mpull($commits, null, 'getCommitIdentifier');
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setHandles(array $handles) {
|
||||
$this->handles = $handles;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
return array_filter(mpull($this->commits, 'getAuthorPHID'));
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$buildables = $this->loadBuildables($this->commits);
|
||||
$has_builds = false;
|
||||
|
||||
$rows = array();
|
||||
foreach ($this->tags as $tag) {
|
||||
$commit = idx($this->commits, $tag->getCommitIdentifier());
|
||||
|
||||
$tag_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $drequest->generateURI(
|
||||
array(
|
||||
'action' => 'browse',
|
||||
'commit' => $tag->getName(),
|
||||
)),
|
||||
),
|
||||
$tag->getName());
|
||||
|
||||
$commit_link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $drequest->generateURI(
|
||||
array(
|
||||
'action' => 'commit',
|
||||
'commit' => $tag->getCommitIdentifier(),
|
||||
)),
|
||||
),
|
||||
$repository->formatCommitName(
|
||||
$tag->getCommitIdentifier()));
|
||||
|
||||
$author = null;
|
||||
if ($commit && $commit->getAuthorPHID()) {
|
||||
$author = $this->handles[$commit->getAuthorPHID()]->renderLink();
|
||||
} else if ($commit && $commit->getCommitData()) {
|
||||
$author = self::renderName($commit->getCommitData()->getAuthorName());
|
||||
} else {
|
||||
$author = self::renderName($tag->getAuthor());
|
||||
}
|
||||
|
||||
$description = null;
|
||||
if ($tag->getType() == 'git/tag') {
|
||||
// In Git, a tag may be a "real" tag, or just a reference to a commit.
|
||||
// If it's a real tag, use the message on the tag, since this may be
|
||||
// unique data which isn't otherwise available.
|
||||
$description = $tag->getDescription();
|
||||
} else {
|
||||
if ($commit) {
|
||||
$description = $commit->getSummary();
|
||||
} else {
|
||||
$description = $tag->getDescription();
|
||||
}
|
||||
}
|
||||
|
||||
$build = null;
|
||||
if ($commit) {
|
||||
$buildable = idx($buildables, $commit->getPHID());
|
||||
if ($buildable) {
|
||||
$build = $this->renderBuildable($buildable);
|
||||
$has_builds = true;
|
||||
}
|
||||
}
|
||||
|
||||
$history = $this->linkTagHistory($tag->getName());
|
||||
|
||||
$rows[] = array(
|
||||
$history,
|
||||
$tag_link,
|
||||
$commit_link,
|
||||
$build,
|
||||
$author,
|
||||
$description,
|
||||
$viewer->formatShortDateTime($tag->getEpoch()),
|
||||
);
|
||||
}
|
||||
|
||||
$table = id(new AphrontTableView($rows))
|
||||
->setHeaders(
|
||||
array(
|
||||
null,
|
||||
pht('Tag'),
|
||||
pht('Commit'),
|
||||
null,
|
||||
pht('Author'),
|
||||
pht('Description'),
|
||||
pht('Created'),
|
||||
))
|
||||
->setColumnClasses(
|
||||
array(
|
||||
'nudgeright',
|
||||
'pri',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'wide',
|
||||
'right',
|
||||
))
|
||||
->setColumnVisibility(
|
||||
array(
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
$has_builds,
|
||||
));
|
||||
|
||||
return $table->render();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -55,6 +55,12 @@ final class DrydockRepositoryOperation extends DrydockDAO
|
||||
'key_repository' => array(
|
||||
'columns' => array('repositoryPHID', 'operationState'),
|
||||
),
|
||||
'key_state' => array(
|
||||
'columns' => array('operationState'),
|
||||
),
|
||||
'key_author' => array(
|
||||
'columns' => array('authorPHID', 'operationState'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ final class PhabricatorChartFunctionArgumentParser
|
||||
pht(
|
||||
'Chart function "%s" emitted an argument specification ("%s") with '.
|
||||
'no type. Each argument specification must have a valid type.',
|
||||
$this->getFunctionArgumentSignature(),
|
||||
$name));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ final class PhabricatorFactDaemon extends PhabricatorDaemon {
|
||||
|
||||
protected function run() {
|
||||
$this->setEngines(PhabricatorFactEngine::loadAllEngines());
|
||||
while (!$this->shouldExit()) {
|
||||
do {
|
||||
PhabricatorCaches::destroyRequestCache();
|
||||
|
||||
$iterators = $this->getAllApplicationIterators();
|
||||
@@ -14,9 +14,14 @@ final class PhabricatorFactDaemon extends PhabricatorDaemon {
|
||||
$this->processIteratorWithCursor($iterator_name, $iterator);
|
||||
}
|
||||
|
||||
$this->log(pht('Zzz...'));
|
||||
$this->sleep(15);
|
||||
}
|
||||
$sleep_duration = 60;
|
||||
|
||||
if ($this->shouldHibernate($sleep_duration)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$this->sleep($sleep_duration);
|
||||
} while (!$this->shouldExit());
|
||||
}
|
||||
|
||||
public static function getAllApplicationIterators() {
|
||||
|
||||
@@ -85,15 +85,8 @@ final class PhabricatorJupyterDocumentEngine
|
||||
if ($utype === $vtype) {
|
||||
switch ($utype) {
|
||||
case 'markdown':
|
||||
$usource = idx($ucell, 'source');
|
||||
if (is_array($usource)) {
|
||||
$usource = implode('', $usource);
|
||||
}
|
||||
|
||||
$vsource = idx($vcell, 'source');
|
||||
if (is_array($vsource)) {
|
||||
$vsource = implode('', $vsource);
|
||||
}
|
||||
$usource = $this->readString($ucell, 'source');
|
||||
$vsource = $this->readString($vcell, 'source');
|
||||
|
||||
$diff = id(new PhutilProseDifferenceEngine())
|
||||
->getDiff($usource, $vsource);
|
||||
@@ -117,8 +110,6 @@ final class PhabricatorJupyterDocumentEngine
|
||||
$vsource = idx($vcell, 'raw');
|
||||
$udisplay = idx($ucell, 'display');
|
||||
$vdisplay = idx($vcell, 'display');
|
||||
$ulabel = idx($ucell, 'label');
|
||||
$vlabel = idx($vcell, 'label');
|
||||
|
||||
$intraline_segments = ArcanistDiffUtils::generateIntralineDiff(
|
||||
$usource,
|
||||
@@ -142,15 +133,15 @@ final class PhabricatorJupyterDocumentEngine
|
||||
$vdisplay,
|
||||
$v_segments);
|
||||
|
||||
$u_content = $this->newCodeLineCell($ucell, $usource);
|
||||
$v_content = $this->newCodeLineCell($vcell, $vsource);
|
||||
list($u_label, $u_content) = $this->newCodeLineCell($ucell, $usource);
|
||||
list($v_label, $v_content) = $this->newCodeLineCell($vcell, $vsource);
|
||||
|
||||
$classes = array(
|
||||
'jupyter-cell-flush',
|
||||
);
|
||||
|
||||
$u_content = $this->newJupyterCell($ulabel, $u_content, $classes);
|
||||
$v_content = $this->newJupyterCell($vlabel, $v_content, $classes);
|
||||
$u_content = $this->newJupyterCell($u_label, $u_content, $classes);
|
||||
$v_content = $this->newJupyterCell($v_label, $v_content, $classes);
|
||||
|
||||
$u_content = $this->newCellContainer($u_content);
|
||||
$v_content = $this->newCellContainer($v_content);
|
||||
@@ -259,10 +250,7 @@ final class PhabricatorJupyterDocumentEngine
|
||||
$hash_input = $cell['raw'];
|
||||
break;
|
||||
case 'markdown':
|
||||
$hash_input = $cell['source'];
|
||||
if (is_array($hash_input)) {
|
||||
$hash_input = implode('', $cell['source']);
|
||||
}
|
||||
$hash_input = $this->readString($cell, 'source');
|
||||
break;
|
||||
default:
|
||||
$hash_input = serialize($cell);
|
||||
@@ -334,7 +322,6 @@ final class PhabricatorJupyterDocumentEngine
|
||||
'be rendered as a Jupyter notebook.'));
|
||||
}
|
||||
|
||||
|
||||
$nbformat = idx($data, 'nbformat');
|
||||
if (!strlen($nbformat)) {
|
||||
throw new Exception(
|
||||
@@ -376,10 +363,7 @@ final class PhabricatorJupyterDocumentEngine
|
||||
foreach ($cells as $cell) {
|
||||
$cell_type = idx($cell, 'cell_type');
|
||||
if ($cell_type === 'markdown') {
|
||||
$source = $cell['source'];
|
||||
if (is_array($source)) {
|
||||
$source = implode('', $source);
|
||||
}
|
||||
$source = $this->readString($cell, 'source');
|
||||
|
||||
// Attempt to split contiguous blocks of markdown into smaller
|
||||
// pieces.
|
||||
@@ -404,11 +388,7 @@ final class PhabricatorJupyterDocumentEngine
|
||||
|
||||
$label = $this->newCellLabel($cell);
|
||||
|
||||
$lines = idx($cell, 'source');
|
||||
if (!is_array($lines)) {
|
||||
$lines = array();
|
||||
}
|
||||
|
||||
$lines = $this->readStringList($cell, 'source');
|
||||
$content = $this->highlightLines($lines);
|
||||
|
||||
$count = count($lines);
|
||||
@@ -526,10 +506,7 @@ final class PhabricatorJupyterDocumentEngine
|
||||
}
|
||||
|
||||
private function newMarkdownCell(array $cell) {
|
||||
$content = idx($cell, 'source');
|
||||
if (!is_array($content)) {
|
||||
$content = array();
|
||||
}
|
||||
$content = $this->readStringList($cell, 'source');
|
||||
|
||||
// TODO: This should ideally highlight as Markdown, but the "md"
|
||||
// highlighter in Pygments is painfully slow and not terribly useful.
|
||||
@@ -549,11 +526,7 @@ final class PhabricatorJupyterDocumentEngine
|
||||
private function newCodeCell(array $cell) {
|
||||
$label = $this->newCellLabel($cell);
|
||||
|
||||
$content = idx($cell, 'source');
|
||||
if (!is_array($content)) {
|
||||
$content = array();
|
||||
}
|
||||
|
||||
$content = $this->readStringList($cell, 'source');
|
||||
$content = $this->highlightLines($content);
|
||||
|
||||
$outputs = array();
|
||||
@@ -660,11 +633,7 @@ final class PhabricatorJupyterDocumentEngine
|
||||
continue;
|
||||
}
|
||||
|
||||
$raw_data = $data[$image_format];
|
||||
if (!is_array($raw_data)) {
|
||||
$raw_data = array($raw_data);
|
||||
}
|
||||
$raw_data = implode('', $raw_data);
|
||||
$raw_data = $this->readString($data, $image_format);
|
||||
|
||||
$content = phutil_tag(
|
||||
'img',
|
||||
@@ -695,11 +664,7 @@ final class PhabricatorJupyterDocumentEngine
|
||||
break;
|
||||
case 'stream':
|
||||
default:
|
||||
$content = idx($output, 'text');
|
||||
if (!is_array($content)) {
|
||||
$content = array();
|
||||
}
|
||||
$content = implode('', $content);
|
||||
$content = $this->readString($output, 'text');
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -761,4 +726,23 @@ final class PhabricatorJupyterDocumentEngine
|
||||
return true;
|
||||
}
|
||||
|
||||
private function readString(array $src, $key) {
|
||||
$list = $this->readStringList($src, $key);
|
||||
return implode('', $list);
|
||||
}
|
||||
|
||||
private function readStringList(array $src, $key) {
|
||||
$list = idx($src, $key);
|
||||
|
||||
if (is_array($list)) {
|
||||
$list = $list;
|
||||
} else if (is_string($list)) {
|
||||
$list = array($list);
|
||||
} else {
|
||||
$list = array();
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,4 +12,16 @@ final class PhabricatorFileHasObjectEdgeType extends PhabricatorEdgeType {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getConduitKey() {
|
||||
return 'file.attached-objects';
|
||||
}
|
||||
|
||||
public function getConduitName() {
|
||||
return pht('File Has Object');
|
||||
}
|
||||
|
||||
public function getConduitDescription() {
|
||||
return pht('The source file is attached to the destination object.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -143,15 +143,10 @@ final class PhabricatorEmbedFileRemarkupRule
|
||||
$xform = PhabricatorFileTransform::getTransformByKey($preview_key);
|
||||
|
||||
$existing_xform = $file->getTransform($preview_key);
|
||||
// if ($existing_xform) {
|
||||
// $xform_uri = $existing_xform->getCDNURI('data');
|
||||
// } else {
|
||||
// $xform_uri = $file->getURIForTransform($xform);
|
||||
// }
|
||||
if ($existing_xform) {
|
||||
$xform_uri = $existing_xform->getInfoURI();
|
||||
$xform_uri = $existing_xform->getCDNURI('data');
|
||||
} else {
|
||||
$xform_uri = $file->getInfoURI();
|
||||
$xform_uri = $file->getURIForTransform($xform);
|
||||
}
|
||||
|
||||
$attrs['src'] = $xform_uri;
|
||||
|
||||
@@ -825,12 +825,11 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||
}
|
||||
|
||||
public function getViewURI() {
|
||||
return $this->getInfoURI();
|
||||
|
||||
if (!$this->getPHID()) {
|
||||
throw new Exception(
|
||||
pht('You must save a file before you can generate a view URI.'));
|
||||
}
|
||||
|
||||
return $this->getCDNURI('data');
|
||||
}
|
||||
|
||||
@@ -876,14 +875,13 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function getInfoURI() {
|
||||
$safe_name = MakeFilemameSafe($this->getName());
|
||||
$subpath = SubpathFromId($this->getID());
|
||||
return '../../../file/' . $subpath . '/' . $safe_name;
|
||||
return '/'.$this->getMonogram();
|
||||
}
|
||||
|
||||
public function getBestURI() {
|
||||
if ($this->isViewableInBrowser() && false) {
|
||||
if ($this->isViewableInBrowser()) {
|
||||
return $this->getViewURI();
|
||||
} else {
|
||||
return $this->getInfoURI();
|
||||
@@ -891,8 +889,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
||||
}
|
||||
|
||||
public function getDownloadURI() {
|
||||
return $this->getInfoURI();
|
||||
// return $this->getCDNURI('download');
|
||||
return $this->getCDNURI('download');
|
||||
}
|
||||
|
||||
public function getURIForTransform(PhabricatorFileTransform $transform) {
|
||||
|
||||
@@ -55,7 +55,7 @@ final class PhabricatorFlagsUIEventListener extends PhabricatorEventListener {
|
||||
}
|
||||
|
||||
$actions = $event->getValue('actions');
|
||||
// $actions[] = $flag_action;
|
||||
$actions[] = $flag_action;
|
||||
$event->setValue('actions', $actions);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
final class HarbormasterBuildStepEditAPIMethod
|
||||
extends PhabricatorEditEngineAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'harbormaster.step.edit';
|
||||
}
|
||||
|
||||
public function newEditEngine() {
|
||||
return new HarbormasterBuildStepEditEngine();
|
||||
}
|
||||
|
||||
public function getMethodSummary() {
|
||||
return pht(
|
||||
'Apply transactions to create a new build step or edit an existing '.
|
||||
'one.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
final class HarbormasterBuildStepSearchAPIMethod
|
||||
extends PhabricatorSearchEngineAPIMethod {
|
||||
|
||||
public function getAPIMethodName() {
|
||||
return 'harbormaster.step.search';
|
||||
}
|
||||
|
||||
public function newSearchEngine() {
|
||||
return new HarbormasterBuildStepSearchEngine();
|
||||
}
|
||||
|
||||
public function getMethodSummary() {
|
||||
return pht('Retrieve information about Harbormaster build steps.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
final class HarbormasterBuildStepEditEngine
|
||||
extends PhabricatorEditEngine {
|
||||
|
||||
const ENGINECONST = 'harbormaster.buildstep';
|
||||
|
||||
private $buildPlan;
|
||||
|
||||
public function setBuildPlan(HarbormasterBuildPlan $build_plan) {
|
||||
$this->buildPlan = $build_plan;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBuildPlan() {
|
||||
if ($this->buildPlan === null) {
|
||||
throw new PhutilInvalidStateException('setBuildPlan');
|
||||
}
|
||||
|
||||
return $this->buildPlan;
|
||||
}
|
||||
|
||||
public function isEngineConfigurable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getEngineName() {
|
||||
return pht('Harbormaster Build Steps');
|
||||
}
|
||||
|
||||
public function getSummaryHeader() {
|
||||
return pht('Edit Harbormaster Build Step Configurations');
|
||||
}
|
||||
|
||||
public function getSummaryText() {
|
||||
return pht('This engine is used to edit Harbormaster build steps.');
|
||||
}
|
||||
|
||||
public function getEngineApplicationClass() {
|
||||
return 'PhabricatorHarbormasterApplication';
|
||||
}
|
||||
|
||||
protected function newEditableObject() {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
||||
$plan = HarbormasterBuildPlan::initializeNewBuildPlan($viewer);
|
||||
$this->setBuildPlan($plan);
|
||||
|
||||
$plan = $this->getBuildPlan();
|
||||
|
||||
$step = HarbormasterBuildStep::initializeNewStep($viewer);
|
||||
|
||||
$step->setBuildPlanPHID($plan->getPHID());
|
||||
$step->attachBuildPlan($plan);
|
||||
|
||||
return $step;
|
||||
}
|
||||
|
||||
protected function newObjectQuery() {
|
||||
return new HarbormasterBuildStepQuery();
|
||||
}
|
||||
|
||||
protected function getObjectCreateTitleText($object) {
|
||||
return pht('Create Build Step');
|
||||
}
|
||||
|
||||
protected function getObjectCreateButtonText($object) {
|
||||
return pht('Create Build Step');
|
||||
}
|
||||
|
||||
protected function getObjectEditTitleText($object) {
|
||||
return pht('Edit Build Step: %s', $object->getName());
|
||||
}
|
||||
|
||||
protected function getObjectEditShortText($object) {
|
||||
return pht('Edit Build Step');
|
||||
}
|
||||
|
||||
protected function getObjectCreateShortText() {
|
||||
return pht('Create Build Step');
|
||||
}
|
||||
|
||||
protected function getObjectName() {
|
||||
return pht('Build Step');
|
||||
}
|
||||
|
||||
protected function getEditorURI() {
|
||||
return '/harbormaster/step/edit/';
|
||||
}
|
||||
|
||||
protected function getObjectCreateCancelURI($object) {
|
||||
return '/harbormaster/step/';
|
||||
}
|
||||
|
||||
protected function getObjectViewURI($object) {
|
||||
$id = $object->getID();
|
||||
return "/harbormaster/step/{$id}/";
|
||||
}
|
||||
|
||||
protected function buildCustomEditFields($object) {
|
||||
$fields = array();
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -147,7 +147,7 @@ final class HarbormasterUIEventListener
|
||||
}
|
||||
|
||||
$view = $ui_event->getValue('view');
|
||||
// $view->addProperty(pht('Build Status'), $status_view);
|
||||
$view->addProperty(pht('Build Status'), $status_view);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ final class HarbormasterManagementPublishWorkflow
|
||||
pht(
|
||||
'Object "%s" is not a HarbormasterBuildable (it is a "%s"). '.
|
||||
'Name one or more buildables to publish, like "B123".',
|
||||
$name,
|
||||
get_class($result)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
final class HarbormasterBuildStepSearchEngine
|
||||
extends PhabricatorApplicationSearchEngine {
|
||||
|
||||
public function getResultTypeDescription() {
|
||||
return pht('Harbormaster Build Steps');
|
||||
}
|
||||
|
||||
public function getApplicationClassName() {
|
||||
return 'PhabricatorHarbormasterApplication';
|
||||
}
|
||||
|
||||
public function newQuery() {
|
||||
return new HarbormasterBuildStepQuery();
|
||||
}
|
||||
|
||||
protected function buildCustomSearchFields() {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function buildQueryFromParameters(array $map) {
|
||||
$query = $this->newQuery();
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function getURI($path) {
|
||||
return '/harbormaster/step/'.$path;
|
||||
}
|
||||
|
||||
protected function getBuiltinQueryNames() {
|
||||
return array(
|
||||
'all' => pht('All Steps'),
|
||||
);
|
||||
}
|
||||
|
||||
public function buildSavedQueryFromBuiltin($query_key) {
|
||||
$query = $this->newSavedQuery();
|
||||
$query->setQueryKey($query_key);
|
||||
|
||||
switch ($query_key) {
|
||||
case 'all':
|
||||
return $query;
|
||||
}
|
||||
|
||||
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||
}
|
||||
|
||||
protected function renderResultList(
|
||||
array $plans,
|
||||
PhabricatorSavedQuery $query,
|
||||
array $handles) {
|
||||
assert_instances_of($plans, 'HarbormasterBuildStep');
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@ final class HarbormasterWaitForPreviousBuildStepImplementation
|
||||
}
|
||||
|
||||
public function getBuildStepGroupKey() {
|
||||
return HarbormasterPrototypeBuildStepGroup::GROUPKEY;
|
||||
return HarbormasterControlBuildStepGroup::GROUPKEY;
|
||||
}
|
||||
|
||||
public function execute(
|
||||
|
||||
@@ -177,6 +177,8 @@ final class HarbormasterBuildLog
|
||||
pht(
|
||||
'Attempt to load log bytes (%d - %d) failed: failed to '.
|
||||
'load a single contiguous range. Actual ranges: %s.',
|
||||
$offset,
|
||||
$end,
|
||||
implode('; ', $display_ranges)));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ final class HarbormasterBuildStep extends HarbormasterDAO
|
||||
implements
|
||||
PhabricatorApplicationTransactionInterface,
|
||||
PhabricatorPolicyInterface,
|
||||
PhabricatorCustomFieldInterface {
|
||||
PhabricatorCustomFieldInterface,
|
||||
PhabricatorConduitResultInterface {
|
||||
|
||||
protected $name;
|
||||
protected $description;
|
||||
@@ -169,5 +170,45 @@ final class HarbormasterBuildStep extends HarbormasterDAO
|
||||
return $this;
|
||||
}
|
||||
|
||||
/* -( PhabricatorConduitResultInterface )---------------------------------- */
|
||||
|
||||
|
||||
public function getFieldSpecificationsForConduit() {
|
||||
return array(
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('name')
|
||||
->setType('string')
|
||||
->setDescription(pht('The name of the build step.')),
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('description')
|
||||
->setType('remarkup')
|
||||
->setDescription(pht('The build step description.')),
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('buildPlanPHID')
|
||||
->setType('phid')
|
||||
->setDescription(
|
||||
pht(
|
||||
'The PHID of the build plan this build step belongs to.')),
|
||||
);
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit() {
|
||||
// T6203: This can be removed once the field becomes non-nullable.
|
||||
$name = $this->getName();
|
||||
$name = phutil_string_cast($name);
|
||||
|
||||
return array(
|
||||
'name' => $name,
|
||||
'description' => array(
|
||||
'raw' => $this->getDescription(),
|
||||
),
|
||||
'buildPlanPHID' => $this->getBuildPlanPHID(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getConduitSearchAttachments() {
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
43
src/applications/herald/field/HeraldCommentContentField.php
Normal file
43
src/applications/herald/field/HeraldCommentContentField.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
final class HeraldCommentContentField extends HeraldField {
|
||||
|
||||
const FIELDCONST = 'comment.content';
|
||||
|
||||
public function getHeraldFieldName() {
|
||||
return pht('Comment content');
|
||||
}
|
||||
|
||||
public function getFieldGroupKey() {
|
||||
return HeraldTransactionsFieldGroup::FIELDGROUPKEY;
|
||||
}
|
||||
|
||||
public function getHeraldFieldValue($object) {
|
||||
$adapter = $this->getAdapter();
|
||||
|
||||
$xactions = $adapter->getAppliedTransactions();
|
||||
|
||||
$result = array();
|
||||
foreach ($xactions as $xaction) {
|
||||
if (!$xaction->hasComment()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$comment = $xaction->getComment();
|
||||
$content = $comment->getContent();
|
||||
|
||||
$result[] = $content;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function supportsObject($object) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getHeraldFieldStandardType() {
|
||||
return self::STANDARD_TEXT_LIST;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,6 +28,17 @@ final class HeraldWebhookCallManagementWorkflow
|
||||
'name' => 'secure',
|
||||
'help' => pht('Set the "secure" flag on the request.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'count',
|
||||
'param' => 'N',
|
||||
'help' => pht('Make a total of __N__ copies of the call.'),
|
||||
),
|
||||
array(
|
||||
'name' => 'background',
|
||||
'help' => pht(
|
||||
'Instead of making calls in the foreground, add the tasks '.
|
||||
'to the daemon queue.'),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
@@ -41,6 +52,17 @@ final class HeraldWebhookCallManagementWorkflow
|
||||
'Specify a webhook to call with "--id".'));
|
||||
}
|
||||
|
||||
$count = $args->getArg('count');
|
||||
if ($count === null) {
|
||||
$count = 1;
|
||||
}
|
||||
|
||||
if ($count <= 0) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Specified "--count" must be larger than 0.'));
|
||||
}
|
||||
|
||||
$hook = id(new HeraldWebhookQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
@@ -69,6 +91,8 @@ final class HeraldWebhookCallManagementWorkflow
|
||||
$object = head($objects);
|
||||
}
|
||||
|
||||
$is_background = $args->getArg('background');
|
||||
|
||||
$xaction_query =
|
||||
PhabricatorApplicationTransactionQuery::newQueryForObject($object);
|
||||
|
||||
@@ -80,25 +104,49 @@ final class HeraldWebhookCallManagementWorkflow
|
||||
|
||||
$application_phid = id(new PhabricatorHeraldApplication())->getPHID();
|
||||
|
||||
$request = HeraldWebhookRequest::initializeNewWebhookRequest($hook)
|
||||
->setObjectPHID($object->getPHID())
|
||||
->setIsTestAction(true)
|
||||
->setIsSilentAction((bool)$args->getArg('silent'))
|
||||
->setIsSecureAction((bool)$args->getArg('secure'))
|
||||
->setTriggerPHIDs(array($application_phid))
|
||||
->setTransactionPHIDs(mpull($xactions, 'getPHID'))
|
||||
->save();
|
||||
if ($is_background) {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Queueing webhook calls...'));
|
||||
$progress_bar = id(new PhutilConsoleProgressBar())
|
||||
->setTotal($count);
|
||||
} else {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Calling webhook...'));
|
||||
PhabricatorWorker::setRunAllTasksInProcess(true);
|
||||
}
|
||||
|
||||
PhabricatorWorker::setRunAllTasksInProcess(true);
|
||||
$request->queueCall();
|
||||
for ($ii = 0; $ii < $count; $ii++) {
|
||||
$request = HeraldWebhookRequest::initializeNewWebhookRequest($hook)
|
||||
->setObjectPHID($object->getPHID())
|
||||
->setIsTestAction(true)
|
||||
->setIsSilentAction((bool)$args->getArg('silent'))
|
||||
->setIsSecureAction((bool)$args->getArg('secure'))
|
||||
->setTriggerPHIDs(array($application_phid))
|
||||
->setTransactionPHIDs(mpull($xactions, 'getPHID'))
|
||||
->save();
|
||||
|
||||
$request->reload();
|
||||
$request->queueCall();
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Success, got HTTP %s from webhook.',
|
||||
$request->getErrorCode()));
|
||||
if ($is_background) {
|
||||
$progress_bar->update(1);
|
||||
} else {
|
||||
$request->reload();
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Success, got HTTP %s from webhook.',
|
||||
$request->getErrorCode()));
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_background) {
|
||||
$progress_bar->done();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ final class PhabricatorMemeRemarkupRule extends PhutilRemarkupRule {
|
||||
|
||||
$is_html_mail = $this->getEngine()->isHTMLMailMode();
|
||||
$is_text = $this->getEngine()->isTextMode();
|
||||
$must_inline = ($is_html_mail || $is_text || true);
|
||||
$must_inline = ($is_html_mail || $is_text);
|
||||
|
||||
if ($must_inline) {
|
||||
if (!$asset) {
|
||||
|
||||
@@ -199,8 +199,7 @@ final class ManiphestTaskPriority extends ManiphestConstants {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Configuration is not valid. Maniphest priority configurations '.
|
||||
'must be dictionaries.',
|
||||
$config));
|
||||
'must be dictionaries.'));
|
||||
}
|
||||
|
||||
$all_keywords = array();
|
||||
|
||||
@@ -148,7 +148,6 @@ abstract class ManiphestController extends PhabricatorController {
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
return $crumbs;
|
||||
|
||||
if ($this->projectKey) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
@@ -210,8 +210,7 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
||||
$view = id(new PHUIHeaderView())
|
||||
->setHeader($task->getTitle())
|
||||
->setUser($this->getRequest()->getUser())
|
||||
// ->setPolicyObject($task)
|
||||
;
|
||||
->setPolicyObject($task);
|
||||
|
||||
$priority_name = ManiphestTaskPriority::getTaskPriorityName(
|
||||
$task->getPriority());
|
||||
@@ -272,7 +271,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
||||
|
||||
$curtain = $this->newCurtainView($task);
|
||||
|
||||
/*
|
||||
$curtain->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit Task'))
|
||||
@@ -280,7 +278,6 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
||||
->setHref($this->getApplicationURI("/task/edit/{$id}/"))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow($workflow_edit));
|
||||
*/
|
||||
|
||||
$subtype_map = $task->newEditEngineSubtypeMap();
|
||||
$subtask_options = $subtype_map->getCreateFormsForSubtype(
|
||||
@@ -328,20 +325,16 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
||||
ManiphestTaskCloseAsDuplicateRelationship::RELATIONSHIPKEY,
|
||||
);
|
||||
|
||||
/*
|
||||
$task_submenu = $relationship_list->newActionSubmenu($submenu_actions)
|
||||
->setName(pht('Edit Related Tasks...'))
|
||||
->setIcon('fa-anchor');
|
||||
|
||||
$curtain->addAction($task_submenu);
|
||||
*/
|
||||
|
||||
/*
|
||||
$relationship_submenu = $relationship_list->newActionMenu();
|
||||
if ($relationship_submenu) {
|
||||
$curtain->addAction($relationship_submenu);
|
||||
}
|
||||
*/
|
||||
|
||||
$viewer_phid = $viewer->getPHID();
|
||||
$owner_phid = $task->getOwnerPHID();
|
||||
@@ -640,9 +633,9 @@ final class ManiphestTaskDetailController extends ManiphestController {
|
||||
$commit_monogram);
|
||||
|
||||
$commit_link = javelin_tag(
|
||||
'span',
|
||||
'a',
|
||||
array(
|
||||
// 'href' => $commit->getURI(),
|
||||
'href' => $commit->getURI(),
|
||||
'sigil' => 'hovercard',
|
||||
'meta' => array(
|
||||
'hoverPHID' => $commit->getPHID(),
|
||||
|
||||
@@ -36,7 +36,7 @@ final class ManiphestTaskPHIDType extends PhabricatorPHIDType {
|
||||
|
||||
$handle->setName("T{$id}");
|
||||
$handle->setFullName("T{$id}: {$title}");
|
||||
$handle->setURI($task->getURI());
|
||||
$handle->setURI("/T{$id}");
|
||||
|
||||
if ($task->isClosed()) {
|
||||
$handle->setStatus(PhabricatorObjectHandle::STATUS_CLOSED);
|
||||
|
||||
@@ -3,30 +3,8 @@
|
||||
final class ManiphestTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
private $updatedEpochAfter;
|
||||
|
||||
public function getTemplateApplicationTransaction() {
|
||||
return new ManiphestTransaction();
|
||||
}
|
||||
|
||||
public function withUpdatedEpochAfter($epoch) {
|
||||
$this->updatedEpochAfter = $epoch;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
|
||||
$where = array();
|
||||
|
||||
if ($this->updatedEpochAfter !== null) {
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'x.dateModified >= %d',
|
||||
$this->updatedEpochAfter);
|
||||
}
|
||||
|
||||
$where[] = $this->buildWhereClauseParts($conn);
|
||||
|
||||
return $this->formatWhereClause($conn, $where);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user