diff --git a/app/Analyzers/DockerHub/BaseEvent.php b/app/Analyzers/DockerHub/BaseEvent.php new file mode 100644 index 0000000..fc951ea --- /dev/null +++ b/app/Analyzers/DockerHub/BaseEvent.php @@ -0,0 +1,48 @@ +payload = $payload; + } + + /// + /// Public methods + /// + + /** + * Gets notification payload. + * + * This method allows analyzer to edit the payload. + */ + public function getPayload () { + return $this->payload; + } + + /** + * Gets notification text for this event. + * + * @return string + */ + abstract public function getText(); + + /** + * Gets notification link related to this event. + * + * @return string + */ + abstract public function getLink(); + +} diff --git a/app/Analyzers/DockerHub/BuildFailureEvent.php b/app/Analyzers/DockerHub/BuildFailureEvent.php new file mode 100644 index 0000000..15e7f18 --- /dev/null +++ b/app/Analyzers/DockerHub/BuildFailureEvent.php @@ -0,0 +1,67 @@ +payload = $this->getMailGunPayload(); + } + + /** + * Gets a MailGun message. + * + * @return stdClass + */ + private function getMailGunPayload () { + return Mailgun::fetchMessageFromPayload($this->payload); + } + + /** + * @return string + */ + private function getMailBody () { + $bodyProperty = 'body-plain'; + return $this->payload->$bodyProperty; + } + + /** + * Extracts a regular expression from the mail body. + * + * @param $string Regular expression + * @return string + */ + private function extractFromBody ($regex) { + preg_match($regex, $this->getMailBody(), $matches); + return $matches[1]; + } + + /** + * Gets text from payload. + * + * @return string + */ + public function getText() { + $repo = $this->extractFromBody("@\"(.*?\/.*?)\"@"); + + return "Image build by Docker Hub registry failure for $repo"; + } + + /** + * Gets link from payload. + * + * @return string + */ + public function getLink() { + return $this->extractFromBody("@(https\:\/\/hub.docker.com\/r.*)@"); + } + +} diff --git a/app/Analyzers/DockerHub/PushEvent.php b/app/Analyzers/DockerHub/PushEvent.php new file mode 100644 index 0000000..8be97bb --- /dev/null +++ b/app/Analyzers/DockerHub/PushEvent.php @@ -0,0 +1,28 @@ +payload->repository->repo_name; + $who = $this->payload->push_data->pusher; + + return "New image pushed to Docker Hub registry for $repo by $who"; + } + + /** + * Gets link from payload. + * + * @return string + */ + public function getLink() { + return $this->payload->repository->repo_url; + } + +} diff --git a/app/Events/DockerHubPayloadEvent.php b/app/Events/DockerHubPayloadEvent.php index 8a1941f..abc59cc 100644 --- a/app/Events/DockerHubPayloadEvent.php +++ b/app/Events/DockerHubPayloadEvent.php @@ -1,40 +1,53 @@ payload->repository->repo_url)) { + return "push"; + } + + return "buildFailure"; + } + /** * Creates a new event instance. * * @param string $door * @param stdClass $payload */ public function __construct($door, $payload) { $this->door = $door; - //$this->event = $event; // Currently, the API only send push events $this->payload = $payload; + $this->event = $this->getEvent(); } } diff --git a/app/Notifications/DockerHubNotification.php b/app/Notifications/DockerHubNotification.php index 5d9f9d9..6cff427 100644 --- a/app/Notifications/DockerHubNotification.php +++ b/app/Notifications/DockerHubNotification.php @@ -1,52 +1,87 @@ service = "DockerHub"; $this->project = $project; $this->type = $event; $this->rawContent = $payload; $this->group = "docker"; // Properties from the payload - $this->text = $this->getText(); - $this->link = $payload->repository->repo_url; + $this->analyzeByEvent(); + } + + /// + /// Analyze by event + /// + + /** + * Fills properties from event payload. + */ + public function analyzeByEvent () { + $analyzer = $this->getAnalyzer(); + $this->rawContent = $analyzer->getPayload(); + $this->text = $analyzer->getText(); + $this->link = $analyzer->getLink(); } /** - * Gets the notification text. Intended to convey a short message (thing Twitter or IRC). + * Gets analyzer class name for the current event. * * @return string */ - public function getText () { - $repo = $this->rawContent->repository->repo_name; - $who = $this->rawContent->push_data->pusher; - return "New image pushed to Docker Hub registry for $repo by $who"; + private function getAnalyzerClassName () { + return "Nasqueron\Notifications\Analyzers\DockerHub\\" + . ucfirst($this->type) + . "Event"; + } + + /** + * Gets analyzer for the current event. + * + * @return \Nasqueron\Notifications\Analyzers\DockerHub\BaseEvent + */ + private function getAnalyzer () { + $class = $this->getAnalyzerClassName(); + + if (!class_exists($class)) { + throw new InvalidArgumentException( + "Event $this->type doesn't have a matching $class class." + ); + } + + return new $class($this->rawContent); } + + + } diff --git a/tests/Notifications/DockerHubNotificationTest.php b/tests/Notifications/DockerHubNotificationTest.php index dead80f..57339c6 100644 --- a/tests/Notifications/DockerHubNotificationTest.php +++ b/tests/Notifications/DockerHubNotificationTest.php @@ -1,45 +1,80 @@ payload = json_decode(file_get_contents($path)); + protected function prepareNotification ($event) { + $path = __DIR__ . '/../data/payloads/DockerHub' . ucfirst($event) + . 'Payload.json'; + $payload = json_decode(file_get_contents($path)); - $this->notification = new DockerHubNotification( - "Acme", - "push", - $this->payload - ); + return new DockerHubNotification("Acme", $event, $payload); } - public function testProperties () { - $this->assertSame("DockerHub", $this->notification->service); - $this->assertSame("Acme", $this->notification->project); - $this->assertSame("docker", $this->notification->group); - $this->assertSame($this->payload, $this->notification->rawContent); - $this->assertSame("push", $this->notification->type); + public function testPropertiesForPush () { + $notification = $this->prepareNotification("push"); + + $this->assertSame("DockerHub", $notification->service); + $this->assertSame("Acme", $notification->project); + $this->assertSame("docker", $notification->group); + $this->assertSame("push", $notification->type); $this->assertSame( "New image pushed to Docker Hub registry for svendowideit/testhook by trustedbuilder", - $this->notification->text + $notification->text ); $this->assertSame( "https://registry.hub.docker.com/u/svendowideit/testhook/", - $this->notification->link + $notification->link ); } + + public function testPropertiesForBuildFailure () { + $this->mockMailgunServiceProvider(); + $notification = $this->prepareNotification("buildFailure"); + $this->assertSame("buildFailure", $notification->type); + + $this->assertSame( + "Image build by Docker Hub registry failure for acme/foo", + $notification->text + ); + $this->assertSame( + "https://hub.docker.com/r/acme/foo/builds/abcdef123456/", + $notification->link + ); + } + + /// + /// Helper mock method + /// + + /** + * Injects into our container a mock of MailgunMessageFactory + */ + protected function mockMailgunServiceProvider () { + $mock = Mockery::mock('Keruald\Mailgun\MailgunMessageFactory'); + $payload = $this->mockMailgunResponse(); + $mock->shouldReceive('fetchMessageFromPayload')->once()->andReturn($payload); + $this->app->instance('mailgun', $mock); + } + + /** + * @return stdClass + */ + protected function mockMailgunResponse () { + return json_decode($this->mockHttpClientResponseBody()); + } + } diff --git a/tests/data/payloads/DockerHubBuildFailurePayload.json b/tests/data/payloads/DockerHubBuildFailurePayload.json new file mode 100644 index 0000000..a079d17 --- /dev/null +++ b/tests/data/payloads/DockerHubBuildFailurePayload.json @@ -0,0 +1,40 @@ +{ + "tags": [], + "timestamp": 1472676730.131279, + "storage": { + "url": "https://so.api.mailgun.net/v3/domains/notifications.domain.tld/messages/somehash", + "key": "somekey" + }, + "envelope": { + "sender": "no-reply@notify.docker.com", + "transport": "smtp", + "targets": "docker-hub-notify@notifications.domain.tld" + }, + "recipient-domain": "notifications.domain.tld", + "method": "smtp", + "campaigns": [], + "user-variables": {}, + "flags": { + "is-routed": null, + "is-authenticated": false, + "is-system-test": false, + "is-test-mode": false + }, + "log-level": "info", + "id": "te1cKBxQTJWxpalPRcnmBw", + "message": { + "headers": { + "to": "docker-hub-notify@notifications.domain.tld", + "message-id": "CAKg6iAHgQ4e8etV=gi4pbBueeA-o0Qsv02u1Cp9ZKTH8-tL9xw@mail.gmail.com", + "from": "no-reply@notify.docker.com", + "subject": "There's been an issue with your automated build" + }, + "attachments": [], + "recipients": [ + "docker-hub-notify@notifications.domain.tld" + ], + "size": 2674 + }, + "recipient": "docker-hub-notify@notifications.domain.tld", + "event": "accepted" +}