1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-20 18:58:56 +01:00

Add staging area support to Harbormaster/Drydock + various fixes

Summary:
Ref T9252. This primarily allows Harbormaster to request (and Drydock to fulfill) working copies with a patch from a staging area. Doing this means we can do builds on in-review changes from `arc diff`.

This is a little cobbled-together but should basically work.

Also fix some other issues:

  - Yielded, awakend workers are fine to update but could complain.
  - We can't log slot lock failures to resources if we don't end up saving them.
  - Killing the transaction would wipe out the log.
  - Fix some TODOs, etc.

Test Plan: Ran Harbormaster builds on a local revision.

Reviewers: hach-que, chad

Reviewed By: chad

Maniphest Tasks: T9252

Differential Revision: https://secure.phabricator.com/D14214
This commit is contained in:
epriestley 2015-10-01 16:55:01 -07:00
parent d4a0b1c870
commit 4496176924
9 changed files with 130 additions and 43 deletions

View file

@ -446,6 +446,13 @@ final class DifferentialDiff
$results['repository.phid'] = $repo->getPHID();
$results['repository.vcs'] = $repo->getVersionControlSystem();
$results['repository.uri'] = $repo->getPublicCloneURI();
// TODO: We're just hoping to get lucky. Instead, `arc` should store
// where it sent changes and we should only provide staging details
// if we reasonably believe they are accurate.
$staging_ref = 'refs/tags/phabricator/diff/'.$this->getID();
$results['repository.staging.uri'] = $repo->getStagingURI();
$results['repository.staging.ref'] = $staging_ref;
}
}
@ -466,6 +473,10 @@ final class DifferentialDiff
pht('The version control system, either "svn", "hg" or "git".'),
'repository.uri' =>
pht('The URI to clone or checkout the repository from.'),
'repository.staging.uri' =>
pht('The URI of the staging repository.'),
'repository.staging.ref' =>
pht('The ref name for this change in the staging repository.'),
);
}

View file

@ -295,14 +295,18 @@ abstract class DrydockBlueprintImplementation extends Phobject {
$lease_status = $lease->getStatus();
switch ($lease_status) {
case DrydockLeaseStatus::STATUS_PENDING:
case DrydockLeaseStatus::STATUS_ACQUIRED:
// TODO: Temporary failure.
throw new Exception(pht('Lease still activating.'));
throw new PhabricatorWorkerYieldException(15);
case DrydockLeaseStatus::STATUS_ACTIVE:
return;
default:
// TODO: Permanent failure.
throw new Exception(pht('Lease in bad state.'));
throw new Exception(
pht(
'Lease ("%s") is in bad state ("%s"), expected "%s".',
$lease->getPHID(),
$lease_status,
DrydockLeaseStatus::STATUS_ACTIVE));
}
}

View file

@ -216,6 +216,8 @@ final class DrydockWorkingCopyBlueprintImplementation
$commit = idx($spec, 'commit');
$branch = idx($spec, 'branch');
$ref = idx($spec, 'ref');
if ($commit !== null) {
$cmd[] = 'git reset --hard %s';
$arg[] = $commit;
@ -225,6 +227,20 @@ final class DrydockWorkingCopyBlueprintImplementation
$cmd[] = 'git reset --hard origin/%s';
$arg[] = $branch;
} else if ($ref) {
$ref_uri = $ref['uri'];
$ref_ref = $ref['ref'];
$cmd[] = 'git fetch --no-tags -- %s +%s:%s';
$arg[] = $ref_uri;
$arg[] = $ref_ref;
$arg[] = $ref_ref;
$cmd[] = 'git checkout %s';
$arg[] = $ref_ref;
$cmd[] = 'git reset --hard %s';
$arg[] = $ref_ref;
} else {
$cmd[] = 'git reset --hard HEAD';
}

View file

@ -107,6 +107,17 @@ final class DrydockBlueprint extends DrydockDAO
return $this->fields;
}
public function logEvent($type, array $data = array()) {
$log = id(new DrydockLog())
->setEpoch(PhabricatorTime::getNow())
->setType($type)
->setData($data);
$log->setBlueprintPHID($this->getPHID());
return $log->save();
}
/* -( Allocating Resources )----------------------------------------------- */

View file

