diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/bin/github-sync-website-shared b/bin/github-sync-website-shared new file mode 100644 index 0000000..0456cc3 --- /dev/null +++ b/bin/github-sync-website-shared @@ -0,0 +1,93 @@ +#!/usr/bin/env php +setOption(Client::OP_DEFAULT_HEADERS, [ + "user-agent" => "amphp/website-tools", + ]); + + $github = new GitHub($httpClient, "http://127.0.0.1:1337/oauth", $clientId, $clientSecret, ["repo"]); + $oauthToken = yield authenticate($github); + + $githubClient = new GitHubClient($oauthToken, $httpClient); + + $reference = yield $githubClient->getHead("amphp/website-shared", "master"); + + yield $stdout->write("amphp/website-shared is at {$reference}\r\n"); + yield $stdout->write("Do you want to update all repositories to that reference? [y/N]: "); + $answer = yield $stdin->read(); + + if (trim($answer) !== "y") { + exit(0); + } + + $repositories = $githubClient->getRepositories("amphp"); + + while (yield $repositories->advance()) { + $repository = $repositories->getCurrent(); + $repository = $repository["full_name"]; + + $currentVersion = yield $githubClient->getSubmoduleVersion($repository, "docs/.shared"); + + if ($currentVersion !== null && $currentVersion !== $reference) { + $stdout->write("{$repository} is not up-to-date, should I update it? [Y/n]: "); + + $answer = trim(yield $stdin->read()); + + if ($answer !== "y" && $answer !== "") { + exit(0); + } + + $master = yield $githubClient->getHead($repository, "master"); + $baseTree = yield $githubClient->getCommitTree($repository, $master); + $baseTree = yield $githubClient->getTree($repository, $baseTree); + + foreach ($baseTree["tree"] as $baseTreeKey => $baseTreeChild) { + if ($baseTreeChild["path"] === "docs") { + $docsTree = yield $githubClient->getTree($repository, $baseTreeChild["sha"]); + + foreach ($docsTree["tree"] as $docsTreeKey => $docsTreeChild) { + if ($docsTreeChild["path"] === ".shared") { + $docsTree["tree"][$docsTreeKey]["sha"] = $reference; + } + } + + $docsTree = yield $githubClient->createTree($repository, $docsTree["sha"], $docsTree["tree"]); + $baseTree["tree"][$baseTreeKey]["sha"] = $docsTree["sha"]; + } + } + + $newTree = yield $githubClient->createTree($repository, $baseTree["sha"], $baseTree["tree"]); + + $commitMessage = <<createCommit($repository, $commitMessage, $newTree["sha"], [$master]); + yield $stdout->write("Created {$commit["sha"]} in {$repository}.\r\n"); + + $ref = yield $githubClient->updateHead($repository, "master", $commit["sha"]); + yield $stdout->write("Updated {$ref["ref"]} in {$repository} to {$commit["sha"]}.\r\n"); + } + } +}); diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..71550bf --- /dev/null +++ b/composer.json @@ -0,0 +1,23 @@ +{ + "name": "amphp/website-tools", + "description": "Website tools for amphp.org.", + "type": "project", + "require": { + "amphp/amp": "^2.0", + "amphp/artax": "^3.0", + "kelunik/oauth-cli": "^1.0", + "kelunik/link-header-rfc5988": "^1.0" + }, + "license": "MIT", + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "autoload": { + "psr-4": { + "Amp\\WebsiteTools\\": "src" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..85286b6 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1193 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "f730462ec95a27e19cb87dbd0d1df20a", + "packages": [ + { + "name": "amphp/aerys", + "version": "v0.6.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/aerys.git", + "reference": "cbf91d62aacb38683aac3cfcb1d72f7955e632e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/aerys/zipball/cbf91d62aacb38683aac3cfcb1d72f7955e632e2", + "reference": "cbf91d62aacb38683aac3cfcb1d72f7955e632e2", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1", + "amphp/file": "^0.2", + "amphp/socket": "^0.10", + "league/climate": "^3", + "nikic/fast-route": "^1", + "php": ">=7", + "psr/log": "^1" + }, + "require-dev": { + "amphp/artax": "^3", + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3@dev", + "http2jp/hpack-test-case": "^1", + "phpunit/phpunit": "^6" + }, + "bin": [ + "bin/aerys" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.6.0-dev" + } + }, + "autoload": { + "psr-4": { + "Aerys\\": "lib/" + }, + "files": [ + "lib/functions.php", + "lib/constants.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net", + "role": "Creator / Lead Developer" + }, + { + "name": "Bob Weinand", + "role": "Developer / API Coordinator" + }, + { + "name": "Niklas Keller", + "role": "Quality Assurance / Developer" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "A non-blocking HTTP/Websocket server", + "homepage": "https://github.com/amphp/aerys", + "keywords": [ + "aerys", + "amp", + "amphp", + "async", + "http", + "non-blocking", + "server", + "websocket" + ], + "time": "2017-08-18T08:43:22+00:00" + }, + { + "name": "amphp/amp", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "916cf3119d96ba6d3b5a8c9d9bdd258960400141" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/916cf3119d96ba6d3b5a8c9d9bdd258960400141", + "reference": "916cf3119d96ba6d3b5a8c9d9bdd258960400141", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6.0.9", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "http://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "time": "2017-07-09T12:20:40+00:00" + }, + { + "name": "amphp/artax", + "version": "v3.0.4", + "source": { + "type": "git", + "url": "https://github.com/amphp/artax.git", + "reference": "48008dcfd6e7376d5631a6c55bdf01ff94878537" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/artax/zipball/48008dcfd6e7376d5631a6c55bdf01ff94878537", + "reference": "48008dcfd6e7376d5631a6c55bdf01ff94878537", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/file": "^0.2", + "amphp/socket": "^0.10", + "amphp/uri": "^0.1", + "kelunik/certificate": "^1.1", + "php": ">=7.0" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Artax\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + } + ], + "description": "Asynchronous parallel HTTP/1.1 client built on the Amp concurrency framework", + "homepage": "https://github.com/amphp/artax", + "keywords": [ + "async", + "client", + "http", + "non-blocking", + "parallel", + "rest" + ], + "time": "2017-07-14T13:01:08+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "fdcf400f19af26d06d183127d7cce57b24c574cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/fdcf400f19af26d06d183127d7cce57b24c574cf", + "reference": "fdcf400f19af26d06d183127d7cce57b24c574cf", + "shasum": "" + }, + "require": { + "amphp/amp": "^2" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\ByteStream\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "time": "2017-09-15T05:17:42+00:00" + }, + { + "name": "amphp/cache", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/cache.git", + "reference": "d6ab81ce35019b0fd84ca6d665fd4817bfd11701" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/cache/zipball/d6ab81ce35019b0fd84ca6d665fd4817bfd11701", + "reference": "d6ab81ce35019b0fd84ca6d665fd4817bfd11701", + "shasum": "" + }, + "require": { + "amphp/amp": "^2" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Cache\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + } + ], + "description": "A promise-aware caching API for Amp.", + "homepage": "https://github.com/amphp/cache", + "time": "2017-06-24T09:51:10+00:00" + }, + { + "name": "amphp/dns", + "version": "v0.9.8", + "source": { + "type": "git", + "url": "https://github.com/amphp/dns.git", + "reference": "1a41089d84675bbeed3b5c655ffccd3318a21f37" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/dns/zipball/1a41089d84675bbeed3b5c655ffccd3318a21f37", + "reference": "1a41089d84675bbeed3b5c655ffccd3318a21f37", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.1", + "amphp/cache": "^1", + "amphp/file": "^0.2", + "amphp/parser": "^1", + "amphp/uri": "^0.1", + "amphp/windows-registry": "^0.3", + "daverandom/libdns": "^1", + "php": ">=7.0" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Dns\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Chris Wright", + "email": "addr@daverandom.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Async DNS resolution for Amp.", + "homepage": "https://github.com/amphp/dns", + "keywords": [ + "amp", + "amphp", + "async", + "client", + "dns", + "resolve" + ], + "time": "2017-09-12T15:08:38+00:00" + }, + { + "name": "amphp/file", + "version": "v0.2.4", + "source": { + "type": "git", + "url": "https://github.com/amphp/file.git", + "reference": "577bcc1f92252a795f9871e183b0caef975c9635" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/file/zipball/577bcc1f92252a795f9871e183b0caef975c9635", + "reference": "577bcc1f92252a795f9871e183b0caef975c9635", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1", + "amphp/parallel": "^0.1.8" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\File\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Allows non-blocking access to the filesystem for Amp.", + "homepage": "https://github.com/amphp/file", + "keywords": [ + "amp", + "amphp", + "async", + "disk", + "file", + "filesystem", + "io", + "non-blocking", + "static" + ], + "time": "2017-07-21T06:32:23+00:00" + }, + { + "name": "amphp/parallel", + "version": "v0.1.8", + "source": { + "type": "git", + "url": "https://github.com/amphp/parallel.git", + "reference": "25b9a2a75c4a6ba4815775267822066abab1054a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parallel/zipball/25b9a2a75c4a6ba4815775267822066abab1054a", + "reference": "25b9a2a75c4a6ba4815775267822066abab1054a", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.1", + "amphp/parser": "^1", + "amphp/process": "^0.2" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "suggest": { + "ext-pcntl": "Required for fork contexts", + "ext-pthreads": "Required for thread contexts", + "ext-sysvsem": "Required for fork synchronization", + "ext-sysvshm": "Required for fork contexts" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\Parallel\\": "lib" + }, + "files": [ + "lib/Worker/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stephen Coakley", + "email": "me@stephencoakley.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Parallel processing component for Amp.", + "homepage": "https://github.com/amphp/parallel", + "keywords": [ + "async", + "asynchronous", + "concurrent", + "multi-processing", + "multi-threading" + ], + "time": "2017-07-18T03:59:56+00:00" + }, + { + "name": "amphp/parser", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/parser.git", + "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/parser/zipball/f83e68f03d5b8e8e0365b8792985a7f341c57ae1", + "reference": "f83e68f03d5b8e8e0365b8792985a7f341c57ae1", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Parser\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "A generator parser to make streaming parsers simple.", + "homepage": "https://github.com/amphp/parser", + "keywords": [ + "async", + "non-blocking", + "parser", + "stream" + ], + "time": "2017-06-06T05:29:10+00:00" + }, + { + "name": "amphp/process", + "version": "v0.2.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/process.git", + "reference": "5aa6040fcf5c98bfb4f4a8e68305cb6cd6a3d37a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/process/zipball/5aa6040fcf5c98bfb4f4a8e68305cb6cd6a3d37a", + "reference": "5aa6040fcf5c98bfb4f4a8e68305cb6cd6a3d37a", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "kelunik/fqn-check": "^0.1.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Process\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Asynchronous process manager", + "homepage": "https://github.com/amphp/process", + "time": "2017-07-18T03:37:19+00:00" + }, + { + "name": "amphp/socket", + "version": "v0.10.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/socket.git", + "reference": "e58766bf0caa59bfa6ba56be260438af109eaea1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/socket/zipball/e58766bf0caa59bfa6ba56be260438af109eaea1", + "reference": "e58766bf0caa59bfa6ba56be260438af109eaea1", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/byte-stream": "^1.1", + "amphp/dns": "^0.9", + "amphp/uri": "^0.1", + "php": ">=7.0" + }, + "require-dev": { + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Socket\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey", + "email": "rdlowrey@gmail.com" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + } + ], + "description": "Async socket connection / server tools for Amp.", + "homepage": "https://github.com/amphp/socket", + "keywords": [ + "amp", + "async", + "encryption", + "non-blocking", + "sockets", + "tcp", + "tls" + ], + "time": "2017-07-03T10:48:49+00:00" + }, + { + "name": "amphp/uri", + "version": "v0.1.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/uri.git", + "reference": "2de94666447319d8695f2d11f3f005d5fee0876a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/uri/zipball/2de94666447319d8695f2d11f3f005d5fee0876a", + "reference": "2de94666447319d8695f2d11f3f005d5fee0876a", + "shasum": "" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\Uri\\": "src" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + }, + { + "name": "Daniel Lowrey" + } + ], + "description": "Uri Parser and Resolver.", + "homepage": "https://github.com/amphp/uri", + "time": "2017-09-10T09:39:50+00:00" + }, + { + "name": "amphp/windows-registry", + "version": "v0.3.0", + "source": { + "type": "git", + "url": "https://github.com/amphp/windows-registry.git", + "reference": "9a5957ee3694c6d78440acd5a1c7adbd2d749de7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/windows-registry/zipball/9a5957ee3694c6d78440acd5a1c7adbd2d749de7", + "reference": "9a5957ee3694c6d78440acd5a1c7adbd2d749de7", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "amphp/process": "^0.2" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\WindowsRegistry\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Windows Registry Reader.", + "time": "2017-06-16T08:55:58+00:00" + }, + { + "name": "daverandom/libdns", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/DaveRandom/LibDNS.git", + "reference": "67de5497e84d179dffc089c5eb6a1945eb4e9460" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DaveRandom/LibDNS/zipball/67de5497e84d179dffc089c5eb6a1945eb4e9460", + "reference": "67de5497e84d179dffc089c5eb6a1945eb4e9460", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "LibDNS\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "DNS protocol implementation written in pure PHP", + "keywords": [ + "dns" + ], + "time": "2016-04-29T20:47:45+00:00" + }, + { + "name": "kelunik/certificate", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/kelunik/certificate.git", + "reference": "524fa432ed1b5f50efbe7749f3c19e28a9866bc7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/certificate/zipball/524fa432ed1b5f50efbe7749f3c19e28a9866bc7", + "reference": "524fa432ed1b5f50efbe7749f3c19e28a9866bc7", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "php": "^5.4 | ^7.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "^1.9", + "phpunit/phpunit": "^4.8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kelunik\\Certificate\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Access certificate details and transform between different formats.", + "keywords": [ + "DER", + "certificate", + "certificates", + "openssl", + "pem", + "x509" + ], + "time": "2017-07-04T19:37:30+00:00" + }, + { + "name": "kelunik/link-header-rfc5988", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/kelunik/link-header-rfc5988.git", + "reference": "027a34c61060eb349c1b9c875186cc68812fd14a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/link-header-rfc5988/zipball/027a34c61060eb349c1b9c875186cc68812fd14a", + "reference": "027a34c61060eb349c1b9c875186cc68812fd14a", + "shasum": "" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kelunik\\LinkHeaderRfc5988\\": "src" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "RFC 5988 compatible link header parser.", + "time": "2017-09-16T16:48:40+00:00" + }, + { + "name": "kelunik/oauth", + "version": "v0.1.2", + "source": { + "type": "git", + "url": "https://github.com/kelunik/oauth.git", + "reference": "4fcdf905b96aff35ac89bc9a6b1d240e7c7a37d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/oauth/zipball/4fcdf905b96aff35ac89bc9a6b1d240e7c7a37d5", + "reference": "4fcdf905b96aff35ac89bc9a6b1d240e7c7a37d5", + "shasum": "" + }, + "require": { + "amphp/artax": "^3" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kelunik\\OAuth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "time": "2017-09-16T08:58:04+00:00" + }, + { + "name": "kelunik/oauth-cli", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/kelunik/oauth-cli.git", + "reference": "40f091562b9079a88ed33e042498859f7ca6415a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kelunik/oauth-cli/zipball/40f091562b9079a88ed33e042498859f7ca6415a", + "reference": "40f091562b9079a88ed33e042498859f7ca6415a", + "shasum": "" + }, + "require": { + "amphp/aerys": "^0.6.0", + "amphp/amp": "^2.0", + "amphp/artax": "^3.0", + "kelunik/oauth": "^0.1.1" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "Allows using OAuth as login method on CLI.", + "time": "2017-09-15T07:38:26+00:00" + }, + { + "name": "league/climate", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/climate.git", + "reference": "b103fc8faa3780c802cc507d5f0ff534ecc94fb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/climate/zipball/b103fc8faa3780c802cc507d5f0ff534ecc94fb5", + "reference": "b103fc8faa3780c802cc507d5f0ff534ecc94fb5", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "seld/cli-prompt": "~1.0" + }, + "require-dev": { + "mikey179/vfsstream": "~1.4", + "mockery/mockery": "~0.9", + "phpunit/phpunit": "~4.6" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\CLImate\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joe Tannenbaum", + "email": "hey@joe.codes", + "homepage": "http://joe.codes/", + "role": "Developer" + } + ], + "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.", + "keywords": [ + "cli", + "colors", + "command", + "php", + "terminal" + ], + "time": "2016-04-04T20:24:59+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "b5f95749071c82a8e0f58586987627054400cdf6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/b5f95749071c82a8e0f58586987627054400cdf6", + "reference": "b5f95749071c82a8e0f58586987627054400cdf6", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "FastRoute\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "time": "2017-01-19T11:35:12+00:00" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + }, + { + "name": "seld/cli-prompt", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/cli-prompt.git", + "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/cli-prompt/zipball/a19a7376a4689d4d94cab66ab4f3c816019ba8dd", + "reference": "a19a7376a4689d4d94cab66ab4f3c816019ba8dd", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\CliPrompt\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Allows you to prompt for user input on the command line, and optionally hide the characters they type", + "keywords": [ + "cli", + "console", + "hidden", + "input", + "prompt" + ], + "time": "2017-03-18T11:32:45+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/src/GitHubClient.php b/src/GitHubClient.php new file mode 100644 index 0000000..84f1919 --- /dev/null +++ b/src/GitHubClient.php @@ -0,0 +1,182 @@ +accessToken = $accessToken; + $this->client = $client ?? new DefaultClient; + } + + public function get(string $uri): Promise { + return call(function () use ($uri) { + /** @var Response $response */ + $response = yield $this->client->request( + (new Request($uri))->withHeader("authorization", "token {$this->accessToken}") + ); + + $json = \json_decode(yield $response->getBody(), true); + + if ($response->getStatus() !== 200) { + throw new \Exception("Request failed ($uri): " . $json["message"] . " (" . $json["documentation_url"] . ")"); + } + + return $json; + }); + } + + public function post(string $uri, array $json): Promise { + return call(function () use ($uri, $json) { + $body = json_encode($json); + + /** @var Response $response */ + $response = yield $this->client->request( + (new Request($uri, "POST"))->withHeader("authorization", "token {$this->accessToken}") + ->withBody($body) + ); + + $json = \json_decode(yield $response->getBody(), true); + + if ((int) ($response->getStatus() / 100) !== 2) { + throw new \Exception("Request failed (" . $response->getStatus() . "): " . yield $response->getBody()); + } + + return $json; + }); + } + + public function patch(string $uri, array $json): Promise { + return call(function () use ($uri, $json) { + $body = json_encode($json); + + /** @var Response $response */ + $response = yield $this->client->request( + (new Request($uri, "PATCH"))->withHeader("authorization", "token {$this->accessToken}") + ->withBody($body) + ); + + $json = \json_decode(yield $response->getBody(), true); + + if ((int) ($response->getStatus() / 100) !== 2) { + throw new \Exception("Request failed (" . $response->getStatus() . "): " . yield $response->getBody()); + } + + return $json; + }); + } + + public function getHead(string $repository, string $branch): Promise { + return call(function () use ($repository, $branch) { + $json = yield $this->get("https://api.github.com/repos/{$repository}/git/refs/heads/{$branch}"); + + return $json["object"]["sha"]; + }); + } + + public function getSubmoduleVersion(string $repository, string $path): Promise { + return call(function () use ($repository, $path) { + try { + $json = yield $this->get("https://api.github.com/repos/{$repository}/contents/{$path}"); + + return $json["sha"]; + } catch (\Exception $e) { + return null; + } + }); + } + + public function getCommitTree($repository, $sha) { + return call(function () use ($repository, $sha) { + $json = yield $this->get("https://api.github.com/repos/{$repository}/git/commits/{$sha}"); + + return $json["tree"]["sha"]; + }); + } + + public function getTree($repository, $baseTree) { + return call(function () use ($repository, $baseTree) { + $json = yield $this->get("https://api.github.com/repos/{$repository}/git/trees/{$baseTree}"); + + if ($json["truncated"] === true) { + throw new \Exception("Got a truncated tree: {$json["sha"]}"); + } + + return $json; + }); + } + + public function createTree($repository, $baseTree, $tree) { + return call(function () use ($repository, $baseTree, $tree) { + $json = yield $this->post("https://api.github.com/repos/{$repository}/git/trees", [ + "base_tree" => $baseTree, + "tree" => $tree, + ]); + + return $json; + }); + } + + public function createCommit(string $repository, string $message, string $tree, array $parents) { + return call(function () use ($repository, $message, $tree, $parents) { + $json = yield $this->post("https://api.github.com/repos/{$repository}/git/commits", [ + "message" => $message, + "tree" => $tree, + "parents" => $parents, + ]); + + return $json; + }); + } + + public function updateHead($repository, $branch, $sha) { + return call(function () use ($repository, $branch, $sha) { + $json = yield $this->patch("https://api.github.com/repos/{$repository}/git/refs/heads/{$branch}", [ + "sha" => $sha, + "force" => false, + ]); + + return $json; + }); + } + + public function getRepositories(string $organization): Iterator { + return new Producer(function ($emit) use ($organization) { + $uri = "https://api.github.com/orgs/{$organization}/repos"; + + do { + /** @var Response $response */ + $response = yield $this->client->request( + (new Request($uri))->withHeader("authorization", "token {$this->accessToken}") + ); + + $json = \json_decode(yield $response->getBody(), true); + + if ($response->getStatus() !== 200) { + throw new \Exception("Request failed ($uri): " . $json["message"] . " (" . $json["documentation_url"] . ")"); + } + + foreach ($json as $repository) { + yield $emit($repository); + } + + $linkHeader = $response->getHeader("link"); + $links = parseLinks($linkHeader ?? ""); + + $uri = ($link = $links->getByRel("next")) ? $link->getUri() : null; + } while ($uri); + }); + } +} \ No newline at end of file