1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-25 05:58:21 +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
->newIssue('extension.opcache.devmode')
->setShortName(pht('OPcache Config'))
->setName(pht('OPCache Not Configured for Development'))
->setName(pht('OPcache Not Configured for Development'))
->setSummary($summary)
->setMessage($message)
->addPHPConfig('opcache.validate_timestamps')

View file

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

View file

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

View file

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

View file

@ -6,6 +6,7 @@ final class DifferentialRevisionViewController
private $revisionID;
private $changesetCount;
private $hiddenChangesets;
private $warnings = array();
public function shouldAllowPublic() {
return true;
@ -68,9 +69,17 @@ final class DifferentialRevisionViewController
$revision->attachActiveDiff(last($diffs));
$diff_vs = $request->getInt('vs');
$target_id = $request->getInt('id');
$target = idx($diffs, $target_id, end($diffs));
$diff_vs = $this->getOldDiffID($revision, $diffs);
if ($diff_vs instanceof AphrontResponse) {
return $diff_vs;
}
$target_id = $this->getNewDiffID($revision, $diffs);
if ($target_id instanceof AphrontResponse) {
return $target_id;
}
$target = $diffs[$target_id];
$target_manual = $target;
if (!$target_id) {
@ -81,10 +90,6 @@ final class DifferentialRevisionViewController
}
}
if (empty($diffs[$diff_vs])) {
$diff_vs = null;
}
$repository = null;
$repository_phid = $target->getRepositoryPHID();
if ($repository_phid) {
@ -170,7 +175,7 @@ final class DifferentialRevisionViewController
}
$handles = $this->loadViewerHandles($object_phids);
$warnings = array();
$warnings = $this->warnings;
$request_uri = $request->getRequestURI();
@ -1312,4 +1317,133 @@ final class DifferentialRevisionViewController
->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->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(
$body,
@ -645,19 +647,6 @@ final class DifferentialTransactionEditor
$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;
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
@ -669,7 +658,28 @@ final class DifferentialTransactionEditor
if ($update_xaction) {
$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(
pht('AFFECTED FILES'),
$this->renderAffectedFilesForMail($diff));

View file

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

View file

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

View file

@ -119,11 +119,23 @@ final class PhabricatorDocumentRef
}
$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 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() {

View file

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

View file

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

View file

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

View file

@ -22,7 +22,13 @@ final class PhabricatorProjectSearchEngine
return array(
id(new PhabricatorSearchTextField())
->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())
->setLabel(pht('Slugs'))
->setIsHidden(true)

View file

@ -57,7 +57,10 @@ final class PhabricatorFerretSearchEngineExtension
$fields[] = id(new PhabricatorSearchTextField())
->setKey('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;
}

View file

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

View file

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

View file

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

View file

@ -138,6 +138,7 @@ some special syntax. These features are supported:
- Field search with `title:platypus`.
- Filtering out matches with `-platypus`.
- Quoted terms with `"platypus attorney"`.
- Matching entire fields with `=platypus`.
- Combining features with `title:~"platypus attorney"`.
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
the result set with `-`. For example: `platypus -mammal`. Documents which match
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_not = PhutilSearchQueryCompiler::OPERATOR_NOT;
$op_exact = PhutilSearchQueryCompiler::OPERATOR_EXACT;
$where = array();
$current_function = 'all';
@ -1941,6 +1942,25 @@ abstract class PhabricatorCursorPagedPolicyAwareQuery
$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
// and we're done.
if ($is_substring) {

View file

@ -24,21 +24,33 @@ final class PhabricatorStorageManagementDestroyWorkflow
$console = PhutilConsole::getConsole();
if (!$this->isDryRun() && !$this->isForce()) {
$console->writeOut(
phutil_console_wrap(
pht(
'Are you completely sure you really want to permanently destroy '.
'all storage for Phabricator data? This operation can not be '.
'undone and your data will not be recoverable if you proceed.')));
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(
phutil_console_wrap(
pht(
'Are you completely sure you really want to permanently destroy '.
'all storage for Phabricator data? This operation can not be '.
'undone and your data will not be recoverable if you proceed.')));
if (!phutil_console_confirm(pht('Permanently destroy all data?'))) {
$console->writeOut("%s\n", pht('Cancelled.'));
exit(1);
}
if (!phutil_console_confirm(pht('Permanently destroy all data?'))) {
$console->writeOut("%s\n", pht('Cancelled.'));
exit(1);
}
if (!phutil_console_confirm(pht('Really destroy all data forever?'))) {
$console->writeOut("%s\n", pht('Cancelled.'));
exit(1);
if (!phutil_console_confirm(pht('Really destroy all data forever?'))) {
$console->writeOut("%s\n", pht('Cancelled.'));
exit(1);
}
}
}