diff --git a/RoboFile.php b/RoboFile.php index 4bb644a1..d5850887 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -116,28 +116,20 @@ public function exportContent( } /** - * Create a release. - * - * @command drupal-project:create-release - * - * @aliases create-release + * Shared functionality to help create and re-tag a release. * * @param string $hotfix_or_release - * Either 'hotfix' or 'release'. - * + * Either 'hotfix' or 'release'. * @param string $semantic_version - * A semantic version number in the form x.y.z. Release must end in 0. + * A semantic version number in the form x.y.z. Release must end in 0. * - * @return \Robo\ResultData + * @return array + * An indexed array of [$tag_description, $new_branch_name, $source_branch]. * * @throws \Exception */ - public function createRelease( - InputInterface $input, - OutputInterface $output, - string $hotfix_or_release, - string $semantic_version, - ): ResultData + + protected function getVariablesForRelease(string $hotfix_or_release, string $semantic_version): array { if (!in_array($hotfix_or_release, ['hotfix', 'release'])) { throw new InvalidArgumentException("hotfix_or_release must be either 'hotfix' or 'release', '$hotfix_or_release' given."); @@ -164,7 +156,37 @@ public function createRelease( } $new_branch_name = "$hotfix_or_release/$semantic_version"; + + return [$tag_description, $new_branch_name, $source_branch]; + } + + /** + * Create a release. + * + * @command drupal-project:create-release + * + * @aliases create-release + * + * @param string $hotfix_or_release + * Either 'hotfix' or 'release'. + * @param string $semantic_version + * A semantic version number in the form x.y.z. Release must end in 0. + * + * @return \Robo\ResultData + * + * @throws \Exception + */ + public function createRelease( + InputInterface $input, + OutputInterface $output, + string $hotfix_or_release, + string $semantic_version, + ): ResultData + { + [$tag_description, $new_branch_name, $source_branch] = $this->getVariablesForRelease($hotfix_or_release, $semantic_version); + `git fetch`; + // Checkout the branch that the release will be created from. $this->taskGitStack() ->stopOnFail() ->checkout($source_branch) @@ -177,7 +199,10 @@ public function createRelease( // also wipe out your changes. `git reset --hard origin/$source_branch`; + // Create the new release branch. `git checkout -b $new_branch_name`; + + // Create a new release tag and push the release branch and tag. $this->taskGitStack() ->stopOnFail() ->push('origin', $new_branch_name) @@ -188,4 +213,60 @@ public function createRelease( return new ResultData(); } + /** + * Re-creates the tag for a release after updates have been pushed. + * + * The release branch will already be up to date because a feature branch + * should have been pushed to it, but the initial tag will be out of date + * now. This checks out the current version of the release, deletes the tag + * then pushes back up the tag. + * + * @command drupal-project:re-tag-release + * + * @aliases re-tag + * + * @param string $hotfix_or_release + * Either 'hotfix' or 'release'. + * @param string $semantic_version + * A semantic version number in the form x.y.z. Release must end in 0. + * + * @return \Robo\ResultData + * + * @throws \Exception + */ + public function reTagRelease( + InputInterface $input, + OutputInterface $output, + string $hotfix_or_release, + string $semantic_version, + ): ResultData + { + [$tag_description, $new_branch_name] = $this->getVariablesForRelease($hotfix_or_release, $semantic_version); + + `git fetch`; + // Check back out the release branch that has been updated by a feature + // request and is ahead of the source branch. + $this->taskGitStack() + ->stopOnFail() + ->checkout($new_branch_name) + ->run(); + + // Ensure that the release is at the latest. + `git reset --hard origin/$new_branch_name`; + + // Delete the old tag locally and remotely. + `git tag --delete v$semantic_version`; + `git push origin --delete v$semantic_version`; + + // Create a new tag of the same named based on the updated release + // branch. + $this->taskGitStack() + ->stopOnFail() + ->tag("v$semantic_version", $tag_description) + ->push('origin', "v$semantic_version") + ->run(); + + return new ResultData(); + } + }