Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -2282,6 +2282,7 @@ 'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php', 'ProjectCapabilityCreateProjects' => 'applications/project/capability/ProjectCapabilityCreateProjects.php', 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', + 'PublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/PublishFragmentBuildStepImplementation.php', 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', @@ -4947,6 +4948,7 @@ 'PonderVoteSaveController' => 'PonderController', 'ProjectCapabilityCreateProjects' => 'PhabricatorPolicyCapability', 'ProjectRemarkupRule' => 'PhabricatorRemarkupRuleObject', + 'PublishFragmentBuildStepImplementation' => 'VariableBuildStepImplementation', 'QueryFormattingTestCase' => 'PhabricatorTestCase', 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', 'ReleephBranch' => Index: src/applications/harbormaster/step/LeaseHostBuildStepImplementation.php =================================================================== --- src/applications/harbormaster/step/LeaseHostBuildStepImplementation.php +++ src/applications/harbormaster/step/LeaseHostBuildStepImplementation.php @@ -53,7 +53,7 @@ $settings = $this->getSettings(); return array( - $settings['name'] => 'host'); + $settings['name'] => HarbormasterBuildArtifact::TYPE_HOST); } public function validateSettings() { Index: src/applications/harbormaster/step/PublishFragmentBuildStepImplementation.php =================================================================== --- /dev/null +++ src/applications/harbormaster/step/PublishFragmentBuildStepImplementation.php @@ -0,0 +1,91 @@ +getSettings(); + + return pht( + 'Publish file artifact \'%s\' to the fragment path \'%s\'.', + $settings['artifact'], + $settings['path']); + } + + public function execute( + HarbormasterBuild $build, + HarbormasterBuildTarget $build_target) { + + $settings = $this->getSettings(); + $variables = $build_target->getVariables(); + + $path = $this->mergeVariables( + 'vsprintf', + $settings['path'], + $variables); + + $artifact = $build->loadArtifact($settings['artifact']); + + $file = $artifact->loadPhabricatorFile(); + + $fragment = id(new PhragmentFragmentQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPaths(array($path)) + ->executeOne(); + + if ($fragment === null) { + PhragmentFragment::createFromFile( + PhabricatorUser::getOmnipotentUser(), + $file, + $path, + PhabricatorPolicies::getMostOpenPolicy(), + PhabricatorPolicies::POLICY_USER); + } else { + if ($file->getMimeType() === "application/zip") { + $fragment->updateFromZIP(PhabricatorUser::getOmnipotentUser(), $file); + } else { + $fragment->updateFromFile(PhabricatorUser::getOmnipotentUser(), $file); + } + } + } + + public function validateSettings() { + $settings = $this->getSettings(); + + if ($settings['path'] === null || !is_string($settings['path'])) { + return false; + } + if ($settings['artifact'] === null || + !is_string($settings['artifact'])) { + return false; + } + + // TODO: Check if the file artifact is provided by previous build steps. + + return true; + } + + public function getSettingDefinitions() { + return array( + 'path' => array( + 'name' => 'Path', + 'description' => + 'The path of the fragment that will be published.', + 'type' => BuildStepImplementation::SETTING_TYPE_STRING), + 'artifact' => array( + 'name' => 'File Artifact', + 'description' => + 'The file artifact that will be published to Phragment.', + 'type' => BuildStepImplementation::SETTING_TYPE_ARTIFACT, + 'artifact_type' => HarbormasterBuildArtifact::TYPE_FILE)); + } + +} Index: src/applications/harbormaster/step/UploadArtifactBuildStepImplementation.php =================================================================== --- src/applications/harbormaster/step/UploadArtifactBuildStepImplementation.php +++ src/applications/harbormaster/step/UploadArtifactBuildStepImplementation.php @@ -51,6 +51,13 @@ $artifact->save(); } + public function getArtifactMappings() { + $settings = $this->getSettings(); + + return array( + $settings['name'] => HarbormasterBuildArtifact::TYPE_FILE); + } + public function validateSettings() { $settings = $this->getSettings(); Index: src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php =================================================================== --- src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php +++ src/applications/harbormaster/storage/build/HarbormasterBuildArtifact.php @@ -96,6 +96,28 @@ return $lease; } + public function loadPhabricatorFile() { + if ($this->getArtifactType() !== self::TYPE_FILE) { + throw new Exception( + "`loadPhabricatorFile` may only be called on file artifacts."); + } + + $data = $this->getArtifactData(); + + // The data for TYPE_FILE is an array with a single PHID in it. + $phid = $data["filePHID"]; + + $file = id(new PhabricatorFileQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withPHIDs(array($phid)) + ->executeOne(); + if ($file === null) { + throw new Exception("Associated file not found!"); + } + return $file; + } + + /* -( PhabricatorPolicyInterface )----------------------------------------- */