diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..196277e --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,32 @@ +name: tests + +on: + push: + branches: + - main + pull_request: + +jobs: + phpunit: + name: PHPUnit (PHP ${{ matrix.php }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['8.2', '8.3', '8.4'] + steps: + - uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: pdo, pdo_sqlite, sqlite3, curl, simplexml + coverage: none + tools: composer:v2 + + - name: Install dependencies + run: composer install --no-interaction --no-progress --prefer-dist + + - name: Run PHPUnit + run: vendor/bin/phpunit diff --git a/.gitignore b/.gitignore index afc0e2b..740022d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,11 @@ /.php-cs-fixer.cache /composer.lock +/composer.phar /vendor/ +/.phpunit.cache/ +/tests/tmp/ + /yarn.lock /node_modules/ diff --git a/action.php b/action.php index a25990d..ee0786f 100644 --- a/action.php +++ b/action.php @@ -1,98 +1,276 @@ ' !== $query[0] && 0 !== strpos($query, 'e >')) { - if ('.git' == substr($query, -4)) { - $query = 'x-github-client://openRepo/'.substr($query, 0, -4); - } - exec('open '.$query); + public static function dispatch(array $parts, bool $enterprise): string + { + switch ($parts[1]) { + case 'enterprise-url': + Workflow::setConfig('enterprise_url', rtrim($parts[2], '/')); + exec('osascript -e "tell application \"Alfred\" to search \"ghe \""'); - return; -} + return ''; -$enterprise = 0 === strpos($query, 'e '); -if ($enterprise) { - $query = substr($query, 2); -} -$parts = explode(' ', $query); - -Workflow::init($enterprise); - -switch ($parts[1]) { - case 'enterprise-url': - Workflow::setConfig('enterprise_url', rtrim($parts[2], '/')); - exec('osascript -e "tell application \"Alfred\" to search \"ghe \""'); - break; - - case 'enterprise-reset': - Workflow::removeConfig('enterprise_url'); - Workflow::removeConfig('enterprise_access_token'); - Workflow::deleteCache(); - break; - - case 'login': - if (isset($parts[2]) && $parts[2]) { - Workflow::setAccessToken($parts[2]); - echo 'Successfully logged in'; - } elseif (!$enterprise) { - Workflow::startServer(); - $state = version_compare(PHP_VERSION, '5.4', '<') ? 'm' : ''; - $url = Workflow::getBaseUrl().'/login/oauth/authorize?client_id=2d4f43826cb68e11c17c&scope=repo&state='.$state; - exec('open '.escapeshellarg($url)); + case 'enterprise-reset': + Workflow::removeConfig('enterprise_url'); + Workflow::removeConfig('enterprise_access_token'); + Workflow::deleteCache(); + + return ''; + + case 'login': + if (isset($parts[2]) && $parts[2]) { + Workflow::setAccessToken($parts[2]); + + return 'Successfully logged in'; + } + if (!$enterprise) { + Workflow::startServer(); + $state = version_compare(PHP_VERSION, '5.4', '<') ? 'm' : ''; + $url = Workflow::getBaseUrl().'/login/oauth/authorize?client_id=2d4f43826cb68e11c17c&scope=repo&state='.$state; + exec('open '.escapeshellarg($url)); + } + + return ''; + + case 'logout': + Workflow::removeAccessToken(); + Workflow::deleteCache(); + + return 'Successfully logged out'; + + case 'delete-cache': + Workflow::deleteCache(); + + return 'Successfully deleted cache'; + + case 'delete-database': + Workflow::deleteDatabase(); + + return 'Successfully deleted database'; + + case 'refresh-cache': + $curl = new Curl(); + foreach (explode(',', $parts[2]) as $url) { + Workflow::requestCache($url, $curl, null, false, 0, false); + } + $curl->execute(); + Workflow::cleanCache(); + + return ''; + + case 'activate-autoupdate': + Workflow::setConfig('autoupdate', 1); + + return 'Activated auto updating'; + + case 'deactivate-autoupdate': + Workflow::setConfig('autoupdate', 0); + + return 'Deactivated auto updating'; + + case 'update': + $release = json_decode(Workflow::request('https://api.github.com/repos/gharlan/alfred-github-workflow/releases/latest')); + if (!isset($release->assets[0]->browser_download_url)) { + return 'Update failed'; + } + $response = Workflow::request($release->assets[0]->browser_download_url, null, null, false); + if (!$response) { + return 'Update failed'; + } + $path = getenv('alfred_workflow_data').'/github.alfredworkflow'; + file_put_contents($path, $response); + exec('open '.escapeshellarg($path)); + + return ''; + + case 'user': + return self::dispatchUser($parts, $enterprise); } - break; - - case 'logout': - Workflow::removeAccessToken(); - Workflow::deleteCache(); - echo 'Successfully logged out'; - break; - - case 'delete-cache': - Workflow::deleteCache(); - echo 'Successfully deleted cache'; - break; - - case 'delete-database': - Workflow::deleteDatabase(); - echo 'Successfully deleted database'; - break; - - case 'refresh-cache': - $curl = new Curl(); - foreach (explode(',', $parts[2]) as $url) { - Workflow::requestCache($url, $curl, null, false, 0, false); + + return ''; + } + + private static function confirmDialog(string $title, string $message): bool + { + if (self::$skipDialogs) { + return true; } - $curl->execute(); - Workflow::cleanCache(); - break; - - case 'activate-autoupdate': - Workflow::setConfig('autoupdate', 1); - echo 'Activated auto updating'; - break; - - case 'deactivate-autoupdate': - Workflow::setConfig('autoupdate', 0); - echo 'Deactivated auto updating'; - break; - - case 'update': - $release = json_decode(Workflow::request('https://api.github.com/repos/gharlan/alfred-github-workflow/releases/latest')); - if (!isset($release->assets[0]->browser_download_url)) { - echo 'Update failed'; - exit; + $safeTitle = str_replace('"', '\\"', $title); + $safeMessage = str_replace('"', '\\"', $message); + $script = 'display dialog "'.$safeMessage.'" buttons {"Cancel", "Delete"} default button "Cancel" cancel button "Cancel" with title "'.$safeTitle.'"'; + exec('osascript -e '.escapeshellarg($script).' 2>&1', $output, $exitCode); + + return 0 === $exitCode; + } + + private static function showSimpleAlert(string $title, string $message): void + { + $safeTitle = str_replace('"', '\\"', $title); + $safeMessage = str_replace('"', '\\"', $message); + $script = 'display dialog "'.$safeMessage.'" buttons {"OK"} default button "OK" with title "'.$safeTitle.'"'; + exec('osascript -e '.escapeshellarg($script).' > /dev/null 2>&1 &'); + } + + private static function showAlert(string $title, string $message): void + { + $safeTitle = str_replace('"', '\\"', $title); + $safeMessage = str_replace('"', '\\"', $message); + $script = 'set r to display dialog "'.$safeMessage.'" buttons {"OK", "Open GitHub"} default button "Open GitHub" with title "'.$safeTitle.'"'."\n". + 'if button returned of r is "Open GitHub" then'."\n". + ' open location "https://github.com"'."\n". + 'end if'; + exec('osascript -e '.escapeshellarg($script).' > /dev/null 2>&1 &'); + } + + private static function dispatchUser(array $parts, bool $enterprise): string + { + $action = $parts[2] ?? ''; + $label = $parts[3] ?? ''; + + switch ($action) { + case 'add': + if ($enterprise) { + return 'Multi-account is only supported for github.com.'; + } + if ('' === $label) { + return 'Usage: gh user add