Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .vortex/docs/content/deployment/notifications.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,22 @@ notification script.
| `VORTEX_NOTIFY_PR_NUMBER` | No | Pull request number (empty for branch deployments) |
| `VORTEX_NOTIFY_LABEL` | **Yes** | Human-readable deployment label |

## Branch filtering

Each notification channel can be restricted to specific branches using
a `VORTEX_NOTIFY_<CHANNEL>_BRANCHES` variable. When set, the channel
only sends notifications for deployments on the listed branches
(comma-separated, exact match). When empty or unset, the channel runs
on all branches.

For example, to restrict New Relic notifications to only `main` and `staging`:

```shell
VORTEX_NOTIFY_NEWRELIC_BRANCHES=main,staging
```

New Relic defaults to `main,master`. All other channels default to no filter.

## Message templates and tokens

Most notification channels support customizable message templates using replacement tokens:
Expand Down Expand Up @@ -88,6 +104,7 @@ Send deployment notification via email.
| `VORTEX_NOTIFY_EMAIL_RECIPIENTS` | **Yes** | | `.env` | Recipients (format: `email\|name`) |
| `VORTEX_NOTIFY_EMAIL_PROJECT` | No | `VORTEX_NOTIFY_PROJECT` | `.env` | Project name for email |
| `VORTEX_NOTIFY_EMAIL_MESSAGE` | No | Default template | `.env` | Custom message template |
| `VORTEX_NOTIFY_EMAIL_BRANCHES` | No | | `.env` | Restrict to specific branches (comma-separated) |

---

Expand All @@ -108,6 +125,7 @@ Post deployment status to GitHub pull requests.
| `VORTEX_NOTIFY_GITHUB_TOKEN` | **Yes** | | Hosting | GitHub personal access token |
| `VORTEX_NOTIFY_GITHUB_REPOSITORY` | **Yes** | | Hosting | Repository in `owner/repo` format |
| `VORTEX_NOTIFY_GITHUB_ENVIRONMENT_TYPE` | No | `${VORTEX_NOTIFY_LABEL}` | `.env` | Environment name (defaults to label, e.g. `PR-123`) |
| `VORTEX_NOTIFY_GITHUB_BRANCHES` | No | | `.env` | Restrict to specific branches (comma-separated) |

### Example

Expand Down Expand Up @@ -139,6 +157,7 @@ Post a deployment comment and optionally update issue status and assignee.
| `VORTEX_NOTIFY_JIRA_ASSIGNEE_EMAIL` | No | | `.env` | Assignee email after deployment |
| `VORTEX_NOTIFY_JIRA_TRANSITION` | No | | `.env` | Transition name (e.g., "In Review") |
| `VORTEX_NOTIFY_JIRA_ENDPOINT` | No | `https://jira.atlassian.com` | `.env` | JIRA API endpoint |
| `VORTEX_NOTIFY_JIRA_BRANCHES` | No | | `.env` | Restrict to specific branches (comma-separated) |

### Issue key extraction

Expand Down Expand Up @@ -183,6 +202,7 @@ in development or feature branch environments.
| `VORTEX_NOTIFY_NEWRELIC_CHANGELOG` | No | Description | `.env` | Deployment changelog |
| `VORTEX_NOTIFY_NEWRELIC_USER` | No | `Deployment robot` | `.env` | User performing deployment |
| `VORTEX_NOTIFY_NEWRELIC_ENDPOINT` | No | `https://api.newrelic.com/v2` | `.env` | API endpoint |
| `VORTEX_NOTIFY_NEWRELIC_BRANCHES` | No | `main,master` | `.env` | Restrict to specific branches (comma-separated) |

### Example

Expand All @@ -209,6 +229,7 @@ Post deployment notifications to a Slack channel.
| `VORTEX_NOTIFY_SLACK_CHANNEL` | No | | `.env` | Target channel (overrides webhook default) |
| `VORTEX_NOTIFY_SLACK_USERNAME` | No | `Deployment Bot` | `.env` | Bot display name |
| `VORTEX_NOTIFY_SLACK_ICON_EMOJI` | No | `:rocket:` | `.env` | Bot icon emoji |
| `VORTEX_NOTIFY_SLACK_BRANCHES` | No | | `.env` | Restrict to specific branches (comma-separated) |

### Event behavior

