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 @@ -4457,6 +4457,22 @@ 'ProjectReplyHandler' => 'applications/project/mail/ProjectReplyHandler.php', 'ProjectSearchConduitAPIMethod' => 'applications/project/conduit/ProjectSearchConduitAPIMethod.php', 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', + 'ReleaseChangeRequest' => 'applications/release/storage/ReleaseChangeRequest.php', + 'ReleaseChangeRequestCommitImplementation' => 'applications/release/changes/ReleaseChangeRequestCommitImplementation.php', + 'ReleaseChangeRequestCustomField' => 'applications/release/customfield/ReleaseChangeRequestCustomField.php', + 'ReleaseChangeRequestCustomFieldNumericIndex' => 'applications/release/storage/ReleaseChangeRequestCustomFieldNumericIndex.php', + 'ReleaseChangeRequestCustomFieldStorage' => 'applications/release/storage/ReleaseChangeRequestCustomFieldStorage.php', + 'ReleaseChangeRequestCustomFieldStringIndex' => 'applications/release/storage/ReleaseChangeRequestCustomFieldStringIndex.php', + 'ReleaseChangeRequestDetailsController' => 'applications/release/controller/ReleaseChangeRequestDetailsController.php', + 'ReleaseChangeRequestEditor' => 'applications/release/editor/ReleaseChangeRequestEditor.php', + 'ReleaseChangeRequestFromRevisionController' => 'applications/release/controller/ReleaseChangeRequestFromRevisionController.php', + 'ReleaseChangeRequestImplementation' => 'applications/release/changes/ReleaseChangeRequestImplementation.php', + 'ReleaseChangeRequestPHIDType' => 'applications/release/phid/ReleaseChangeRequestPHIDType.php', + 'ReleaseChangeRequestQuery' => 'applications/release/query/ReleaseChangeRequestQuery.php', + 'ReleaseChangeRequestRevisionImplementation' => 'applications/release/changes/ReleaseChangeRequestRevisionImplementation.php', + 'ReleaseChangeRequestStateTransaction' => 'applications/release/xaction/ReleaseChangeRequestStateTransaction.php', + 'ReleaseChangeRequestTransaction' => 'applications/release/storage/ReleaseChangeRequestTransaction.php', + 'ReleaseChangeRequestTransactionType' => 'applications/release/xaction/ReleaseChangeRequestTransactionType.php', 'ReleaseCustomField' => 'applications/release/customfield/ReleaseCustomField.php', 'ReleaseCustomFieldNumericIndex' => 'applications/release/storage/ReleaseCustomFieldNumericIndex.php', 'ReleaseCustomFieldStorage' => 'applications/release/storage/ReleaseCustomFieldStorage.php', @@ -4464,6 +4480,7 @@ 'ReleaseReleaseEditController' => 'applications/release/controller/ReleaseReleaseEditController.php', 'ReleaseReleaseListController' => 'applications/release/controller/ReleaseReleaseListController.php', 'ReleaseReleaseViewController' => 'applications/release/controller/ReleaseReleaseViewController.php', + 'ReleaseRenderEventListener' => 'applications/release/ReleaseRenderEventListener.php', 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', 'ReleephBranchAccessController' => 'applications/releeph/controller/branch/ReleephBranchAccessController.php', @@ -9855,6 +9872,27 @@ 'ProjectReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'ProjectSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod', 'QueryFormattingTestCase' => 'PhabricatorTestCase', + 'ReleaseChangeRequest' => array( + 'PhabricatorReleaseDAO', + 'PhabricatorApplicationTransactionInterface', + 'PhabricatorPolicyInterface', + 'PhabricatorCustomFieldInterface', + ), + 'ReleaseChangeRequestCommitImplementation' => 'Phobject', + 'ReleaseChangeRequestCustomField' => 'PhabricatorCustomField', + 'ReleaseChangeRequestCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', + 'ReleaseChangeRequestCustomFieldStorage' => 'PhabricatorCustomFieldStorage', + 'ReleaseChangeRequestCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', + 'ReleaseChangeRequestDetailsController' => 'PhabricatorController', + 'ReleaseChangeRequestEditor' => 'PhabricatorApplicationTransactionEditor', + 'ReleaseChangeRequestFromRevisionController' => 'PhabricatorController', + 'ReleaseChangeRequestImplementation' => 'Phobject', + 'ReleaseChangeRequestPHIDType' => 'PhabricatorPHIDType', + 'ReleaseChangeRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'ReleaseChangeRequestRevisionImplementation' => 'ReleaseChangeRequestImplementation', + 'ReleaseChangeRequestStateTransaction' => 'ReleaseChangeRequestTransactionType', + 'ReleaseChangeRequestTransaction' => 'PhabricatorModularTransaction', + 'ReleaseChangeRequestTransactionType' => 'PhabricatorModularTransactionType', 'ReleaseCustomField' => 'PhabricatorCustomField', 'ReleaseCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'ReleaseCustomFieldStorage' => 'PhabricatorCustomFieldStorage', @@ -9862,6 +9900,7 @@ 'ReleaseReleaseEditController' => 'PhabricatorController', 'ReleaseReleaseListController' => 'PhabricatorController', 'ReleaseReleaseViewController' => 'PhabricatorController', + 'ReleaseRenderEventListener' => 'PhabricatorEventListener', 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', 'ReleephBranch' => array( 'ReleephDAO', diff --git a/src/applications/release/ReleaseRenderEventListener.php b/src/applications/release/ReleaseRenderEventListener.php new file mode 100644 --- /dev/null +++ b/src/applications/release/ReleaseRenderEventListener.php @@ -0,0 +1,52 @@ +listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS); + } + + public function handleEvent(PhutilEvent $event) { + switch ($event->getType()) { + case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS: + $this->handleActionsEvent($event); + break; + } + } + + private function handleActionsEvent(PhutilEvent $event) { + if (!$this->canUseApplication($event->getUser())) { + return; + } + + $object = $event->getValue('object'); + + if ($object instanceof DifferentialRevision) { + $this->addRevisionAction($event, $object); + } + // if ($object instanceof PhabricatorRepository) { + // $this->addRepositoryActions($event); + // } + // if ($object instanceof PhabricatorRepositoryCommit) { + // $this->addCommitActions($event); + // } + } + + private function addRevisionAction( + PhutilEvent $event, + DifferentialRevision $revision) { + + $repository = $revision->getRepository(); + if (!$repository) { + return; + } + $revision_phid = $revision->getPHID(); + $actions[] = id(new PhabricatorActionView()) + ->setWorkflow(true) + ->setName('Request Pick To Release') + ->setIcon('fa-steam') + ->setHref("/release/request/revision/{$revision_phid}/"); + + $this->addActionMenuItems($event, $actions); + } +} diff --git a/src/applications/release/application/PhabricatorReleaseApplication.php b/src/applications/release/application/PhabricatorReleaseApplication.php --- a/src/applications/release/application/PhabricatorReleaseApplication.php +++ b/src/applications/release/application/PhabricatorReleaseApplication.php @@ -54,11 +54,15 @@ public function getRoutes() { return array( '/X(?P[1-9]\d*)' => 'ReleaseReleaseViewController', + '/Y(?P[1-9]\d*)' => 'ReleaseChangeRequestDetailsController', '/release/' => array( $this->getEditRoutePattern('edit/') => 'ReleaseReleaseEditController', '(?:query/(?P[^/]+)/)?' => 'ReleaseReleaseListController', // TODO new release - + '/request/' => array( + 'revision/[^/]*)/' => +'ReleaseChangeRequestFromRevisionController', +), ), ); } diff --git a/src/applications/release/changes/ReleaseChangeRequestCommitImplementation.php b/src/applications/release/changes/ReleaseChangeRequestCommitImplementation.php new file mode 100644 --- /dev/null +++ b/src/applications/release/changes/ReleaseChangeRequestCommitImplementation.php @@ -0,0 +1,7 @@ +getPhobjectClassConstant('IMPLEMENTATION_KEY'); + } + + public function createRequest() { + return id(new ReleaseChangeRequest()) + ->setImplementationKey($this->getImplementationKey()) + ->setRequestReference($this->getRequestReference()); + } + + + /** + * Return the value to use for the requestReference field in the Request. + */ + protected abstract function getRequestReference(); + + +} diff --git a/src/applications/release/changes/ReleaseChangeRequestRevisionImplementation.php b/src/applications/release/changes/ReleaseChangeRequestRevisionImplementation.php new file mode 100644 --- /dev/null +++ b/src/applications/release/changes/ReleaseChangeRequestRevisionImplementation.php @@ -0,0 +1,21 @@ +revisionPHID = $phid; + return $this; + } + + protected function getRequestReference() { + return $this->revisionPHID; + } +} diff --git a/src/applications/release/controller/ReleaseChangeRequestDetailsController.php b/src/applications/release/controller/ReleaseChangeRequestDetailsController.php new file mode 100755 --- /dev/null +++ b/src/applications/release/controller/ReleaseChangeRequestDetailsController.php @@ -0,0 +1,109 @@ +getViewer(); + $id = $request->getURIData('id'); + + $change = id(new ReleaseChangeRequestQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needReleases(true) + ->executeOne(); + if (!$change) { + return new Aphront404Response(); + } + $release = $change->getRelease(); + + $header = id(new PHUIHeaderView()) + ->setHeader( + hsprintf('%s %s', $change->getMonogram(), $change->getTitle())) + ->setUser($viewer) + ->setPolicyObject($release); + $curtain = $this->buildCurtain($change); + + $release_properties = $this->buildReleaseProperties($release); + $change_properties = $this->buildChangeProperties($change); + + $timeline = $this->buildTransactionTimeline( + $change, + new ReleaseChangeRequestTransactionQuery()); + $timeline->setQuoteRef($change->getMonogram()); + + $view = id(new PHUITwoColumnView()) + ->setHeader($header) + ->setCurtain($curtain) + ->setMainColumn(array( + $timeline, + // $comment_view, + )) + ->addPropertySection($release->getName(), $release_properties) + ->addPropertySection(pht('Change Request'), $change_properties); + + + // release information (lite) + // request properties + // message + // actions + // timeline + + // crumbs = release crumbs + this change. + + $title = $change->getTitle(); + return $this->newPage() + ->setTitle($change->getMonogram().' '.$title) + // ->setCrumbs($crumbs) + ->setPageObjectPHIDs( + array( + $release->getPHID(), + $change->getPHID(), + )) + ->appendChild( + array( + $view, + )); + + } + + + private function buildChangeProperties($change) { + $viewer = $this->getViewer(); + + $requestor = $viewer->renderHandle($change->getRequestorPHID()) + ->setShowHovercard(true); + $status = $change->getStatus(); // houmanize + + $properties = id(new PHUIPropertyListView()) + ->addProperty(pht('Type'), $change->getImplementationKey()) // humanize + ->addProperty(pht('Requested By'), $requestor) + ->addProperty(pht('Status'), $status); +// author - implementation specific! + + + $description = $change->getDescription(); + if (strlen($description)) { + $properties + ->addSectionHeader('Description') + ->addTextContent( + new PHUIRemarkupView($this->getViewer(), $description)); + } + + // TODO custom fields + + return $properties; + } + + private function buildReleaseProperties($release) { + $properties = id(new PHUIPropertyListView()) + ->addProperty(pht('Release Type'), $release->getReleaseTemplateName()) + ->addProperty(pht('Status'), $release->getStateName()); + + return $properties; + } + + private function buildCurtain($release) { + $curtain = $this->newCurtainView($release); + return $curtain; + } + +} \ No newline at end of file diff --git a/src/applications/release/controller/ReleaseChangeRequestFromRevisionController.php b/src/applications/release/controller/ReleaseChangeRequestFromRevisionController.php new file mode 100755 --- /dev/null +++ b/src/applications/release/controller/ReleaseChangeRequestFromRevisionController.php @@ -0,0 +1,118 @@ +getViewer(); + + $revision_phid = $request->getURIData('revision'); + + $revision = id(new DifferentialRevisionQuery()) + ->withPHIDs(array($revision_phid)) + ->setViewer($viewer) + ->executeOne(); + if (!$revision) { + return new Aphront404Response(); + } + + $repository = $revision->getRepository(); + $errors = array(); + + // TODO requireCapability + + $v_release = null; + $e_release = true; + + $v_message = null; + + if ($request->isDialogFormPost()) { + + $v_release = $request->getArr('release'); + if (!$v_release) { + $e_release = pht('Required'); + $errors[] = 'Specify target release'; + } else { + $release = id(new PhabricatorReleaseReleaseQuery()) + ->setViewer($viewer) + ->withPHIDs($v_release) + ->executeOne(); + + // if (!$release->canAcceptChangeRequests()) { // TODO + // $e_release = pht('Invalid'); + // $errors[] = + // pht('This release can not accept cany change requests at this time.'); + // } + } + + $v_message = $request->getStr('message'); + + $actor_phid = $viewer->getPHID(); + $revision_id = $revision->getID(); + + if (!$errors) { + + $implementation = id(new ReleaseChangeRequestRevisionImplementation()) + ->setRevisionPHID($revision_phid); + $change_request = $implementation->createRequest() + ->setRequestorPHID($actor_phid) + ->setReleasePHID($release->getPHID()) + ->setDescription($v_message); + + $xactions = array( + id(new ReleaseChangeRequestTransaction()) + ->setTransactionType(PhabricatorTransactions::TYPE_CREATE), + ); + $editor = id(new ReleaseChangeRequestEditor()) + ->setActor($viewer) + ->setContentSource( + PhabricatorContentSource::newFromRequest($request)); + $editor->applyTransactions($change_request, $xactions); + + // maybe add some xactions to the Release here. + + return id(new AphrontRedirectResponse())->setURI($change_request->getURI()); + } + } + + $prompt = hsprintf( + 'This will request the Release Managers to include this Revision in the '. + 'selected Release.'); + + // TODO filter only to relevant releases + $datasource = id(new PhabricatorReleaseReleaseDatasource()); + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendControl( + id(new AphrontFormTokenizerControl()) + ->setDatasource($datasource) + ->setLimit(1) + ->setName('release') + ->setLabel(pht('Release')) + ->setValue($v_release) + ->setError($e_release)) + ->appendControl( + id(new PhabricatorRemarkupControl()) + ->setLabel('Reason') + ->setValue($v_message) + ->setName('message')); + + $errors_view = null; + if ($errors) { + $errors_view = id(new PHUIInfoView()) + ->setErrors($errors); + } + + $dialog = $this->newDialog() + ->setTitle(pht('Pick Revision to Release?')) + ->appendChild($prompt) + ->appendChild($errors_view) + ->appendForm($form) + ->addSubmitButton(pht('Please')) + ->addCancelButton('#'); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + +} diff --git a/src/applications/release/controller/ReleaseReleaseViewController.php b/src/applications/release/controller/ReleaseReleaseViewController.php --- a/src/applications/release/controller/ReleaseReleaseViewController.php +++ b/src/applications/release/controller/ReleaseReleaseViewController.php @@ -59,6 +59,7 @@ $comment_view->setTransactionTimeline($timeline); $commits = $this->buildCommitsSection($viewer, $release); + $changes = $this->buildChangesSection($viewer, $release); $view = id(new PHUITwoColumnView()) ->setHeader($header) @@ -68,7 +69,8 @@ $comment_view, )) ->addPropertySection(pht('Details'), $properties) - ->addPropertySection(pht('Repositories'), $commits); + ->addPropertySection(pht('Repositories'), $commits) + ->addPropertySection(pht('Pending Changes'), $changes); return $this->newPage() ->setTitle('X'.$release->getID().' '.$release_name) @@ -83,6 +85,41 @@ )); } + private function buildChangesSection($viewer, $release) { + // TODO see all + $changes = id(new ReleaseChangeRequestQuery()) + ->setViewer($viewer) + ->setLimit(4) // TODO TODO TODO + ->withReleasePHIDs(array($release->getPHID())) + ->withStatuses(array(ReleaseChangeRequest::STATUS_PENDING)) + ->execute(); + + if (!$changes) { + return null; + } + + $list = id(new PHUIObjectItemListView()); + + foreach ($changes as $change) { + $item = id(new PHUIObjectItemView()) + ->setObjectName($change->getMonogram()) + ->setHref($change->getURI()) + ->setHeader($change->getTitle()) + ->addAttribute(pht('(impl: %s)', $change->getImplementationKey())); + + $field_list = PhabricatorCustomField::getObjectFields( + $change, + PhabricatorCustomField::ROLE_LIST); + $field_list + ->appendFieldsToListItem($change, $this->getViewer(), $item); + + $list->addItem($item); + } + + return $list; + } + + private function buildCommitsSection($viewer, $release) { $cutpoints = $release->getCutpoints(); $currentrefs = $release->getCurrentRefs(); diff --git a/src/applications/release/customfield/ReleaseChangeRequestCustomField.php b/src/applications/release/customfield/ReleaseChangeRequestCustomField.php new file mode 100755 --- /dev/null +++ b/src/applications/release/customfield/ReleaseChangeRequestCustomField.php @@ -0,0 +1,24 @@ + + pht('Other activity not listed above occurs.'), + ); + } + + protected function buildReplyHandler(PhabricatorLiskDAO $object) { + return id(new PhabricatorReleaseReleaseReplyHandler()) + ->setMailReceiver($object); + } + + + protected function buildMailTemplate(PhabricatorLiskDAO $object) { + $id = $object->getID(); + $name = $object->getName(); + + return id(new PhabricatorMetaMTAMail()) + ->setSubject("Y{$id} {$name}") + ->addHeader('Thread-Topic', "Change Request {$id}"); + } + + protected function shouldPublishFeedStory( + PhabricatorLiskDAO $object, + array $xactions) { + + return true; + } + + protected function supportsSearch() { + return false; + } + + protected function expandTransaction( + PhabricatorLiskDAO $release, + PhabricatorApplicationTransaction $xaction) { + $xactions = parent::expandTransaction($release, $xaction); + + return $xactions; + } + + protected function getMailTo(PhabricatorLiskDAO $object) { + $tos = array(); + return $tos; + } + + protected function buildMailBody( + PhabricatorLiskDAO $object, + array $xactions) { + + $body = parent::buildMailBody($object, $xactions); + + foreach ($xactions as $xaction) { + $type = $xaction->getTransactionType(); + $new = $xaction->getNewValue(); + } + + $body->addLinkSection( + pht('REQUEST DETAILS'), + PhabricatorEnv::getProductionURI($object->getURI())); + + return $body; + } + +} diff --git a/src/applications/release/phid/ReleaseChangeRequestPHIDType.php b/src/applications/release/phid/ReleaseChangeRequestPHIDType.php new file mode 100755 --- /dev/null +++ b/src/applications/release/phid/ReleaseChangeRequestPHIDType.php @@ -0,0 +1,44 @@ +withPHIDs($phids); + } + + public function loadHandles( + PhabricatorHandleQuery $query, + array $handles, + array $objects) { + + foreach ($handles as $phid => $handle) { /// modernize this? support lookup by monogram. + $request = $objects[$phid]; + + $id = $request->getID(); + $title = $request->getTitle(); + + $handle->setURI("/Y{$id}"); + $handle->setName($title); + $handle->setFullName("Y{$id}: {$title}"); + } + } + +} diff --git a/src/applications/release/query/ReleaseChangeRequestQuery.php b/src/applications/release/query/ReleaseChangeRequestQuery.php new file mode 100755 --- /dev/null +++ b/src/applications/release/query/ReleaseChangeRequestQuery.php @@ -0,0 +1,196 @@ +ids = $ids; + return $this; + } + + public function withPHIDs(array $phids) { + $this->phids = $phids; + return $this; + } + + public function withReleasePHIDs(array $release_phids) { + $this->releasePHIDs = $release_phids; + return $this; + } + + public function withStatuses(array $statuses) { + $this->statuses = $statuses; + return $this; + } + + public function withImplementationKeys(array $implementation_keys) { + $this->implementationKeys = $implementation_keys; + return $this; + } + + public function withDatasourceQuery($query) { + $this->datasourceQuery = $query; + return $this; + } + + public function needReleases($need_releases) { + $this->needReleases = $need_releases; + return $this; + } + + public function newResultObject() { + return new ReleaseChangeRequest(); + } + + protected function loadPage() { + return $this->loadStandardPage($this->newResultObject()); + } + + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { + $where = parent::buildWhereClauseParts($conn); + + if ($this->ids !== null) { + $where[] = qsprintf( + $conn, + 'id IN (%Ld)', + $this->ids); + } + + if ($this->phids !== null) { + $where[] = qsprintf( + $conn, + 'phid IN (%Ls)', + $this->phids); + } + + if ($this->releasePHIDs !== null) { + $where[] = qsprintf( + $conn, + 'releasePHID IN (%Ls)', + $this->releasePHIDs); + } + + if ($this->statuses !== null) { + $where[] = qsprintf( + $conn, + 'status IN (%Ls)', + $this->statuses); + } + + if ($this->implementationKeys !== null) { + $where[] = qsprintf( + $conn, + 'implementationKey IN (%Ls)', + $this->implementationKeys); + } + + if (strlen($this->datasourceQuery)) { + // TODO + // $where[] = qsprintf( + // $conn, + // 'name LIKE %~', + // $this->datasourceQuery); + } + + return $where; + } + + protected function didFilterPage(array $objects) { + $viewer = $this->getViewer(); + + if ($this->needReleases) { + $release_phids = mpull($objects, 'getReleasePHID'); + $releases = id(new PhabricatorReleaseReleaseQuery()) + ->setViewer($viewer) + ->setParentQuery($this) + ->withPHIDs($release_phids) + ->execute(); + $releases = mpull($releases, null, 'getPHID'); + + foreach ($objects as $change) { + $change->attachRelease(idx($releases, $change->getReleasePHID())); + } + } + + return $objects; + } + + // protected function getDefaultOrderVector() { + // return array('name'); + // } + + public function getBuiltinOrders() { + return array( + 'name' => array( + 'vector' => array('name'), + 'name' => pht('Name'), + ), + 'select' => array( + 'vector' => array('state', 'name'), + 'name' => pht('Name'), + ), + ) + parent::getBuiltinOrders(); + } + + public function setGroupBy($group) { + $this->groupBy = $group; + $vector = array(); + + switch ($this->groupBy) { + case self::GROUP_NONE: + $vector = array(); + break; + case self::GROUP_STATE: + $vector = array('status'); + break; + } + + // $this->setGroupVector($vector); + + return $this; + } + + public function getOrderableColumns() { + return parent::getOrderableColumns() + array( + 'name' => array( + 'table' => $this->getPrimaryTableAlias(), + 'column' => 'name', + 'reverse' => true, + 'type' => 'string', + 'unique' => true, + ), + 'release' => array( + 'table' => $this->getPrimaryTableAlias(), + 'column' => 'releasePHID', + 'reverse' => false, + 'type' => 'phid', + 'unique' => false, + ), + 'state' => array( + 'table' => $this->getPrimaryTableAlias(), + 'column' => 'state', + 'reverse' => false, + 'type' => 'string', + 'unique' => false, + ), + ); + } + + public function getQueryApplicationClass() { + return 'PhabricatorReleaseApplication'; + } + +} diff --git a/src/applications/release/storage/ReleaseChangeRequest.php b/src/applications/release/storage/ReleaseChangeRequest.php new file mode 100644 --- /dev/null +++ b/src/applications/release/storage/ReleaseChangeRequest.php @@ -0,0 +1,155 @@ +getDetails(), $key, $default); + } + + public function setDetail($key, $value) { + $this->details[$key] = $value; + return $this; + } + + public function getURI() { + return '/Y'.$this->getID(); + } + + public function getMonogram() { + return 'Y'.$this->getID(); + } + + protected function getConfiguration() { + return array( + self::CONFIG_AUX_PHID => true, + self::CONFIG_SERIALIZATION => array( + 'details' => self::SERIALIZATION_JSON, + ), + self::CONFIG_COLUMN_SCHEMA => array( + 'requestorPHID' => 'phid', + 'releasePHID' => 'phid', + 'requestReference' => 'text255', + 'status' => 'text32', + 'implementationKey' => 'text32', + ), + self::CONFIG_KEY_SCHEMA => array( + 'key_release' => array( + 'columns' => array('releasePHID'), + 'unique' => false, + ), + ), + ) + parent::getConfiguration(); + } + + public function getPHIDType() { + return ReleaseChangeRequestPHIDType::TYPECONST; + } + + public function attachRelease(PhabricatorReleaseRelease $release) { + $this->release = $release; + return $this; + } + public function getRelease() { + return $this->assertAttached($this->release); + } + +/* -( PhabricatorApplicationTransactionInterface )------------------------- */ + + public function getApplicationTransactionEditor() { + return new ReleaseChangeRequestEditor(); + } + + public function getApplicationTransactionObject() { + return $this; + } + + public function getApplicationTransactionTemplate() { + return new ReleaseChangeRequestTransaction(); + } + + public function willRenderTimeline( + PhabricatorApplicationTransactionView $timeline, + AphrontRequest $request) { + + return $timeline; + } + + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + ); + } + + public function getPolicy($capability) { + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + case PhabricatorPolicyCapability::CAN_EDIT: // TODO + return PhabricatorPolicies::POLICY_USER; + } + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return false; + } + + +/* -( PhabricatorCustomFieldInterface )------------------------------------ */ + + private $customFields = self::ATTACHABLE; + + public function getCustomFieldSpecificationForRole($role) { + return array(); // TODO + // return PhabricatorEnv::getEnvConfig(<<<'application.fields'>>>); + } + + public function getCustomFieldBaseClass() { + return 'ReleaseChangeRequestCustomField'; + } + + public function getCustomFields() { + return $this->assertAttached($this->customFields); + } + + public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { + $this->customFields = $fields; + return $this; + } + +} diff --git a/src/applications/release/storage/ReleaseChangeRequestCustomFieldNumericIndex.php b/src/applications/release/storage/ReleaseChangeRequestCustomFieldNumericIndex.php new file mode 100644 --- /dev/null +++ b/src/applications/release/storage/ReleaseChangeRequestCustomFieldNumericIndex.php @@ -0,0 +1,10 @@ +getTransactionType()) { + default: + $tags[] = self::MAILTAG_OTHER; + break; + } + return $tags; + } +} diff --git a/src/applications/release/xaction/ReleaseChangeRequestStateTransaction.php b/src/applications/release/xaction/ReleaseChangeRequestStateTransaction.php new file mode 100755 --- /dev/null +++ b/src/applications/release/xaction/ReleaseChangeRequestStateTransaction.php @@ -0,0 +1,6 @@ +getViewer(); + + $old = $this->getOldValue(); + $new = $this->getNewValue(); + + $json = new PhutilJSON(); + + return id(new PhabricatorApplicationTransactionTextDiffDetailView()) + ->setViewer($viewer) + ->setOldText($old ? $json->encodeFormatted($old) : null) + ->setNewText($new ? $json->encodeFormatted($new) : null); + } +}