1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-28 09:42:40 +01:00

Add modern refs and hardpoints for buildables, builds, and build plans

Summary: Ref T13546. Prepares "arc land" to use hardpoint queries to load build information.

Test Plan: Ran `arc inspect --explore revision(1234)`, got a full related object tree including build information.

Maniphest Tasks: T13546

Differential Revision: https://secure.phabricator.com/D21312
This commit is contained in:
epriestley 2020-06-04 10:14:05 -07:00
parent c1a4bee4a1
commit de607e9fbc
15 changed files with 501 additions and 173 deletions

View file

@ -64,8 +64,14 @@ phutil_register_library_map(array(
'ArcanistBrowseURIHardpointQuery' => 'browse/query/ArcanistBrowseURIHardpointQuery.php',
'ArcanistBrowseURIRef' => 'browse/ref/ArcanistBrowseURIRef.php',
'ArcanistBrowseWorkflow' => 'browse/workflow/ArcanistBrowseWorkflow.php',
'ArcanistBuildPlanRef' => 'ref/ArcanistBuildPlanRef.php',
'ArcanistBuildRef' => 'ref/ArcanistBuildRef.php',
'ArcanistBuildBuildplanHardpointQuery' => 'ref/build/ArcanistBuildBuildplanHardpointQuery.php',
'ArcanistBuildPlanRef' => 'ref/buildplan/ArcanistBuildPlanRef.php',
'ArcanistBuildPlanSymbolRef' => 'ref/buildplan/ArcanistBuildPlanSymbolRef.php',
'ArcanistBuildRef' => 'ref/build/ArcanistBuildRef.php',
'ArcanistBuildSymbolRef' => 'ref/build/ArcanistBuildSymbolRef.php',
'ArcanistBuildableBuildsHardpointQuery' => 'ref/buildable/ArcanistBuildableBuildsHardpointQuery.php',
'ArcanistBuildableRef' => 'ref/buildable/ArcanistBuildableRef.php',
'ArcanistBuildableSymbolRef' => 'ref/buildable/ArcanistBuildableSymbolRef.php',
'ArcanistBundle' => 'parser/ArcanistBundle.php',
'ArcanistBundleTestCase' => 'parser/__tests__/ArcanistBundleTestCase.php',
'ArcanistCSSLintLinter' => 'lint/linter/ArcanistCSSLintLinter.php',
@ -401,8 +407,9 @@ phutil_register_library_map(array(
'ArcanistReusedIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorXHPASTLinterRule.php',
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedIteratorXHPASTLinterRuleTestCase.php',
'ArcanistRevisionAuthorHardpointQuery' => 'ref/revision/ArcanistRevisionAuthorHardpointQuery.php',
'ArcanistRevisionBuildableHardpointQuery' => 'ref/revision/ArcanistRevisionBuildableHardpointQuery.php',
'ArcanistRevisionCommitMessageHardpointQuery' => 'ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php',
'ArcanistRevisionParentRevisionRefsHardpointQuery' => 'ref/revision/ArcanistRevisionParentRevisionRefsHardpointQuery.php',
'ArcanistRevisionParentRevisionsHardpointQuery' => 'ref/revision/ArcanistRevisionParentRevisionsHardpointQuery.php',
'ArcanistRevisionRef' => 'ref/revision/ArcanistRevisionRef.php',
'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php',
'ArcanistRevisionSymbolRef' => 'ref/revision/ArcanistRevisionSymbolRef.php',
@ -1048,8 +1055,23 @@ phutil_register_library_map(array(
'ArcanistBrowseURIHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistBrowseURIRef' => 'ArcanistRef',
'ArcanistBrowseWorkflow' => 'ArcanistArcWorkflow',
'ArcanistBuildPlanRef' => 'Phobject',
'ArcanistBuildRef' => 'Phobject',
'ArcanistBuildBuildplanHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistBuildPlanRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistBuildPlanSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistBuildRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistBuildSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistBuildableBuildsHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistBuildableRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistBuildableSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistBundle' => 'Phobject',
'ArcanistBundleTestCase' => 'PhutilTestCase',
'ArcanistCSSLintLinter' => 'ArcanistExternalLinter',
@ -1393,8 +1415,9 @@ phutil_register_library_map(array(
'ArcanistReusedIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistRevisionAuthorHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionBuildableHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionCommitMessageHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionParentRevisionRefsHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionParentRevisionsHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',

View file

@ -1,25 +0,0 @@
<?php
final class ArcanistBuildPlanRef
extends Phobject {
private $parameters;
public static function newFromConduit(array $data) {
$ref = new self();
$ref->parameters = $data;
return $ref;
}
public function getPHID() {
return $this->parameters['phid'];
}
public function getBehavior($behavior_key, $default = null) {
return idxv(
$this->parameters,
array('fields', 'behaviors', $behavior_key, 'value'),
$default);
}
}

View file

@ -1,140 +0,0 @@
<?php
final class ArcanistBuildRef
extends Phobject {
private $parameters;
public static function newFromConduit(array $data) {
$ref = new self();
$ref->parameters = $data;
return $ref;
}
private function getStatusMap() {
// The modern "harbormaster.build.search" API method returns this in the
// "fields" list; the older API method returns it at the root level.
if (isset($this->parameters['fields']['buildStatus'])) {
$status = $this->parameters['fields']['buildStatus'];
} else if (isset($this->parameters['buildStatus'])) {
$status = $this->parameters['buildStatus'];
} else {
$status = 'unknown';
}
// We may either have an array or a scalar here. The array comes from
// "harbormaster.build.search", or from "harbormaster.querybuilds" if
// the server is newer than August 2016. The scalar comes from older
// versions of that method. See PHI261.
if (is_array($status)) {
$map = $status;
} else {
$map = array(
'value' => $status,
);
}
// If we don't have a name, try to fill one in.
if (!isset($map['name'])) {
$name_map = array(
'inactive' => pht('Inactive'),
'pending' => pht('Pending'),
'building' => pht('Building'),
'passed' => pht('Passed'),
'failed' => pht('Failed'),
'aborted' => pht('Aborted'),
'error' => pht('Error'),
'paused' => pht('Paused'),
'deadlocked' => pht('Deadlocked'),
'unknown' => pht('Unknown'),
);
$map['name'] = idx($name_map, $map['value'], $map['value']);
}
// If we don't have an ANSI color code, try to fill one in.
if (!isset($map['color.ansi'])) {
$color_map = array(
'failed' => 'red',
'passed' => 'green',
);
$map['color.ansi'] = idx($color_map, $map['value'], 'yellow');
}
return $map;
}
public function getID() {
return $this->parameters['id'];
}
public function getPHID() {
return $this->parameters['phid'];
}
public function getName() {
if (isset($this->parameters['fields']['name'])) {
return $this->parameters['fields']['name'];
}
return $this->parameters['name'];
}
public function getStatus() {
$map = $this->getStatusMap();
return $map['value'];
}
public function getStatusName() {
$map = $this->getStatusMap();
return $map['name'];
}
public function getStatusANSIColor() {
$map = $this->getStatusMap();
return $map['color.ansi'];
}
public function getObjectName() {
return pht('Build %d', $this->getID());
}
public function getBuildPlanPHID() {
return idxv($this->parameters, array('fields', 'buildPlanPHID'));
}
public function isComplete() {
switch ($this->getStatus()) {
case 'passed':
case 'failed':
case 'aborted':
case 'error':
case 'deadlocked':
return true;
default:
return false;
}
}
public function isPassed() {
return ($this->getStatus() === 'passed');
}
public function getStatusSortVector() {
$status = $this->getStatus();
// For now, just sort passed builds first.
if ($this->isPassed()) {
$status_class = 1;
} else {
$status_class = 2;
}
return id(new PhutilSortVector())
->addInt($status_class)
->addString($status);
}
}

View file

@ -0,0 +1,44 @@
<?php
final class ArcanistBuildBuildplanHardpointQuery
extends ArcanistRuntimeHardpointQuery {
public function getHardpoints() {
return array(
ArcanistBuildRef::HARDPOINT_BUILDPLANREF,
);
}
protected function canLoadRef(ArcanistRef $ref) {
return ($ref instanceof ArcanistBuildRef);
}
public function loadHardpoint(array $refs, $hardpoint) {
$plan_phids = mpull($refs, 'getBuildPlanPHID');
$plan_phids = array_fuse($plan_phids);
$plan_phids = array_values($plan_phids);
$plans = (yield $this->yieldConduitSearch(
'harbormaster.buildplan.search',
array(
'phids' => $plan_phids,
)));
$plan_refs = array();
foreach ($plans as $plan) {
$plan_ref = ArcanistBuildPlanRef::newFromConduit($plan);
$plan_refs[] = $plan_ref;
}
$plan_refs = mpull($plan_refs, 'getPHID');
$results = array();
foreach ($refs as $key => $build_ref) {
$plan_phid = $build_ref->getBuildPlanPHID();
$plan = idx($plan_refs, $plan_phid);
$results[$key] = $plan;
}
yield $this->yieldMap($results);
}
}

View file

@ -0,0 +1,106 @@
<?php
final class ArcanistBuildRef
extends ArcanistRef
implements
ArcanistDisplayRefInterface {
const HARDPOINT_BUILDPLANREF = 'ref.build.buildplanRef';
private $parameters;
protected function newHardpoints() {
return array(
$this->newHardpoint(self::HARDPOINT_BUILDPLANREF),
);
}
public function getRefDisplayName() {
return $this->getDisplayRefObjectName();
}
public static function newFromConduit(array $parameters) {
$ref = new self();
$ref->parameters = $parameters;
return $ref;
}
public function getID() {
return idx($this->parameters, 'id');
}
public function getPHID() {
return idx($this->parameters, 'phid');
}
public function getName() {
return idxv($this->parameters, array('fields', 'name'));
}
public function getDisplayRefObjectName() {
return pht('Build %d', $this->getID());
}
public function getDisplayRefTitle() {
return $this->getName();
}
public function getBuildPlanRef() {
return $this->getHardpoint(self::HARDPOINT_BUILDPLANREF);
}
public function getBuildablePHID() {
return idxv($this->parameters, array('fields', 'buildablePHID'));
}
public function getBuildPlanPHID() {
return idxv($this->parameters, array('fields', 'buildPlanPHID'));
}
public function getStatus() {
return idxv($this->parameters, array('fields', 'buildStatus', 'value'));
}
public function getStatusName() {
return idxv($this->parameters, array('fields', 'buildStatus', 'name'));
}
public function getStatusANSIColor() {
return idxv(
$this->parameters,
array('fields', 'buildStatus', 'color.ansi'));
}
public function isComplete() {
switch ($this->getStatus()) {
case 'passed':
case 'failed':
case 'aborted':
case 'error':
case 'deadlocked':
return true;
default:
return false;
}
}
public function isPassed() {
return ($this->getStatus() === 'passed');
}
public function getStatusSortVector() {
$status = $this->getStatus();
// For now, just sort passed builds first.
if ($this->isPassed()) {
$status_class = 1;
} else {
$status_class = 2;
}
return id(new PhutilSortVector())
->addInt($status_class)
->addString($status);
}
}

View file

@ -0,0 +1,30 @@
<?php
final class ArcanistBuildSymbolRef
extends ArcanistSimpleSymbolRef {
public function getRefDisplayName() {
return pht('Build Symbol "%s"', $this->getSymbol());
}
protected function getSimpleSymbolPHIDType() {
return 'HMBD';
}
public function getSimpleSymbolConduitSearchMethodName() {
return 'harbormaster.build.search';
}
public function getSimpleSymbolConduitSearchAttachments() {
return array();
}
public function getSimpleSymbolInspectFunctionName() {
return 'build';
}
public function newSimpleSymbolObjectRef() {
return new ArcanistBuildRef();
}
}

View file

@ -0,0 +1,43 @@
<?php
final class ArcanistBuildableBuildsHardpointQuery
extends ArcanistRuntimeHardpointQuery {
public function getHardpoints() {
return array(
ArcanistBuildableRef::HARDPOINT_BUILDREFS,
);
}
protected function canLoadRef(ArcanistRef $ref) {
return ($ref instanceof ArcanistBuildableRef);
}
public function loadHardpoint(array $refs, $hardpoint) {
$buildable_phids = mpull($refs, 'getPHID');
$builds = (yield $this->yieldConduitSearch(
'harbormaster.build.search',
array(
'buildables' => $buildable_phids,
)));
$build_refs = array();
foreach ($builds as $build) {
$build_ref = ArcanistBuildRef::newFromConduit($build);
$build_refs[] = $build_ref;
}
$build_refs = mgroup($build_refs, 'getBuildablePHID');
$results = array();
foreach ($refs as $key => $buildable_ref) {
$buildable_phid = $buildable_ref->getPHID();
$buildable_builds = idx($build_refs, $buildable_phid, array());
$results[$key] = $buildable_builds;
}
yield $this->yieldMap($results);
}
}

View file

@ -0,0 +1,63 @@
<?php
final class ArcanistBuildableRef
extends ArcanistRef
implements
ArcanistDisplayRefInterface {
const HARDPOINT_BUILDREFS = 'ref.buildable.buildRefs';
private $parameters;
protected function newHardpoints() {
$object_list = new ArcanistObjectListHardpoint();
return array(
$this->newTemplateHardpoint(
self::HARDPOINT_BUILDREFS,
$object_list),
);
}
public function getRefDisplayName() {
return pht('Buildable "%s"', $this->getMonogram());
}
public static function newFromConduit(array $parameters) {
$ref = new self();
$ref->parameters = $parameters;
return $ref;
}
public function getID() {
return idx($this->parameters, 'id');
}
public function getPHID() {
return idx($this->parameters, 'phid');
}
public function getName() {
return idxv($this->parameters, array('fields', 'name'));
}
public function getObjectPHID() {
return idxv($this->parameters, array('fields', 'objectPHID'));
}
public function getMonogram() {
return 'B'.$this->getID();
}
public function getDisplayRefObjectName() {
return $this->getMonogram();
}
public function getDisplayRefTitle() {
return $this->getName();
}
public function getBuildRefs() {
return $this->getHardpoint(self::HARDPOINT_BUILDREFS);
}
}

View file

@ -0,0 +1,30 @@
<?php
final class ArcanistBuildableSymbolRef
extends ArcanistSimpleSymbolRef {
public function getRefDisplayName() {
return pht('Buildable Symbol "%s"', $this->getSymbol());
}
protected function getSimpleSymbolPHIDType() {
return 'HMBB';
}
public function getSimpleSymbolConduitSearchMethodName() {
return 'harbormaster.buildable.search';
}
public function getSimpleSymbolConduitSearchAttachments() {
return array();
}
public function getSimpleSymbolInspectFunctionName() {
return 'buildable';
}
public function newSimpleSymbolObjectRef() {
return new ArcanistBuildableRef();
}
}

View file

@ -0,0 +1,47 @@
<?php
final class ArcanistBuildPlanRef
extends ArcanistRef
implements
ArcanistDisplayRefInterface {
private $parameters;
public function getRefDisplayName() {
return $this->getDisplayRefObjectName();
}
public static function newFromConduit(array $parameters) {
$ref = new self();
$ref->parameters = $parameters;
return $ref;
}
public function getID() {
return idx($this->parameters, 'id');
}
public function getPHID() {
return idx($this->parameters, 'phid');
}
public function getName() {
return idxv($this->parameters, array('fields', 'name'));
}
public function getDisplayRefObjectName() {
return pht('Build Plan %d', $this->getID());
}
public function getDisplayRefTitle() {
return $this->getName();
}
public function getBehavior($behavior_key, $default = null) {
return idxv(
$this->parameters,
array('fields', 'behaviors', $behavior_key, 'value'),
$default);
}
}

View file

@ -0,0 +1,30 @@
<?php
final class ArcanistBuildPlanSymbolRef
extends ArcanistSimpleSymbolRef {
public function getRefDisplayName() {
return pht('Build Plan Symbol "%s"', $this->getSymbol());
}
protected function getSimpleSymbolPHIDType() {
return 'HMCP';
}
public function getSimpleSymbolConduitSearchMethodName() {
return 'harbormaster.buildplan.search';
}
public function getSimpleSymbolConduitSearchAttachments() {
return array();
}
public function getSimpleSymbolInspectFunctionName() {
return 'buildplan';
}
public function newSimpleSymbolObjectRef() {
return new ArcanistBuildPlanRef();
}
}

View file

@ -0,0 +1,60 @@
<?php
final class ArcanistRevisionBuildableHardpointQuery
extends ArcanistRuntimeHardpointQuery {
public function getHardpoints() {
return array(
ArcanistRevisionRef::HARDPOINT_BUILDABLEREF,
);
}
protected function canLoadRef(ArcanistRef $ref) {
return ($ref instanceof ArcanistRevisionRef);
}
public function loadHardpoint(array $refs, $hardpoint) {
$diff_map = array();
foreach ($refs as $key => $revision_ref) {
$diff_phid = $revision_ref->getDiffPHID();
if ($diff_phid) {
$diff_map[$key] = $diff_phid;
}
}
if (!$diff_map) {
yield $this->yieldValue($refs, null);
}
$buildables = (yield $this->yieldConduitSearch(
'harbormaster.buildable.search',
array(
'objectPHIDs' => $diff_map,
'manual' => false,
)));
$buildable_refs = array();
foreach ($buildables as $buildable) {
$buildable_ref = ArcanistBuildableRef::newFromConduit($buildable);
$object_phid = $buildable_ref->getObjectPHID();
$buildable_refs[$object_phid] = $buildable_ref;
}
$results = array_fill_keys(array_keys($refs), null);
foreach ($refs as $key => $revision_ref) {
if (!isset($diff_map[$key])) {
continue;
}
$diff_phid = $diff_map[$key];
if (!isset($buildable_refs[$diff_phid])) {
continue;
}
$results[$key] = $buildable_refs[$diff_phid];
}
yield $this->yieldMap($results);
}
}

View file

@ -1,6 +1,6 @@
<?php
final class ArcanistRevisionParentRevisionRefsHardpointQuery
final class ArcanistRevisionParentRevisionsHardpointQuery
extends ArcanistRuntimeHardpointQuery {
public function getHardpoints() {

View file

@ -7,6 +7,7 @@ final class ArcanistRevisionRef
const HARDPOINT_COMMITMESSAGE = 'ref.revision.commitmessage';
const HARDPOINT_AUTHORREF = 'ref.revision.authorRef';
const HARDPOINT_BUILDABLEREF = 'ref.revision.buildableRef';
const HARDPOINT_PARENTREVISIONREFS = 'ref.revision.parentRevisionRefs';
private $parameters;
@ -21,6 +22,7 @@ final class ArcanistRevisionRef
return array(
$this->newHardpoint(self::HARDPOINT_COMMITMESSAGE),
$this->newHardpoint(self::HARDPOINT_AUTHORREF),
$this->newHardpoint(self::HARDPOINT_BUILDABLEREF),
$this->newTemplateHardpoint(
self::HARDPOINT_PARENTREVISIONREFS,
$object_list),
@ -124,6 +126,10 @@ final class ArcanistRevisionRef
return idx($this->parameters, 'phid');
}
public function getDiffPHID() {
return idxv($this->parameters, array('fields', 'diffPHID'));
}
public function getName() {
return idxv($this->parameters, array('fields', 'title'));
}
@ -153,6 +159,10 @@ final class ArcanistRevisionRef
return $this->getHardpoint(self::HARDPOINT_PARENTREVISIONREFS);
}
public function getBuildableRef() {
return $this->getHardpoint(self::HARDPOINT_BUILDABLEREF);
}
public function getDisplayRefObjectName() {
return $this->getMonogram();
}

View file

@ -22,6 +22,10 @@ abstract class ArcanistSimpleSymbolRef
$matches = null;
$prefix_pattern = $this->getSimpleSymbolPrefixPattern();
if ($prefix_pattern === null) {
$prefix_pattern = '';
}
$id_pattern = '(^'.$prefix_pattern.'([1-9]\d*)\z)';
$is_id = preg_match($id_pattern, $symbol, $matches);
@ -46,7 +50,10 @@ abstract class ArcanistSimpleSymbolRef
$symbol));
}
abstract protected function getSimpleSymbolPrefixPattern();
protected function getSimpleSymbolPrefixPattern() {
return null;
}
abstract protected function getSimpleSymbolPHIDType();
abstract public function getSimpleSymbolConduitSearchMethodName();
abstract public function getSimpleSymbolInspectFunctionName();