Expand Down Expand Up @@ -240,6 +261,7 @@ Send HTTP requests to arbitrary webhook URLs.
| `VORTEX_NOTIFY_WEBHOOK_HEADERS` | No | `Content-Type: application/json` | `.env` | Pipe-separated headers |
| `VORTEX_NOTIFY_WEBHOOK_PAYLOAD` | No | Default template | `.env` | JSON payload |
| `VORTEX_NOTIFY_WEBHOOK_RESPONSE_STATUS` | No | `200` | `.env` | Expected HTTP status |
| `VORTEX_NOTIFY_WEBHOOK_BRANCHES` | No | | `.env` | Restrict to specific branches (comma-separated) |

### Default payload template

Expand Down
7 changes: 6 additions & 1 deletion .vortex/docs/content/development/variables.mdx

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions .vortex/tests/bats/unit/notify-email.bats
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,30 @@ load ../_helper.bash
popd >/dev/null || exit 1
}

@test "Notify: email, branch filter skip" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

export VORTEX_NOTIFY_CHANNELS="email"
export VORTEX_NOTIFY_PROJECT="testproject"
export DRUPAL_SITE_EMAIL="testproject@example.com"
export VORTEX_NOTIFY_EMAIL_RECIPIENTS="john@example.com"
export VORTEX_NOTIFY_BRANCH="feature/test"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="feature/test"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com"
export VORTEX_NOTIFY_EMAIL_BRANCHES="main,develop"

run ./scripts/vortex/notify.sh
assert_success

assert_output_contains "Started dispatching notifications."
assert_output_contains "Skipping email notification for branch 'feature/test'."
assert_output_not_contains "Started email notification."
assert_output_contains "Finished dispatching notifications."

popd >/dev/null || exit 1
}

@test "Notify: email, shell injection protection" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

Expand Down
24 changes: 24 additions & 0 deletions .vortex/tests/bats/unit/notify-github.bats
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,30 @@ load ../_helper.bash
popd >/dev/null || exit 1
}

@test "Notify: github, branch filter skip" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

export VORTEX_NOTIFY_CHANNELS="github"
export VORTEX_NOTIFY_EVENT="pre_deployment"
export VORTEX_NOTIFY_GITHUB_TOKEN="token12345"
export VORTEX_NOTIFY_GITHUB_REPOSITORY="myorg/myrepo"
export VORTEX_NOTIFY_BRANCH="feature/test"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="feature/test"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com"
export VORTEX_NOTIFY_GITHUB_BRANCHES="main,develop"

run ./scripts/vortex/notify.sh
assert_success

assert_output_contains "Started dispatching notifications."
assert_output_contains "Skipping GitHub notification for branch 'feature/test'."
assert_output_not_contains "Started GitHub notification"
assert_output_contains "Finished dispatching notifications."

popd >/dev/null || exit 1
}

@test "Notify: github, post_deployment, failure to set status" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

Expand Down
24 changes: 24 additions & 0 deletions .vortex/tests/bats/unit/notify-jira.bats
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,30 @@ load ../_helper.bash
popd >/dev/null || exit 1
}

@test "Notify: jira, branch filter skip" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

export VORTEX_NOTIFY_CHANNELS="jira"
export VORTEX_NOTIFY_JIRA_USER_EMAIL="john.doe@example.com"
export VORTEX_NOTIFY_JIRA_TOKEN="token12345"
export VORTEX_NOTIFY_JIRA_PROJECT="PROJ"
export VORTEX_NOTIFY_BRANCH="feature/proj-1234-test"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="feature/proj-1234-test"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com"
export VORTEX_NOTIFY_JIRA_BRANCHES="main,develop"

run ./scripts/vortex/notify.sh
assert_success

assert_output_contains "Started dispatching notifications."
assert_output_contains "Skipping JIRA notification for branch 'feature/proj-1234-test'."
assert_output_not_contains "Started JIRA notification."
assert_output_contains "Finished dispatching notifications."

popd >/dev/null || exit 1
}

@test "Notify: jira, shell injection protection" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

Expand Down
78 changes: 66 additions & 12 deletions .vortex/tests/bats/unit/notify-newrelic.bats
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ load ../_helper.bash
export VORTEX_NOTIFY_CHANNELS="newrelic"
export VORTEX_NOTIFY_PROJECT="testproject"
export VORTEX_NOTIFY_NEWRELIC_USER_KEY="key1234"
export VORTEX_NOTIFY_BRANCH="develop"
export VORTEX_NOTIFY_BRANCH="main"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="develop"
export VORTEX_NOTIFY_LABEL="main"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://test.example.com"
# VORTEX_NOTIFY_NEWRELIC_ENABLED is intentionally not set

