diff --git a/app/Livewire/Project/Shared/Webhooks.php b/app/Livewire/Project/Shared/Webhooks.php
index c54a1c38f..6bb9428d5 100644
--- a/app/Livewire/Project/Shared/Webhooks.php
+++ b/app/Livewire/Project/Shared/Webhooks.php
@@ -10,9 +10,11 @@ class Webhooks extends Component
public ?string $deploywebhook = null;
public ?string $githubManualWebhook = null;
public ?string $gitlabManualWebhook = null;
+ public ?string $bitbucketManualWebhook = null;
protected $rules = [
'resource.manual_webhook_secret_github' => 'nullable|string',
'resource.manual_webhook_secret_gitlab' => 'nullable|string',
+ 'resource.manual_webhook_secret_bitbucket' => 'nullable|string',
];
public function saveSecret()
{
@@ -29,6 +31,7 @@ class Webhooks extends Component
$this->deploywebhook = generateDeployWebhook($this->resource);
$this->githubManualWebhook = generateGitManualWebhook($this->resource, 'github');
$this->gitlabManualWebhook = generateGitManualWebhook($this->resource, 'gitlab');
+ $this->bitbucketManualWebhook = generateGitManualWebhook($this->resource, 'bitbucket');
}
public function render()
{
diff --git a/database/migrations/2024_01_23_095832_add_manual_webhook_secret_bitbucket.php b/database/migrations/2024_01_23_095832_add_manual_webhook_secret_bitbucket.php
new file mode 100755
index 000000000..74917a049
--- /dev/null
+++ b/database/migrations/2024_01_23_095832_add_manual_webhook_secret_bitbucket.php
@@ -0,0 +1,28 @@
+string('manual_webhook_secret_bitbucket')->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('applications', function (Blueprint $table) {
+ $table->dropColumn('manual_webhook_secret_bitbucket');
+ });
+ }
+};
diff --git a/resources/views/livewire/project/shared/webhooks.blade.php b/resources/views/livewire/project/shared/webhooks.blade.php
index a90b01b58..121cdf058 100644
--- a/resources/views/livewire/project/shared/webhooks.blade.php
+++ b/resources/views/livewire/project/shared/webhooks.blade.php
@@ -33,6 +33,10 @@
helper="Need to set a secret to be able to use this webhook. It should match with the secret in GitLab."
label="GitLab Webhook Secret" id="resource.manual_webhook_secret_gitlab">
+
+
+
+
Save
@else
diff --git a/routes/webhooks.php b/routes/webhooks.php
index 1fb0bce4e..f55dddd13 100644
--- a/routes/webhooks.php
+++ b/routes/webhooks.php
@@ -231,6 +231,92 @@ Route::post('/source/gitlab/events/manual', function () {
return handleError($e);
}
});
+Route::post('/source/bitbucket/events/manual', function () {
+ try {
+ $return_payloads = collect([]);
+ $payload = request()->collect();
+ $headers = request()->headers->all();
+ $x_bitbucket_token = data_get($headers, 'x-hub-signature', [""])[0];
+ $x_bitbucket_event = data_get($headers, 'x-event-key', [""])[0];
+ if ($x_bitbucket_event === 'repo:push') {
+ $branch = data_get($payload, 'push.changes.0.new.name');
+ $name = data_get($payload, 'repository.name');
+
+ if (!$branch) {
+ $return_payloads->push([
+ 'status' => 'failed',
+ 'message' => 'Nothing to do. No branch found in the request.',
+ ]);
+ return response($return_payloads);
+ }
+ ray('Manual Webhook bitbucket Push Event with branch: ' . $branch);
+ }
+ $applications = Application::where('git_repository', 'like', "%$name%");
+ if ($x_bitbucket_event === 'repo:push') {
+ $applications = $applications->where('git_branch', $branch)->get();
+ if ($applications->isEmpty()) {
+ $return_payloads->push([
+ 'status' => 'failed',
+ 'message' => "Nothing to do. No applications found with deploy key set, branch is '$branch' and Git Repository name has $name.",
+ ]);
+ return response($return_payloads);
+ }
+ }
+ foreach ($applications as $application) {
+ $webhook_secret = data_get($application, 'manual_webhook_secret_bitbucket');
+ $payload = request()->getContent();
+
+ fwrite(STDOUT, $payload);
+
+ list($algo, $hash) = explode('=', $x_bitbucket_token, 2);
+
+ $payloadHash = hash_hmac($algo, $payload, $webhook_secret);
+
+ if (!hash_equals($hash, $payloadHash)) {
+ $return_payloads->push([
+ 'application' => $application->name,
+ 'status' => 'failed',
+ 'message' => 'Invalid token.',
+ ]);
+ ray('Invalid signature');
+ continue;
+ }
+ $isFunctional = $application->destination->server->isFunctional();
+ if (!$isFunctional) {
+ $return_payloads->push([
+ 'application' => $application->name,
+ 'status' => 'failed',
+ 'message' => 'Server is not functional',
+ ]);
+ ray('Server is not functional: ' . $application->destination->server->name);
+ continue;
+ }
+ if ($x_bitbucket_event === 'repo:push') {
+ if ($application->isDeployable()) {
+ ray('Deploying ' . $application->name . ' with branch ' . $branch);
+ $deployment_uuid = new Cuid2(7);
+ queue_application_deployment(
+ application_id: $application->id,
+ deployment_uuid: $deployment_uuid,
+ force_rebuild: false,
+ is_webhook: true
+ );
+ } else {
+ $return_payloads->push([
+ 'application' => $application->name,
+ 'status' => 'failed',
+ 'message' => 'Deployments disabled',
+ ]);
+ ray('Deployments disabled for ' . $application->name);
+ }
+ }
+ }
+ return response($return_payloads);
+ } catch (Exception $e) {
+ ray($e->getMessage());
+ return handleError($e);
+ }
+});
Route::post('/source/github/events/manual', function () {
try {
$x_github_event = Str::lower(request()->header('X-GitHub-Event'));