Changeset View
Changeset View
Standalone View
Standalone View
src/workflow/ArcanistDiffWorkflow.php
Show All 16 Lines | final class ArcanistDiffWorkflow extends ArcanistWorkflow { | ||||
private $testResults; | private $testResults; | ||||
private $diffID; | private $diffID; | ||||
private $revisionID; | private $revisionID; | ||||
private $haveUncommittedChanges = false; | private $haveUncommittedChanges = false; | ||||
private $diffPropertyFutures = array(); | private $diffPropertyFutures = array(); | ||||
private $commitMessageFromRevision; | private $commitMessageFromRevision; | ||||
private $hitAutotargets; | private $hitAutotargets; | ||||
const STAGING_PUSHED = 'pushed'; | |||||
const STAGING_USER_SKIP = 'user.skip'; | |||||
const STAGING_DIFF_RAW = 'diff.raw'; | |||||
const STAGING_REPOSITORY_UNKNOWN = 'repository.unknown'; | |||||
const STAGING_REPOSITORY_UNAVAILABLE = 'repository.unavailable'; | |||||
const STAGING_REPOSITORY_UNSUPPORTED = 'repository.unsupported'; | |||||
const STAGING_REPOSITORY_UNCONFIGURED = 'repository.unconfigured'; | |||||
const STAGING_CLIENT_UNSUPPORTED = 'client.unsupported'; | |||||
public function getWorkflowName() { | public function getWorkflowName() { | ||||
return 'diff'; | return 'diff'; | ||||
} | } | ||||
public function getCommandSynopses() { | public function getCommandSynopses() { | ||||
return phutil_console_format(<<<EOTEXT | return phutil_console_format(<<<EOTEXT | ||||
**diff** [__paths__] (svn) | **diff** [__paths__] (svn) | ||||
**diff** [__commit__] (git, hg) | **diff** [__commit__] (git, hg) | ||||
▲ Show 20 Lines • Show All 481 Lines • ▼ Show 20 Lines | public function run() { | ||||
$event = $this->dispatchEvent( | $event = $this->dispatchEvent( | ||||
ArcanistEventType::TYPE_DIFF_WASCREATED, | ArcanistEventType::TYPE_DIFF_WASCREATED, | ||||
array( | array( | ||||
'diffID' => $diff_info['diffid'], | 'diffID' => $diff_info['diffid'], | ||||
'lintResult' => $lint_result, | 'lintResult' => $lint_result, | ||||
'unitResult' => $unit_result, | 'unitResult' => $unit_result, | ||||
)); | )); | ||||
$this->pushChangesToStagingArea($this->diffID); | $this->submitChangesToStagingArea($this->diffID); | ||||
$phid = idx($diff_info, 'phid'); | $phid = idx($diff_info, 'phid'); | ||||
if ($phid) { | if ($phid) { | ||||
$this->hitAutotargets = $this->updateAutotargets( | $this->hitAutotargets = $this->updateAutotargets( | ||||
$phid, | $phid, | ||||
$unit_result); | $unit_result); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,121 Lines • ▼ Show 20 Lines | private function getFileMimeType($data) { | ||||
Filesystem::writeFile($tmp, $data); | Filesystem::writeFile($tmp, $data); | ||||
return Filesystem::getMimeType($tmp); | return Filesystem::getMimeType($tmp); | ||||
} | } | ||||
private function shouldOpenCreatedObjectsInBrowser() { | private function shouldOpenCreatedObjectsInBrowser() { | ||||
return $this->getArgument('browse'); | return $this->getArgument('browse'); | ||||
} | } | ||||
private function submitChangesToStagingArea($id) { | |||||
$result = $this->pushChangesToStagingArea($id); | |||||
// We'll either get a failure constant on error, or a list of pushed | |||||
// refs on success. | |||||
$ok = is_array($result); | |||||
if ($ok) { | |||||
$staging = array( | |||||
'status' => self::STAGING_PUSHED, | |||||
'refs' => $result, | |||||
); | |||||
} else { | |||||
$staging = array( | |||||
'status' => $result, | |||||
'refs' => array(), | |||||
); | |||||
} | |||||
$this->updateDiffProperty( | |||||
'arc.staging', | |||||
phutil_json_encode($staging)); | |||||
} | |||||
private function pushChangesToStagingArea($id) { | private function pushChangesToStagingArea($id) { | ||||
if ($this->getArgument('skip-staging')) { | if ($this->getArgument('skip-staging')) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('Flag --skip-staging was specified.')); | pht('Flag --skip-staging was specified.')); | ||||
return; | return self::STAGING_USER_SKIP; | ||||
} | } | ||||
if ($this->isRawDiffSource()) { | if ($this->isRawDiffSource()) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('Raw changes can not be pushed to a staging area.')); | pht('Raw changes can not be pushed to a staging area.')); | ||||
return; | return self::STAGING_DIFF_RAW; | ||||
} | } | ||||
if (!$this->getRepositoryPHID()) { | if (!$this->getRepositoryPHID()) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('Unable to determine repository for this change.')); | pht('Unable to determine repository for this change.')); | ||||
return; | return self::STAGING_REPOSITORY_UNKNOWN; | ||||
} | } | ||||
$staging = $this->getRepositoryStagingConfiguration(); | $staging = $this->getRepositoryStagingConfiguration(); | ||||
if ($staging === null) { | if ($staging === null) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('The server does not support staging areas.')); | pht('The server does not support staging areas.')); | ||||
return; | return self::STAGING_REPOSITORY_UNAVAILABLE; | ||||
} | } | ||||
$supported = idx($staging, 'supported'); | $supported = idx($staging, 'supported'); | ||||
if (!$supported) { | if (!$supported) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('Phabricator does not support staging areas for this repository.')); | pht('Phabricator does not support staging areas for this repository.')); | ||||
return; | return self::STAGING_REPOSITORY_UNSUPPORTED; | ||||
} | } | ||||
$staging_uri = idx($staging, 'uri'); | $staging_uri = idx($staging, 'uri'); | ||||
if (!$staging_uri) { | if (!$staging_uri) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('No staging area is configured for this repository.')); | pht('No staging area is configured for this repository.')); | ||||
return; | return self::STAGING_REPOSITORY_UNCONFIGURED; | ||||
} | } | ||||
$api = $this->getRepositoryAPI(); | $api = $this->getRepositoryAPI(); | ||||
if (!($api instanceof ArcanistGitAPI)) { | if (!($api instanceof ArcanistGitAPI)) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('This client version does not support staging this repository.')); | pht('This client version does not support staging this repository.')); | ||||
return; | return self::STAGING_CLIENT_UNSUPPORTED; | ||||
} | } | ||||
$commit = $api->getHeadCommit(); | $commit = $api->getHeadCommit(); | ||||
$prefix = idx($staging, 'prefix', 'phabricator'); | $prefix = idx($staging, 'prefix', 'phabricator'); | ||||
$base_tag = $prefix.'/base/'.$id; | $base_tag = "refs/tags/{$prefix}/base/{$id}"; | ||||
$diff_tag = $prefix.'/diff/'.$id; | $diff_tag = "refs/tags/{$prefix}/diff/{$id}"; | ||||
$this->writeOkay( | $this->writeOkay( | ||||
pht('PUSH STAGING'), | pht('PUSH STAGING'), | ||||
pht('Pushing changes to staging area...')); | pht('Pushing changes to staging area...')); | ||||
$push_flags = array(); | $push_flags = array(); | ||||
if (version_compare($api->getGitVersion(), '1.8.2', '>=')) { | if (version_compare($api->getGitVersion(), '1.8.2', '>=')) { | ||||
$push_flags[] = '--no-verify'; | $push_flags[] = '--no-verify'; | ||||
} | } | ||||
$refs = array(); | $refs = array(); | ||||
$remote = array( | |||||
'uri' => $staging_uri, | |||||
); | |||||
// If the base commit is a real commit, we're going to push it. We don't | // If the base commit is a real commit, we're going to push it. We don't | ||||
// use this, but pushing it to a ref reduces the amount of redundant work | // use this, but pushing it to a ref reduces the amount of redundant work | ||||
// that Git does on later pushes by helping it figure out that the remote | // that Git does on later pushes by helping it figure out that the remote | ||||
// already has most of the history. See T10509. | // already has most of the history. See T10509. | ||||
// In the future, we could avoid this push if the staging area is the same | // In the future, we could avoid this push if the staging area is the same | ||||
// as the main repository, or if the staging area is a virtual repository. | // as the main repository, or if the staging area is a virtual repository. | ||||
// In these cases, the staging area should automatically have up-to-date | // In these cases, the staging area should automatically have up-to-date | ||||
// refs. | // refs. | ||||
$base_commit = $api->getSourceControlBaseRevision(); | $base_commit = $api->getSourceControlBaseRevision(); | ||||
if ($base_commit !== ArcanistGitAPI::GIT_MAGIC_ROOT_COMMIT) { | if ($base_commit !== ArcanistGitAPI::GIT_MAGIC_ROOT_COMMIT) { | ||||
$refs[] = "{$base_commit}:refs/tags/{$base_tag}"; | $refs[] = array( | ||||
'ref' => $base_tag, | |||||
'type' => 'base', | |||||
'commit' => $base_commit, | |||||
'remote' => $remote, | |||||
); | |||||
} | } | ||||
// We're always going to push the change itself. | // We're always going to push the change itself. | ||||
$refs[] = "{$commit}:refs/tags/{$diff_tag}"; | $refs[] = array( | ||||
'ref' => $diff_tag, | |||||
'type' => 'diff', | |||||
'commit' => $commit, | |||||
'remote' => $remote, | |||||
); | |||||
$ref_list = array(); | |||||
foreach ($refs as $ref) { | |||||
$ref_list[] = $ref['commit'].':'.$ref['ref']; | |||||
} | |||||
$err = phutil_passthru( | $err = phutil_passthru( | ||||
'git push %Ls -- %s %Ls', | 'git push %Ls -- %s %Ls', | ||||
$push_flags, | $push_flags, | ||||
$staging_uri, | $staging_uri, | ||||
$refs); | $ref_list); | ||||
if ($err) { | if ($err) { | ||||
$this->writeWarn( | $this->writeWarn( | ||||
pht('STAGING FAILED'), | pht('STAGING FAILED'), | ||||
pht('Unable to push changes to the staging area.')); | pht('Unable to push changes to the staging area.')); | ||||
throw new ArcanistUsageException( | throw new ArcanistUsageException( | ||||
pht( | pht( | ||||
'Failed to push changes to staging area. Correct the issue, or '. | 'Failed to push changes to staging area. Correct the issue, or '. | ||||
'use --skip-staging to skip this step.')); | 'use --skip-staging to skip this step.')); | ||||
} | } | ||||
return $refs; | |||||
} | } | ||||
/** | /** | ||||
* Try to upload lint and unit test results into modern Harbormaster build | * Try to upload lint and unit test results into modern Harbormaster build | ||||
* targets. | * targets. | ||||
* | * | ||||
* @return bool True if everything was uploaded to build targets. | * @return bool True if everything was uploaded to build targets. | ||||
▲ Show 20 Lines • Show All 82 Lines • Show Last 20 Lines |