Expand All @@ -36,17 +36,17 @@ load ../_helper.bash
app_id="9876543210"
mock_curl=$(mock_command "curl")

mock_set_output "${mock_curl}" "{\"applications\": [{\"id\": ${app_id}, \"name\": \"testproject-develop\"}]}" 1
mock_set_output "${mock_curl}" "{\"applications\": [{\"id\": ${app_id}, \"name\": \"testproject-main\"}]}" 1
mock_set_output "${mock_curl}" "201" 2

export VORTEX_NOTIFY_CHANNELS="newrelic"
export VORTEX_NOTIFY_NEWRELIC_ENABLED=true
export VORTEX_NOTIFY_PROJECT="testproject"
export VORTEX_NOTIFY_NEWRELIC_USER_KEY="key1234"
export VORTEX_NOTIFY_EMAIL_RECIPIENTS="john@example.com|John Doe,jane@example.com|Jane Doe"
export VORTEX_NOTIFY_BRANCH="develop"
export VORTEX_NOTIFY_BRANCH="main"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="develop"
export VORTEX_NOTIFY_LABEL="main"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://test.example.com"

run ./scripts/vortex/notify.sh
Expand All @@ -57,9 +57,9 @@ load ../_helper.bash
assert_output_contains "Started New Relic notification."
assert_output_contains "Discovering APP id by name if it was not provided."
assert_output_contains "Checking if the application ID is valid."
assert_output_contains "Creating a deployment notification for application testproject-develop with ID 9876543210."
assert_output_contains "Creating a deployment notification for application testproject-main with ID 9876543210."

assert_equal "-s -X GET https://api.newrelic.com/v2/applications.json -H Api-Key: key1234 -s -G -d filter[name]=testproject-develop&exclude_links=true" "$(mock_get_call_args "${mock_curl}" 1)"
assert_equal "-s -X GET https://api.newrelic.com/v2/applications.json -H Api-Key: key1234 -s -G -d filter[name]=testproject-main&exclude_links=true" "$(mock_get_call_args "${mock_curl}" 1)"

# Extract revision from actual curl call (since it's auto-generated with timestamp)
actual_curl_call="$(mock_get_call_args "${mock_curl}" 2)"
Expand All @@ -86,9 +86,9 @@ load ../_helper.bash
export VORTEX_NOTIFY_EVENT="pre_deployment"
export VORTEX_NOTIFY_PROJECT="testproject"
export VORTEX_NOTIFY_NEWRELIC_USER_KEY="key1234"
export VORTEX_NOTIFY_BRANCH="develop"
export VORTEX_NOTIFY_BRANCH="main"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="develop"
export VORTEX_NOTIFY_LABEL="main"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://test.example.com"
run ./scripts/vortex/notify.sh
assert_success
Expand All @@ -102,23 +102,77 @@ load ../_helper.bash
popd >/dev/null || exit 1
}

@test "Notify: newrelic, branch filter default skip" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

export VORTEX_NOTIFY_CHANNELS="newrelic"
export VORTEX_NOTIFY_NEWRELIC_ENABLED=true
export VORTEX_NOTIFY_PROJECT="testproject"
export VORTEX_NOTIFY_NEWRELIC_USER_KEY="key1234"
export VORTEX_NOTIFY_BRANCH="develop"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="develop"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://test.example.com"
# VORTEX_NOTIFY_NEWRELIC_BRANCHES defaults to "main,master"

run ./scripts/vortex/notify.sh
assert_success

assert_output_contains "Started dispatching notifications."
assert_output_contains "Skipping New Relic notification for branch 'develop'."
assert_output_not_contains "Started New Relic notification."
assert_output_contains "Finished dispatching notifications."

popd >/dev/null || exit 1
}

@test "Notify: newrelic, branch filter custom" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

app_id="9876543210"
mock_curl=$(mock_command "curl")

mock_set_output "${mock_curl}" "{\"applications\": [{\"id\": ${app_id}, \"name\": \"testproject-staging\"}]}" 1
mock_set_output "${mock_curl}" "201" 2

export VORTEX_NOTIFY_CHANNELS="newrelic"
export VORTEX_NOTIFY_NEWRELIC_ENABLED=true
export VORTEX_NOTIFY_PROJECT="testproject"
export VORTEX_NOTIFY_NEWRELIC_USER_KEY="key1234"
export VORTEX_NOTIFY_BRANCH="staging"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="staging"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://test.example.com"
export VORTEX_NOTIFY_NEWRELIC_BRANCHES="main,staging"

