diff --git a/src/applications/differential/storage/DifferentialDiff.php b/src/applications/differential/storage/DifferentialDiff.php --- a/src/applications/differential/storage/DifferentialDiff.php +++ b/src/applications/differential/storage/DifferentialDiff.php @@ -446,6 +446,13 @@ $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 @@ 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.'), ); } diff --git a/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php --- a/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php +++ b/src/applications/drydock/blueprint/DrydockBlueprintImplementation.php @@ -295,14 +295,18 @@ $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)); } } diff --git a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php --- a/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php +++ b/src/applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php @@ -216,6 +216,8 @@ $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 @@ $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'; } diff --git a/src/applications/drydock/storage/DrydockBlueprint.php b/src/applications/drydock/storage/DrydockBlueprint.php --- a/src/applications/drydock/storage/DrydockBlueprint.php +++ b/src/applications/drydock/storage/DrydockBlueprint.php @@ -107,6 +107,17 @@ 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 )----------------------------------------------- */ diff --git a/src/applications/drydock/storage/DrydockLease.php b/src/applications/drydock/storage/DrydockLease.php --- a/src/applications/drydock/storage/DrydockLease.php +++ b/src/applications/drydock/storage/DrydockLease.php @@ -233,18 +233,21 @@ $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) diff --git a/src/applications/drydock/storage/DrydockResource.php b/src/applications/drydock/storage/DrydockResource.php --- a/src/applications/drydock/storage/DrydockResource.php +++ b/src/applications/drydock/storage/DrydockResource.php @@ -148,19 +148,25 @@ } $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(); + + // 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 @@ $this->killTransaction(); throw $ex; } + $this->saveTransaction(); $this->isAllocated = true; diff --git a/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php b/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php --- a/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php +++ b/src/applications/drydock/worker/DrydockLeaseUpdateWorker.php @@ -660,9 +660,10 @@ $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); } diff --git a/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php --- a/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php +++ b/src/applications/harbormaster/step/HarbormasterLeaseWorkingCopyBuildStepImplementation.php @@ -113,6 +113,13 @@ $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 @@ } } - $commit = idx($variables, 'repository.commit'); - $map = array(); foreach ($also_phids as $also_phid) { @@ -147,12 +152,33 @@ $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; } diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php --- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php +++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php @@ -86,15 +86,23 @@ } 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())); } }