1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-20 05:42:40 +01:00

Implement step for publishing files as fragments to Phragment in Harbormaster

Summary: This adds a build step in Harbormaster for publishing file artifacts as fragments in Phragment.

Test Plan:
Created a build plan with the following steps:

  * Lease Host
  * Upload Artifact
  * Publish Fragment

Ran the build plan against a buildable and saw the fragment get created in Phragment.  Ran the plan again and saw the fragment get updated with a new version.  Modified the file that got uploaded and ran the plan again, checked the history of the fragment, and saw the differences represented as a Diff-Match-Patch patch.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley

CC: Korvin, epriestley, aran

Maniphest Tasks: T4205

Differential Revision: https://secure.phabricator.com/D7742
This commit is contained in:
James Rhodes 2013-12-09 09:34:09 +11:00
parent 8bb6e807f0
commit 8fd256a1fd
5 changed files with 123 additions and 1 deletions

View file

@ -2282,6 +2282,7 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'PonderVoteSaveController' => 'PonderController',
'ProjectCapabilityCreateProjects' => 'PhabricatorPolicyCapability',
'ProjectRemarkupRule' => 'PhabricatorRemarkupRuleObject',
'PublishFragmentBuildStepImplementation' => 'VariableBuildStepImplementation',
'QueryFormattingTestCase' => 'PhabricatorTestCase',
'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification',
'ReleephBranch' =>

View file

@ -53,7 +53,7 @@ final class LeaseHostBuildStepImplementation
$settings = $this->getSettings();
return array(
$settings['name'] => 'host');
$settings['name'] => HarbormasterBuildArtifact::TYPE_HOST);
}
public function validateSettings() {

View file

@ -0,0 +1,91 @@
<?php
final class PublishFragmentBuildStepImplementation
extends VariableBuildStepImplementation {
public function getName() {
return pht('Publish Fragment');
}
public function getGenericDescription() {
return pht('Publish a fragment based on a file artifact.');
}
public function getDescription() {
$settings = $this->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));
}
}

View file

@ -51,6 +51,13 @@ final class UploadArtifactBuildStepImplementation
$artifact->save();
}
public function getArtifactMappings() {
$settings = $this->getSettings();
return array(
$settings['name'] => HarbormasterBuildArtifact::TYPE_FILE);
}
public function validateSettings() {
$settings = $this->getSettings();

View file

@ -96,6 +96,28 @@ final class HarbormasterBuildArtifact extends HarbormasterDAO
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 )----------------------------------------- */