Rich Block Kit Slack notifications for Deployer — environment, commit list, and ticket summary linked to your issue tracker.
✅ Deploy successful
Application: widget
Environment: web-prod-1
Branch: main ← linked to GitHub
Deployer: Ada Lovelace (ada@acme.io)
Old commit: a1b2c3d4 ← linked
Deployed commit: e5f6a7b8 ← linked
────────────────────────────────────────
TICKET SUMMARY
• ROS-9 feat(security): 30-day sessions for users… ← linked to YouTrack/Jira/…
• ROS-2 fix(users): prevent duplicate employee creation…
────────────────────────────────────────
COMMITS (5)
• e5f6a7b8 fix(users): prevent duplicate employee creation…
• 70b695f7 feat(security): 30-day sessions for users…
• …
Failure variant gets a red :x: header; redeploys with no new commits get a :neutral_face: Nothing new deployed empty state instead of a confusing green "successful".
composer require --dev hexis-hr/deployer-fanfareIn your deploy.php:
require 'recipe/symfony.php';
require __DIR__ . '/vendor/hexis-hr/deployer-fanfare/recipe.php';
set('repository', 'git@github.com:acme/widget.git');
set('fanfare_webhook', 'https://hooks.slack.com/services/…');
set('fanfare_issue_url_template', 'https://acme.atlassian.net/browse/{key}');
before('deploy:update_code', 'fanfare:revision');
after('deploy:success', 'fanfare:notify');
after('deploy:failed', 'fanfare:notify:failure');fanfare_webhook falls back to slack_webhook if you already have it set, so dropping the recipe into a project that uses the Deployer contrib/slack.php recipe works without renaming.
| Setting | Default | Purpose |
|---|---|---|
fanfare_webhook |
falls back to slack_webhook |
Slack incoming webhook URL. Required. |
fanfare_channel |
false (use webhook default) |
Override channel; e.g. '#deploys'. |
fanfare_issue_url_template |
'' (no linking) |
Issue URL with {key} placeholder. See examples. |
fanfare_ticket_pattern |
/\b([A-Z][A-Z0-9]{1,9}-\d+)\b/ |
Regex extracting ticket keys from commit subjects. Capture group 1 is the key. |
fanfare_commit_cap |
30 |
Commits beyond this collapse to … and N more. |
fanfare_emoji_success |
:white_check_mark: |
Header emoji on success. |
fanfare_emoji_failure |
:x: |
Header emoji on failure. |
fanfare_emoji_empty |
:neutral_face: |
Header emoji when redeploy has no new commits. |
fanfare_header_success |
Deploy successful |
Header text on success. |
fanfare_header_failure |
Deploy FAILED |
Header text on failure. |
fanfare_header_empty |
Nothing new deployed |
Header text on no-op redeploy. |
fanfare_github_repo_url |
derived from repository |
Auto-detected GitHub web URL; commit/branch links are skipped if repository is not a GitHub remote. |
// YouTrack
set('fanfare_issue_url_template', 'https://youtrack.example.com/issue/{key}');
// Jira Cloud
set('fanfare_issue_url_template', 'https://acme.atlassian.net/browse/{key}');
// Linear
set('fanfare_issue_url_template', 'https://linear.app/acme/issue/{key}');
// GitHub Issues — adjust the regex to match #123 instead of ROS-9
set('fanfare_issue_url_template', 'https://github.com/acme/widget/issues/{key}');
set('fanfare_ticket_pattern', '/#(\d+)/');| Task | Hook it via | Visibility |
|---|---|---|
fanfare:revision |
before('deploy:update_code', 'fanfare:revision') |
hidden |
fanfare:notify |
after('deploy:success', 'fanfare:notify') |
listed |
fanfare:notify:failure |
after('deploy:failed', 'fanfare:notify:failure') |
listed |
fanfare:revision reads the previous deploy's REVISION file under current/ so the recipe can compute the commit diff after a successful release. State is keyed by host alias, so concurrent multi-host deploys do not stomp on each other.
fanfare:revision(beforedeploy:update_code) reads{{deploy_path}}/current/REVISION— that's the previous deploy's HEAD. Empty on first deploy.fanfare:notify(afterdeploy:success) reads the new{{current_path}}/REVISION, then runsgit log <previous>..<new>against the cached deploy repo at{{deploy_path}}/.dep/repo. The result is parsed line-by-line using\x1f(ASCII unit-separator) as the field delimiter so commit subjects containing|aren't truncated.
If previous is empty (first deploy) or equals new (no-op redeploy), the empty-state header is shown instead.
- Local
git config user.name/user.emailfailures fall back tounknown— won't crash the deploy. - The Slack POST is wrapped in
try/catch; webhook failures emit a Deployer warning but the deploy continues. - A plain-text
textfallback ships alongside everyblockspayload (Slack a11y requirement). fanfare:notifyandfanfare:notify:failureare marked->once()so multi-host deploys send a single roll-up message rather than one per host.
Apache-2.0. See LICENSE.