1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-04 19:08:27 +01:00

(stable) Promote 2018 Week 30

This commit is contained in:
epriestley 2018-07-27 16:26:53 -07:00
commit 79c15e936c
20 changed files with 298 additions and 72 deletions

View file

@ -143,7 +143,7 @@ final class PhabricatorOpcodeCacheSpec extends PhabricatorCacheSpec {
$this $this
->newIssue('extension.opcache.devmode') ->newIssue('extension.opcache.devmode')
->setShortName(pht('OPcache Config')) ->setShortName(pht('OPcache Config'))
->setName(pht('OPCache Not Configured for Development')) ->setName(pht('OPcache Not Configured for Development'))
->setSummary($summary) ->setSummary($summary)
->setMessage($message) ->setMessage($message)
->addPHPConfig('opcache.validate_timestamps') ->addPHPConfig('opcache.validate_timestamps')

View file

@ -15,7 +15,7 @@ final class PhabricatorConfigApplication extends PhabricatorApplication {
} }
public function getTitleGlyph() { public function getTitleGlyph() {
return "\xE2\x98\xBA"; return "\xE2\x9C\xA8";
} }
public function getApplicationGroup() { public function getApplicationGroup() {

View file

@ -445,7 +445,7 @@ final class PhabricatorSetupIssueView extends AphrontView {
'p', 'p',
array(), array(),
pht( pht(
'You can find more information about configuring OPCache in '. 'You can find more information about configuring OPcache in '.
'the %s.', 'the %s.',
phutil_tag( phutil_tag(
'a', 'a',
@ -453,7 +453,7 @@ final class PhabricatorSetupIssueView extends AphrontView {
'href' => 'http://php.net/manual/opcache.configuration.php', 'href' => 'http://php.net/manual/opcache.configuration.php',
'target' => '_blank', 'target' => '_blank',
), ),
pht('PHP OPCache Documentation')))); pht('PHP OPcache Documentation'))));
} }
$info[] = phutil_tag( $info[] = phutil_tag(

View file

@ -43,7 +43,10 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
public function getRoutes() { public function getRoutes() {
return array( return array(
'/D(?P<id>[1-9]\d*)' => 'DifferentialRevisionViewController', '/D(?P<id>[1-9]\d*)' => array(
'' => 'DifferentialRevisionViewController',
'/(?P<filter>new)/' => 'DifferentialRevisionViewController',
),
'/differential/' => array( '/differential/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?' '(?:query/(?P<queryKey>[^/]+)/)?'
=> 'DifferentialRevisionListController', => 'DifferentialRevisionListController',

View file

@ -6,6 +6,7 @@ final class DifferentialRevisionViewController
private $revisionID; private $revisionID;
private $changesetCount; private $changesetCount;
private $hiddenChangesets; private $hiddenChangesets;
private $warnings = array();
public function shouldAllowPublic() { public function shouldAllowPublic() {
return true; return true;
@ -68,9 +69,17 @@ final class DifferentialRevisionViewController
$revision->attachActiveDiff(last($diffs)); $revision->attachActiveDiff(last($diffs));
$diff_vs = $request->getInt('vs'); $diff_vs = $this->getOldDiffID($revision, $diffs);
$target_id = $request->getInt('id'); if ($diff_vs instanceof AphrontResponse) {
$target = idx($diffs, $target_id, end($diffs)); return $diff_vs;
}
$target_id = $this->getNewDiffID($revision, $diffs);
if ($target_id instanceof AphrontResponse) {
return $target_id;
}
$target = $diffs[$target_id];
$target_manual = $target; $target_manual = $target;
if (!$target_id) { if (!$target_id) {
@ -81,10 +90,6 @@ final class DifferentialRevisionViewController
} }
} }
if (empty($diffs[$diff_vs])) {
$diff_vs = null;
}
$repository = null; $repository = null;
$repository_phid = $target->getRepositoryPHID(); $repository_phid = $target->getRepositoryPHID();
if ($repository_phid) { if ($repository_phid) {
@ -170,7 +175,7 @@ final class DifferentialRevisionViewController
} }
$handles = $this->loadViewerHandles($object_phids); $handles = $this->loadViewerHandles($object_phids);
$warnings = array(); $warnings = $this->warnings;
$request_uri = $request->getRequestURI(); $request_uri = $request->getRequestURI();
@ -1312,4 +1317,133 @@ final class DifferentialRevisionViewController
->setShowViewAll(true); ->setShowViewAll(true);
} }
private function getOldDiffID(DifferentialRevision $revision, array $diffs) {
assert_instances_of($diffs, 'DifferentialDiff');
$request = $this->getRequest();
$diffs = mpull($diffs, null, 'getID');
$is_new = ($request->getURIData('filter') === 'new');
$old_id = $request->getInt('vs');
// This is ambiguous, so just 404 rather than trying to figure out what
// the user expects.
if ($is_new && $old_id) {
return new Aphront404Response();
}
if ($is_new) {
$viewer = $this->getViewer();
$xactions = id(new DifferentialTransactionQuery())
->setViewer($viewer)
->withObjectPHIDs(array($revision->getPHID()))
->withAuthorPHIDs(array($viewer->getPHID()))
->setOrder('newest')
->setLimit(1)
->execute();
if (!$xactions) {
$this->warnings[] = id(new PHUIInfoView())
->setTitle(pht('No Actions'))
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->appendChild(
pht(
'Showing all changes because you have never taken an '.
'action on this revision.'));
} else {
$xaction = head($xactions);
// Find the transactions which updated this revision. We want to
// figure out which diff was active when you last took an action.
$updates = id(new DifferentialTransactionQuery())
->setViewer($viewer)
->withObjectPHIDs(array($revision->getPHID()))
->withTransactionTypes(
array(
DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE,
))
->setOrder('oldest')
->execute();
// Sort the diffs into two buckets: those older than your last action
// and those newer than your last action.
$older = array();
$newer = array();
foreach ($updates as $update) {
// If you updated the revision with "arc diff", try to count that
// update as "before your last action".
if ($update->getDateCreated() <= $xaction->getDateCreated()) {
$older[] = $update->getNewValue();
} else {
$newer[] = $update->getNewValue();
}
}
if (!$newer) {
$this->warnings[] = id(new PHUIInfoView())
->setTitle(pht('No Recent Updates'))
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->appendChild(
pht(
'Showing all changes because the diff for this revision '.
'has not been updated since your last action.'));
} else {
$older = array_fuse($older);
// Find the most recent diff from before the last action.
$old = null;
foreach ($diffs as $diff) {
if (!isset($older[$diff->getPHID()])) {
break;
}
$old = $diff;
}
// It's possible we may not find such a diff: transactions may have
// been removed from the database, for example. If we miss, just
// fail into some reasonable state since 404'ing would be perplexing.
if ($old) {
$this->warnings[] = id(new PHUIInfoView())
->setTitle(pht('New Changes Shown'))
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->appendChild(
pht(
'Showing changes since the last action you took on this '.
'revision.'));
$old_id = $old->getID();
}
}
}
}
if (isset($diffs[$old_id])) {
return $old_id;
}
return null;
}
private function getNewDiffID(DifferentialRevision $revision, array $diffs) {
assert_instances_of($diffs, 'DifferentialDiff');
$request = $this->getRequest();
$diffs = mpull($diffs, null, 'getID');
$is_new = ($request->getURIData('filter') === 'new');
$new_id = $request->getInt('id');
if ($is_new && $new_id) {
return new Aphront404Response();
}
if (isset($diffs[$new_id])) {
return $new_id;
}
return (int)last_key($diffs);
}
} }

View file

@ -624,7 +624,9 @@ final class DifferentialTransactionEditor
$body = new PhabricatorMetaMTAMailBody(); $body = new PhabricatorMetaMTAMailBody();
$body->setViewer($this->requireActor()); $body->setViewer($this->requireActor());
$revision_uri = PhabricatorEnv::getProductionURI('/D'.$object->getID()); $revision_uri = $object->getURI();
$revision_uri = PhabricatorEnv::getProductionURI($revision_uri);
$new_uri = $revision_uri.'/new/';
$this->addHeadersAndCommentsToMailBody( $this->addHeadersAndCommentsToMailBody(
$body, $body,
@ -645,19 +647,6 @@ final class DifferentialTransactionEditor
$this->appendInlineCommentsForMail($object, $inlines, $body); $this->appendInlineCommentsForMail($object, $inlines, $body);
} }
$changed_uri = $this->getChangedPriorToCommitURI();
if ($changed_uri) {
$body->addLinkSection(
pht('CHANGED PRIOR TO COMMIT'),
$changed_uri);
}
$this->addCustomFieldsToMailBody($body, $object, $xactions);
$body->addLinkSection(
pht('REVISION DETAIL'),
$revision_uri);
$update_xaction = null; $update_xaction = null;
foreach ($xactions as $xaction) { foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) { switch ($xaction->getTransactionType()) {
@ -669,7 +658,28 @@ final class DifferentialTransactionEditor
if ($update_xaction) { if ($update_xaction) {
$diff = $this->requireDiff($update_xaction->getNewValue(), true); $diff = $this->requireDiff($update_xaction->getNewValue(), true);
} else {
$diff = null;
}
$changed_uri = $this->getChangedPriorToCommitURI();
if ($changed_uri) {
$body->addLinkSection(
pht('CHANGED PRIOR TO COMMIT'),
$changed_uri);
}
$this->addCustomFieldsToMailBody($body, $object, $xactions);
if (!$this->getIsNewObject()) {
$body->addLinkSection(pht('CHANGES SINCE LAST ACTION'), $new_uri);
}
$body->addLinkSection(
pht('REVISION DETAIL'),
$revision_uri);
if ($update_xaction) {
$body->addTextSection( $body->addTextSection(
pht('AFFECTED FILES'), pht('AFFECTED FILES'),
$this->renderAffectedFilesForMail($diff)); $this->renderAffectedFilesForMail($diff));

View file

@ -48,10 +48,12 @@ final class PhabricatorDifferentialRevisionTestDataGenerator
public function generateDiff($author) { public function generateDiff($author) {
$paste_generator = new PhabricatorPasteTestDataGenerator(); $paste_generator = new PhabricatorPasteTestDataGenerator();
$languages = $paste_generator->supportedLanguages; $languages = $paste_generator->getSupportedLanguages();
$lang = array_rand($languages); $language = array_rand($languages);
$code = $paste_generator->generateContent($lang); $spec = $languages[$language];
$altcode = $paste_generator->generateContent($lang);
$code = $paste_generator->generateContent($spec);
$altcode = $paste_generator->generateContent($spec);
$newcode = $this->randomlyModify($code, $altcode); $newcode = $this->randomlyModify($code, $altcode);
$diff = id(new PhabricatorDifferenceEngine()) $diff = id(new PhabricatorDifferenceEngine())
->generateRawDiffFromFileContent($code, $newcode); ->generateRawDiffFromFileContent($code, $newcode);

View file

@ -307,7 +307,7 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
$content = phabricator_form( $content = phabricator_form(
$this->getUser(), $this->getUser(),
array( array(
'action' => '#toc', 'action' => '/D'.$revision_id.'#toc',
), ),
array( array(
$table, $table,

View file

@ -119,11 +119,23 @@ final class PhabricatorDocumentRef
} }
$snippet = $this->getSnippet(); $snippet = $this->getSnippet();
if (!preg_match('/^\s*[{[]/', $snippet)) {
// If the file is longer than the snippet, we don't detect the content
// as JSON. We could use some kind of heuristic here if we wanted, but
// see PHI749 for a false positive.
if (strlen($snippet) < $this->getByteLength()) {
return false; return false;
} }
return phutil_is_utf8($snippet); // If the snippet is the whole file, just check if the snippet is valid
// JSON. Note that `phutil_json_decode()` only accepts arrays and objects
// as JSON, so this won't misfire on files with content like "3".
try {
phutil_json_decode($snippet);
return true;
} catch (Exception $ex) {
return false;
}
} }
public function getSnippet() { public function getSnippet() {

View file

@ -492,12 +492,13 @@ final class PhabricatorFile extends PhabricatorFileDAO
$this->setStorageFormat($format->getStorageFormatKey()); $this->setStorageFormat($format->getStorageFormatKey());
$this->setStorageProperties($properties); $this->setStorageProperties($properties);
list($identifier, $new_handle) = $this->writeToEngine( list($identifier, $new_handle, $integrity_hash) = $this->writeToEngine(
$engine, $engine,
$data, $data,
$params); $params);
$this->setStorageHandle($new_handle); $this->setStorageHandle($new_handle);
$this->setIntegrityHash($integrity_hash);
$this->save(); $this->save();
$this->deleteFileDataIfUnused( $this->deleteFileDataIfUnused(

View file

@ -104,8 +104,8 @@ final class PhabricatorMemeEngine extends Phobject {
private function newTransformHash() { private function newTransformHash() {
$properties = array( $properties = array(
'kind' => 'meme', 'kind' => 'meme',
'above' => phutil_utf8_strtoupper($this->getAboveText()), 'above' => $this->getAboveText(),
'below' => phutil_utf8_strtoupper($this->getBelowText()), 'below' => $this->getBelowText(),
); );
$properties = phutil_json_encode($properties); $properties = phutil_json_encode($properties);

View file

@ -22,9 +22,11 @@ final class PhabricatorPasteTestDataGenerator
PhabricatorPasteTitleTransaction::TRANSACTIONTYPE, PhabricatorPasteTitleTransaction::TRANSACTIONTYPE,
$name); $name);
if (strlen($language) > 0) {
$xactions[] = $this->newTransaction( $xactions[] = $this->newTransaction(
PhabricatorPasteLanguageTransaction::TRANSACTIONTYPE, PhabricatorPasteLanguageTransaction::TRANSACTIONTYPE,
$language); $language);
}
$xactions[] = $this->newTransaction( $xactions[] = $this->newTransaction(
PhabricatorPasteContentTransaction::TRANSACTIONTYPE, PhabricatorPasteContentTransaction::TRANSACTIONTYPE,
@ -43,9 +45,8 @@ final class PhabricatorPasteTestDataGenerator
return new PhabricatorPasteTransaction(); return new PhabricatorPasteTransaction();
} }
private function newPasteContent() { public function getSupportedLanguages() {
$languages = array( return array(
'txt' => array(),
'php' => array( 'php' => array(
'content' => 'PhutilPHPCodeSnippetContextFreeGrammar', 'content' => 'PhutilPHPCodeSnippetContextFreeGrammar',
), ),
@ -53,7 +54,20 @@ final class PhabricatorPasteTestDataGenerator
'content' => 'PhutilJavaCodeSnippetContextFreeGrammar', 'content' => 'PhutilJavaCodeSnippetContextFreeGrammar',
), ),
); );
}
public function generateContent($spec) {
$content_generator = idx($spec, 'content');
if (!$content_generator) {
$content_generator = 'PhutilLipsumContextFreeGrammar';
}
return newv($content_generator, array())
->generateSeveral($this->roll(4, 12, 10));
}
private function newPasteContent() {
$languages = $this->getSupportedLanguages();
$language = array_rand($languages); $language = array_rand($languages);
$spec = $languages[$language]; $spec = $languages[$language];
@ -62,16 +76,10 @@ final class PhabricatorPasteTestDataGenerator
$title_generator = 'PhabricatorPasteFilenameContextFreeGrammar'; $title_generator = 'PhabricatorPasteFilenameContextFreeGrammar';
} }
$content_generator = idx($spec, 'content');
if (!$content_generator) {
$content_generator = 'PhutilLipsumContextFreeGrammar';
}
$title = newv($title_generator, array()) $title = newv($title_generator, array())
->generate(); ->generate();
$content = newv($content_generator, array()) $content = $this->generateContent($spec);
->generateSeveral($this->roll(4, 12, 10));
// Usually add the language as a suffix. // Usually add the language as a suffix.
if ($this->roll(1, 20) > 2) { if ($this->roll(1, 20) > 2) {

View file

@ -22,7 +22,13 @@ final class PhabricatorProjectSearchEngine
return array( return array(
id(new PhabricatorSearchTextField()) id(new PhabricatorSearchTextField())
->setLabel(pht('Name')) ->setLabel(pht('Name'))
->setKey('name'), ->setKey('name')
->setDescription(
pht(
'(Deprecated.) Search for projects with a given name or '.
'hashtag using tokenizer/datasource query matching rules. This '.
'is deprecated in favor of the more powerful "query" '.
'constraint.')),
id(new PhabricatorSearchStringListField()) id(new PhabricatorSearchStringListField())
->setLabel(pht('Slugs')) ->setLabel(pht('Slugs'))
->setIsHidden(true) ->setIsHidden(true)

View file

@ -57,7 +57,10 @@ final class PhabricatorFerretSearchEngineExtension
$fields[] = id(new PhabricatorSearchTextField()) $fields[] = id(new PhabricatorSearchTextField())
->setKey('query') ->setKey('query')
->setLabel(pht('Query')) ->setLabel(pht('Query'))
->setDescription(pht('Fulltext search.')); ->setDescription(
pht(
'Find objects matching a fulltext search query. See '.
'"Search User Guide" in the documentation for details.'));
return $fields; return $fields;
} }

View file

@ -60,6 +60,10 @@ final class PhabricatorFulltextToken extends Phobject {
$tip = pht('Substring Search'); $tip = pht('Substring Search');
$shade = PHUITagView::COLOR_VIOLET; $shade = PHUITagView::COLOR_VIOLET;
break; break;
case PhutilSearchQueryCompiler::OPERATOR_EXACT:
$tip = pht('Exact Search');
$shade = PHUITagView::COLOR_GREEN;
break;
default: default:
$shade = PHUITagView::COLOR_BLUE; $shade = PHUITagView::COLOR_BLUE;
break; break;

View file

@ -84,6 +84,7 @@ final class PhabricatorSearchResultView extends AphrontView {
switch ($operator) { switch ($operator) {
case PhutilSearchQueryCompiler::OPERATOR_SUBSTRING: case PhutilSearchQueryCompiler::OPERATOR_SUBSTRING:
case PhutilSearchQueryCompiler::OPERATOR_EXACT:
$patterns[] = '(('.preg_quote($value).'))ui'; $patterns[] = '(('.preg_quote($value).'))ui';
break; break;
case PhutilSearchQueryCompiler::OPERATOR_AND: case PhutilSearchQueryCompiler::OPERATOR_AND:

View file

@ -3599,6 +3599,7 @@ abstract class PhabricatorApplicationTransactionEditor
->setContinueOnMissingFields(true) ->setContinueOnMissingFields(true)
->setParentMessageID($this->getParentMessageID()) ->setParentMessageID($this->getParentMessageID())
->setIsInverseEdgeEditor(true) ->setIsInverseEdgeEditor(true)
->setIsSilent($this->getIsSilent())
->setActor($this->requireActor()) ->setActor($this->requireActor())
->setActingAsPHID($this->getActingAsPHID()) ->setActingAsPHID($this->getActingAsPHID())
->setContentSource($this->getContentSource()); ->setContentSource($this->getContentSource());

View file

@ -138,6 +138,7 @@ some special syntax. These features are supported:
- Field search with `title:platypus`. - Field search with `title:platypus`.
- Filtering out matches with `-platypus`. - Filtering out matches with `-platypus`.
- Quoted terms with `"platypus attorney"`. - Quoted terms with `"platypus attorney"`.
- Matching entire fields with `=platypus`.
- Combining features with `title:~"platypus attorney"`. - Combining features with `title:~"platypus attorney"`.
See below for more detail. See below for more detail.
@ -173,3 +174,11 @@ or `title:"platypus attorney"`. These scopes are also supported:
**Filtering Matches**: You can remove documents which match certain terms from **Filtering Matches**: You can remove documents which match certain terms from
the result set with `-`. For example: `platypus -mammal`. Documents which match the result set with `-`. For example: `platypus -mammal`. Documents which match
negated terms will be filtered out of the result set. negated terms will be filtered out of the result set.
**Matching Entire Fields**: If you know the exact name of an object and want
to find only that object, you can use the `=` operator. A query like
`title:"warp drive"` will find a document titled "Warp Drive", but will also
find documents with longer titles, like "Not a Warp Drive". The `=` operator
requires that the entire field match the query exactly, so //only// documents
exactly titled "Warp Drive" will be matched by the query (but note that the
query is still case insensitive).

View file

@ -1918,6 +1918,7 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING; $op_sub = PhutilSearchQueryCompiler::OPERATOR_SUBSTRING;
$op_not = PhutilSearchQueryCompiler::OPERATOR_NOT; $op_not = PhutilSearchQueryCompiler::OPERATOR_NOT;
$op_exact = PhutilSearchQueryCompiler::OPERATOR_EXACT;
$where = array(); $where = array();
$current_function = 'all'; $current_function = 'all';
@ -1941,6 +1942,25 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$is_substring = false; $is_substring = false;
} }
// If we're doing exact search, just test the raw corpus.
$is_exact = ($raw_token->getOperator() == $op_exact);
if ($is_exact) {
if ($is_not) {
$where[] = qsprintf(
$conn,
'(%T.rawCorpus != %s)',
$table_alias,
$value);
} else {
$where[] = qsprintf(
$conn,
'(%T.rawCorpus = %s)',
$table_alias,
$value);
}
continue;
}
// If we're doing substring search, we just match against the raw corpus // If we're doing substring search, we just match against the raw corpus
// and we're done. // and we're done.
if ($is_substring) { if ($is_substring) {

View file

@ -24,6 +24,17 @@ final class PhabricatorStorageManagementDestroyWorkflow
$console = PhutilConsole::getConsole(); $console = PhutilConsole::getConsole();
if (!$this->isDryRun() && !$this->isForce()) { if (!$this->isDryRun() && !$this->isForce()) {
if ($args->getArg('unittest-fixtures')) {
$console->writeOut(
phutil_console_wrap(
pht(
'Are you completely sure you really want to destroy all unit '.
'test fixure data? This operation can not be undone.')));
if (!phutil_console_confirm(pht('Destroy all unit test data?'))) {
$console->writeOut("%s\n", pht('Cancelled.'));
exit(1);
}
} else {
$console->writeOut( $console->writeOut(
phutil_console_wrap( phutil_console_wrap(
pht( pht(
@ -41,6 +52,7 @@ final class PhabricatorStorageManagementDestroyWorkflow
exit(1); exit(1);
} }
} }
}
$apis = $this->getMasterAPIs(); $apis = $this->getMasterAPIs();
foreach ($apis as $api) { foreach ($apis as $api) {