@ -233,18 +233,21 @@ final class DrydockLease extends DrydockDAO
$this->openTransaction();
try {
try {
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
$this->slotLocks = array();
} catch (DrydockSlotLockException $ex) {
$this->logEvent(
DrydockSlotLockFailureLogType::LOGCONST,
array(
'locks' => $ex->getLockMap(),
));
throw $ex;
}
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
$this->slotLocks = array();
} catch (DrydockSlotLockException $ex) {
$this->killTransaction();
$this->logEvent(
DrydockSlotLockFailureLogType::LOGCONST,
array(
'locks' => $ex->getLockMap(),
));
throw $ex;
}
try {
$this
->setResourcePHID($resource->getPHID())
->attachResource($resource)

View file

@ -148,19 +148,25 @@ final class DrydockResource extends DrydockDAO
}
$this->openTransaction();
try {
try {
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
$this->slotLocks = array();
} catch (DrydockSlotLockException $ex) {
$this->logEvent(
DrydockSlotLockFailureLogType::LOGCONST,
array(
'locks' => $ex->getLockMap(),
));
throw $ex;
}
try {
DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
$this->slotLocks = array();
} catch (DrydockSlotLockException $ex) {
$this->killTransaction();
// NOTE: We have to log this on the blueprint, as the resource is not
// going to be saved so the PHID will vanish.
$this->getBlueprint()->logEvent(
DrydockSlotLockFailureLogType::LOGCONST,
array(
'locks' => $ex->getLockMap(),
));
throw $ex;
}
try {
$this
->setStatus($new_status)
->save();
@ -168,6 +174,7 @@ final class DrydockResource extends DrydockDAO
$this->killTransaction();
throw $ex;
}
$this->saveTransaction();
$this->isAllocated = true;

View file

@ -660,9 +660,10 @@ final class DrydockLeaseUpdateWorker extends DrydockWorker {
$lease->logEvent(DrydockLeaseReleasedLogType::LOGCONST);
$resource = $lease->getResource();
$blueprint = $resource->getBlueprint();
$blueprint->didReleaseLease($resource, $lease);
if ($resource) {
$blueprint = $resource->getBlueprint();
$blueprint->didReleaseLease($resource, $lease);
}
$this->destroyLease($lease);
}

View file

@ -113,6 +113,13 @@ final class HarbormasterLeaseWorkingCopyBuildStepImplementation
$variables = $build_target->getVariables();
$repository_phid = idx($variables, 'repository.phid');
if (!$repository_phid) {
throw new Exception(
pht(
'Unable to determine how to clone the repository for this '.
'buildable: it is not associated with a tracked repository.'));
}
$also_phids = $build_target->getFieldValue('repositoryPHIDs');
$all_phids = $also_phids;
@ -133,8 +140,6 @@ final class HarbormasterLeaseWorkingCopyBuildStepImplementation
}
}
$commit = idx($variables, 'repository.commit');
$map = array();
foreach ($also_phids as $also_phid) {
@ -147,12 +152,33 @@ final class HarbormasterLeaseWorkingCopyBuildStepImplementation
$repository = $repositories[$repository_phid];
$commit = idx($variables, 'repository.commit');
$ref_uri = idx($variables, 'repository.staging.uri');
$ref_ref = idx($variables, 'repository.staging.ref');
if ($commit) {
$spec = array(
'commit' => $commit,
);
} else if ($ref_uri && $ref_ref) {
$spec = array(
'ref' => array(
'uri' => $ref_uri,
'ref' => $ref_ref,
),
);
} else {
throw new Exception(
pht(
'Unable to determine how to fetch changes: this buildable does not '.
'identify a commit or a staging ref. You may need to configure a '.
'repository staging area.'));
}
$directory = $repository->getCloneName();
$map[$directory] = array(
'phid' => $repository->getPHID(),
'commit' => $commit,
'default' => true,
);
) + $spec;
return $map;
}

View file

@ -86,15 +86,23 @@ final class PhabricatorWorkerActiveTask extends PhabricatorWorkerTask {
}
protected function checkLease() {
if ($this->leaseOwner) {
$current_server_time = $this->serverTime + (time() - $this->localTime);
if ($current_server_time >= $this->leaseExpires) {
throw new Exception(
pht(
'Trying to update Task %d (%s) after lease expiration!',
$this->getID(),
$this->getTaskClass()));
}
$owner = $this->leaseOwner;
if (!$owner) {
return;
}
if ($owner == PhabricatorWorker::YIELD_OWNER) {
return;
}
$current_server_time = $this->serverTime + (time() - $this->localTime);
if ($current_server_time >= $this->leaseExpires) {
throw new Exception(
pht(
'Trying to update Task %d (%s) after lease expiration!',
$this->getID(),
$this->getTaskClass()));
}
}