diff --git a/contrib/sentry.php b/contrib/sentry.php index 516c16557..d22bbce9a 100644 --- a/contrib/sentry.php +++ b/contrib/sentry.php @@ -8,6 +8,7 @@ - **token** *(required)*: authentication token. Can be created at [https://sentry.io/settings/account/api/auth-tokens/] - **version** *(required)* – a version identifier for this release. Can be a version number, a commit hash etc. (Defaults is set to git log -n 1 --format="%h".) +When [`release_version_file`](/docs/recipe/deploy/update_code.md#release_version_file) is set and the file exists, defaults to its content. - **version_prefix** *(optional)* - a string prefixed to version. Releases are global per organization so indipentent projects needs to prefix version number with unique string to avoid conflicts - **environment** *(optional)* - the environment you’re deploying to. By default framework's environment is used. @@ -237,6 +238,10 @@ function getReleaseGitRef(): Closure return trim(run($config['git_version_command'])); } + if (!empty(get('release_version_file')) && test('[ -f {{current_path}}/{{release_version_file}} ]')) { + return run('cat {{current_path}}/{{release_version_file}}'); + } + if ($strategy !== 'clone') { return run('cat {{current_path}}/REVISION'); } diff --git a/docs/contrib/sentry.md b/docs/contrib/sentry.md index 434131fa3..721af0f1e 100644 --- a/docs/contrib/sentry.md +++ b/docs/contrib/sentry.md @@ -18,6 +18,7 @@ require 'contrib/sentry.php'; - **token** *(required)*: authentication token. Can be created at [https://sentry.io/settings/account/api/auth-tokens/] - **version** *(required)* – a version identifier for this release. Can be a version number, a commit hash etc. (Defaults is set to git log -n 1 --format="%h".) +When [`release_version_file`](/docs/recipe/deploy/update_code.md#release_version_file) is set and the file exists, defaults to its content. - **version_prefix** *(optional)* - a string prefixed to version. Releases are global per organization so indipentent projects needs to prefix version number with unique string to avoid conflicts - **environment** *(optional)* - the environment you’re deploying to. By default framework's environment is used. diff --git a/docs/recipe/deploy/release.md b/docs/recipe/deploy/release.md index 0099a41d3..003e8c09e 100644 --- a/docs/recipe/deploy/release.md +++ b/docs/recipe/deploy/release.md @@ -68,8 +68,18 @@ return run('cat {{release_path}}/REVISION'); ``` +### release_version +[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/release.php#L75) + +Current release version, saved when `release_version_file` is set. Usually a git tag. + +```php title="Default value" +return run('cat {{release_path}}/{{release_version_file}}'); +``` + + ### release_or_current_path -[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/release.php#L76) +[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/release.php#L81) Return the release path during a deployment but fallback to the current path otherwise. @@ -84,7 +94,7 @@ return $releaseExists ? get('release_path') : get('current_path'); ## Tasks ### deploy\:release {#deploy-release} -[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/release.php#L83) +[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/release.php#L88) Prepares release. @@ -92,7 +102,7 @@ Clean up unfinished releases and prepare next release ### releases {#releases} -[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/release.php#L158) +[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/release.php#L163) Shows releases list. diff --git a/docs/recipe/deploy/update_code.md b/docs/recipe/deploy/update_code.md index 2063c2972..82cb36cd1 100644 --- a/docs/recipe/deploy/update_code.md +++ b/docs/recipe/deploy/update_code.md @@ -78,11 +78,35 @@ false ``` +### release_version_file +[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/update_code.php#L73) + +File, relative to [`release_path`](/docs/recipe/deploy/release.md#release_path), where the release version is saved. +Disabled by default. Set it to `VERSION` to expose a human-readable version to the deployed application. + +```php title="Default value" +false +``` + + +### release_version_command +[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/update_code.php#L81) + +Git command computing the release version saved in [`release_version_file`](#release_version_file). +Defaults to `git describe`: the tag pointing at the deployed target (`v1.2.0`), the latest tag followed by +the number of commits since and the abbreviated commit hash (`v1.2.0-3-gabc1234`), or the abbreviated +commit hash if there is no tag. + +```php title="Default value" +'git describe --tags --always {{target}}' +``` + + ## Tasks ### deploy\:update_code {#deploy-update_code} -[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/update_code.php#L73) +[Source](https://github.com/deployphp/deployer/blob/master/recipe/deploy/update_code.php#L87) Updates code. diff --git a/recipe/deploy/release.php b/recipe/deploy/release.php index 25c8b817c..4e98055e5 100644 --- a/recipe/deploy/release.php +++ b/recipe/deploy/release.php @@ -71,6 +71,11 @@ return run('cat {{release_path}}/REVISION'); }); +// Current release version, saved when `release_version_file` is set. Usually a git tag. +set('release_version', function () { + return run('cat {{release_path}}/{{release_version_file}}'); +}); + // Return the release path during a deployment // but fallback to the current path otherwise. set('release_or_current_path', function () { diff --git a/recipe/deploy/update_code.php b/recipe/deploy/update_code.php index 5ec662179..6ed2ccca6 100644 --- a/recipe/deploy/update_code.php +++ b/recipe/deploy/update_code.php @@ -66,6 +66,20 @@ */ set('sub_directory', false); +/** + * File, relative to [`release_path`](/docs/recipe/deploy/release.md#release_path), where the release version is saved. + * Disabled by default. Set it to `VERSION` to expose a human-readable version to the deployed application. + */ +set('release_version_file', false); + +/** + * Git command computing the release version saved in [`release_version_file`](#release_version_file). + * Defaults to `git describe`: the tag pointing at the deployed target (`v1.2.0`), the latest tag followed by + * the number of commits since and the abbreviated commit hash (`v1.2.0-3-gabc1234`), or the abbreviated + * commit hash if there is no tag. + */ +set('release_version_command', 'git describe --tags --always {{target}}'); + /** * Update code at {{release_path}} on host. */ @@ -88,6 +102,9 @@ unlink("$gitRoot/archive.tar"); $rev = quote(runLocally("git rev-list $target -1")); + if (!empty(get('release_version_file'))) { + $version = quote(runLocally(get('release_version_command'))); + } } else { $git = get('bin/git'); $repository = get('repository'); @@ -131,8 +148,15 @@ } $rev = quote(run("$git rev-list $target -1")); + if (!empty(get('release_version_file'))) { + $version = quote(run(get('release_version_command'))); + } } // Save git revision in REVISION file. run("echo $rev > {{release_path}}/REVISION"); + + if (isset($version)) { + run("echo $version > {{release_path}}/{{release_version_file}}"); + } }); diff --git a/tests/spec/ReleaseVersionTest.php b/tests/spec/ReleaseVersionTest.php new file mode 100644 index 000000000..fdf3b0327 --- /dev/null +++ b/tests/spec/ReleaseVersionTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Deployer; + +use spec\SpecTest; + +class ReleaseVersionTest extends SpecTest +{ + public const RECIPE = __DIR__ . '/recipe/release_version.php'; + private const TAG = 'v1.2.3'; + + protected function setUp(): void + { + // Each test needs a fresh deploy path: the mirror in .dep/repo keeps tags deleted from the repository. + self::cleanUp(); + mkdir(__TEMP_DIR__); + // The current symlink may point to a release of a previous test: clear PHP realpath cache. + clearstatcache(true); + } + + protected function tearDown(): void + { + exec('git -C ' . __REPOSITORY__ . ' tag -d ' . self::TAG . ' 2>&1'); + } + + public function testVersionIsAbbreviatedCommitHashWithoutTag() + { + $this->depFile(self::RECIPE, 'deploy'); + self::assertEquals(0, $this->tester->getStatusCode(), $this->tester->getDisplay()); + + $hash = trim(exec('git -C ' . __REPOSITORY__ . ' rev-parse HEAD')); + $shortHash = trim(exec('git -C ' . __REPOSITORY__ . ' rev-parse --short HEAD')); + foreach ($this->deployer->hosts as $host) { + self::assertEquals($shortHash, trim(file_get_contents($host->get('deploy_path') . '/current/VERSION'))); + self::assertEquals($hash, trim(file_get_contents($host->get('deploy_path') . '/current/REVISION'))); + } + } + + public function testVersionIsTagWhenTargetIsTagged() + { + exec('git -C ' . __REPOSITORY__ . ' tag ' . self::TAG); + + $this->depFile(self::RECIPE, 'deploy'); + self::assertEquals(0, $this->tester->getStatusCode(), $this->tester->getDisplay()); + + $hash = trim(exec('git -C ' . __REPOSITORY__ . ' rev-parse HEAD')); + foreach ($this->deployer->hosts as $host) { + self::assertEquals(self::TAG, trim(file_get_contents($host->get('deploy_path') . '/current/VERSION'))); + self::assertEquals($hash, trim(file_get_contents($host->get('deploy_path') . '/current/REVISION'))); + } + } +} diff --git a/tests/spec/recipe/release_version.php b/tests/spec/recipe/release_version.php new file mode 100644 index 000000000..4a3dc7666 --- /dev/null +++ b/tests/spec/recipe/release_version.php @@ -0,0 +1,7 @@ +