1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-10 23:01:04 +01:00

(stable) Promote 2018 Week 13

This commit is contained in:
epriestley 2018-03-30 17:50:09 -07:00
commit 126f7f0d56
27 changed files with 892 additions and 92 deletions

View file

@ -9,8 +9,8 @@ return array(
'names' => array(
'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65',
'core.pkg.css' => '3fd3b7b8',
'core.pkg.js' => 'b9b4a943',
'core.pkg.css' => '1dd5fa4b',
'core.pkg.js' => '1ea38af8',
'differential.pkg.css' => '113e692c',
'differential.pkg.js' => 'f6d809c0',
'diffusion.pkg.css' => 'a2d17c7d',
@ -112,7 +112,7 @@ return array(
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
'rsrc/css/core/core.css' => '62fa3ace',
'rsrc/css/core/remarkup.css' => 'b375546d',
'rsrc/css/core/remarkup.css' => '1828e2ad',
'rsrc/css/core/syntax.css' => 'cae95e89',
'rsrc/css/core/z-index.css' => '9d8f7c4b',
'rsrc/css/diviner/diviner-shared.css' => '896f1d43',
@ -392,7 +392,7 @@ return array(
'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc',
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '1db13e70',
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
'rsrc/js/application/files/behavior-document-engine.js' => 'd3f8623c',
'rsrc/js/application/files/behavior-document-engine.js' => '9108ee1a',
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => '191b4909',
@ -508,8 +508,8 @@ return array(
'rsrc/js/phui/behavior-phui-submenu.js' => 'a6f7a73b',
'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9',
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => 'ed18356a',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '7fa5c915',
'rsrc/js/phuix/PHUIXActionView.js' => '8d4a8c72',
'rsrc/js/phuix/PHUIXAutocomplete.js' => 'df1bbd34',
'rsrc/js/phuix/PHUIXButtonView.js' => '8a91e1ac',
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '04b2ae03',
'rsrc/js/phuix/PHUIXExample.js' => '68af71ca',
@ -607,7 +607,7 @@ return array(
'javelin-behavior-diffusion-jump-to' => '73d09eef',
'javelin-behavior-diffusion-locate-file' => '6d3e1947',
'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc',
'javelin-behavior-document-engine' => 'd3f8623c',
'javelin-behavior-document-engine' => '9108ee1a',
'javelin-behavior-doorkeeper-tag' => '1db13e70',
'javelin-behavior-drydock-live-operation-status' => '901935ef',
'javelin-behavior-durable-column' => '2ae077e1',
@ -780,7 +780,7 @@ return array(
'phabricator-object-selector-css' => '85ee8ce6',
'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => '77b0ae28',
'phabricator-remarkup-css' => 'b375546d',
'phabricator-remarkup-css' => '1828e2ad',
'phabricator-search-results-css' => '505dd8cf',
'phabricator-shaped-request' => '7cbe244b',
'phabricator-slowvote-css' => 'a94b7230',
@ -864,8 +864,8 @@ return array(
'phui-workcard-view-css' => 'cca5fa92',
'phui-workpanel-view-css' => 'a3a63478',
'phuix-action-list-view' => 'b5c256b8',
'phuix-action-view' => 'ed18356a',
'phuix-autocomplete' => '7fa5c915',
'phuix-action-view' => '8d4a8c72',
'phuix-autocomplete' => 'df1bbd34',
'phuix-button-view' => '8a91e1ac',
'phuix-dropdown-menu' => '04b2ae03',
'phuix-form-control-view' => '210a16c1',
@ -1553,12 +1553,6 @@ return array(
'7f243deb' => array(
'javelin-install',
),
'7fa5c915' => array(
'javelin-install',
'javelin-dom',
'phuix-icon-view',
'phabricator-prefab',
),
'834a1173' => array(
'javelin-behavior',
'javelin-scrollbar',
@ -1620,6 +1614,11 @@ return array(
'javelin-stratcom',
'javelin-install',
),
'8d4a8c72' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
),
'8e1baf68' => array(
'phui-button-css',
),
@ -1645,6 +1644,11 @@ return array(
'javelin-stratcom',
'javelin-vector',
),
'9108ee1a' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'92b9ec77' => array(
'javelin-behavior',
'javelin-stratcom',
@ -2002,11 +2006,6 @@ return array(
'd254d646' => array(
'javelin-util',
),
'd3f8623c' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'd4505101' => array(
'javelin-stratcom',
'javelin-install',
@ -2047,6 +2046,12 @@ return array(
'javelin-typeahead-ondemand-source',
'javelin-dom',
),
'df1bbd34' => array(
'javelin-install',
'javelin-dom',
'phuix-icon-view',
'phabricator-prefab',
),
'e1d25dfb' => array(
'javelin-behavior',
'javelin-stratcom',
@ -2125,11 +2130,6 @@ return array(
'javelin-stratcom',
'javelin-vector',
),
'ed18356a' => array(
'javelin-install',
'javelin-dom',
'javelin-util',
),
'edf8a145' => array(
'javelin-behavior',
'javelin-uri',

View file

@ -4020,6 +4020,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryManagementRefsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRefsWorkflow.php',
'PhabricatorRepositoryManagementReparseWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php',
'PhabricatorRepositoryManagementThawWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementThawWorkflow.php',
'PhabricatorRepositoryManagementUnpublishWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementUnpublishWorkflow.php',
'PhabricatorRepositoryManagementUpdateWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementUpdateWorkflow.php',
'PhabricatorRepositoryManagementWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementWorkflow.php',
'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryMercurialCommitChangeParserWorker.php',
@ -6525,6 +6526,7 @@ phutil_register_library_map(array(
'PhabricatorApplicationTransactionInterface',
'PhabricatorPolicyInterface',
'PhabricatorConduitResultInterface',
'PhabricatorDestructibleInterface',
),
'HarbormasterBuildAbortedException' => 'Exception',
'HarbormasterBuildActionController' => 'HarbormasterController',
@ -6532,6 +6534,7 @@ phutil_register_library_map(array(
'HarbormasterBuildArtifact' => array(
'HarbormasterDAO',
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
),
'HarbormasterBuildArtifactPHIDType' => 'PhabricatorPHIDType',
'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
@ -6564,6 +6567,7 @@ phutil_register_library_map(array(
'HarbormasterBuildMessage' => array(
'HarbormasterDAO',
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
),
'HarbormasterBuildMessageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'HarbormasterBuildPHIDType' => 'PhabricatorPHIDType',
@ -6614,6 +6618,7 @@ phutil_register_library_map(array(
'HarbormasterBuildTarget' => array(
'HarbormasterDAO',
'PhabricatorPolicyInterface',
'PhabricatorDestructibleInterface',
),
'HarbormasterBuildTargetPHIDType' => 'PhabricatorPHIDType',
'HarbormasterBuildTargetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
@ -6628,6 +6633,7 @@ phutil_register_library_map(array(
'PhabricatorApplicationTransactionInterface',
'PhabricatorPolicyInterface',
'HarbormasterBuildableInterface',
'PhabricatorDestructibleInterface',
),
'HarbormasterBuildableActionController' => 'HarbormasterController',
'HarbormasterBuildableListController' => 'HarbormasterController',
@ -8558,7 +8564,10 @@ phutil_register_library_map(array(
'PhabricatorPolicyInterface',
'PhabricatorMarkupInterface',
),
'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO',
'PhabricatorFeedStoryData' => array(
'PhabricatorFeedDAO',
'PhabricatorDestructibleInterface',
),
'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO',
'PhabricatorFeedStoryPublisher' => 'Phobject',
'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO',
@ -9809,6 +9818,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryManagementRefsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementReparseWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementThawWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementUnpublishWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementUpdateWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker',

View file

@ -137,7 +137,34 @@ final class DifferentialRevisionUpdateTransaction
continue;
}
if ($diff->getRevisionID()) {
$is_attached =
($diff->getRevisionID()) &&
($diff->getRevisionID() == $object->getID());
if ($is_attached) {
$is_active = ($diff_phid == $object->getActiveDiffPHID());
} else {
$is_active = false;
}
if ($is_attached) {
if ($is_active) {
// This is a no-op: we're reattaching the current active diff to the
// revision it is already attached to. This is valid and will just
// be dropped later on in the process.
} else {
// At least for now, there's no support for "undoing" a diff and
// reverting to an older proposed change without just creating a
// new diff from whole cloth.
$errors[] = $this->newInvalidError(
pht(
'You can not update this revision with the specified diff '.
'("%s") because this diff is already attached to the revision '.
'as an older version of the change.',
$diff_phid),
$xaction);
continue;
}
} else if ($diff->getRevisionID()) {
$errors[] = $this->newInvalidError(
pht(
'You can not update this revision with the specified diff ("%s") '.

View file

@ -126,7 +126,6 @@ final class DiffusionCommitHookEngine extends Phobject {
public function execute() {
$ref_updates = $this->findRefUpdates();
$all_updates = $ref_updates;
$caught = null;
try {
@ -140,21 +139,32 @@ final class DiffusionCommitHookEngine extends Phobject {
throw $ex;
}
$this->applyHeraldRefRules($ref_updates, $all_updates);
$content_updates = $this->findContentUpdates($ref_updates);
$all_updates = array_merge($ref_updates, $content_updates);
// If this is an "initial import" (a sizable push to a previously empty
// repository) we'll allow enormous changes and disable Herald rules.
// These rulesets can consume a large amount of time and memory and are
// generally not relevant when importing repository history.
$is_initial_import = $this->isInitialImport($all_updates);
if (!$is_initial_import) {
$this->applyHeraldRefRules($ref_updates);
}
try {
$this->rejectEnormousChanges($content_updates);
if (!$is_initial_import) {
$this->rejectEnormousChanges($content_updates);
}
} catch (DiffusionCommitHookRejectException $ex) {
// If we're rejecting enormous changes, flag everything.
$this->rejectCode = PhabricatorRepositoryPushLog::REJECT_ENORMOUS;
throw $ex;
}
$all_updates = array_merge($all_updates, $content_updates);
$this->applyHeraldContentRules($content_updates, $all_updates);
if (!$is_initial_import) {
$this->applyHeraldContentRules($content_updates);
}
// Run custom scripts in `hook.d/` directories.
$this->applyCustomHooks($all_updates);
@ -186,12 +196,10 @@ final class DiffusionCommitHookEngine extends Phobject {
throw $caught;
}
// If this went through cleanly, detect pushes which are actually imports
// of an existing repository rather than an addition of new commits. If
// this push is importing a bunch of stuff, set the importing flag on
// the repository. It will be cleared once we fully process everything.
// If this went through cleanly and was an import, set the importing flag
// on the repository. It will be cleared once we fully process everything.
if ($this->isInitialImport($all_updates)) {
if ($is_initial_import) {
$repository = $this->getRepository();
$repository->markImporting();
}
@ -281,28 +289,21 @@ final class DiffusionCommitHookEngine extends Phobject {
/* -( Herald )------------------------------------------------------------- */
private function applyHeraldRefRules(
array $ref_updates,
array $all_updates) {
private function applyHeraldRefRules(array $ref_updates) {
$this->applyHeraldRules(
$ref_updates,
new HeraldPreCommitRefAdapter(),
$all_updates);
new HeraldPreCommitRefAdapter());
}
private function applyHeraldContentRules(
array $content_updates,
array $all_updates) {
private function applyHeraldContentRules(array $content_updates) {
$this->applyHeraldRules(
$content_updates,
new HeraldPreCommitContentAdapter(),
$all_updates);
new HeraldPreCommitContentAdapter());
}
private function applyHeraldRules(
array $updates,
HeraldAdapter $adapter_template,
array $all_updates) {
HeraldAdapter $adapter_template) {
if (!$updates) {
return;

View file

@ -57,8 +57,8 @@ final class DrydockManagementCommandWorkflow
array($interface, 'execx'),
array('%Ls', $argv));
fprintf(STDOUT, $stdout);
fprintf(STDERR, $stderr);
fwrite(STDOUT, $stdout);
fwrite(STDERR, $stderr);
return 0;
}

View file

@ -1,6 +1,8 @@
<?php
final class PhabricatorFeedStoryData extends PhabricatorFeedDAO {
final class PhabricatorFeedStoryData
extends PhabricatorFeedDAO
implements PhabricatorDestructibleInterface {
protected $phid;
@ -66,4 +68,30 @@ final class PhabricatorFeedStoryData extends PhabricatorFeedDAO {
return idx($this->storyData, $key, $default);
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$this->openTransaction();
$conn = $this->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T WHERE chronologicalKey = %s',
id(new PhabricatorFeedStoryNotification())->getTableName(),
$this->getChronologicalKey());
queryfx(
$conn,
'DELETE FROM %T WHERE chronologicalKey = %s',
id(new PhabricatorFeedStoryReference())->getTableName(),
$this->getChronologicalKey());
$this->delete();
$this->saveTransaction();
}
}

View file

@ -7,6 +7,10 @@ final class PhabricatorFileDocumentController
private $engine;
private $ref;
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
@ -39,6 +43,16 @@ final class PhabricatorFileDocumentController
$engine = $engines[$engine_key];
$this->engine = $engine;
$encode_setting = $request->getStr('encode');
if (strlen($encode_setting)) {
$engine->setEncodingConfiguration($encode_setting);
}
$highlight_setting = $request->getStr('highlight');
if (strlen($highlight_setting)) {
$engine->setHighlightingConfiguration($highlight_setting);
}
try {
$content = $engine->newDocument($ref);
} catch (Exception $ex) {

View file

@ -422,6 +422,16 @@ final class PhabricatorFileViewController extends PhabricatorFileController {
$engine->setHighlightedLines(range($lines[0], $lines[1]));
}
$encode_setting = $request->getStr('encode');
if (strlen($encode_setting)) {
$engine->setEncodingConfiguration($encode_setting);
}
$highlight_setting = $request->getStr('highlight');
if (strlen($highlight_setting)) {
$engine->setHighlightingConfiguration($highlight_setting);
}
$views = array();
foreach ($engines as $candidate_key => $candidate_engine) {
$label = $candidate_engine->getViewAsLabel($ref);
@ -443,6 +453,8 @@ final class PhabricatorFileViewController extends PhabricatorFileController {
'engineURI' => $candidate_engine->getRenderURI($ref),
'viewURI' => $view_uri,
'loadingMarkup' => hsprintf('%s', $loading),
'canEncode' => $candidate_engine->canConfigureEncoding($ref),
'canHighlight' => $candidate_engine->CanConfigureHighlighting($ref),
);
}
@ -474,6 +486,18 @@ final class PhabricatorFileViewController extends PhabricatorFileController {
'viewKey' => $engine->getDocumentEngineKey(),
'views' => $views,
'standaloneURI' => $engine->getRenderURI($ref),
'encode' => array(
'icon' => 'fa-font',
'name' => pht('Change Text Encoding...'),
'uri' => '/services/encoding/',
'value' => $encode_setting,
),
'highlight' => array(
'icon' => 'fa-lightbulb-o',
'name' => pht('Highlight As...'),
'uri' => '/services/highlight/',
'value' => $highlight_setting,
),
);
$view_button = id(new PHUIButtonView())

View file

@ -5,6 +5,8 @@ abstract class PhabricatorDocumentEngine
private $viewer;
private $highlightedLines = array();
private $encodingConfiguration;
private $highlightingConfiguration;
final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
@ -28,6 +30,32 @@ abstract class PhabricatorDocumentEngine
return $this->canRenderDocumentType($ref);
}
public function canConfigureEncoding(PhabricatorDocumentRef $ref) {
return false;
}
public function canConfigureHighlighting(PhabricatorDocumentRef $ref) {
return false;
}
final public function setEncodingConfiguration($config) {
$this->encodingConfiguration = $config;
return $this;
}
final public function getEncodingConfiguration() {
return $this->encodingConfiguration;
}
final public function setHighlightingConfiguration($config) {
$this->highlightingConfiguration = $config;
return $this;
}
final public function getHighlightingConfiguration() {
return $this->highlightingConfiguration;
}
public function shouldRenderAsync(PhabricatorDocumentRef $ref) {
return false;
}

View file

@ -196,7 +196,7 @@ final class PhabricatorJupyterDocumentEngine
$content = implode('', $content);
$content = PhabricatorSyntaxHighlighter::highlightWithLanguage(
'python',
'py',
$content);
$outputs = array();
@ -260,9 +260,8 @@ final class PhabricatorJupyterDocumentEngine
$raw_data = $data[$image_format];
if (!is_array($raw_data)) {
continue;
$raw_data = array($raw_data);
}
$raw_data = implode('', $raw_data);
$content = phutil_tag(

View file

@ -9,6 +9,10 @@ final class PhabricatorSourceDocumentEngine
return pht('View as Source');
}
public function canConfigureHighlighting(PhabricatorDocumentRef $ref) {
return true;
}
protected function getDocumentIconIcon(PhabricatorDocumentRef $ref) {
return 'fa-code';
}
@ -20,9 +24,16 @@ final class PhabricatorSourceDocumentEngine
protected function newDocumentContent(PhabricatorDocumentRef $ref) {
$content = $this->loadTextData($ref);
$content = PhabricatorSyntaxHighlighter::highlightWithFilename(
$ref->getName(),
$content);
$highlighting = $this->getHighlightingConfiguration();
if ($highlighting !== null) {
$content = PhabricatorSyntaxHighlighter::highlightWithLanguage(
$highlighting,
$content);
} else {
$content = PhabricatorSyntaxHighlighter::highlightWithFilename(
$ref->getName(),
$content);
}
return $this->newTextDocumentContent($content);
}

View file

@ -3,10 +3,16 @@
abstract class PhabricatorTextDocumentEngine
extends PhabricatorDocumentEngine {
private $encodingMessage = null;
protected function canRenderDocumentType(PhabricatorDocumentRef $ref) {
return $ref->isProbablyText();
}
public function canConfigureEncoding(PhabricatorDocumentRef $ref) {
return true;
}
protected function newTextDocumentContent($content) {
$lines = phutil_split_lines($content);
@ -14,19 +20,69 @@ abstract class PhabricatorTextDocumentEngine
->setHighlights($this->getHighlightedLines())
->setLines($lines);
$message = null;
if ($this->encodingMessage !== null) {
$message = $this->newMessage($this->encodingMessage);
}
$container = phutil_tag(
'div',
array(
'class' => 'document-engine-text',
),
$view);
array(
$message,
$view,
));
return $container;
}
protected function loadTextData(PhabricatorDocumentRef $ref) {
$content = $ref->loadData();
$content = phutil_utf8ize($content);
$encoding = $this->getEncodingConfiguration();
if ($encoding !== null) {
if (function_exists('mb_convert_encoding')) {
$content = mb_convert_encoding($content, 'UTF-8', $encoding);
$this->encodingMessage = pht(
'This document was converted from %s to UTF8 for display.',
$encoding);
} else {
$this->encodingMessage = pht(
'Unable to perform text encoding conversion: mbstring extension '.
'is not available.');
}
} else {
if (!phutil_is_utf8($content)) {
if (function_exists('mb_detect_encoding')) {
$try_encodings = array(
'JIS' => pht('JIS'),
'EUC-JP' => pht('EUC-JP'),
'SJIS' => pht('Shift JIS'),
'ISO-8859-1' => pht('ISO-8859-1 (Latin 1)'),
);
$guess = mb_detect_encoding($content, array_keys($try_encodings));
if ($guess) {
$content = mb_convert_encoding($content, 'UTF-8', $guess);
$this->encodingMessage = pht(
'This document is not UTF8. It was detected as %s and '.
'converted to UTF8 for display.',
idx($try_encodings, $guess, $guess));
}
}
}
}
if (!phutil_is_utf8($content)) {
$content = phutil_utf8ize($content);
$this->encodingMessage = pht(
'This document is not UTF8 and its text encoding could not be '.
'detected automatically. Use "Change Text Encoding..." to choose '.
'an encoding.');
}
return $content;
}

View file

@ -6,8 +6,11 @@
* conditions where we receive a message before a build plan is ready to
* accept it.
*/
final class HarbormasterBuildMessage extends HarbormasterDAO
implements PhabricatorPolicyInterface {
final class HarbormasterBuildMessage
extends HarbormasterDAO
implements
PhabricatorPolicyInterface,
PhabricatorDestructibleInterface {
protected $authorPHID;
protected $receiverPHID;
@ -74,4 +77,13 @@ final class HarbormasterBuildMessage extends HarbormasterDAO
return pht('Build messages have the same policies as their receivers.');
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$this->delete();
}
}

View file

@ -1,10 +1,12 @@
<?php
final class HarbormasterBuildable extends HarbormasterDAO
final class HarbormasterBuildable
extends HarbormasterDAO
implements
PhabricatorApplicationTransactionInterface,
PhabricatorPolicyInterface,
HarbormasterBuildableInterface {
HarbormasterBuildableInterface,
PhabricatorDestructibleInterface {
protected $buildablePHID;
protected $containerPHID;
@ -340,4 +342,32 @@ final class HarbormasterBuildable extends HarbormasterDAO
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$viewer = $engine->getViewer();
$this->openTransaction();
$builds = id(new HarbormasterBuildQuery())
->setViewer($viewer)
->withBuildablePHIDs(array($this->getPHID()))
->execute();
foreach ($builds as $build) {
$engine->destroyObject($build);
}
$messages = id(new HarbormasterBuildMessageQuery())
->setViewer($viewer)
->withReceiverPHIDs(array($this->getPHID()))
->execute();
foreach ($messages as $message) {
$engine->destroyObject($message);
}
$this->delete();
$this->saveTransaction();
}
}

View file

@ -4,7 +4,8 @@ final class HarbormasterBuild extends HarbormasterDAO
implements
PhabricatorApplicationTransactionInterface,
PhabricatorPolicyInterface,
PhabricatorConduitResultInterface {
PhabricatorConduitResultInterface,
PhabricatorDestructibleInterface {
protected $buildablePHID;
protected $buildPlanPHID;
@ -455,4 +456,33 @@ final class HarbormasterBuild extends HarbormasterDAO
);
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$viewer = $engine->getViewer();
$this->openTransaction();
$targets = id(new HarbormasterBuildTargetQuery())
->setViewer($viewer)
->withBuildPHIDs(array($this->getPHID()))
->execute();
foreach ($targets as $target) {
$engine->destroyObject($target);
}
$messages = id(new HarbormasterBuildMessageQuery())
->setViewer($viewer)
->withReceiverPHIDs(array($this->getPHID()))
->execute();
foreach ($messages as $message) {
$engine->destroyObject($message);
}
$this->delete();
$this->saveTransaction();
}
}

View file

@ -1,7 +1,10 @@
<?php
final class HarbormasterBuildArtifact extends HarbormasterDAO
implements PhabricatorPolicyInterface {
final class HarbormasterBuildArtifact
extends HarbormasterDAO
implements
PhabricatorPolicyInterface,
PhabricatorDestructibleInterface {
protected $buildTargetPHID;
protected $artifactType;
@ -147,4 +150,19 @@ final class HarbormasterBuildArtifact extends HarbormasterDAO
return pht('Users must be able to see a buildable to see its artifacts.');
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$viewer = $this->getViewer();
$this->openTransaction();
$this->releaseArtifact($viewer);
$this->delete();
$this->saveTransaction();
}
}

View file

@ -1,7 +1,10 @@
<?php
final class HarbormasterBuildTarget extends HarbormasterDAO
implements PhabricatorPolicyInterface {
final class HarbormasterBuildTarget
extends HarbormasterDAO
implements
PhabricatorPolicyInterface,
PhabricatorDestructibleInterface {
protected $name;
protected $buildPHID;
@ -354,4 +357,59 @@ final class HarbormasterBuildTarget extends HarbormasterDAO
return pht('Users must be able to see a build to view its build targets.');
}
/* -( PhabricatorDestructibleInterface )----------------------------------- */
public function destroyObjectPermanently(
PhabricatorDestructionEngine $engine) {
$viewer = $engine->getViewer();
$this->openTransaction();
$lint_message = new HarbormasterBuildLintMessage();
$conn = $lint_message->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T WHERE buildTargetPHID = %s',
$lint_message->getTableName(),
$this->getPHID());
$unit_message = new HarbormasterBuildUnitMessage();
$conn = $unit_message->establishConnection('w');
queryfx(
$conn,
'DELETE FROM %T WHERE buildTargetPHID = %s',
$unit_message->getTableName(),
$this->getPHID());
$logs = id(new HarbormasterBuildLogQuery())
->setViewer($viewer)
->withBuildTargetPHIDs(array($this->getPHID()))
->execute();
foreach ($logs as $log) {
$engine->destroyObject($log);
}
$artifacts = id(new HarbormasterBuildArtifactQuery())
->setViewer($viewer)
->withBuildTargetPHIDs(array($this->getPHID()))
->execute();
foreach ($artifacts as $artifact) {
$engine->destroyObject($artifact);
}
$messages = id(new HarbormasterBuildMessageQuery())
->setViewer($viewer)
->withReceiverPHIDs(array($this->getPHID()))
->execute();
foreach ($messages as $message) {
$engine->destroyObject($message);
}
$this->delete();
$this->saveTransaction();
}
}

View file

@ -393,19 +393,22 @@ final class PhabricatorOwnersPackage
}
public static function splitPath($path) {
$trailing_slash = preg_match('@/$@', $path) ? '/' : '';
$path = trim($path, '/');
$result = array(
'/',
);
$parts = explode('/', $path);
$buffer = '/';
foreach ($parts as $part) {
if (!strlen($part)) {
continue;
}
$result = array();
while (count($parts)) {
$result[] = '/'.implode('/', $parts).$trailing_slash;
$trailing_slash = '/';
array_pop($parts);
$buffer = $buffer.$part.'/';
$result[] = $buffer;
}
$result[] = '/';
return array_reverse($result);
return $result;
}
public function attachPaths(array $paths) {

View file

@ -0,0 +1,273 @@
<?php
final class PhabricatorRepositoryManagementUnpublishWorkflow
extends PhabricatorRepositoryManagementWorkflow {
protected function didConstruct() {
$this
->setName('unpublish')
->setExamples(
'**unpublish** [__options__] __repository__')
->setSynopsis(
pht(
'Unpublish all feed stories and notifications that a repository '.
'has generated. Keep expectations low; can not rewind time.'))
->setArguments(
array(
array(
'name' => 'force',
'help' => pht('Do not prompt for confirmation.'),
),
array(
'name' => 'dry-run',
'help' => pht('Do not perform any writes.'),
),
array(
'name' => 'repositories',
'wildcard' => true,
),
));
}
public function execute(PhutilArgumentParser $args) {
$viewer = $this->getViewer();
$is_force = $args->getArg('force');
$is_dry_run = $args->getArg('dry-run');
$repositories = $this->loadLocalRepositories($args, 'repositories');
if (count($repositories) !== 1) {
throw new PhutilArgumentUsageException(
pht('Specify exactly one repository to unpublish.'));
}
$repository = head($repositories);
if (!$is_force) {
echo tsprintf(
"%s\n",
pht(
'This script will unpublish all feed stories and notifications '.
'which a repository generated during import. This action can not '.
'be undone.'));
$prompt = pht(
'Permanently unpublish "%s"?',
$repository->getDisplayName());
if (!phutil_console_confirm($prompt)) {
throw new PhutilArgumentUsageException(
pht('User aborted workflow.'));
}
}
$commits = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withRepositoryPHIDs(array($repository->getPHID()))
->execute();
echo pht("Will unpublish %s commits.\n", count($commits));
foreach ($commits as $commit) {
$this->unpublishCommit($commit, $is_dry_run);
}
return 0;
}
private function unpublishCommit(
PhabricatorRepositoryCommit $commit,
$is_dry_run) {
$viewer = $this->getViewer();
echo tsprintf(
"%s\n",
pht(
'Unpublishing commit "%s".',
$commit->getMonogram()));
$stories = id(new PhabricatorFeedQuery())
->setViewer($viewer)
->withFilterPHIDs(array($commit->getPHID()))
->execute();
if ($stories) {
echo tsprintf(
"%s\n",
pht(
'Found %s feed storie(s).',
count($stories)));
if (!$is_dry_run) {
$engine = new PhabricatorDestructionEngine();
foreach ($stories as $story) {
$story_data = $story->getStoryData();
$engine->destroyObject($story_data);
}
echo tsprintf(
"%s\n",
pht(
'Destroyed %s feed storie(s).',
count($stories)));
}
}
$edge_types = array(
PhabricatorObjectMentionsObjectEdgeType::EDGECONST => true,
DiffusionCommitHasTaskEdgeType::EDGECONST => true,
DiffusionCommitHasRevisionEdgeType::EDGECONST => true,
DiffusionCommitRevertsCommitEdgeType::EDGECONST => true,
);
$query = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array($commit->getPHID()))
->withEdgeTypes(array_keys($edge_types));
$edges = $query->execute();
foreach ($edges[$commit->getPHID()] as $type => $edge_list) {
foreach ($edge_list as $edge) {
$dst = $edge['dst'];
echo tsprintf(
"%s\n",
pht(
'Commit "%s" has edge of type "%s" to object "%s".',
$commit->getMonogram(),
$type,
$dst));
$object = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withPHIDs(array($dst))
->executeOne();
if ($object) {
if ($object instanceof PhabricatorApplicationTransactionInterface) {
$this->unpublishEdgeTransaction(
$commit,
$type,
$object,
$is_dry_run);
}
}
}
}
}
private function unpublishEdgeTransaction(
$src,
$type,
PhabricatorApplicationTransactionInterface $dst,
$is_dry_run) {
$viewer = $this->getViewer();
$query = PhabricatorApplicationTransactionQuery::newQueryForObject($dst)
->setViewer($viewer)
->withObjectPHIDs(array($dst->getPHID()));
$xactions = id(clone $query)
->withTransactionTypes(
array(
PhabricatorTransactions::TYPE_EDGE,
))
->execute();
$type_obj = PhabricatorEdgeType::getByConstant($type);
$inverse_type = $type_obj->getInverseEdgeConstant();
$engine = new PhabricatorDestructionEngine();
foreach ($xactions as $xaction) {
$edge_type = $xaction->getMetadataValue('edge:type');
if ($edge_type != $inverse_type) {
// Some other type of edge was edited.
continue;
}
$record = PhabricatorEdgeChangeRecord::newFromTransaction($xaction);
$changed = $record->getChangedPHIDs();
if ($changed !== array($src->getPHID())) {
// Affected objects were not just the object we're unpublishing.
continue;
}
echo tsprintf(
"%s\n",
pht(
'Found edge transaction "%s" on object "%s" for type "%s".',
$xaction->getPHID(),
$dst->getPHID(),
$type));
if (!$is_dry_run) {
$engine->destroyObject($xaction);
echo tsprintf(
"%s\n",
pht(
'Destroyed transaction "%s" on object "%s".',
$xaction->getPHID(),
$dst->getPHID()));
}
}
if ($type === DiffusionCommitHasTaskEdgeType::EDGECONST) {
$xactions = id(clone $query)
->withTransactionTypes(
array(
ManiphestTaskStatusTransaction::TRANSACTIONTYPE,
))
->execute();
if ($xactions) {
foreach ($xactions as $xaction) {
$metadata = $xaction->getMetadata();
if (idx($metadata, 'commitPHID') === $src->getPHID()) {
echo tsprintf(
"%s\n",
pht(
'MANUAL Task "%s" was likely closed improperly by "%s".',
$dst->getMonogram(),
$src->getMonogram()));
}
}
}
}
if ($type === DiffusionCommitHasRevisionEdgeType::EDGECONST) {
$xactions = id(clone $query)
->withTransactionTypes(
array(
DifferentialRevisionCloseTransaction::TRANSACTIONTYPE,
))
->execute();
if ($xactions) {
foreach ($xactions as $xaction) {
$metadata = $xaction->getMetadata();
if (idx($metadata, 'isCommitClose')) {
if (idx($metadata, 'commitPHID') === $src->getPHID()) {
echo tsprintf(
"%s\n",
pht(
'MANUAL Revision "%s" was likely closed improperly by "%s".',
$dst->getMonogram(),
$src->getMonogram()));
}
}
}
}
}
if (!$is_dry_run) {
id(new PhabricatorEdgeEditor())
->removeEdge($src->getPHID(), $type, $dst->getPHID())
->save();
echo tsprintf(
"%s\n",
pht(
'Destroyed edge of type "%s" between "%s" and "%s".',
$type,
$src->getPHID(),
$dst->getPHID()));
}
}
}

View file

@ -1120,6 +1120,11 @@ abstract class PhabricatorApplicationTransactionEditor
// We are the Herald editor, so stop work here and return the updated
// transactions.
return $xactions;
} else if ($this->getIsInverseEdgeEditor()) {
// Do not run Herald if we're just recording that this object was
// mentioned elsewhere. This tends to create Herald side effects which
// feel arbitrary, and can really slow down edits which mention a large
// number of other objects. See T13114.
} else if ($this->shouldApplyHeraldRules($object, $xactions)) {
// We are not the Herald editor, so try to apply Herald rules.
$herald_xactions = $this->applyHeraldRules($object, $xactions);

View file

@ -7,6 +7,7 @@ final class PhabricatorCustomFieldEditField
private $httpParameterType;
private $conduitParameterType;
private $bulkParameterType;
private $commentAction;
public function setCustomField(PhabricatorCustomField $custom_field) {
$this->customField = $custom_field;
@ -47,6 +48,16 @@ final class PhabricatorCustomFieldEditField
return $this->bulkParameterType;
}
public function setCustomFieldCommentAction(
PhabricatorEditEngineCommentAction $comment_action) {
$this->commentAction = $comment_action;
return $this;
}
public function getCustomFieldCommentAction() {
return $this->commentAction;
}
protected function buildControl() {
if ($this->getIsConduitOnly()) {
return null;
@ -77,6 +88,19 @@ final class PhabricatorCustomFieldEditField
return $clone->getNewValueForApplicationTransactions();
}
protected function getValueForCommentAction($value) {
$field = $this->getCustomField();
$clone = clone $field;
$clone->setValueFromApplicationTransactions($value);
// TODO: This is somewhat bogus because only StandardCustomFields
// implement a getFieldValue() method -- not all CustomFields. Today,
// only StandardCustomFields can ever actually generate a comment action
// so we never reach this method with other field types.
return $clone->getFieldValue();
}
protected function getValueExistsInSubmit(AphrontRequest $request, $key) {
return true;
}
@ -110,6 +134,16 @@ final class PhabricatorCustomFieldEditField
return null;
}
protected function newCommentAction() {
$action = $this->getCustomFieldCommentAction();
if ($action) {
return clone $action;
}
return null;
}
protected function newConduitParameterType() {
$type = $this->getCustomFieldConduitParameterType();

View file

@ -1127,6 +1127,16 @@ abstract class PhabricatorCustomField extends Phobject {
$field->setCustomFieldBulkParameterType($bulk_type);
}
$comment_action = $this->getCommentAction();
if ($comment_action) {
$field
->setCustomFieldCommentAction($comment_action)
->setCommentActionLabel(
pht(
'Change %s',
$this->getFieldName()));
}
return $field;
}
@ -1459,6 +1469,17 @@ abstract class PhabricatorCustomField extends Phobject {
return null;
}
public function getCommentAction() {
return $this->newCommentAction();
}
protected function newCommentAction() {
if ($this->proxy) {
return $this->proxy->newCommentAction();
}
return null;
}
/* -( Herald )------------------------------------------------------------- */

View file

@ -143,4 +143,26 @@ abstract class PhabricatorStandardCustomFieldTokenizer
->setDatasource($datasource);
}
protected function newCommentAction() {
$viewer = $this->getViewer();
$datasource = $this->getDatasource()
->setViewer($viewer);
$action = id(new PhabricatorEditEngineTokenizerCommentAction())
->setDatasource($datasource);
$limit = $this->getFieldConfigValue('limit');
if ($limit) {
$action->setLimit($limit);
}
$value = $this->getFieldValue();
if ($value !== null) {
$action->setInitialValue($value);
}
return $action;
}
}

View file

@ -724,6 +724,11 @@ var.remarkup-assist-textarea {
color: {$darkgreytext};
}
.phuix-autocomplete-list a.jx-result .tokenizer-result-closed {
color: {$lightgreytext};
text-decoration: line-through;
}
.phuix-autocomplete-list a.jx-result .phui-icon-view {
margin-right: 4px;
color: {$lightbluetext};

View file

@ -52,6 +52,61 @@ JX.behavior('document-engine', function(config, statics) {
});
}
list.addItem(
new JX.PHUIXActionView()
.setDivider(true));
var encode_item = new JX.PHUIXActionView()
.setName(data.encode.name)
.setIcon(data.encode.icon);
var onencode = JX.bind(null, function(data, e) {
e.prevent();
if (encode_item.getDisabled()) {
return;
}
new JX.Workflow(data.encode.uri, {encoding: data.encode.value})
.setHandler(function(r) {
data.encode.value = r.encoding;
onview(data);
})
.start();
menu.close();
}, data);
encode_item.setHandler(onencode);
list.addItem(encode_item);
var highlight_item = new JX.PHUIXActionView()
.setName(data.highlight.name)
.setIcon(data.highlight.icon);
var onhighlight = JX.bind(null, function(data, e) {
e.prevent();
if (highlight_item.getDisabled()) {
return;
}
new JX.Workflow(data.highlight.uri, {highlight: data.highlight.value})
.setHandler(function(r) {
data.highlight.value = r.highlight;
onview(data);
})
.start();
menu.close();
}, data);
highlight_item.setHandler(onhighlight);
list.addItem(highlight_item);
menu.setContent(list.getNode());
menu.listen('open', function() {
@ -61,6 +116,11 @@ JX.behavior('document-engine', function(config, statics) {
// Highlight the current rendering engine.
var is_selected = (engine.spec.viewKey == data.viewKey);
engine.view.setSelected(is_selected);
if (is_selected) {
encode_item.setDisabled(!engine.spec.canEncode);
highlight_item.setDisabled(!engine.spec.canHighlight);
}
}
});
@ -68,14 +128,38 @@ JX.behavior('document-engine', function(config, statics) {
menu.open();
}
function add_params(uri, data) {
uri = JX.$U(uri);
if (data.highlight.value) {
uri.setQueryParam('highlight', data.highlight.value);
}
if (data.encode.value) {
uri.setQueryParam('encode', data.encode.value);
}
return uri.toString();
}
function onview(data, spec, immediate) {
if (!spec) {
for (var ii = 0; ii < data.views.length; ii++) {
if (data.views[ii].viewKey == data.viewKey) {
spec = data.views[ii];
break;
}
}
}
data.sequence = (data.sequence || 0) + 1;
var handler = JX.bind(null, onrender, data, data.sequence);
data.viewKey = spec.viewKey;
JX.History.replace(spec.viewURI);
new JX.Request(spec.engineURI, handler)
var uri = add_params(spec.engineURI, data);
new JX.Request(uri, handler)
.send();
if (data.loadingView) {
@ -91,6 +175,12 @@ JX.behavior('document-engine', function(config, statics) {
var load = JX.bind(null, onloading, data, spec);
data.loadTimer = setTimeout(load, 333);
// Replace the URI with the URI for the specific rendering the user
// has selected.
var view_uri = add_params(spec.viewURI, data);
JX.History.replace(view_uri);
}
}
@ -128,16 +218,10 @@ JX.behavior('document-engine', function(config, statics) {
statics.initialized = true;
}
if (config.renderControlID) {
if (config && config.renderControlID) {
var control = JX.$(config.renderControlID);
var data = JX.Stratcom.getData(control);
for (var ii = 0; ii < data.views.length; ii++) {
if (data.views[ii].viewKey == data.viewKey) {
onview(data, data.views[ii], true);
break;
}
}
onview(data, null, true);
}
});

View file

@ -34,6 +34,10 @@ JX.install('PHUIXActionView', {
return this;
},
getDisabled: function() {
return this._disabled;
},
setLabel: function(label) {
this._label = label;
JX.DOM.alterClass(

View file

@ -185,7 +185,10 @@ JX.install('PHUIXAutocomplete', {
.getNode();
}
map.display = [icon, map.displayName];
var display = JX.$N('span', {}, [icon, map.displayName]);
JX.DOM.alterClass(display, 'tokenizer-result-closed', !!map.closed);
map.display = display;
return map;
},