Remove all "FileHasObject" edge reads and writes
[phabricator.git] / src / applications / harbormaster / step / HarbormasterLeaseWorkingCopyBuildStepImplementation.php
blob82c041f42393fff6f42dccfdb6715c5ead1363a5
1 <?php
3 final class HarbormasterLeaseWorkingCopyBuildStepImplementation
4 extends HarbormasterBuildStepImplementation {
6 public function getName() {
7 return pht('Lease Working Copy');
10 public function getGenericDescription() {
11 return pht('Build a working copy in Drydock.');
14 public function getBuildStepGroupKey() {
15 return HarbormasterDrydockBuildStepGroup::GROUPKEY;
18 public function execute(
19 HarbormasterBuild $build,
20 HarbormasterBuildTarget $build_target) {
21 $viewer = PhabricatorUser::getOmnipotentUser();
23 $settings = $this->getSettings();
25 // TODO: We should probably have a separate temporary storage area for
26 // execution stuff that doesn't step on configuration state?
27 $lease_phid = $build_target->getDetail('exec.leasePHID');
29 if ($lease_phid) {
30 $lease = id(new DrydockLeaseQuery())
31 ->setViewer($viewer)
32 ->withPHIDs(array($lease_phid))
33 ->executeOne();
34 if (!$lease) {
35 throw new PhabricatorWorkerPermanentFailureException(
36 pht(
37 'Lease "%s" could not be loaded.',
38 $lease_phid));
40 } else {
41 $working_copy_type = id(new DrydockWorkingCopyBlueprintImplementation())
42 ->getType();
44 $allowed_phids = $build_target->getFieldValue('blueprintPHIDs');
45 if (!is_array($allowed_phids)) {
46 $allowed_phids = array();
48 $authorizing_phid = $build_target->getBuildStep()->getPHID();
50 $lease = DrydockLease::initializeNewLease()
51 ->setResourceType($working_copy_type)
52 ->setOwnerPHID($build_target->getPHID())
53 ->setAuthorizingPHID($authorizing_phid)
54 ->setAllowedBlueprintPHIDs($allowed_phids);
56 $map = $this->buildRepositoryMap($build_target);
58 $lease->setAttribute('repositories.map', $map);
60 $task_id = $this->getCurrentWorkerTaskID();
61 if ($task_id) {
62 $lease->setAwakenTaskIDs(array($task_id));
65 // TODO: Maybe add a method to mark artifacts like this as pending?
67 // Create the artifact now so that the lease is always disposed of, even
68 // if this target is aborted.
69 $build_target->createArtifact(
70 $viewer,
71 $settings['name'],
72 HarbormasterWorkingCopyArtifact::ARTIFACTCONST,
73 array(
74 'drydockLeasePHID' => $lease->getPHID(),
75 ));
77 $lease->queueForActivation();
79 $build_target
80 ->setDetail('exec.leasePHID', $lease->getPHID())
81 ->save();
84 if ($lease->isActivating()) {
85 // TODO: Smart backoff?
86 throw new PhabricatorWorkerYieldException(15);
89 if (!$lease->isActive()) {
90 // TODO: We could just forget about this lease and retry?
91 throw new PhabricatorWorkerPermanentFailureException(
92 pht(
93 'Lease "%s" never activated.',
94 $lease->getPHID()));
98 public function getArtifactOutputs() {
99 return array(
100 array(
101 'name' => pht('Working Copy'),
102 'key' => $this->getSetting('name'),
103 'type' => HarbormasterWorkingCopyArtifact::ARTIFACTCONST,
108 public function getFieldSpecifications() {
109 return array(
110 'name' => array(
111 'name' => pht('Artifact Name'),
112 'type' => 'text',
113 'required' => true,
115 'blueprintPHIDs' => array(
116 'name' => pht('Use Blueprints'),
117 'type' => 'blueprints',
118 'required' => true,
120 'repositoryPHIDs' => array(
121 'name' => pht('Also Clone'),
122 'type' => 'datasource',
123 'datasource.class' => 'DiffusionRepositoryDatasource',
128 private function buildRepositoryMap(HarbormasterBuildTarget $build_target) {
129 $viewer = PhabricatorUser::getOmnipotentUser();
130 $variables = $build_target->getVariables();
132 $repository_phid = idx($variables, 'repository.phid');
133 if (!$repository_phid) {
134 throw new Exception(
135 pht(
136 'Unable to determine how to clone the repository for this '.
137 'buildable: it is not associated with a tracked repository.'));
140 $also_phids = $build_target->getFieldValue('repositoryPHIDs');
141 if (!is_array($also_phids)) {
142 $also_phids = array();
145 $all_phids = $also_phids;
146 $all_phids[] = $repository_phid;
148 $repositories = id(new PhabricatorRepositoryQuery())
149 ->setViewer($viewer)
150 ->withPHIDs($all_phids)
151 ->execute();
152 $repositories = mpull($repositories, null, 'getPHID');
154 foreach ($all_phids as $phid) {
155 if (empty($repositories[$phid])) {
156 throw new PhabricatorWorkerPermanentFailureException(
157 pht(
158 'Unable to load repository with PHID "%s".',
159 $phid));
163 $map = array();
165 foreach ($also_phids as $also_phid) {
166 $also_repo = $repositories[$also_phid];
167 $map[$also_repo->getCloneName()] = array(
168 'phid' => $also_repo->getPHID(),
169 'branch' => 'master',
173 $repository = $repositories[$repository_phid];
175 $commit = idx($variables, 'buildable.commit');
176 $ref_uri = idx($variables, 'repository.staging.uri');
177 $ref_ref = idx($variables, 'repository.staging.ref');
178 if ($commit) {
179 $spec = array(
180 'commit' => $commit,
182 } else if ($ref_uri && $ref_ref) {
183 $spec = array(
184 'ref' => array(
185 'uri' => $ref_uri,
186 'ref' => $ref_ref,
189 } else {
190 throw new Exception(
191 pht(
192 'Unable to determine how to fetch changes: this buildable does not '.
193 'identify a commit or a staging ref. You may need to configure a '.
194 'repository staging area.'));
197 $directory = $repository->getCloneName();
198 $map[$directory] = array(
199 'phid' => $repository->getPHID(),
200 'default' => true,
201 ) + $spec;
203 return $map;