run ./scripts/vortex/notify.sh
assert_success

assert_output_contains "Started dispatching notifications."
assert_output_contains "Started New Relic notification."
assert_output_not_contains "Skipping New Relic notification for branch"
assert_output_contains "Finished dispatching notifications."

popd >/dev/null || exit 1
}

@test "Notify: newrelic, shell injection protection" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

app_id="9876543210"
mock_curl=$(mock_command "curl")

mock_set_output "${mock_curl}" "{\"applications\": [{\"id\": ${app_id}, \"name\": \"test-develop\"}]}" 1
mock_set_output "${mock_curl}" "{\"applications\": [{\"id\": ${app_id}, \"name\": \"test-main\"}]}" 1
mock_set_output "${mock_curl}" "201" 2

# Attempt shell injection through project name with PHP code that would create a file
export VORTEX_NOTIFY_CHANNELS="newrelic"
export VORTEX_NOTIFY_NEWRELIC_ENABLED=true
export VORTEX_NOTIFY_PROJECT="test'); file_put_contents('/tmp/injected_newrelic_test', 'HACKED'); //"
export VORTEX_NOTIFY_NEWRELIC_USER_KEY="key1234"
export VORTEX_NOTIFY_BRANCH="develop"
export VORTEX_NOTIFY_BRANCH="main"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="develop"
export VORTEX_NOTIFY_LABEL="main"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://test.example.com"

# Ensure test file doesn't exist before
Expand Down
23 changes: 23 additions & 0 deletions .vortex/tests/bats/unit/notify-slack.bats
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,29 @@ load ../_helper.bash
popd >/dev/null || exit 1
}

@test "Notify: slack, branch filter skip" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

export VORTEX_NOTIFY_CHANNELS="slack"
export VORTEX_NOTIFY_PROJECT="testproject"
export VORTEX_NOTIFY_BRANCH="feature/test"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="feature/test"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com"
export VORTEX_NOTIFY_SLACK_WEBHOOK="https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX"
export VORTEX_NOTIFY_SLACK_BRANCHES="main,develop"

run ./scripts/vortex/notify.sh
assert_success

assert_output_contains "Started dispatching notifications."
assert_output_contains "Skipping Slack notification for branch 'feature/test'."
assert_output_not_contains "Started Slack notification."
assert_output_contains "Finished dispatching notifications."

popd >/dev/null || exit 1
}

@test "Notify: slack, shell injection protection" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

Expand Down
25 changes: 25 additions & 0 deletions .vortex/tests/bats/unit/notify-webhook.bats
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,31 @@ load ../_helper.bash
popd >/dev/null || exit 1
}

@test "Notify: webhook, branch filter skip" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

export VORTEX_NOTIFY_CHANNELS="webhook"
export VORTEX_NOTIFY_PROJECT="testproject"
export VORTEX_NOTIFY_BRANCH="feature/test"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="feature/test"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://develop.testproject.com"
export VORTEX_NOTIFY_WEBHOOK_URL="https://example-webhook-url.com"
export VORTEX_NOTIFY_WEBHOOK_METHOD="POST"
export VORTEX_NOTIFY_WEBHOOK_HEADERS="Content-type: application/json"
export VORTEX_NOTIFY_WEBHOOK_BRANCHES="main,develop"

run ./scripts/vortex/notify.sh
assert_success

assert_output_contains "Started dispatching notifications."
assert_output_contains "Skipping Webhook notification for branch 'feature/test'."
assert_output_not_contains "Started Webhook notification."
assert_output_contains "Finished dispatching notifications."

popd >/dev/null || exit 1
}

@test "Notify: webhook, shell injection protection" {
pushd "${LOCAL_REPO_DIR}" >/dev/null || exit 1

Expand Down
4 changes: 2 additions & 2 deletions .vortex/tests/bats/unit/notify.bats
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ load ../_helper.bash
export VORTEX_NOTIFY_CHANNELS="email,slack,github,newrelic,webhook,jira"
export VORTEX_NOTIFY_EVENT="pre_deployment"
export VORTEX_NOTIFY_PROJECT="testproject"
export VORTEX_NOTIFY_BRANCH="develop"
export VORTEX_NOTIFY_BRANCH="main"
export VORTEX_NOTIFY_SHA="abc123def456"
export VORTEX_NOTIFY_LABEL="develop"
export VORTEX_NOTIFY_LABEL="main"
export VORTEX_NOTIFY_ENVIRONMENT_URL="https://test.example.com"

# Email required variables
Expand Down
Loading
Loading