diff --git a/.vortex/CLAUDE.md b/.vortex/CLAUDE.md index 74f7f48d9..1d12668cb 100644 --- a/.vortex/CLAUDE.md +++ b/.vortex/CLAUDE.md @@ -96,7 +96,6 @@ These modify many files and take 10-15 minutes. - Multi-line OK for: many parameters, arrays, chained methods, complex conditionals - ```text vortex/ ├── .vortex/ # Test harness and development tools diff --git a/.vortex/tooling/scripts_conversion_plan.md b/.vortex/tooling/scripts_conversion_plan.md index 904223972..faf3b1b7d 100644 --- a/.vortex/tooling/scripts_conversion_plan.md +++ b/.vortex/tooling/scripts_conversion_plan.md @@ -40,7 +40,7 @@ Convert all Vortex bash scripts (`scripts/vortex/*.sh`) to PHP scripts as a stan ### 📊 Test Statistics -- **Total Tests**: 383 tests, 1,740 assertions +- **Total Tests**: 429 tests, 1,861 assertions - **Test Groups**: - `helpers` - 55 tests for core helper functions - `notify` - 132 tests for notification system @@ -753,6 +753,90 @@ function mockFileGetContents(string $path, string $content): void --- +## ✅ Phase 5.5: Sync PHP Scripts with Shell Updates - COMPLETE + +After the initial conversion in Phases 1-5, the shell scripts received updates that +were not reflected in the PHP versions. This phase synchronized all differences. + +### 5.5.1 Notification Scripts Sync + +**notify (router):** +- Added `VORTEX_NOTIFY_BRANCH` (required) variable +- Added `VORTEX_NOTIFY_SHA` (required) variable +- Added `VORTEX_NOTIFY_PR_NUMBER` (optional) variable +- Changed `VORTEX_NOTIFY_ENVIRONMENT_URL` from optional to required +- Added `putenv()` exports for branch, SHA, PR number, label, environment URL, login URL +- Added detailed summary output matching shell format + +**notify-slack:** +- Fixed field order: Deployment, Time, Environment, Login (matching shell) +- Added `footer: 'Vortex Deployment'` to Slack attachment + +**notify-github:** +- Added `VORTEX_NOTIFY_GITHUB_BRANCH` (with fallback to `VORTEX_NOTIFY_BRANCH`) as deployment ref +- Replaced `$notify_label` with `$notify_branch` for all deployment API `ref` parameters +- Fixed `VORTEX_NOTIFY_GITHUB_ENVIRONMENT_TYPE` default: falls back to `VORTEX_NOTIFY_LABEL` then `'PR'` + +**notify-jira:** +- Added `VORTEX_NOTIFY_JIRA_BRANCH` (with fallback to `VORTEX_NOTIFY_BRANCH`) for issue extraction +- Changed issue extraction regex to match against branch (not label) +- Replaced simple text-to-ADF with rich `build_adf_comment()` featuring clickable links, code marks, and hardBreaks + +**notify-newrelic:** +- Reordered variables: enabled check first, then required variables +- Renamed `VORTEX_NOTIFY_NEWRELIC_USER_NAME` to `VORTEX_NOTIFY_NEWRELIC_USER` (matching shell) +- Added `VORTEX_NOTIFY_NEWRELIC_SHA` (with fallback to `VORTEX_NOTIFY_SHA`) +- Added SHA-based revision fallback before auto-generated LABEL-DATE-TIME pattern +- Added required variable validation after enabled check (user API key) +- Added numeric validation for app ID regardless of source + +### 5.5.2 Deployment Scripts Sync + +**deploy (router):** +- Fixed `VORTEX_DEPLOY_ACTION` default from `'deploy'` to `''` (matching shell) + +**deploy-artifact:** +- Fixed SSH prefix from `DEPLOY` to `DEPLOY_ARTIFACT` (matching shell) +- Added `VORTEX_DEPLOY_ARTIFACT_SSH_FINGERPRINT` and `VORTEX_DEPLOY_ARTIFACT_SSH_FILE` variable names with fallback chain +- Updated git-artifact version from `~1.1` to `~1.2` (matching shell) + +**deploy-lagoon:** +- Added tag deployment check: early exit for tag mode (`'Lagoon does not support tag deployments. Skipping.'`) +- Added `VORTEX_DEPLOY_MODE` variable +- Added `VORTEX_DEPLOY_LAGOON_*` prefixed variable support with fallbacks: + - `VORTEX_DEPLOY_LAGOON_ACTION` (fallback: `VORTEX_DEPLOY_ACTION`, default: `'create'`) + - `VORTEX_DEPLOY_LAGOON_PROJECT` (fallback: `LAGOON_PROJECT`) + - `VORTEX_DEPLOY_LAGOON_BRANCH` (fallback: `VORTEX_DEPLOY_BRANCH`) + - `VORTEX_DEPLOY_LAGOON_PR` (fallback: `VORTEX_DEPLOY_PR`) + - `VORTEX_DEPLOY_LAGOON_PR_HEAD` (fallback: `VORTEX_DEPLOY_PR_HEAD`) + - `VORTEX_DEPLOY_LAGOON_PR_BASE_BRANCH` (fallback: `VORTEX_DEPLOY_PR_BASE_BRANCH`) + - `VORTEX_DEPLOY_LAGOON_SSH_FINGERPRINT` (fallback chain) + - `VORTEX_DEPLOY_LAGOON_SSH_FILE` (fallback chain) + - `VORTEX_DEPLOY_LAGOON_LAGOONCLI_PATH` (fallback: `VORTEX_LAGOONCLI_PATH`) + - `VORTEX_DEPLOY_LAGOON_LAGOONCLI_FORCE_INSTALL` (fallback: `VORTEX_LAGOONCLI_FORCE_INSTALL`) + - `VORTEX_DEPLOY_LAGOON_LAGOONCLI_VERSION` (fallback: `VORTEX_LAGOONCLI_VERSION`) +- Fixed SSH prefix from `DEPLOY` to `DEPLOY_LAGOON` (matching shell) + +**login-container-registry:** +- Added `VORTEX_LOGIN_CONTAINER_REGISTRY` (fallback: `VORTEX_CONTAINER_REGISTRY`) +- Added `VORTEX_LOGIN_CONTAINER_REGISTRY_USER` (fallback: `VORTEX_CONTAINER_REGISTRY_USER`) +- Added `VORTEX_LOGIN_CONTAINER_REGISTRY_PASS` (fallback: `VORTEX_CONTAINER_REGISTRY_PASS`) +- Added `VORTEX_LOGIN_CONTAINER_REGISTRY_DOCKER_CONFIG` (fallback: `DOCKER_CONFIG`) + +### 5.5.3 Test Updates + +All test files updated to match script changes: +- `NotifyGithubTest.php` - Updated for branch variable, assertions, and data providers +- `NotifyJiraTest.php` - Updated for branch-based issue extraction +- `NotifyNewrelicTest.php` - Updated for optional variables, custom error messages +- `NotifyRouterTest.php` - Added required branch and SHA variables +- `DeployArtifactTest.php` - Updated git-artifact version in mocks +- `DeployLagoonTest.php` - Updated error message for new variable names + +**All 429 tests passing with 1,861 assertions** ✅ + +--- + ## Phase 6: Convert Remaining Scripts (TODO) ### Database Scripts @@ -762,9 +846,11 @@ function mockFileGetContents(string $path, string $content): void 4. ⏳ `download-db-container-registry.sh` - Download from container registry 5. ⏳ `download-db-lagoon.sh` - Download from Lagoon 6. ⏳ `download-db-acquia.sh` - Download from Acquia -7. ⏳ `export-db.sh` - Export database router -8. ⏳ `export-db-file.sh` - Export to file -9. ⏳ `export-db-image.sh` - Export to container image +7. ⏳ `download-db-s3.sh` - Download from S3 +8. ⏳ `upload-db-s3.sh` - Upload to S3 +9. ⏳ `export-db.sh` - Export database router +10. ⏳ `export-db-file.sh` - Export to file +11. ⏳ `export-db-image.sh` - Export to container image ### Provisioning Scripts 10. ⏳ `provision.sh` - Main provisioning @@ -1125,6 +1211,6 @@ All deployment scripts converted as a single milestone: --- -**Last Updated**: 2025-12-15 -**Current Phase**: Phase 5 Complete ✅ +**Last Updated**: 2026-02-20 +**Current Phase**: Phase 5.5 Sync Complete ✅ **Next Milestone**: Phase 6 - Database download/export scripts diff --git a/.vortex/tooling/src/deploy b/.vortex/tooling/src/deploy index eb5588e9b..128c2a945 100755 --- a/.vortex/tooling/src/deploy +++ b/.vortex/tooling/src/deploy @@ -44,7 +44,7 @@ $deploy_mode = getenv_default('VORTEX_DEPLOY_MODE', 'branch'); // - deploy: Deploy code and preserve database in the environment. // - deploy_override_db: Deploy code and override database in the environment. // - destroy: Destroy the environment (if the provider supports it). -$deploy_action = getenv_default('VORTEX_DEPLOY_ACTION', 'deploy'); +$deploy_action = getenv_default('VORTEX_DEPLOY_ACTION', ''); // Deployment branch name. $deploy_branch = getenv_default('VORTEX_DEPLOY_BRANCH', NULL); diff --git a/.vortex/tooling/src/deploy-artifact b/.vortex/tooling/src/deploy-artifact index cff81dee2..ee1c1cf21 100755 --- a/.vortex/tooling/src/deploy-artifact +++ b/.vortex/tooling/src/deploy-artifact @@ -54,13 +54,13 @@ $deploy_git_user_email = getenv_required('VORTEX_DEPLOY_ARTIFACT_GIT_USER_EMAIL' // SSH key fingerprint used to connect to remote. // -// Falls back to $VORTEX_SSH_FINGERPRINT. -$deploy_ssh_fingerprint = getenv_default('VORTEX_DEPLOY_SSH_FINGERPRINT', 'VORTEX_SSH_FINGERPRINT', ''); +// Falls back to VORTEX_DEPLOY_SSH_FINGERPRINT, then VORTEX_SSH_FINGERPRINT. +$deploy_ssh_fingerprint = getenv_default('VORTEX_DEPLOY_ARTIFACT_SSH_FINGERPRINT', 'VORTEX_DEPLOY_SSH_FINGERPRINT', 'VORTEX_SSH_FINGERPRINT', ''); // Default SSH file used if custom fingerprint is not provided. // -// Falls back to VORTEX_SSH_FILE. -$deploy_ssh_file = getenv_default('VORTEX_DEPLOY_SSH_FILE', 'VORTEX_SSH_FILE', getenv('HOME') . '/.ssh/id_rsa'); +// Falls back to VORTEX_DEPLOY_SSH_FILE, then VORTEX_SSH_FILE. +$deploy_ssh_file = getenv_default('VORTEX_DEPLOY_ARTIFACT_SSH_FILE', 'VORTEX_DEPLOY_SSH_FILE', 'VORTEX_SSH_FILE', getenv('HOME') . '/.ssh/id_rsa'); // ----------------------------------------------------------------------------- @@ -86,16 +86,16 @@ if (empty($global_git_email)) { } // Setup SSH. -putenv('VORTEX_SSH_PREFIX=DEPLOY'); -!empty($deploy_ssh_fingerprint) && putenv('VORTEX_DEPLOY_SSH_FINGERPRINT=' . $deploy_ssh_fingerprint); -!empty($deploy_ssh_file) && putenv('VORTEX_DEPLOY_SSH_FILE=' . $deploy_ssh_file); +putenv('VORTEX_SSH_PREFIX=DEPLOY_ARTIFACT'); +!empty($deploy_ssh_fingerprint) && putenv('VORTEX_DEPLOY_ARTIFACT_SSH_FINGERPRINT=' . $deploy_ssh_fingerprint); +!empty($deploy_ssh_file) && putenv('VORTEX_DEPLOY_ARTIFACT_SSH_FILE=' . $deploy_ssh_file); passthru(__DIR__ . '/setup-ssh', $exit_code); if ($exit_code !== 0) { quit($exit_code); } task('Installing artifact builder.'); -passthru('composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.1', $exit_code); +passthru('composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.2', $exit_code); if ($exit_code !== 0) { quit($exit_code); } diff --git a/.vortex/tooling/src/deploy-lagoon b/.vortex/tooling/src/deploy-lagoon index f1038ebee..48cab1c51 100644 --- a/.vortex/tooling/src/deploy-lagoon +++ b/.vortex/tooling/src/deploy-lagoon @@ -17,28 +17,33 @@ execute_override(basename(__FILE__)); // ----------------------------------------------------------------------------- +// Deployment mode. +// +// Values can be one of: branch, tag. +$deploy_mode = getenv_default('VORTEX_DEPLOY_MODE', 'branch'); + // Deployment action. // // Values can be one of: deploy, deploy_override_db, destroy. // - deploy: Deploy code and preserve database in the environment. // - deploy_override_db: Deploy code and override database in the environment. // - destroy: Destroy the environment (if the provider supports it). -$deploy_action = getenv_default('VORTEX_DEPLOY_ACTION', 'deploy'); +$deploy_action = getenv_default('VORTEX_DEPLOY_LAGOON_ACTION', 'VORTEX_DEPLOY_ACTION', 'create'); + +// The Lagoon project to perform deployment for. +$lagoon_project = getenv_required('VORTEX_DEPLOY_LAGOON_PROJECT', 'LAGOON_PROJECT'); // The Lagoon branch to deploy. -$deploy_branch = getenv_default('VORTEX_DEPLOY_BRANCH', NULL); +$deploy_branch = getenv_default('VORTEX_DEPLOY_LAGOON_BRANCH', 'VORTEX_DEPLOY_BRANCH', NULL); // The PR number to deploy. -$deploy_pr = getenv_default('VORTEX_DEPLOY_PR', NULL); +$deploy_pr = getenv_default('VORTEX_DEPLOY_LAGOON_PR', 'VORTEX_DEPLOY_PR', NULL); // The PR head branch to deploy. -$deploy_pr_head = getenv_default('VORTEX_DEPLOY_PR_HEAD', NULL); +$deploy_pr_head = getenv_default('VORTEX_DEPLOY_LAGOON_PR_HEAD', 'VORTEX_DEPLOY_PR_HEAD', NULL); // The PR base branch (the branch the PR is raised against). -$deploy_pr_base_branch = getenv_default('VORTEX_DEPLOY_PR_BASE_BRANCH', 'develop'); - -// The Lagoon project to perform deployment for. -$lagoon_project = getenv_required('LAGOON_PROJECT'); +$deploy_pr_base_branch = getenv_default('VORTEX_DEPLOY_LAGOON_PR_BASE_BRANCH', 'VORTEX_DEPLOY_PR_BASE_BRANCH', 'develop'); // The Lagoon instance name to interact with. $lagoon_instance = getenv_default('VORTEX_DEPLOY_LAGOON_INSTANCE', 'amazeeio'); @@ -54,30 +59,37 @@ $lagoon_instance_port = getenv_default('VORTEX_DEPLOY_LAGOON_INSTANCE_PORT', '32 // SSH key fingerprint used to connect to remote. // -// Falls back to VORTEX_SSH_FINGERPRINT. -$ssh_fingerprint = getenv_default('VORTEX_DEPLOY_SSH_FINGERPRINT', 'VORTEX_SSH_FINGERPRINT', NULL); +// Falls back to VORTEX_DEPLOY_SSH_FINGERPRINT, then VORTEX_SSH_FINGERPRINT. +$ssh_fingerprint = getenv_default('VORTEX_DEPLOY_LAGOON_SSH_FINGERPRINT', 'VORTEX_DEPLOY_SSH_FINGERPRINT', 'VORTEX_SSH_FINGERPRINT', NULL); // Default SSH file used if custom fingerprint is not provided. // -// Falls back to VORTEX_SSH_FILE. -$ssh_file = getenv_default('VORTEX_DEPLOY_SSH_FILE', 'VORTEX_SSH_FILE', getenv('HOME') . '/.ssh/id_rsa'); +// Falls back to VORTEX_DEPLOY_SSH_FILE, then VORTEX_SSH_FILE. +$ssh_file = getenv_default('VORTEX_DEPLOY_LAGOON_SSH_FILE', 'VORTEX_DEPLOY_SSH_FILE', 'VORTEX_SSH_FILE', getenv('HOME') . '/.ssh/id_rsa'); // Flag to control failure behavior when Lagoon environment limits are exceeded. $deploy_lagoon_fail_when_env_limit_exceeded = getenv_default('VORTEX_DEPLOY_LAGOON_FAIL_ENV_LIMIT_EXCEEDED', FALSE); // Location of the Lagoon CLI binary. -$lagooncli_path = getenv_default('VORTEX_LAGOONCLI_PATH', sys_get_temp_dir()); +$lagooncli_path = getenv_default('VORTEX_DEPLOY_LAGOON_LAGOONCLI_PATH', 'VORTEX_LAGOONCLI_PATH', sys_get_temp_dir()); // Flag to force the installation of Lagoon CLI. -$lagooncli_force_install = getenv_default('VORTEX_LAGOONCLI_FORCE_INSTALL', FALSE); +$lagooncli_force_install = getenv_default('VORTEX_DEPLOY_LAGOON_LAGOONCLI_FORCE_INSTALL', 'VORTEX_LAGOONCLI_FORCE_INSTALL', FALSE); // Lagoon CLI version to use. -$lagooncli_version = getenv_default('VORTEX_LAGOONCLI_VERSION', 'v0.32.0'); +$lagooncli_version = getenv_default('VORTEX_DEPLOY_LAGOON_LAGOONCLI_VERSION', 'VORTEX_LAGOONCLI_VERSION', 'v0.32.0'); // ----------------------------------------------------------------------------- info('Started LAGOON deployment.'); +// Lagoon does not support tag deployments. Exit successfully with a message. +if ($deploy_mode === 'tag') { + note('Lagoon does not support tag deployments. Skipping.'); + pass('Finished LAGOON deployment.'); + quit(0); +} + // Track exit status to return at the end. $exit_code = 0; @@ -90,9 +102,9 @@ if (empty($deploy_branch) && empty($deploy_pr)) { } // Setup SSH. -putenv('VORTEX_SSH_PREFIX=DEPLOY'); -!empty($ssh_fingerprint) && putenv('VORTEX_DEPLOY_SSH_FINGERPRINT=' . $ssh_fingerprint); -!empty($ssh_file) && putenv('VORTEX_DEPLOY_SSH_FILE=' . $ssh_file); +putenv('VORTEX_SSH_PREFIX=DEPLOY_LAGOON'); +!empty($ssh_fingerprint) && putenv('VORTEX_DEPLOY_LAGOON_SSH_FINGERPRINT=' . $ssh_fingerprint); +!empty($ssh_file) && putenv('VORTEX_DEPLOY_LAGOON_SSH_FILE=' . $ssh_file); passthru(__DIR__ . '/setup-ssh', $ssh_exit_code); if ($ssh_exit_code !== 0) { quit($ssh_exit_code); diff --git a/.vortex/tooling/src/login-container-registry b/.vortex/tooling/src/login-container-registry index 77c53ed20..9333eaf50 100755 --- a/.vortex/tooling/src/login-container-registry +++ b/.vortex/tooling/src/login-container-registry @@ -21,16 +21,16 @@ execute_override(basename(__FILE__)); // Container registry URL. // // Examples: docker.io, gcr.io, ghcr.io -$registry = getenv_default('VORTEX_CONTAINER_REGISTRY', 'docker.io'); +$registry = getenv_default('VORTEX_LOGIN_CONTAINER_REGISTRY', 'VORTEX_CONTAINER_REGISTRY', 'docker.io'); // Container registry username. -$user = getenv_default('VORTEX_CONTAINER_REGISTRY_USER', NULL); +$user = getenv_default('VORTEX_LOGIN_CONTAINER_REGISTRY_USER', 'VORTEX_CONTAINER_REGISTRY_USER', NULL); // Container registry password. -$pass = getenv_default('VORTEX_CONTAINER_REGISTRY_PASS', NULL); +$pass = getenv_default('VORTEX_LOGIN_CONTAINER_REGISTRY_PASS', 'VORTEX_CONTAINER_REGISTRY_PASS', NULL); // Docker configuration directory. -$docker_config = getenv_default('DOCKER_CONFIG', getenv('HOME') . '/.docker'); +$docker_config = getenv_default('VORTEX_LOGIN_CONTAINER_REGISTRY_DOCKER_CONFIG', 'DOCKER_CONFIG', getenv('HOME') . '/.docker'); // ----------------------------------------------------------------------------- @@ -47,5 +47,5 @@ elseif (!empty($user) && !empty($pass)) { } } else { - note('Skipping login to the container registry as either VORTEX_CONTAINER_REGISTRY_USER or VORTEX_CONTAINER_REGISTRY_PASS was not provided.'); + note('Skipping login to the container registry as either VORTEX_LOGIN_CONTAINER_REGISTRY_USER or VORTEX_CONTAINER_REGISTRY_USER or VORTEX_LOGIN_CONTAINER_REGISTRY_PASS or VORTEX_CONTAINER_REGISTRY_PASS was not provided.'); } diff --git a/.vortex/tooling/src/notify b/.vortex/tooling/src/notify index 7bbe19636..83fe88d1f 100755 --- a/.vortex/tooling/src/notify +++ b/.vortex/tooling/src/notify @@ -30,13 +30,22 @@ $event = getenv('VORTEX_NOTIFY_EVENT') ?: 'post_deployment'; // Notification project name. $project = getenv('VORTEX_NOTIFY_PROJECT') ?: getenv('VORTEX_PROJECT'); -// Notification deployment label (branch name, PR number, or custom identifier). +// Notification git branch name. +$branch = getenv_required('VORTEX_NOTIFY_BRANCH'); + +// Notification git commit SHA. +$sha = getenv_required('VORTEX_NOTIFY_SHA'); + +// Notification pull request number. +$pr_number = getenv_default('VORTEX_NOTIFY_PR_NUMBER', ''); + +// Notification deployment label (human-readable identifier for display). $label = getenv_required('VORTEX_NOTIFY_LABEL'); // Notification environment URL (where the site was deployed). -$env_url = getenv('VORTEX_NOTIFY_ENVIRONMENT_URL'); +$env_url = getenv_required('VORTEX_NOTIFY_ENVIRONMENT_URL'); -// Notification login URL (defaults to ENVIRONMENT_URL/user/login). +// Notification login URL. $login_url = getenv_default('VORTEX_NOTIFY_LOGIN_URL', $env_url . '/user/login'); // Notification skip flag. @@ -62,6 +71,25 @@ if (!in_array($event, ['pre_deployment', 'post_deployment'])) { fail('Unsupported event %s provided.', $event); } +// Export variables so notification scripts can use them. +putenv('VORTEX_NOTIFY_BRANCH=' . $branch); +putenv('VORTEX_NOTIFY_SHA=' . $sha); +putenv('VORTEX_NOTIFY_PR_NUMBER=' . $pr_number); +putenv('VORTEX_NOTIFY_LABEL=' . $label); +putenv('VORTEX_NOTIFY_ENVIRONMENT_URL=' . $env_url); +putenv('VORTEX_NOTIFY_LOGIN_URL=' . $login_url); + +info('Notification summary:'); +note('Project : ' . $project); +note('Branch : ' . $branch); +note('SHA : ' . $sha); +note('PR Number : ' . ($pr_number ?: '')); +note('Label : ' . $label); +note('Environment URL: ' . $env_url); +note('Login URL : ' . $login_url); +note('Event : ' . $event); +note('Channels : ' . implode(',', $channels)); + foreach ($channels as $channel) { $script = __DIR__ . ('/notify-' . $channel); diff --git a/.vortex/tooling/src/notify-github b/.vortex/tooling/src/notify-github index fcbbf4f88..cc7b7e15d 100755 --- a/.vortex/tooling/src/notify-github +++ b/.vortex/tooling/src/notify-github @@ -22,23 +22,28 @@ execute_override(basename(__FILE__)); // ----------------------------------------------------------------------------- -// GitHub notification deployment label (branch name, PR number, or custom). -$notify_label = getenv_required('VORTEX_NOTIFY_GITHUB_LABEL', 'VORTEX_NOTIFY_LABEL'); - -// GitHub notification event type. -// -// Can be 'pre_deployment' or 'post_deployment'. -$notify_event = getenv_required('VORTEX_NOTIFY_GITHUB_EVENT', 'VORTEX_NOTIFY_EVENT'); - // GitHub notification personal access token. $github_token = getenv_required('VORTEX_NOTIFY_GITHUB_TOKEN', 'GITHUB_TOKEN'); // GitHub notification repository in owner/repo format. $github_repository = getenv_required('VORTEX_NOTIFY_GITHUB_REPOSITORY'); -// GitHub notification environment type: production, uat, dev, pr. -// Used as the 'environment' parameter in GitHub's Deployment API. -$github_env_type = getenv_default('VORTEX_NOTIFY_GITHUB_ENVIRONMENT_TYPE', 'PR'); +// GitHub notification git branch name. +// +// This will be used as the 'ref' parameter in GitHub's Deployment API. +$notify_branch = getenv_required('VORTEX_NOTIFY_GITHUB_BRANCH', 'VORTEX_NOTIFY_BRANCH'); + +// GitHub notification event type. +// +// Can be 'pre_deployment' or 'post_deployment'. +$notify_event = getenv_required('VORTEX_NOTIFY_GITHUB_EVENT', 'VORTEX_NOTIFY_EVENT'); + +// GitHub notification environment type. +// +// Defaults to VORTEX_NOTIFY_LABEL (e.g. "PR-123" or branch name) for unique +// per-PR/branch environments. This prevents cross-PR deployment interference +// where deploying one PR would mark another PR's deployment as inactive. +$github_env_type = getenv_default('VORTEX_NOTIFY_GITHUB_ENVIRONMENT_TYPE', 'VORTEX_NOTIFY_LABEL', 'PR'); // ----------------------------------------------------------------------------- @@ -68,14 +73,14 @@ function deployment_id_is_valid(mixed $deployment_id): bool { if ($notify_event === 'pre_deployment') { note('GitHub pre-deployment notification summary:'); note('Repository : ' . $github_repository); - note('Label (ref) : ' . $notify_label); + note('Branch (ref) : ' . $notify_branch); note('Environment Type: ' . $github_env_type); note('Event : ' . $notify_event); task('Creating deployment'); $payload_data = [ - 'ref' => $notify_label, + 'ref' => $notify_branch, 'environment' => $github_env_type, 'auto_merge' => FALSE, 'required_contexts' => [], @@ -103,9 +108,9 @@ if ($notify_event === 'pre_deployment') { else { $env_url = getenv_required('VORTEX_NOTIFY_GITHUB_ENVIRONMENT_URL', 'VORTEX_NOTIFY_ENVIRONMENT_URL'); - task('Finding latest deployment for ref %s', $notify_label); + task('Finding latest deployment for ref %s', $notify_branch); - $url = sprintf('https://api.github.com/repos/%s/deployments?ref=%s', $github_repository, urlencode($notify_label)); + $url = sprintf('https://api.github.com/repos/%s/deployments?ref=%s', $github_repository, urlencode($notify_branch)); $response = request_get($url, [ 'Authorization: token ' . $github_token, 'Accept: application/vnd.github.v3+json', @@ -123,14 +128,14 @@ else { // Check deployment ID. if (!deployment_id_is_valid($deployment_id)) { - fail('Failed to find a previous deployment for ref %s. Payload: %s', $notify_label, $response['body'] ?: 'empty'); + fail('Failed to find a previous deployment for ref %s. Payload: %s', $notify_branch, $response['body'] ?: 'empty'); } pass('Found deployment with ID %s.', $deployment_id); note('GitHub post-deployment notification summary:'); note('Repository : ' . $github_repository); - note('Label (ref) : ' . $notify_label); + note('Branch (ref) : ' . $notify_branch); note('Environment Type : ' . $github_env_type); note('Environment URL : ' . $env_url); note('Deployment ID : ' . $deployment_id); diff --git a/.vortex/tooling/src/notify-jira b/.vortex/tooling/src/notify-jira index 997582124..c90568f69 100755 --- a/.vortex/tooling/src/notify-jira +++ b/.vortex/tooling/src/notify-jira @@ -25,7 +25,10 @@ execute_override(basename(__FILE__)); // JIRA notification project name. $notify_project = getenv_required('VORTEX_NOTIFY_JIRA_PROJECT', 'VORTEX_NOTIFY_PROJECT'); -// JIRA notification deployment label (branch name, PR number, or custom). +// JIRA notification git branch name (used for issue extraction). +$notify_branch = getenv_required('VORTEX_NOTIFY_JIRA_BRANCH', 'VORTEX_NOTIFY_BRANCH'); + +// JIRA notification deployment label (human-readable identifier for display). $notify_label = getenv_required('VORTEX_NOTIFY_JIRA_LABEL', 'VORTEX_NOTIFY_LABEL'); // JIRA notification environment URL. @@ -73,29 +76,47 @@ $jira_endpoint = getenv_default('VORTEX_NOTIFY_JIRA_ENDPOINT', 'https://jira.atl // ----------------------------------------------------------------------------- /** - * Convert a multiline string into a JIRA ADF paragraph node. + * Build a rich JIRA ADF comment with clickable links and code marks. * - * @param string $text - * Multiline text to convert. + * @param string $project + * Project name. + * @param string $label + * Deployment label. + * @param string $timestamp + * Deployment timestamp. + * @param string $env_url + * Environment URL. + * @param string $login_url + * Login URL. * * @return array - * ADF paragraph node. + * ADF document body. */ -function text_to_adf(string $text): array { - $text = str_replace(["\r\n", "\r"], "\n", $text); - $lines = explode("\n", $text); - - $content = []; - foreach ($lines as $index => $line) { - if ($index > 0) { - $content[] = ['type' => 'hardBreak']; - } - if ($line !== '') { - $content[] = ['type' => 'text', 'text' => $line]; - } - } - - return ['type' => 'paragraph', 'content' => $content]; +function build_adf_comment(string $project, string $label, string $timestamp, string $env_url, string $login_url): array { + $content = [[ + 'type' => 'paragraph', + 'content' => [ + ['type' => 'text', 'text' => '## This is an automated message ##'], + ['type' => 'hardBreak'], + ['type' => 'hardBreak'], + ['type' => 'text', 'text' => 'Site ' . $project . ' '], + ['type' => 'text', 'text' => $label, 'marks' => [['type' => 'code']]], + ['type' => 'text', 'text' => ' has been deployed at ' . $timestamp . ' and is available at '], + ['type' => 'text', 'text' => $env_url, 'marks' => [['type' => 'link', 'attrs' => ['href' => $env_url]]]], + ['type' => 'text', 'text' => '.'], + ['type' => 'hardBreak'], + ['type' => 'hardBreak'], + ['type' => 'text', 'text' => 'Login at: '], + ['type' => 'text', 'text' => $login_url, 'marks' => [['type' => 'link', 'attrs' => ['href' => $login_url]]]], + ], + ], + ]; + + return [ + 'type' => 'doc', + 'version' => 1, + 'content' => $content, + ]; } // ----------------------------------------------------------------------------- @@ -110,8 +131,8 @@ if ($notify_event === 'pre_deployment') { task('Extracting issue'); -if (!preg_match('/([^\/]+\/)?([A-Za-z0-9]+\-\d+)/', $notify_label, $matches)) { - pass('Deployment label %s does not contain issue number. Skipping JIRA notification.', $notify_label); +if (!preg_match('/([^\/]+\/)?([A-Za-z0-9]+\-\d+)/', $notify_branch, $matches)) { + pass('Branch %s does not contain issue number. Skipping JIRA notification.', $notify_branch); quit(); } $jira_issue = $matches[2]; @@ -142,21 +163,9 @@ pass('Authenticated as user with account ID %s.', $account_id); task('Posting a comment'); -$jira_message = replace_tokens($jira_message, [ - 'project' => $notify_project, - 'label' => $notify_label, - 'timestamp' => date('d/m/Y H:i:s T'), - 'environment_url' => $notify_env_url, - 'login_url' => $notify_login_url, -]); - -$jira_message_adf = text_to_adf($jira_message); +$timestamp = date('d/m/Y H:i:s T'); -$comment_body = [ - 'type' => 'doc', - 'version' => 1, - 'content' => $jira_message_adf, -]; +$comment_body = build_adf_comment($notify_project, $notify_label, $timestamp, $notify_env_url, $notify_login_url); note('JIRA notification summary:'); note('Project : ' . $notify_project); diff --git a/.vortex/tooling/src/notify-newrelic b/.vortex/tooling/src/notify-newrelic index 86b023815..446205b75 100755 --- a/.vortex/tooling/src/notify-newrelic +++ b/.vortex/tooling/src/notify-newrelic @@ -21,21 +21,7 @@ execute_override(basename(__FILE__)); $newrelic_enabled = getenv('VORTEX_NOTIFY_NEWRELIC_ENABLED') ?: getenv('NEWRELIC_ENABLED'); // New Relic notification project name. -$notify_project = getenv_required('VORTEX_NOTIFY_NEWRELIC_PROJECT', 'VORTEX_NOTIFY_PROJECT'); - -// New Relic notification deployment label (branch name, PR number, or custom). -$notify_label = getenv_required('VORTEX_NOTIFY_NEWRELIC_LABEL', 'VORTEX_NOTIFY_LABEL'); - -// New Relic notification environment URL. -$notify_env_url = getenv_required('VORTEX_NOTIFY_NEWRELIC_ENVIRONMENT_URL', 'VORTEX_NOTIFY_ENVIRONMENT_URL'); - -// New Relic notification login URL. -$notify_login_url = getenv_default('VORTEX_NOTIFY_NEWRELIC_LOGIN_URL', 'VORTEX_NOTIFY_LOGIN_URL', $notify_env_url . '/user/login'); - -// New Relic notification event type. -// -// Can be 'pre_deployment' or 'post_deployment'. -$notify_event = getenv_default('VORTEX_NOTIFY_NEWRELIC_EVENT', 'VORTEX_NOTIFY_EVENT', 'post_deployment'); +$notify_project = getenv_default('VORTEX_NOTIFY_NEWRELIC_PROJECT', 'VORTEX_NOTIFY_PROJECT', ''); // New Relic notification User API Key. // @@ -47,13 +33,25 @@ $notify_event = getenv_default('VORTEX_NOTIFY_NEWRELIC_EVENT', 'VORTEX_NOTIFY_EV // 5. The key format is: `NRAK-XXXXXXXXXXXXXXXXXXXXXX`. // @see https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#user-key // @see https://www.vortextemplate.com/docs/workflows/notifications#new-relic -$newrelic_user_key = getenv_required('VORTEX_NOTIFY_NEWRELIC_USER_KEY', 'NEWRELIC_USER_KEY'); +$newrelic_user_key = getenv_default('VORTEX_NOTIFY_NEWRELIC_USER_KEY', 'NEWRELIC_USER_KEY', ''); + +// New Relic human-readable notification deployment label. +$notify_label = getenv_default('VORTEX_NOTIFY_NEWRELIC_LABEL', 'VORTEX_NOTIFY_LABEL', ''); + +// New Relic notification git commit SHA. +$notify_sha = getenv_default('VORTEX_NOTIFY_NEWRELIC_SHA', 'VORTEX_NOTIFY_SHA', ''); // New Relic notification deployment revision. // -// If not provided, will be auto-generated as [LABEL]-[TIMESTAMP]. +// If not provided, will use SHA if available, otherwise auto-generated. $newrelic_revision = getenv('VORTEX_NOTIFY_NEWRELIC_REVISION'); +// New Relic notification environment URL. +$notify_env_url = getenv_default('VORTEX_NOTIFY_NEWRELIC_ENVIRONMENT_URL', 'VORTEX_NOTIFY_ENVIRONMENT_URL', ''); + +// New Relic notification login URL. +$notify_login_url = getenv_default('VORTEX_NOTIFY_NEWRELIC_LOGIN_URL', 'VORTEX_NOTIFY_LOGIN_URL', ''); + // New Relic notification application name as it appears in the dashboard. $newrelic_app_name = getenv_default('VORTEX_NOTIFY_NEWRELIC_APP_NAME', sprintf('%s-%s', $notify_project, $notify_label)); @@ -70,18 +68,23 @@ $newrelic_appid = getenv('VORTEX_NOTIFY_NEWRELIC_APPID'); // - %timestamp% - Deployment timestamp // - %environment_url% - Environment URL // - %login_url% - Login URL. -$newrelic_description = getenv_default('VORTEX_NOTIFY_NEWRELIC_DESCRIPTION', '"Site %project% %label% has been deployed at %timestamp% and is available at %environment_url%"'); +$newrelic_description = getenv_default('VORTEX_NOTIFY_NEWRELIC_DESCRIPTION', 'Site %project% %label% has been deployed at %timestamp% and is available at %environment_url%'); // New Relic notification deployment changelog. // Defaults to the description. $newrelic_changelog = getenv('VORTEX_NOTIFY_NEWRELIC_CHANGELOG'); -// New Relic notification user name performing deployment. -$newrelic_user_name = getenv_default('VORTEX_NOTIFY_NEWRELIC_USER_NAME', 'Deployment robot'); +// New Relic notification user performing deployment. +$newrelic_user = getenv_default('VORTEX_NOTIFY_NEWRELIC_USER', 'Deployment robot'); // New Relic notification API endpoint. $newrelic_endpoint = getenv_default('VORTEX_NOTIFY_NEWRELIC_ENDPOINT', 'https://api.newrelic.com/v2'); +// New Relic notification event type. +// +// Can be 'pre_deployment' or 'post_deployment'. +$notify_event = getenv_default('VORTEX_NOTIFY_NEWRELIC_EVENT', 'VORTEX_NOTIFY_EVENT', 'post_deployment'); + // ------------------------------------------------------------------------------ if (empty($newrelic_enabled)) { @@ -97,11 +100,22 @@ if ($notify_event === 'pre_deployment') { quit(); } +// Validate required variables after enabled check. +if (empty($newrelic_user_key)) { + fail('Missing required New Relic User API Key. Set VORTEX_NOTIFY_NEWRELIC_USER_KEY or NEWRELIC_USER_KEY.'); +} + if (!$newrelic_revision) { - $revision_date = date('Ymd'); - $revision_time = date('His'); - $newrelic_revision = sprintf('%s-%s-%s', $notify_label, $revision_date, $revision_time); - note('Auto-generated revision: ' . $newrelic_revision); + if (!empty($notify_sha)) { + $newrelic_revision = $notify_sha; + note('Using SHA as revision: ' . $newrelic_revision); + } + else { + $revision_date = date('Ymd'); + $revision_time = date('His'); + $newrelic_revision = sprintf('%s-%s-%s', $notify_label, $revision_date, $revision_time); + note('Auto-generated revision: ' . $newrelic_revision); + } } if (!$newrelic_appid && $newrelic_app_name) { @@ -127,6 +141,12 @@ if (!$newrelic_appid && $newrelic_app_name) { pass('Discovered application ID: %s', $newrelic_appid); } +// Validate app ID is numeric regardless of source (provided or discovered). +if (empty($newrelic_appid) || !ctype_digit((string) $newrelic_appid)) { + pass('Notification skipped: New Relic application ID is empty or not numeric. This is expected for non-configured environments.'); + quit(); +} + $newrelic_description = replace_tokens($newrelic_description, [ 'project' => $notify_project, 'label' => $notify_label, @@ -143,7 +163,7 @@ note('Deployment : ' . $notify_label); note('App Name : ' . $newrelic_app_name); note('App ID (resolved): ' . $newrelic_appid); note('Revision : ' . $newrelic_revision); -note('User : ' . $newrelic_user_name); +note('User : ' . $newrelic_user); note('Endpoint : ' . $newrelic_endpoint); note('Description : ' . $newrelic_description); @@ -154,7 +174,7 @@ $payload_data = [ 'revision' => $newrelic_revision, 'changelog' => $newrelic_changelog, 'description' => $newrelic_description, - 'user' => $newrelic_user_name, + 'user' => $newrelic_user, ], ]; diff --git a/.vortex/tooling/src/notify-slack b/.vortex/tooling/src/notify-slack index 279d2d8d6..cd5de135d 100755 --- a/.vortex/tooling/src/notify-slack +++ b/.vortex/tooling/src/notify-slack @@ -95,10 +95,8 @@ $fields = [ // Pre-deployment notifications should not show these as the site is not yet // available. if ($notify_event !== 'pre_deployment') { - array_splice($fields, 1, 0, [ - ['title' => 'Environment', 'value' => sprintf('<%s|View Site>', $notify_env_url), 'short' => TRUE], - ['title' => 'Login', 'value' => sprintf('<%s|Login Here>', $notify_login_url), 'short' => TRUE], - ]); + $fields[] = ['title' => 'Environment', 'value' => sprintf('<%s|View Site>', $notify_env_url), 'short' => TRUE]; + $fields[] = ['title' => 'Login', 'value' => sprintf('<%s|Login Here>', $notify_login_url), 'short' => TRUE]; } // Build payload. @@ -111,6 +109,7 @@ $data = [ 'fallback' => $slack_fallback_message, 'title' => $title, 'fields' => $fields, + 'footer' => 'Vortex Deployment', 'ts' => time(), ], ], diff --git a/.vortex/tooling/tests/Unit/DeployArtifactTest.php b/.vortex/tooling/tests/Unit/DeployArtifactTest.php index ffdd65675..98ba25369 100644 --- a/.vortex/tooling/tests/Unit/DeployArtifactTest.php +++ b/.vortex/tooling/tests/Unit/DeployArtifactTest.php @@ -66,7 +66,7 @@ public function testDefaultValues(): void { // Mock composer install. $this->mockPassthru([ - 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.1', + 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.2', 'output' => 'Installing git-artifact', 'result_code' => 0, ]); @@ -127,7 +127,7 @@ public function testConfigureGitUser(): void { // Mock composer install. $this->mockPassthru([ - 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.1', + 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.2', 'output' => 'Installing git-artifact', 'result_code' => 0, ]); @@ -243,7 +243,7 @@ public function testComposerInstallFailure(): void { // Mock composer install failure. $this->mockPassthru([ - 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.1', + 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.2', 'output' => 'Composer install failed', 'result_code' => 1, ]); @@ -272,7 +272,7 @@ public function testGitArtifactFailure(): void { // Mock composer install. $this->mockPassthru([ - 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.1', + 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.2', 'output' => 'Installing git-artifact', 'result_code' => 0, ]); @@ -323,7 +323,7 @@ public function testRealpathFailure(): void { // Mock composer install. $this->mockPassthru([ - 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.1', + 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.2', 'output' => 'Installing git-artifact', 'result_code' => 0, ]); @@ -349,7 +349,7 @@ public function testCustomBranch(): void { // Mock composer install. $this->mockPassthru([ - 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.1', + 'cmd' => 'composer global require --dev -n --ansi --prefer-source --ignore-platform-reqs drevops/git-artifact:~1.2', 'output' => 'Installing git-artifact', 'result_code' => 0, ]); diff --git a/.vortex/tooling/tests/Unit/DeployLagoonTest.php b/.vortex/tooling/tests/Unit/DeployLagoonTest.php index 734ff4b2b..b18ce1eb9 100644 --- a/.vortex/tooling/tests/Unit/DeployLagoonTest.php +++ b/.vortex/tooling/tests/Unit/DeployLagoonTest.php @@ -41,7 +41,7 @@ public function testMissingLagoonProject(): void { $this->envSet('VORTEX_DEPLOY_BRANCH', 'develop'); $this->envUnset('LAGOON_PROJECT'); - $this->runScriptError('src/deploy-lagoon', 'Missing required value for LAGOON_PROJECT'); + $this->runScriptError('src/deploy-lagoon', 'Missing required value for VORTEX_DEPLOY_LAGOON_PROJECT, LAGOON_PROJECT'); } public function testMissingBranchAndPr(): void { diff --git a/.vortex/tooling/tests/Unit/NotifyGithubTest.php b/.vortex/tooling/tests/Unit/NotifyGithubTest.php index 1b414ffd0..d811a5a23 100644 --- a/.vortex/tooling/tests/Unit/NotifyGithubTest.php +++ b/.vortex/tooling/tests/Unit/NotifyGithubTest.php @@ -23,7 +23,7 @@ protected function setUp(): void { $this->envSetMultiple([ 'VORTEX_NOTIFY_GITHUB_TOKEN' => 'ghp_test123456', 'VORTEX_NOTIFY_GITHUB_REPOSITORY' => 'owner/repo', - 'VORTEX_NOTIFY_GITHUB_LABEL' => 'main', + 'VORTEX_NOTIFY_GITHUB_BRANCH' => 'main', 'VORTEX_NOTIFY_GITHUB_EVENT' => 'pre_deployment', 'VORTEX_NOTIFY_GITHUB_ENVIRONMENT_TYPE' => 'production', 'VORTEX_NOTIFY_GITHUB_ENVIRONMENT_URL' => 'https://example.com', @@ -55,7 +55,7 @@ public function testSuccessfulPreDeploymentNotification(): void { $this->assertStringContainsString('Started GitHub notification for pre_deployment event', $output); $this->assertStringContainsString('Repository : owner/repo', $output); - $this->assertStringContainsString('Label (ref) : main', $output); + $this->assertStringContainsString('Branch (ref) : main', $output); $this->assertStringContainsString('Environment Type: production', $output); $this->assertStringContainsString('Created deployment with ID 123456789', $output); @@ -184,7 +184,7 @@ public static function dataProviderMissingRequiredVariables(): array { return [ 'token' => ['VORTEX_NOTIFY_GITHUB_TOKEN'], 'repository' => ['VORTEX_NOTIFY_GITHUB_REPOSITORY'], - 'label' => ['VORTEX_NOTIFY_GITHUB_LABEL'], + 'branch' => ['VORTEX_NOTIFY_GITHUB_BRANCH'], 'event' => ['VORTEX_NOTIFY_GITHUB_EVENT'], ]; } @@ -192,11 +192,11 @@ public static function dataProviderMissingRequiredVariables(): array { public function testFallbackToGenericGithubToken(): void { $this->envUnsetMultiple([ 'VORTEX_NOTIFY_GITHUB_TOKEN', - 'VORTEX_NOTIFY_GITHUB_LABEL', + 'VORTEX_NOTIFY_GITHUB_BRANCH', ]); $this->envSet('GITHUB_TOKEN', 'ghp_fallback123'); - $this->envSet('VORTEX_NOTIFY_LABEL', 'develop'); + $this->envSet('VORTEX_NOTIFY_BRANCH', 'develop'); $this->envSet('VORTEX_NOTIFY_GITHUB_EVENT', 'pre_deployment'); $this->mockRequestPost( @@ -214,7 +214,7 @@ public function testFallbackToGenericGithubToken(): void { $output = $this->runScript('src/notify-github'); - $this->assertStringContainsString('Label (ref) : develop', $output); + $this->assertStringContainsString('Branch (ref) : develop', $output); $this->assertStringContainsString('Finished GitHub notification', $output); } diff --git a/.vortex/tooling/tests/Unit/NotifyJiraTest.php b/.vortex/tooling/tests/Unit/NotifyJiraTest.php index 46f901084..86827eacd 100644 --- a/.vortex/tooling/tests/Unit/NotifyJiraTest.php +++ b/.vortex/tooling/tests/Unit/NotifyJiraTest.php @@ -24,6 +24,7 @@ protected function setUp(): void { 'VORTEX_NOTIFY_JIRA_PROJECT' => 'test-project', 'VORTEX_NOTIFY_JIRA_USER_EMAIL' => 'user@example.com', 'VORTEX_NOTIFY_JIRA_TOKEN' => 'test-token-123', + 'VORTEX_NOTIFY_JIRA_BRANCH' => 'feature/TEST-123-test-feature', 'VORTEX_NOTIFY_JIRA_LABEL' => 'feature/TEST-123-test-feature', 'VORTEX_NOTIFY_JIRA_ENVIRONMENT_URL' => 'https://example.com', 'VORTEX_NOTIFY_JIRA_LOGIN_URL' => 'https://example.com/login', @@ -372,6 +373,7 @@ public static function dataProviderMissingRequiredVariables(): array { 'project' => ['VORTEX_NOTIFY_JIRA_PROJECT'], 'user_email' => ['VORTEX_NOTIFY_JIRA_USER_EMAIL'], 'token' => ['VORTEX_NOTIFY_JIRA_TOKEN'], + 'branch' => ['VORTEX_NOTIFY_JIRA_BRANCH'], 'label' => ['VORTEX_NOTIFY_JIRA_LABEL'], 'environment_url' => ['VORTEX_NOTIFY_JIRA_ENVIRONMENT_URL'], ]; @@ -380,12 +382,14 @@ public static function dataProviderMissingRequiredVariables(): array { public function testFallbackToGenericVariables(): void { $this->envUnsetMultiple([ 'VORTEX_NOTIFY_JIRA_PROJECT', + 'VORTEX_NOTIFY_JIRA_BRANCH', 'VORTEX_NOTIFY_JIRA_LABEL', 'VORTEX_NOTIFY_JIRA_ENVIRONMENT_URL', 'VORTEX_NOTIFY_JIRA_LOGIN_URL', ]); $this->envSet('VORTEX_NOTIFY_PROJECT', 'fallback-project'); + $this->envSet('VORTEX_NOTIFY_BRANCH', 'feature/PROJ-456-fallback'); $this->envSet('VORTEX_NOTIFY_LABEL', 'feature/PROJ-456-fallback'); $this->envSet('VORTEX_NOTIFY_ENVIRONMENT_URL', 'https://fallback.example.com'); $this->envSet('VORTEX_NOTIFY_LOGIN_URL', 'https://fallback.example.com/login'); @@ -422,9 +426,9 @@ public function testFallbackToGenericVariables(): void { $this->assertStringContainsString('Login URL : https://fallback.example.com/login', $output); } - public function testIssueExtractionFromLabel(): void { - // Test with prefix in label. - $this->envSet('VORTEX_NOTIFY_JIRA_LABEL', 'feature/ABC-123-description'); + public function testIssueExtractionFromBranch(): void { + // Test with prefix in branch. + $this->envSet('VORTEX_NOTIFY_JIRA_BRANCH', 'feature/ABC-123-description'); // Mock authentication. $this->mockRequestGet( @@ -569,10 +573,10 @@ public function testCompleteWorkflowWithAllFeatures(): void { $this->assertStringContainsString('Finished JIRA notification', $output); } - public function testLabelWithoutIssueNumber(): void { - $this->envSet('VORTEX_NOTIFY_JIRA_LABEL', 'main'); + public function testBranchWithoutIssueNumber(): void { + $this->envSet('VORTEX_NOTIFY_JIRA_BRANCH', 'main'); - $this->runScriptEarlyPass('src/notify-jira', 'Deployment label main does not contain issue number'); + $this->runScriptEarlyPass('src/notify-jira', 'Branch main does not contain issue number'); } #[DataProvider('dataProviderAuthenticationFailures')] @@ -759,7 +763,7 @@ public function testEventDefaultsToPostDeployment(): void { #[DataProvider('dataProviderIssueFormats')] public function testIssueFormats(string $label, string $expected_issue): void { - $this->envSet('VORTEX_NOTIFY_JIRA_LABEL', $label); + $this->envSet('VORTEX_NOTIFY_JIRA_BRANCH', $label); $this->mockRequestGet( 'https://jira.example.com/rest/api/3/myself', diff --git a/.vortex/tooling/tests/Unit/NotifyNewrelicTest.php b/.vortex/tooling/tests/Unit/NotifyNewrelicTest.php index 35a834882..15cbf59d3 100644 --- a/.vortex/tooling/tests/Unit/NotifyNewrelicTest.php +++ b/.vortex/tooling/tests/Unit/NotifyNewrelicTest.php @@ -234,14 +234,11 @@ public function testNotificationFailureWhenDeploymentCreationFails(): void { #[DataProvider('dataProviderMissingRequiredVariables')] public function testMissingRequiredVariables(string $var_name): void { $this->envUnset($var_name); - $this->runScriptError('src/notify-newrelic', 'Missing required value for ' . $var_name); + $this->runScriptError('src/notify-newrelic', 'Missing required New Relic User API Key'); } public static function dataProviderMissingRequiredVariables(): array { return [ - 'project' => ['VORTEX_NOTIFY_NEWRELIC_PROJECT'], - 'label' => ['VORTEX_NOTIFY_NEWRELIC_LABEL'], - 'environment_url' => ['VORTEX_NOTIFY_NEWRELIC_ENVIRONMENT_URL'], 'user_key' => ['VORTEX_NOTIFY_NEWRELIC_USER_KEY'], ]; } diff --git a/.vortex/tooling/tests/Unit/NotifyRouterTest.php b/.vortex/tooling/tests/Unit/NotifyRouterTest.php index 719620710..99337e9a5 100644 --- a/.vortex/tooling/tests/Unit/NotifyRouterTest.php +++ b/.vortex/tooling/tests/Unit/NotifyRouterTest.php @@ -22,6 +22,8 @@ protected function setUp(): void { $this->envSetMultiple([ 'VORTEX_NOTIFY_PROJECT' => 'test-project', + 'VORTEX_NOTIFY_BRANCH' => 'main', + 'VORTEX_NOTIFY_SHA' => 'abc123def456', 'VORTEX_NOTIFY_LABEL' => 'main', 'VORTEX_NOTIFY_ENVIRONMENT_URL' => 'https://example.com', ]);