diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1058,11 +1058,17 @@ 'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php', 'HarbormasterBuildableActionController' => 'applications/harbormaster/controller/HarbormasterBuildableActionController.php', 'HarbormasterBuildableAdapterInterface' => 'applications/harbormaster/herald/HarbormasterBuildableAdapterInterface.php', + 'HarbormasterBuildableBuildPlanHeraldField' => 'applications/harbormaster/herald/HarbormasterBuildableBuildPlanHeraldField.php', + 'HarbormasterBuildableBuildableStatusHeraldField' => 'applications/harbormaster/herald/HarbormasterBuildableBuildableStatusHeraldField.php', + 'HarbormasterBuildableHeraldField' => 'applications/harbormaster/herald/HarbormasterBuildableHeraldField.php', + 'HarbormasterBuildableHeraldFieldGroup' => 'applications/harbormaster/herald/HarbormasterBuildableHeraldFieldGroup.php', 'HarbormasterBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildableInterface.php', 'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php', 'HarbormasterBuildablePHIDType' => 'applications/harbormaster/phid/HarbormasterBuildablePHIDType.php', 'HarbormasterBuildableQuery' => 'applications/harbormaster/query/HarbormasterBuildableQuery.php', 'HarbormasterBuildableSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildableSearchEngine.php', + 'HarbormasterBuildableStatus' => 'applications/harbormaster/constants/HarbormasterBuildableStatus.php', + 'HarbormasterBuildableStatusDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildableStatusDatasource.php', 'HarbormasterBuildableTransaction' => 'applications/harbormaster/storage/HarbormasterBuildableTransaction.php', 'HarbormasterBuildableTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php', 'HarbormasterBuildableTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildableTransactionQuery.php', @@ -1155,6 +1161,8 @@ 'HeraldFieldTestCase' => 'applications/herald/field/__tests__/HeraldFieldTestCase.php', 'HeraldFieldValue' => 'applications/herald/value/HeraldFieldValue.php', 'HeraldGroup' => 'applications/herald/group/HeraldGroup.php', + 'HeraldHarbormasterAdapter' => 'applications/harbormaster/herald/HeraldHarbormasterAdapter.php', + 'HeraldHarbormasterBuildableAdapter' => 'applications/harbormaster/herald/HeraldHarbormasterBuildableAdapter.php', 'HeraldInvalidActionException' => 'applications/herald/engine/exception/HeraldInvalidActionException.php', 'HeraldInvalidConditionException' => 'applications/herald/engine/exception/HeraldInvalidConditionException.php', 'HeraldManageGlobalRulesCapability' => 'applications/herald/capability/HeraldManageGlobalRulesCapability.php', @@ -5186,10 +5194,16 @@ 'HarbormasterBuildableInterface', ), 'HarbormasterBuildableActionController' => 'HarbormasterController', + 'HarbormasterBuildableBuildPlanHeraldField' => 'HarbormasterBuildableHeraldField', + 'HarbormasterBuildableBuildableStatusHeraldField' => 'HarbormasterBuildableHeraldField', + 'HarbormasterBuildableHeraldField' => 'HeraldField', + 'HarbormasterBuildableHeraldFieldGroup' => 'HeraldFieldGroup', 'HarbormasterBuildableListController' => 'HarbormasterController', 'HarbormasterBuildablePHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildableQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildableSearchEngine' => 'PhabricatorApplicationSearchEngine', + 'HarbormasterBuildableStatus' => 'Phobject', + 'HarbormasterBuildableStatusDatasource' => 'PhabricatorTypeaheadDatasource', 'HarbormasterBuildableTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildableTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildableTransactionQuery' => 'PhabricatorApplicationTransactionQuery', @@ -5288,6 +5302,8 @@ 'HeraldFieldTestCase' => 'PhutilTestCase', 'HeraldFieldValue' => 'Phobject', 'HeraldGroup' => 'Phobject', + 'HeraldHarbormasterAdapter' => 'HeraldAdapter', + 'HeraldHarbormasterBuildableAdapter' => 'HeraldHarbormasterAdapter', 'HeraldInvalidActionException' => 'Exception', 'HeraldInvalidConditionException' => 'Exception', 'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability', diff --git a/src/applications/harbormaster/constants/HarbormasterBuildableStatus.php b/src/applications/harbormaster/constants/HarbormasterBuildableStatus.php new file mode 100644 --- /dev/null +++ b/src/applications/harbormaster/constants/HarbormasterBuildableStatus.php @@ -0,0 +1,15 @@ +getTransactionType()) { case HarbormasterBuildableTransaction::TYPE_CREATE: + case HarbormasterBuildableTransaction::TYPE_STATUS: case HarbormasterBuildableTransaction::TYPE_COMMAND: return null; } @@ -40,6 +42,7 @@ switch ($xaction->getTransactionType()) { case HarbormasterBuildableTransaction::TYPE_CREATE: return true; + case HarbormasterBuildableTransaction::TYPE_STATUS: case HarbormasterBuildableTransaction::TYPE_COMMAND: return $xaction->getNewValue(); } @@ -54,6 +57,7 @@ switch ($xaction->getTransactionType()) { case HarbormasterBuildableTransaction::TYPE_CREATE: case HarbormasterBuildableTransaction::TYPE_COMMAND: + case HarbormasterBuildableTransaction::TYPE_STATUS: return; } @@ -67,10 +71,29 @@ switch ($xaction->getTransactionType()) { case HarbormasterBuildableTransaction::TYPE_CREATE: case HarbormasterBuildableTransaction::TYPE_COMMAND: + case HarbormasterBuildableTransaction::TYPE_STATUS: return; } return parent::applyCustomExternalTransaction($object, $xaction); } +/* -( Herald Integration )------------------------------------------------- */ + protected function shouldApplyHeraldRules( + PhabricatorLiskDAO $object, + array $xactions) { + + return true; + } + + protected function buildHeraldAdapter( + PhabricatorLiskDAO $object, + array $xactions) { + + $adapter = id(new HeraldHarbormasterBuildableAdapter()) + ->setBuildable($object); + + return $adapter; + } + } diff --git a/src/applications/harbormaster/engine/HarbormasterBuildEngine.php b/src/applications/harbormaster/engine/HarbormasterBuildEngine.php --- a/src/applications/harbormaster/engine/HarbormasterBuildEngine.php +++ b/src/applications/harbormaster/engine/HarbormasterBuildEngine.php @@ -427,6 +427,7 @@ ->setViewer($viewer) ->withPHIDs(array($buildable->getBuildablePHID())) ->executeOne(); + if (!$object) { return; } @@ -435,6 +436,26 @@ return; } + $daemon_source = PhabricatorContentSource::newForSource( + PhabricatorContentSource::SOURCE_DAEMON, + array()); + + $harbormaster_phid = id(new PhabricatorHarbormasterApplication()) + ->getPHID(); + + $buildable_editor = id(new HarbormasterBuildableTransactionEditor()) + ->setActor($viewer) + ->setActingAsPHID($harbormaster_phid) + ->setContentSource($daemon_source) + ->setContinueOnNoEffect(true) + ->setContinueOnMissingFields(true); + + $xaction = id(new HarbormasterBuildableTransaction()) + ->setTransactionType(HarbormasterBuildableTransaction::TYPE_STATUS) + ->setNewValue($new_status); + + $buildable_editor->applyTransactions($buildable, array($xaction)); + // TODO: Publishing these transactions is causing a race. See T8650. // We shouldn't be publishing to diffs anyway. if ($object instanceof DifferentialDiff) { @@ -454,13 +475,6 @@ ->setOldValue($old_status) ->setNewValue($new_status); - $harbormaster_phid = id(new PhabricatorHarbormasterApplication()) - ->getPHID(); - - $daemon_source = PhabricatorContentSource::newForSource( - PhabricatorContentSource::SOURCE_DAEMON, - array()); - $editor = $object->getApplicationTransactionEditor() ->setActor($viewer) ->setActingAsPHID($harbormaster_phid) diff --git a/src/applications/harbormaster/herald/HarbormasterBuildableBuildPlanHeraldField.php b/src/applications/harbormaster/herald/HarbormasterBuildableBuildPlanHeraldField.php new file mode 100644 --- /dev/null +++ b/src/applications/harbormaster/herald/HarbormasterBuildableBuildPlanHeraldField.php @@ -0,0 +1,32 @@ +getAdapter()->loadBuilds(); + + if (!$builds) { + return null; + } + + return mpull($builds, 'getBuildPlanPHID'); + } + + protected function getHeraldFieldStandardType() { + return self::STANDARD_PHID_LIST; + } + + protected function getDatasource() { + return new HarbormasterBuildPlanDatasource(); + } + +} diff --git a/src/applications/harbormaster/herald/HarbormasterBuildableBuildableStatusHeraldField.php b/src/applications/harbormaster/herald/HarbormasterBuildableBuildableStatusHeraldField.php new file mode 100644 --- /dev/null +++ b/src/applications/harbormaster/herald/HarbormasterBuildableBuildableStatusHeraldField.php @@ -0,0 +1,28 @@ +getBuildableStatus(); + } + + protected function getHeraldFieldStandardType() { + return self::STANDARD_PHID; + } + + protected function getDatasource() { + return new HarbormasterBuildableStatusDatasource(); + } + + protected function getDatasourceValueMap() { + return HarbormasterBuildableStatus::getBuildableStatusMap(); + } + +} diff --git a/src/applications/harbormaster/herald/HarbormasterBuildableHeraldField.php b/src/applications/harbormaster/herald/HarbormasterBuildableHeraldField.php new file mode 100644 --- /dev/null +++ b/src/applications/harbormaster/herald/HarbormasterBuildableHeraldField.php @@ -0,0 +1,14 @@ +builds === false) { + $buildable_id = $this->getObject()->getID(); + + if ($buildable_id) { + $builds = id(new HarbormasterBuildableQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withIDs([$buildable_id]) + ->needBuilds(true) + ->executeOne() + ->getBuilds(); + } else { + $builds = null; + } + + $this->builds = $builds; + } + + return $this->builds; + } + +} diff --git a/src/applications/harbormaster/herald/HeraldHarbormasterBuildableAdapter.php b/src/applications/harbormaster/herald/HeraldHarbormasterBuildableAdapter.php new file mode 100644 --- /dev/null +++ b/src/applications/harbormaster/herald/HeraldHarbormasterBuildableAdapter.php @@ -0,0 +1,63 @@ +buildable = $this->newObject(); + } + + public function getObject() { + return $this->buildable; + } + + public function getAdapterContentType() { + return 'harbormaster.buildable'; + } + + public function getAdapterContentName() { + return pht('Harbormaster Buildable'); + } + + public function getAdapterContentDescription() { + return pht( + 'React to a buildable that has been created or updated.'); + } + + public function supportsRuleType($rule_type) { + switch ($rule_type) { + case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL: + return true; + case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL: + case HeraldRuleTypeConfig::RULE_TYPE_OBJECT: + default: + return false; + } + } + + public function getHeraldName() { + return $this->buildable->getMonogram(); + } + + /** + * Only used for testing since the actual Herable API + * never makes use of this function. + **/ + public function setBuildable(HarbormasterBuildable $buildable) { + $this->buildable = clone $buildable; + $this->loadBuilds(); + + return $this; + } + +} diff --git a/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php b/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php --- a/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php @@ -4,6 +4,7 @@ extends PhabricatorApplicationTransaction { const TYPE_CREATE = 'harbormaster:buildable:create'; + const TYPE_STATUS = 'harbormaster:buildable:status'; const TYPE_COMMAND = 'harbormaster:buildable:command'; public function getApplicationName() { @@ -25,6 +26,17 @@ return pht( '%s created this buildable.', $this->renderHandleLink($author_phid)); + case self::TYPE_STATUS: + switch ($new) { + case HarbormasterBuildable::STATUS_FAILED: + return pht( + '%s marked buildable as failed', + $this->renderHandleLink($author_phid)); + case HarbormasterBuildable::STATUS_PASSED: + return pht( + '%s marked buildable as passed', + $this->renderHandleLink($author_phid)); + } case self::TYPE_COMMAND: switch ($new) { case HarbormasterBuildCommand::COMMAND_RESTART: @@ -62,6 +74,13 @@ case HarbormasterBuildCommand::COMMAND_PAUSE: return 'fa-pause'; } + case self::TYPE_STATUS: + switch ($new) { + case HarbormasterBuildable::STATUS_FAILED: + return 'fa-minus'; + case HarbormasterBuildable::STATUS_PASSED: + return 'fa-check'; + } } return parent::getIcon(); @@ -81,6 +100,13 @@ case HarbormasterBuildCommand::COMMAND_PAUSE: return 'red'; } + case self::TYPE_STATUS: + switch ($new) { + case HarbormasterBuildable::STATUS_FAILED: + return 'red'; + case HarbormasterBuildable::STATUS_PASSED: + return 'green'; + } } return parent::getColor(); } diff --git a/src/applications/harbormaster/typeahead/HarbormasterBuildableStatusDatasource.php b/src/applications/harbormaster/typeahead/HarbormasterBuildableStatusDatasource.php new file mode 100644 --- /dev/null +++ b/src/applications/harbormaster/typeahead/HarbormasterBuildableStatusDatasource.php @@ -0,0 +1,43 @@ +buildResults(); + return $this->filterResultsAgainstTokens($results); + } + + public function renderTokens(array $values) { + return $this->renderTokensFromResults($this->buildResults(), $values); + } + + private function buildResults() { + $results = array(); + + $status_map = HarbormasterBuildableStatus::getBuildableStatusMap(); + foreach ($status_map as $status) { + $result = id(new PhabricatorTypeaheadResult()) + ->setIcon(HarbormasterBuildable::getBuildableStatusIcon($status)) + ->setPHID($status) + ->setName(HarbormasterBuildable::getBuildableStatusName($status)); + + $results[$status] = $result; + } + + return $results; + } + +} diff --git a/src/applications/herald/controller/HeraldTestConsoleController.php b/src/applications/herald/controller/HeraldTestConsoleController.php --- a/src/applications/herald/controller/HeraldTestConsoleController.php +++ b/src/applications/herald/controller/HeraldTestConsoleController.php @@ -45,6 +45,9 @@ } else if ($object instanceof PhrictionDocument) { $adapter = id(new PhrictionDocumentHeraldAdapter()) ->setDocument($object); + } else if ($object instanceof HarbormasterBuildable) { + $adapter = id(new HeraldHarbormasterBuildableAdapter()) + ->setBuildable($object); } else if ($object instanceof PonderQuestion) { $adapter = id(new HeraldPonderQuestionAdapter()) ->setQuestion($object);