@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at recaptime-dev/main 237 lines 6.8 kB view raw
1<?php 2 3final class HarbormasterBuildkiteBuildStepImplementation 4 extends HarbormasterBuildStepImplementation { 5 6 public function getName() { 7 return pht('Build with Buildkite'); 8 } 9 10 public function getGenericDescription() { 11 return pht('Trigger a build in Buildkite.'); 12 } 13 14 public function getBuildStepGroupKey() { 15 return HarbormasterExternalBuildStepGroup::GROUPKEY; 16 } 17 18 public function getDescription() { 19 return pht('Run a build in Buildkite.'); 20 } 21 22 public function getEditInstructions() { 23 $hook_uri = '/harbormaster/hook/buildkite/'; 24 $hook_uri = PhabricatorEnv::getProductionURI($hook_uri); 25 26 return pht(<<<EOTEXT 27WARNING: This build step is new and experimental! 28 29To build **revisions** with Buildkite, they must: 30 31 - belong to a tracked repository; 32 - the repository must have a Staging Area configured; 33 - you must configure a Buildkite pipeline for that Staging Area; and 34 - you must configure the webhook described below. 35 36To build **commits** with Buildkite, they must: 37 38 - belong to a tracked repository; 39 - you must configure a Buildkite pipeline for that repository; and 40 - you must configure the webhook described below. 41 42Webhook Configuration 43===================== 44 45In {nav Settings} for your Organization in Buildkite, under 46{nav Notification Services}, add a new **Webhook Notification**. 47 48Use these settings: 49 50 - **Webhook URL**: %s 51 - **Token**: The "Webhook Token" field below and the "Token" field in 52 Buildkite should both be set to the same nonempty value (any random 53 secret). You can use copy/paste the value Buildkite generates into 54 this form. 55 - **Events**: Only **build.finish** needs to be active. 56 57Environment 58=========== 59 60These variables will be available in the build environment: 61 62| Variable | Description | 63|----------|-------------| 64| `HARBORMASTER_BUILD_TARGET_PHID` | PHID of the Build Target. | 65EOTEXT 66 , 67 $hook_uri); 68 } 69 70 public function execute( 71 HarbormasterBuild $build, 72 HarbormasterBuildTarget $build_target) { 73 $viewer = PhabricatorUser::getOmnipotentUser(); 74 75 if (PhabricatorEnv::getEnvConfig('phabricator.silent')) { 76 $this->logSilencedCall($build, $build_target, pht('Buildkite')); 77 throw new HarbormasterBuildFailureException(); 78 } 79 80 $buildable = $build->getBuildable(); 81 82 $object = $buildable->getBuildableObject(); 83 if (!($object instanceof HarbormasterBuildkiteBuildableInterface)) { 84 throw new Exception( 85 pht('This object does not support builds with Buildkite.')); 86 } 87 88 $organization = $this->getSetting('organization'); 89 $pipeline = $this->getSetting('pipeline'); 90 91 $uri = urisprintf( 92 'https://api.buildkite.com/v2/organizations/%s/pipelines/%s/builds', 93 $organization, 94 $pipeline); 95 96 $data_structure = array( 97 'commit' => $object->getBuildkiteCommit(), 98 'branch' => $object->getBuildkiteBranch(), 99 'message' => pht( 100 'Harbormaster Build %s ("%s") for %s', 101 $build->getID(), 102 $build->getName(), 103 $buildable->getMonogram()), 104 'env' => array( 105 'HARBORMASTER_BUILD_TARGET_PHID' => $build_target->getPHID(), 106 ), 107 'meta_data' => array( 108 'buildTargetPHID' => $build_target->getPHID(), 109 110 // See PHI611. These are undocumented secret magic. 111 'phabricator:build:id' => (int)$build->getID(), 112 'phabricator:build:url' => 113 PhabricatorEnv::getProductionURI($build->getURI()), 114 'phabricator:buildable:id' => (int)$buildable->getID(), 115 'phabricator:buildable:url' => 116 PhabricatorEnv::getProductionURI($buildable->getURI()), 117 ), 118 ); 119 120 $engine = HarbormasterBuildableEngine::newForObject( 121 $object, 122 $viewer); 123 124 $author_identity = $engine->getAuthorIdentity(); 125 if ($author_identity) { 126 $data_structure += array( 127 'author' => array( 128 'name' => $author_identity->getIdentityDisplayName(), 129 'email' => $author_identity->getIdentityEmailAddress(), 130 ), 131 ); 132 } 133 134 $json_data = phutil_json_encode($data_structure); 135 136 $credential_phid = $this->getSetting('token'); 137 $api_token = id(new PassphraseCredentialQuery()) 138 ->setViewer($viewer) 139 ->withPHIDs(array($credential_phid)) 140 ->needSecrets(true) 141 ->executeOne(); 142 if (!$api_token) { 143 throw new Exception( 144 pht( 145 'Unable to load API token ("%s")!', 146 $credential_phid)); 147 } 148 149 $token = $api_token->getSecret()->openEnvelope(); 150 151 $future = id(new HTTPSFuture($uri, $json_data)) 152 ->setMethod('POST') 153 ->addHeader('Content-Type', 'application/json') 154 ->addHeader('Accept', 'application/json') 155 ->addHeader('Authorization', "Bearer {$token}") 156 ->setTimeout(60); 157 158 $this->resolveFutures( 159 $build, 160 $build_target, 161 array($future)); 162 163 $this->logHTTPResponse($build, $build_target, $future, pht('Buildkite')); 164 165 list($status, $body) = $future->resolve(); 166 if ($status->isError()) { 167 throw new HarbormasterBuildFailureException(); 168 } 169 170 $response = phutil_json_decode($body); 171 172 $uri_key = 'web_url'; 173 $build_uri = idx($response, $uri_key); 174 if (!$build_uri) { 175 throw new Exception( 176 pht( 177 'Buildkite did not return a "%s"!', 178 $uri_key)); 179 } 180 181 $target_phid = $build_target->getPHID(); 182 183 $api_method = 'harbormaster.createartifact'; 184 $api_params = array( 185 'buildTargetPHID' => $target_phid, 186 'artifactType' => HarbormasterURIArtifact::ARTIFACTCONST, 187 'artifactKey' => 'buildkite.uri', 188 'artifactData' => array( 189 'uri' => $build_uri, 190 'name' => pht('View in Buildkite'), 191 'ui.external' => true, 192 ), 193 ); 194 195 id(new ConduitCall($api_method, $api_params)) 196 ->setUser($viewer) 197 ->execute(); 198 } 199 200 public function getFieldSpecifications() { 201 return array( 202 'token' => array( 203 'name' => pht('API Token'), 204 'type' => 'credential', 205 'credential.type' 206 => PassphraseTokenCredentialType::CREDENTIAL_TYPE, 207 'credential.provides' 208 => PassphraseTokenCredentialType::PROVIDES_TYPE, 209 'required' => true, 210 ), 211 'organization' => array( 212 'name' => pht('Organization Name'), 213 'type' => 'text', 214 'required' => true, 215 ), 216 'pipeline' => array( 217 'name' => pht('Pipeline Name'), 218 'type' => 'text', 219 'required' => true, 220 ), 221 'webhook.token' => array( 222 'name' => pht('Webhook Token'), 223 'type' => 'text', 224 'required' => true, 225 ), 226 ); 227 } 228 229 public function supportsWaitForMessage() { 230 return false; 231 } 232 233 public function shouldWaitForMessage(HarbormasterBuildTarget $target) { 234 return true; 235 } 236 237}