diff --git a/src/workflow/ArcanistDiffWorkflow.php b/src/workflow/ArcanistDiffWorkflow.php --- a/src/workflow/ArcanistDiffWorkflow.php +++ b/src/workflow/ArcanistDiffWorkflow.php @@ -370,6 +370,9 @@ 'skip-binaries' => array( 'help' => pht('Do not upload binaries (like images).'), ), + 'skip-staging' => array( + 'help' => pht('Do not copy changes to the staging area.'), + ), 'ignore-unsound-tests' => array( 'help' => pht('Ignore unsound test failures without prompting.'), ), @@ -517,6 +520,8 @@ 'unitResult' => $unit_result, )); + $this->pushChangesToStagingArea($this->diffID); + $this->updateLintDiffProperty(); $this->updateUnitDiffProperty(); $this->updateLocalDiffProperty(); @@ -2604,4 +2609,85 @@ return $this->getArgument('browse'); } + private function pushChangesToStagingArea($id) { + if ($this->getArgument('skip-staging')) { + $this->writeInfo( + pht('SKIP STAGING'), + pht('Flag --skip-staging was specified.')); + return; + } + + if ($this->isRawDiffSource()) { + $this->writeInfo( + pht('SKIP STAGING'), + pht('Raw changes can not be pushed to a staging area.')); + return; + } + + if (!$this->getRepositoryPHID()) { + $this->writeInfo( + pht('SKIP STAGING'), + pht('Unable to determine repository for this change.')); + return; + } + + $staging = $this->getRepositoryStagingConfiguration(); + if ($staging === null) { + $this->writeInfo( + pht('SKIP STAGING'), + pht('The server does not support staging areas.')); + return; + } + + $supported = idx($staging, 'supported'); + if (!$supported) { + $this->writeInfo( + pht('SKIP STAGING'), + pht('Phabricator does not support staging areas for this repository.')); + return; + } + + $staging_uri = idx($staging, 'uri'); + if (!$staging_uri) { + $this->writeInfo( + pht('SKIP STAGING'), + pht('No staging area is configured for this repository.')); + return; + } + + $api = $this->getRepositoryAPI(); + if (!($api instanceof ArcanistGitAPI)) { + $this->writeInfo( + pht('SKIP STAGING'), + pht('This client version does not support staging this repository.')); + return; + } + + $commit = $api->getHeadCommit(); + $prefix = idx($staging, 'prefix', 'phabricator'); + $tag = $prefix.'/diff/'.$id; + + $this->writeOkay( + pht('PUSH STAGING'), + pht('Pushing changes to staging area...')); + + $err = phutil_passthru( + 'git push --no-verify -- %s %s:refs/tags/%s', + $staging_uri, + $commit, + $tag); + + if ($err) { + $this->writeWarn( + pht('STAGING FAILED'), + pht('Unable to push changes to the staging area.')); + } else { + $this->writeOkay( + pht('STAGING PUSHED'), + pht( + 'Pushed a copy of the changes to tag "%s" in the staging area.', + $tag)); + } + } + } diff --git a/src/workflow/ArcanistWorkflow.php b/src/workflow/ArcanistWorkflow.php --- a/src/workflow/ArcanistWorkflow.php +++ b/src/workflow/ArcanistWorkflow.php @@ -1338,6 +1338,30 @@ fwrite(STDERR, $msg); } + final protected function writeInfo($title, $message) { + $this->writeStatusMessage( + phutil_console_format( + "** %s ** %s\n", + $title, + $message)); + } + + final protected function writeWarn($title, $message) { + $this->writeStatusMessage( + phutil_console_format( + "** %s ** %s\n", + $title, + $message)); + } + + final protected function writeOkay($title, $message) { + $this->writeStatusMessage( + phutil_console_format( + "** %s ** %s\n", + $title, + $message)); + } + final protected function isHistoryImmutable() { $repository_api = $this->getRepositoryAPI(); @@ -1669,6 +1693,11 @@ } + final protected function getRepositoryStagingConfiguration() { + return idx($this->getRepositoryInformation(), 'staging'); + } + + /** * Get human-readable reasoning explaining how `arc` evaluated which * Phabricator repository corresponds to this working copy. Used by