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 .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Tests

on:
push:
pull_request:

jobs:
tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ['7.1', '8.5']

steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
- run: composer update --prefer-dist --no-interaction
- run: vendor/bin/phpunit
14 changes: 5 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
# PHP GitHub Status API

[![Build Status](https://travis-ci.com/Jord-JD/php-github-status-api.svg?branch=master)](https://travis-ci.com/Jord-JD/php-github-status-api)

---

⚠️ **Warning:** As of 11th December 2018, GitHub have deprecated the status page that this package parses, so current status information may not be up-to-date. More information: https://blog.github.com/2018-12-11-introducing-the-new-github-status-site/

---
[![Tests](https://github.com/Jord-JD/php-github-status-api/actions/workflows/tests.yml/badge.svg)](https://github.com/Jord-JD/php-github-status-api/actions/workflows/tests.yml)

This package provides a way to programmatically determine if GitHub is working
well, or experiencing issues.
Both the current status and historical statuses can be looked up by date.
well, or experiencing issues. It uses GitHub's current Statuspage API.

The replacement API does not provide the historical feed used by older package
versions. Passing a past date therefore returns `GitHubStatus::UNKNOWN`.

<p align="center">
<img height="500" src="https://user-images.githubusercontent.com/650645/49678157-77f06f00-fa7a-11e8-857c-0586751a3540.png" />
Expand Down
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
],
"license": "LGPL-3.0-only",
"require": {
"ivopetkov/html5-dom-document-php": "^1.1",
"nesbot/carbon": "^2.7",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.6"
"phpunit/phpunit": "^7.5 || ^9.6"
},
"autoload": {
"psr-4": {
Expand Down
67 changes: 28 additions & 39 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,49 @@

use Carbon\Carbon;
use JordJD\GitHubStatusApi\Enums\GitHubStatus;
use IvoPetkov\HTML5DOMDocument;

class Client
{
const GITHUB_STATUS_URL = 'https://status.github.com/messages';
const GITHUB_STATUS_URL = 'https://www.githubstatus.com/api/v2/status.json';

const CLASS_TO_STATUS_MAP = [
'good' => GitHubStatus::GOOD,
'major' => GitHubStatus::MAJOR,
const INDICATOR_TO_STATUS_MAP = [
'none' => GitHubStatus::GOOD,
'minor' => GitHubStatus::MINOR,
'major' => GitHubStatus::MAJOR,
'critical' => GitHubStatus::MAJOR,
];

private $statusFetcher;

public function __construct(callable $statusFetcher = null)
{
$this->statusFetcher = $statusFetcher;
}

public function status(Carbon $datetime = null)
{
if ($datetime === null) {
$datetime = Carbon::now();
if ($datetime !== null && !$datetime->isToday()) {
return GitHubStatus::UNKNOWN;
}

$dom = $this->getDomDocument($datetime);

$timeElements = $dom->querySelectorAll('time');

/** @var HTML5DOMDocument $timeElement*/
foreach($timeElements as $timeElement) {

$timeElementDatetime = Carbon::parse($timeElement->getAttribute('datetime'));
$response = $this->statusFetcher
? call_user_func($this->statusFetcher)
: @file_get_contents(self::GITHUB_STATUS_URL);

if ($datetime >= $timeElementDatetime) {

$class = $timeElement->parentNode->attributes->getNamedItem('class')->textContent;
$classParts = explode(' ', $class);

foreach($classParts as $classPart) {

if (array_key_exists($classPart, self::CLASS_TO_STATUS_MAP)) {
return self::CLASS_TO_STATUS_MAP[$classPart];
}

}
if (!is_string($response)) {
return GitHubStatus::UNKNOWN;
}

return GitHubStatus::UNKNOWN;
}
$statusResponse = json_decode($response, true);

if (!is_array($statusResponse) || empty($statusResponse['status']['indicator'])) {
return GitHubStatus::UNKNOWN;
}
}

private function getDomDocument(Carbon $datetime)
{
$url = self::GITHUB_STATUS_URL.'/'.$datetime->format('Y-m-d');
$html = file_get_contents($url);

$dom = new HTML5DOMDocument();
$dom->loadHTML($html);
$indicator = $statusResponse['status']['indicator'];

return $dom;
return array_key_exists($indicator, self::INDICATOR_TO_STATUS_MAP)
? self::INDICATOR_TO_STATUS_MAP[$indicator]
: GitHubStatus::UNKNOWN;
}
}
}
49 changes: 27 additions & 22 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,50 @@

namespace JordJD\GitHubStatusApi;

use JordJD\GitHubStatusApi\Client;
use Carbon\Carbon;
use JordJD\GitHubStatusApi\Enums\GitHubStatus;
use PHPUnit\Framework\TestCase;

class ClientTest extends TestCase
{
public function testStatusShouldReturnGood()
/**
* @dataProvider statusIndicatorProvider
*/
public function testStatusIndicatorsAreMapped($indicator, $expectedStatus)
{
$mockedClient = $this->createMock(Client::class);
$mockedClient->method('status')
->willReturn(GitHubStatus::GOOD);
$client = new Client(function () use ($indicator) {
return json_encode(['status' => ['indicator' => $indicator]]);
});

$this->assertSame(GitHubStatus::GOOD, $mockedClient->status());
$this->assertSame($expectedStatus, $client->status());
}

public function testStatusShouldReturnMinor()
public function statusIndicatorProvider()
{
$mockedClient = $this->createMock(Client::class);
$mockedClient->method('status')
->willReturn(GitHubStatus::MINOR);

$this->assertSame(GitHubStatus::MINOR, $mockedClient->status());
return [
['none', GitHubStatus::GOOD],
['minor', GitHubStatus::MINOR],
['major', GitHubStatus::MAJOR],
['critical', GitHubStatus::MAJOR],
['unrecognised', GitHubStatus::UNKNOWN],
];
}

public function testStatusShouldReturnMajor()
public function testInvalidResponsesReturnUnknown()
{
$mockedClient = $this->createMock(Client::class);
$mockedClient->method('status')
->willReturn(GitHubStatus::MAJOR);
$client = new Client(function () {
return 'not-json';
});

$this->assertSame(GitHubStatus::MAJOR, $mockedClient->status());
$this->assertSame(GitHubStatus::UNKNOWN, $client->status());
}

public function testStatusShouldReturnUnknown()
public function testHistoricalDatesReturnUnknown()
{
$mockedClient = $this->createMock(Client::class);
$mockedClient->method('status')
->willReturn(GitHubStatus::UNKNOWN);
$client = new Client(function () {
return json_encode(['status' => ['indicator' => 'none']]);
});

$this->assertSame(GitHubStatus::UNKNOWN, $mockedClient->status());
$this->assertSame(GitHubStatus::UNKNOWN, $client->status(Carbon::parse('2018-12-06 17:00')));
}
}
Loading