Skip to content
Open
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
5 changes: 5 additions & 0 deletions app/Livewire/Notifications/Slack.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ class Slack extends Component
#[Validate(['nullable', new SafeWebhookUrl])]
public ?string $slackWebhookUrl = null;

#[Validate(['boolean'])]
public bool $includeProjectNameInTitle = false;

#[Validate(['boolean'])]
public bool $deploymentSuccessSlackNotifications = false;

Expand Down Expand Up @@ -90,6 +93,7 @@ public function syncData(bool $toModel = false)
$this->authorize('update', $this->settings);
$this->settings->slack_enabled = $this->slackEnabled;
$this->settings->slack_webhook_url = $this->slackWebhookUrl;
$this->settings->include_project_name_in_title = $this->includeProjectNameInTitle;

$this->settings->deployment_success_slack_notifications = $this->deploymentSuccessSlackNotifications;
$this->settings->deployment_failure_slack_notifications = $this->deploymentFailureSlackNotifications;
Expand All @@ -113,6 +117,7 @@ public function syncData(bool $toModel = false)
$this->slackWebhookUrl = auth()->user()->can('update', $this->settings)
? $this->settings->slack_webhook_url
: null;
$this->includeProjectNameInTitle = $this->settings->include_project_name_in_title;

$this->deploymentSuccessSlackNotifications = $this->settings->deployment_success_slack_notifications;
$this->deploymentFailureSlackNotifications = $this->settings->deployment_failure_slack_notifications;
Expand Down
2 changes: 2 additions & 0 deletions app/Models/SlackNotificationSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class SlackNotificationSettings extends Model

'slack_enabled',
'slack_webhook_url',
'include_project_name_in_title',

'deployment_success_slack_notifications',
'deployment_failure_slack_notifications',
Expand All @@ -40,6 +41,7 @@ class SlackNotificationSettings extends Model
protected $casts = [
'slack_enabled' => 'boolean',
'slack_webhook_url' => 'encrypted',
'include_project_name_in_title' => 'boolean',

'deployment_success_slack_notifications' => 'boolean',
'deployment_failure_slack_notifications' => 'boolean',
Expand Down
3 changes: 2 additions & 1 deletion app/Notifications/Application/DeploymentFailed.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ public function toSlack(): SlackMessage
return new SlackMessage(
title: $title,
description: $description,
color: SlackMessage::errorColor()
color: SlackMessage::errorColor(),
projectName: data_get($this->application, 'environment.project.name'),
);
}

Expand Down
3 changes: 2 additions & 1 deletion app/Notifications/Application/DeploymentSuccess.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ public function toSlack(): SlackMessage
return new SlackMessage(
title: $title,
description: $description,
color: SlackMessage::successColor()
color: SlackMessage::successColor(),
projectName: data_get($this->application, 'environment.project.name'),
);
}

Expand Down
4 changes: 4 additions & 0 deletions app/Notifications/Channels/SlackChannel.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public function send(SendsSlack $notifiable, Notification $notification): void
return;
}

if ($slackSettings->include_project_name_in_title) {
$message->prependProjectNameToTitle();
}

SendMessageToSlackJob::dispatch($message, $slackSettings->slack_webhook_url);
}
}
12 changes: 11 additions & 1 deletion app/Notifications/Dto/SlackMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,19 @@ class SlackMessage
public function __construct(
public string $title,
public string $description,
public string $color = '#0099ff'
public string $color = '#0099ff',
public ?string $projectName = null,
) {}

public function prependProjectNameToTitle(): void
{
if ($this->projectName === null || $this->projectName === '') {
return;
}

$this->title = "{$this->projectName}: {$this->title}";
}

public static function infoColor(): string
{
return '#0099ff';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::table('slack_notification_settings', function (Blueprint $table) {
$table->boolean('include_project_name_in_title')->default(false);
});
}

public function down(): void
{
Schema::table('slack_notification_settings', function (Blueprint $table) {
$table->dropColumn('include_project_name_in_title');
});
}
};
3 changes: 3 additions & 0 deletions resources/views/livewire/notifications/slack.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
label="Deployment Success" />
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="saveModel" id="deploymentFailureSlackNotifications"
label="Deployment Failure" />
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="saveModel" id="includeProjectNameInTitle"
helper="Prefix deployment notification titles with the project name, for example: My Project: Deployment failed."
label="Show Project Name in Title" />
<x-forms.checkbox canGate="update" :canResource="$settings" instantSave="saveModel"
helper="Send a notification when a container status changes. It will notify for Stopped and Restarted events of a container."
id="statusChangeSlackNotifications" label="Container Status Changes" />
Expand Down
78 changes: 78 additions & 0 deletions tests/Feature/SlackNotificationProjectNameTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

use App\Jobs\SendMessageToSlackJob;
use App\Models\Application;
use App\Models\Environment;
use App\Models\InstanceSettings;
use App\Models\Project;
use App\Models\Team;
use App\Notifications\Application\DeploymentFailed;
use App\Notifications\Application\DeploymentSuccess;
use App\Notifications\Channels\SlackChannel;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;

uses(RefreshDatabase::class);

beforeEach(function () {
InstanceSettings::forceCreate(['id' => 0]);
});

it('prefixes a Slack title with the project name when enabled', function () {
Queue::fake();

$team = Team::factory()->create();
$project = Project::factory()->create([
'name' => 'My Project',
'team_id' => $team->id,
]);
$environment = Environment::factory()->create(['project_id' => $project->id]);
$application = Application::factory()->create(['environment_id' => $environment->id]);

expect($team->slackNotificationSettings->include_project_name_in_title)->toBeFalse();

$team->slackNotificationSettings->update([
'slack_enabled' => true,
'slack_webhook_url' => 'https://hooks.slack.com/services/test',
'include_project_name_in_title' => true,
]);
$notification = new DeploymentFailed($application, 'deployment-uuid');
$message = $notification->toSlack();

app(SlackChannel::class)->send($team, $notification);

expect($message->projectName)->toBe('My Project');
Queue::assertPushed(SendMessageToSlackJob::class, function (SendMessageToSlackJob $job) {
$message = (new ReflectionProperty($job, 'message'))->getValue($job);

return $message->title === 'My Project: Deployment failed';
});
});

it('keeps the original Slack title when the project name option is disabled', function () {
Queue::fake();

$team = Team::factory()->create();
$project = Project::factory()->create([
'name' => 'My Project',
'team_id' => $team->id,
]);
$environment = Environment::factory()->create(['project_id' => $project->id]);
$application = Application::factory()->create(['environment_id' => $environment->id]);
$team->slackNotificationSettings->update([
'slack_enabled' => true,
'slack_webhook_url' => 'https://hooks.slack.com/services/test',
'include_project_name_in_title' => false,
]);
$notification = new DeploymentSuccess($application, 'deployment-uuid');
$message = $notification->toSlack();

app(SlackChannel::class)->send($team, $notification);

expect($message->projectName)->toBe('My Project');
Queue::assertPushed(SendMessageToSlackJob::class, function (SendMessageToSlackJob $job) {
$message = (new ReflectionProperty($job, 'message'))->getValue($job);

return $message->title === 'New version successfully deployed';
});
});