From 94c5ebcd13cdbd36881ab482c36701eb29464675 Mon Sep 17 00:00:00 2001 From: Peter Jaap Blaakmeer Date: Fri, 10 Oct 2025 13:32:54 +0200 Subject: [PATCH 1/4] Add Tideways deployment notification task This file contains a task to notify Tideways of deployments, including configuration options and usage instructions. --- contrib/tideways.php | 151 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 contrib/tideways.php diff --git a/contrib/tideways.php b/contrib/tideways.php new file mode 100644 index 000000000..4284e3e8b --- /dev/null +++ b/contrib/tideways.php @@ -0,0 +1,151 @@ + 'your-api-key', + 'version' => '', + 'environment' => 'production', + 'service' => 'web', + 'compare_after_minutes' => 90, +]); +``` + +### Suggested Usage + +Since you should only notify Tideways of a successful deployment, the deploy:tideways task should be executed right at the end. + +```php +// deploy.php + +after('deploy:success', 'deploy:tideways'); +``` + + */ + +namespace Deployer; + +use Deployer\Utility\Httpie; + +desc('Notifies Tideways of deployment'); +task( + 'deploy:tideways', + static function () { + $defaultConfig = [ + 'version' => getReleaseGitRef(), + 'environment' => 'production', + 'service' => 'web', + 'compare_after_minutes' => 90, + 'project' => null, + 'description' => null, + 'tideways_server' => 'https://app.tideways.io', + ]; + + $config = array_merge($defaultConfig, (array) get('tideways')); + array_walk( + $config, + static function (&$value) use ($config) { + if (is_callable($value)) { + $value = $value($config); + } + }, + ); + + if (!isset($config['api_key']) || empty($config['api_key'])) { + writeln('Skipping Tideways release creation: api_key not set'); + return; + } + + if (!isset($config['version']) || empty($config['version'])) { + throw new \RuntimeException( + << 'your-api-key', + 'version' => '1.0.0', + ] + ); + EXAMPLE, + ); + } + + $payload = [ + 'apiKey' => $config['api_key'], + 'name' => $config['version'], + 'type' => 'release', + 'environment' => $config['environment'], + 'service' => $config['service'], + 'compareAfterMinutes' => (int) $config['compare_after_minutes'], + ]; + + // Add description if provided or generate from project + if (!empty($config['description'])) { + $payload['description'] = $config['description']; + } elseif (!empty($config['project'])) { + $payload['description'] = "Release {$config['version']} for project {$config['project']}"; + } + + $eventsApiUrl = $config['tideways_server'] . '/api/events'; + + try { + Httpie::post($eventsApiUrl) + ->setopt(CURLOPT_TIMEOUT, 10) + ->header('Content-Type', 'application/json') + ->body(json_encode($payload)) + ->send(); + + writeln( + sprintf( + 'Tideways: Release %s ' . + 'for environment %s and service %s created successfully.', + $config['version'], + $config['environment'], + $config['service'], + ), + ); + } catch (\Throwable $e) { + writeln('Failed to create Tideways release: ' . $e->getMessage() . ''); + throw $e; + } + }, +); + +function getReleaseGitRef(): \Closure +{ + return static function ($config = []): string { + if (get('update_code_strategy') === 'archive') { + if (isset($config['git_version_command'])) { + cd('{{deploy_path}}/.dep/repo'); + + return trim(run($config['git_version_command'])); + } + + return run('cat {{current_path}}/REVISION'); + } + + cd('{{release_path}}'); + + if (isset($config['git_version_command'])) { + return trim(run($config['git_version_command'])); + } + + return trim(run('git log -n 1 --format="%h"')); + }; +} + From 8b6d496a30a7c5f43fd3f8244e17904545e7adcd Mon Sep 17 00:00:00 2001 From: peterjaap Date: Fri, 10 Oct 2025 13:34:21 +0200 Subject: [PATCH 2/4] update docs --- docs/contrib/README.md | 1 + docs/contrib/tideways.md | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 docs/contrib/tideways.md diff --git a/docs/contrib/README.md b/docs/contrib/README.md index c75174196..94830a2b0 100644 --- a/docs/contrib/README.md +++ b/docs/contrib/README.md @@ -29,6 +29,7 @@ * [Slack Recipe](/docs/contrib/slack.md) * [Supervisord-monitor Recipe](/docs/contrib/supervisord-monitor.md) * [Telegram Recipe](/docs/contrib/telegram.md) +* [Tideways Recipe](/docs/contrib/tideways.md) * [Webpack_encore Recipe](/docs/contrib/webpack_encore.md) * [Workplace Recipe](/docs/contrib/workplace.md) * [Yammer Recipe](/docs/contrib/yammer.md) diff --git a/docs/contrib/tideways.md b/docs/contrib/tideways.md new file mode 100644 index 000000000..f1b86f782 --- /dev/null +++ b/docs/contrib/tideways.md @@ -0,0 +1,43 @@ + + + + +# Tideways Recipe + +```php +require 'contrib/tideways.php'; +``` + +[Source](/contrib/tideways.php) + + + +### Configuration options +- **api_key** *(required)*: Tideways API key for authentication. +- **version** *(required)*: A version identifier for this release. Can be a version number, a commit hash etc. (Default is set to git log -n 1 --format="%h".) +- **environment** *(optional)*: The environment you're deploying to. Defaults to 'production'. +- **service** *(optional)*: The service name for the release. Defaults to 'web'. +- **compare_after_minutes** *(optional)*: Time in minutes to compare performance before/after release. Defaults to 90. +- **project** *(optional)*: Project name/path for the description field. +- **description** *(optional)*: Custom description for the release. +- **tideways_server** *(optional)*: Tideways server URL. Defaults to 'https://app.tideways.io'. +- **git_version_command** *(optional)*: The command that retrieves the git version information. Defaults to 'git log -n 1 --format="%h"'. +```php +deploy.php +set('tideways', [ + 'api_key' => 'your-api-key', + 'version' => '', + 'environment' => 'production', + 'service' => 'web', + 'compare_after_minutes' => 90, +]); +``` +### Suggested Usage +Since you should only notify Tideways of a successful deployment, the deploy:tideways task should be executed right at the end. +```php +deploy.php +after('deploy:success', 'deploy:tideways'); +``` + + + From 89b45c69e17bb20695b15660bd8576e5c9e47f78 Mon Sep 17 00:00:00 2001 From: Peter Jaap Blaakmeer Date: Fri, 10 Oct 2025 16:33:21 +0200 Subject: [PATCH 3/4] Add Tideways deployment hook after successful deploy --- contrib/tideways.php | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/tideways.php b/contrib/tideways.php index 4284e3e8b..d18b4744d 100644 --- a/contrib/tideways.php +++ b/contrib/tideways.php @@ -149,3 +149,4 @@ function getReleaseGitRef(): \Closure }; } +after('deploy:success', 'deploy:tideways'); From 9029738ed9f35aad50c53410d4835af36d49a624 Mon Sep 17 00:00:00 2001 From: Peter Jaap Blaakmeer Date: Fri, 10 Oct 2025 16:38:34 +0200 Subject: [PATCH 4/4] Refactor Tideways deployment notification logic --- contrib/tideways.php | 179 ++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 96 deletions(-) diff --git a/contrib/tideways.php b/contrib/tideways.php index d18b4744d..52194d5aa 100644 --- a/contrib/tideways.php +++ b/contrib/tideways.php @@ -1,17 +1,17 @@ 'web', 'compare_after_minutes' => 90, ]); -``` - -### Suggested Usage - -Since you should only notify Tideways of a successful deployment, the deploy:tideways task should be executed right at the end. - -```php -// deploy.php - -after('deploy:success', 'deploy:tideways'); -``` */ @@ -42,89 +31,87 @@ use Deployer\Utility\Httpie; desc('Notifies Tideways of deployment'); -task( - 'deploy:tideways', - static function () { - $defaultConfig = [ - 'version' => getReleaseGitRef(), - 'environment' => 'production', - 'service' => 'web', - 'compare_after_minutes' => 90, - 'project' => null, - 'description' => null, - 'tideways_server' => 'https://app.tideways.io', - ]; - - $config = array_merge($defaultConfig, (array) get('tideways')); - array_walk( - $config, - static function (&$value) use ($config) { - if (is_callable($value)) { - $value = $value($config); - } - }, +task('deploy:tideways', static function () { + $defaultConfig = [ + 'version' => getReleaseGitRef(), + 'environment' => 'production', + 'service' => 'web', + 'compare_after_minutes' => 90, + 'project' => null, + 'description' => null, + 'tideways_server' => 'https://app.tideways.io', + ]; + + $config = array_merge($defaultConfig, (array)get('tideways')); + array_walk( + $config, + static function (&$value) use ($config) { + if (is_callable($value)) { + $value = $value($config); + } + }, + ); + + if (!isset($config['api_key']) || empty($config['api_key'])) { + writeln('Skipping Tideways release creation: api_key not set'); + + return; + } + + if (!isset($config['version']) || empty($config['version'])) { + throw new \RuntimeException( + << 'your-api-key', + 'version' => '1.0.0', + ] + ); + EXAMPLE, ); - - if (!isset($config['api_key']) || empty($config['api_key'])) { - writeln('Skipping Tideways release creation: api_key not set'); - return; - } - - if (!isset($config['version']) || empty($config['version'])) { - throw new \RuntimeException( - << 'your-api-key', - 'version' => '1.0.0', - ] - ); - EXAMPLE, - ); - } - - $payload = [ - 'apiKey' => $config['api_key'], - 'name' => $config['version'], - 'type' => 'release', - 'environment' => $config['environment'], - 'service' => $config['service'], - 'compareAfterMinutes' => (int) $config['compare_after_minutes'], - ]; - - // Add description if provided or generate from project - if (!empty($config['description'])) { - $payload['description'] = $config['description']; - } elseif (!empty($config['project'])) { - $payload['description'] = "Release {$config['version']} for project {$config['project']}"; - } - - $eventsApiUrl = $config['tideways_server'] . '/api/events'; - - try { - Httpie::post($eventsApiUrl) - ->setopt(CURLOPT_TIMEOUT, 10) - ->header('Content-Type', 'application/json') - ->body(json_encode($payload)) - ->send(); - - writeln( - sprintf( - 'Tideways: Release %s ' . - 'for environment %s and service %s created successfully.', - $config['version'], - $config['environment'], - $config['service'], - ), - ); - } catch (\Throwable $e) { - writeln('Failed to create Tideways release: ' . $e->getMessage() . ''); - throw $e; - } - }, -); + } + + $payload = [ + 'apiKey' => $config['api_key'], + 'name' => $config['version'], + 'type' => 'release', + 'environment' => $config['environment'], + 'service' => $config['service'], + 'compareAfterMinutes' => (int)$config['compare_after_minutes'], + ]; + + // Add description if provided or generate from project + if (!empty($config['description'])) { + $payload['description'] = $config['description']; + } elseif (!empty($config['project'])) { + $payload['description'] = "Release {$config['version']} for project {$config['project']}"; + } + + $eventsApiUrl = $config['tideways_server'] . '/api/events'; + + try { + Httpie::post($eventsApiUrl) + ->setopt(CURLOPT_TIMEOUT, 10) + ->header('Content-Type', 'application/json') + ->body(json_encode($payload)) + ->send(); + + writeln( + sprintf( + 'Tideways: Release %s ' . + 'for environment %s and service %s created successfully.', + $config['version'], + $config['environment'], + $config['service'], + ), + ); + } catch (\Throwable $e) { + writeln('Failed to create Tideways release: ' . $e->getMessage() . ''); + throw $e; + } +}); function getReleaseGitRef(): \Closure {