From f9668e34d533472c3b35d39f85b17b5208c49105 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Tue, 14 Feb 2023 15:18:00 +0530 Subject: [PATCH 001/147] Initial commit --- README.md | 6 +++- src/VCS/Adapter.php | 7 ++++ src/VCS/Adapter/Git.php | 9 +++++ src/VCS/Adapter/Git/GitHub.php | 64 ++++++++++++++++++++++++++++++++++ tests/VCS/GitHubTest.php | 0 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/VCS/Adapter.php create mode 100644 src/VCS/Adapter/Git.php create mode 100644 src/VCS/Adapter/Git/GitHub.php create mode 100644 tests/VCS/GitHubTest.php diff --git a/README.md b/README.md index 5356415f..476c2ec9 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -# vcs +# Utopia VCS + +Utopia VCS is a simple and lite library to integrate version control systems like GitHub, GitLab etc. to receive webhook events like push, new pull request etc. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io). + +Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project, it is dependency free and can be used as standalone with any other PHP project or framework. \ No newline at end of file diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php new file mode 100644 index 00000000..3d2a23ce --- /dev/null +++ b/src/VCS/Adapter.php @@ -0,0 +1,7 @@ +accessToken = $accessToken; + } + + /** + * Get access token + * + * @return string + */ + public function getAccessToken(): string + { + return $this->accessToken; + } +} \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php new file mode 100644 index 00000000..e69de29b From 78a565de675ffe5eae68456f501ef21a5cef06cc Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 14 Feb 2023 16:33:44 +0530 Subject: [PATCH 002/147] Add list repositories and get repository methods --- src/VCS/Adapter/Git/GitHub.php | 86 ++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 893e34b6..595c1fa5 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -2,10 +2,15 @@ namespace Utopia\VCS\Adapter\Git; +use Exception; use Utopia\VCS\Adapter\Git; class GitHub extends Git { + /** + * @var HttpClient + */ + protected $httpClient; /** * @var string @@ -61,4 +66,85 @@ public function getAccessToken(): string { return $this->accessToken; } + + /** + * Get HTTP client + * + * @return HttpClient + */ + public function getHttpClient(): HttpClient + { + return $this->httpClient; + } + + /** + * Set HTTP client + * + * @param HttpClient $httpClient + */ + public function setHttpClient(HttpClient $httpClient) + { + $this->httpClient = $httpClient; + } + + /** + * Send a request to the GitHub API + * + * @param string $method + * @param string $url + * @param array $headers + * @param array|null $body + * @return HttpClientResponse + * @throws Exception + */ + public function request(string $method, string $url, array $headers = [], ?array $body = null): HttpClientResponse + { + if (!$this->accessToken) { + throw new Exception('Access token not set'); + } + + $headers['Authorization'] = 'token ' . $this->accessToken; + + try { + $request = new HttpClientRequest($method, $url, $headers, $body); + $response = $this->httpClient->send($request); + } catch (Exception $e) { + throw new Exception($e->getMessage(), $e->getCode(), $e); + } + + if ($response->getStatusCode() >= 400) { + throw new Exception($response->getBody(), $response->getStatusCode()); + } + + return $response; + } + + + /** + * List repositories + * + * @return array + * @throws Exception + */ + public function listRepositories(): array + { + $response = $this->request('GET', 'https://api.github.com/user/repos'); + + return json_decode($response->getBody(), true); + } + + /** + * Get repository + * + * @param string $owner + * @param string $repo + * @return array + * @throws Exception + */ + public function getRepository(string $owner, string $repo): array + { + $response = $this->request('GET', 'https://api.github.com/repos/' . urlencode($owner) . '/' . urlencode($repo)); + + return json_decode($response->getBody(), true); + } } \ No newline at end of file From 6abc11728b9b2ccb5a69a5064d19326c2875ec18 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 14 Feb 2023 20:48:36 +0530 Subject: [PATCH 003/147] Added call method to Adapter and basic tests --- .gitignore | 3 + composer.json | 26 + composer.lock | 1817 ++++++++++++++++++++++++++++++++ phpunit.xml | 16 + src/VCS/Adapter.php | 168 +++ src/VCS/Adapter/Git/GitHub.php | 71 +- tests/VCS/GitHubTest.php | 28 + 7 files changed, 2072 insertions(+), 57 deletions(-) create mode 100644 .gitignore create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 phpunit.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..921bd61e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/vendor/ +/.idea/ +.phpunit.result.cache \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..3d13a024 --- /dev/null +++ b/composer.json @@ -0,0 +1,26 @@ +{ + "name": "utopia-php/vcs", + "description": "A simple library to integrate version control systems like GitHub, GitLab etc. to receive webhook events", + "type": "library", + "keywords": ["php","framework", "utopia", "vcs"], + "license": "MIT", + "minimum-stability": "stable", + "scripts": { + "lint": "./vendor/bin/pint --test", + "format": "./vendor/bin/pint", + "test": "vendor/bin/phpunit --configuration phpunit.xml" + }, + "autoload": { + "psr-4": {"Utopia\\VCS\\": "src/VCS"} + }, + "autoload-dev": { + "psr-4": {"Utopia\\Tests\\": "tests/VCS"} + }, + "require": { + "php": ">=8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.4", + "laravel/pint": "1.2.*" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000..36aa4d1b --- /dev/null +++ b/composer.lock @@ -0,0 +1,1817 @@ +{ + "_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#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "99fdf954c3c284cf3675a5d78004f8d8", + "packages": [], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2022-12-30T00:23:10+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.2.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/e60e2112ee779ce60f253695b273d1646a17d6f1", + "reference": "e60e2112ee779ce60f253695b273d1646a17d6f1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.11.0", + "illuminate/view": "^9.32.0", + "laravel-zero/framework": "^9.2.0", + "mockery/mockery": "^1.5.1", + "nunomaduro/larastan": "^2.2.0", + "nunomaduro/termwind": "^1.14.0", + "pestphp/pest": "^1.22.1" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2022-11-29T16:25:20+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", + "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2022-03-03T13:19:32+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.15.3", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + }, + "time": "2023-01-16T22:05:37+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "9.2.24", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", + "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.14", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcov": "*", + "ext-xdebug": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-01-26T08:26:55+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "3.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:16:10+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "9.6.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1 || ^2", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "9.6-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-02-04T13:37:15+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" + }, + { + "name": "sebastian/comparator", + "version": "4.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "sebastian/environment", + "version": "5.1.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" + }, + { + "name": "sebastian/exporter", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" + }, + { + "name": "sebastian/global-state", + "version": "5.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-02-14T08:28:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" + }, + { + "name": "sebastian/version", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c6c1022351a901512170118436c764e473f6de8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=8.0" + }, + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..ec39a7ed --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,16 @@ + + + + ./tests/ + + + \ No newline at end of file diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 3d2a23ce..2e98dbed 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -2,6 +2,174 @@ namespace Utopia\VCS; +use Exception; + abstract class Adapter{ + public const METHOD_GET = 'GET'; + public const METHOD_POST = 'POST'; + public const METHOD_PUT = 'PUT'; + public const METHOD_PATCH = 'PATCH'; + public const METHOD_DELETE = 'DELETE'; + public const METHOD_HEAD = 'HEAD'; + public const METHOD_OPTIONS = 'OPTIONS'; + public const METHOD_CONNECT = 'CONNECT'; + public const METHOD_TRACE = 'TRACE'; + + /** + * Is Self Signed Certificates Allowed? + * + * @var bool + */ + protected $selfSigned = true; + + /** + * Service host name + * + * @var string + */ + protected $endpoint; + + /** + * Global Headers + * + * @var array + */ + protected $headers = []; + + /** + * Call + * + * Make an API call + * + * @param string $method + * @param string $path + * @param array $params + * @param array $headers + * @param bool $decode + * @return array|string + * @throws Exception + */ + public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true) + { + $headers = array_merge($this->headers, $headers); + $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); + $responseHeaders = []; + $responseStatus = -1; + $responseType = ''; + $responseBody = ''; + + switch ($headers['content-type']) { + case 'application/json': + $query = json_encode($params); + break; + + case 'multipart/form-data': + $query = $this->flatten($params); + break; + + case 'application/graphql': + $query = $params[0]; + break; + + default: + $query = http_build_query($params); + break; + } + + foreach ($headers as $i => $header) { + $headers[] = $i . ':' . $header; + unset($headers[$i]); + } + + curl_setopt($ch, CURLOPT_PATH_AS_IS, 1); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); + curl_setopt($ch, CURLOPT_TIMEOUT, 15); + curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) { + $len = strlen($header); + $header = explode(':', $header, 2); + + if (count($header) < 2) { // ignore invalid headers + return $len; + } + + $responseHeaders[strtolower(trim($header[0]))] = trim($header[1]); + + return $len; + }); + + if ($method != self::METHOD_GET) { + curl_setopt($ch, CURLOPT_POSTFIELDS, $query); + } + + // Allow self signed certificates + if ($this->selfSigned) { + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + } + + $responseBody = curl_exec($ch); + $responseType = $responseHeaders['content-type'] ?? ''; + $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + if ($decode) { + switch (substr($responseType, 0, strpos($responseType, ';'))) { + case 'application/json': + $json = json_decode($responseBody, true); + + if ($json === null) { + throw new Exception('Failed to parse response: ' . $responseBody); + } + + $responseBody = $json; + $json = null; + break; + } + } + + if ((curl_errno($ch)/* || 200 != $responseStatus*/)) { + throw new Exception(curl_error($ch) . ' with status code ' . $responseStatus, $responseStatus); + } + + curl_close($ch); + + $responseHeaders['status-code'] = $responseStatus; + + if ($responseStatus === 500) { + echo 'Server error(' . $method . ': ' . $path . '. Params: ' . json_encode($params) . '): ' . json_encode($responseBody) . "\n"; + } + + return [ + 'headers' => $responseHeaders, + 'body' => $responseBody + ]; + } + + /** + * Flatten params array to PHP multiple format + * + * @param array $data + * @param string $prefix + * @return array + */ + protected function flatten(array $data, string $prefix = ''): array + { + $output = []; + + foreach ($data as $key => $value) { + $finalKey = $prefix ? "{$prefix}[{$key}]" : $key; + + if (is_array($value)) { + $output += $this->flatten($value, $finalKey); // @todo: handle name collision here if needed + } else { + $output[$finalKey] = $value; + } + } + return $output; + } } \ No newline at end of file diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 595c1fa5..d1fe18ec 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -7,20 +7,15 @@ class GitHub extends Git { - /** - * @var HttpClient - */ - protected $httpClient; - /** * @var string */ - protected $apiUrl = 'https://api.github.com/'; + protected $endpoint = 'https://api.github.com'; /** - * @var array + * @var string */ - protected $user = []; + protected $user; /** * @var string @@ -68,69 +63,31 @@ public function getAccessToken(): string } /** - * Get HTTP client + * Get user * - * @return HttpClient - */ - public function getHttpClient(): HttpClient - { - return $this->httpClient; - } - - /** - * Set HTTP client - * - * @param HttpClient $httpClient - */ - public function setHttpClient(HttpClient $httpClient) - { - $this->httpClient = $httpClient; - } - - /** - * Send a request to the GitHub API - * - * @param string $method - * @param string $url - * @param array $headers - * @param array|null $body - * @return HttpClientResponse + * @param string $owner + * @return array * @throws Exception */ - public function request(string $method, string $url, array $headers = [], ?array $body = null): HttpClientResponse + public function getUser(string $owner): array { - if (!$this->accessToken) { - throw new Exception('Access token not set'); - } - - $headers['Authorization'] = 'token ' . $this->accessToken; - - try { - $request = new HttpClientRequest($method, $url, $headers, $body); - $response = $this->httpClient->send($request); - } catch (Exception $e) { - throw new Exception($e->getMessage(), $e->getCode(), $e); - } - - if ($response->getStatusCode() >= 400) { - throw new Exception($response->getBody(), $response->getStatusCode()); - } + $response = $this->call(self::METHOD_GET, '/users/' . urlencode($owner), ['content-type' => 'application/json']); return $response; } - /** * List repositories * + * @param string $owner * @return array * @throws Exception */ - public function listRepositories(): array + public function listRepositories(string $owner): array { - $response = $this->request('GET', 'https://api.github.com/user/repos'); + $response = $this->call(self::METHOD_GET, '/users/'. urlencode($owner) .'/repos', ['content-type' => 'application/json']); - return json_decode($response->getBody(), true); + return $response; } /** @@ -143,8 +100,8 @@ public function listRepositories(): array */ public function getRepository(string $owner, string $repo): array { - $response = $this->request('GET', 'https://api.github.com/repos/' . urlencode($owner) . '/' . urlencode($repo)); + $response = $this->call(self::METHOD_GET, '/repos/' . urlencode($owner) . '/' . urlencode($repo), ['content-type' => 'application/json']); - return json_decode($response->getBody(), true); + return $response; } } \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index e69de29b..3c1ec34b 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -0,0 +1,28 @@ +getUser("vermakhushboo"); + } + + public function testListRepositories(): void + { + $github = new GitHub(); + $repos = $github->listRepositories("vermakhushboo"); + } + + public function testGetRepository(): void + { + $github = new GitHub(); + $repoDetails = $github->getRepository("vermakhushboo", "TodoApp"); + var_dump($repoDetails); + } +} \ No newline at end of file From 8339ba6b9456b6568c61e84f1eabbbff3bfbd7fc Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 15 Feb 2023 21:57:01 +0530 Subject: [PATCH 004/147] Add APIs to add and update comment --- .gitignore | 3 +- composer.json | 5 +- composer.lock | 575 ++++++++++++++++++++++++++++++++- src/VCS/Adapter/Git/GitHub.php | 110 +++++-- tests/VCS/GitHubTest.php | 35 +- 5 files changed, 683 insertions(+), 45 deletions(-) diff --git a/.gitignore b/.gitignore index 921bd61e..8b8036b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /vendor/ /.idea/ -.phpunit.result.cache \ No newline at end of file +.phpunit.result.cache +.env \ No newline at end of file diff --git a/composer.json b/composer.json index 3d13a024..db9b7b70 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,10 @@ "psr-4": {"Utopia\\Tests\\": "tests/VCS"} }, "require": { - "php": ">=8.0" + "php": ">=8.0", + "adhocore/jwt": "^1.1", + "vlucas/phpdotenv": "^5.5", + "utopia-php/framework": "^0.27.0" }, "require-dev": { "phpunit/phpunit": "^9.4", diff --git a/composer.lock b/composer.lock index 36aa4d1b..612158bc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,579 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "99fdf954c3c284cf3675a5d78004f8d8", - "packages": [], + "content-hash": "c49686b712c6423390df3fde708a1d32", + "packages": [ + { + "name": "adhocore/jwt", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/adhocore/php-jwt.git", + "reference": "6c434af7170090bb7a8880d2bc220a2254ba7899" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/adhocore/php-jwt/zipball/6c434af7170090bb7a8880d2bc220a2254ba7899", + "reference": "6c434af7170090bb7a8880d2bc220a2254ba7899", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.5 || ^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ahc\\Jwt\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jitendra Adhikari", + "email": "jiten.adhikary@gmail.com" + } + ], + "description": "Ultra lightweight JSON web token (JWT) library for PHP5.5+.", + "keywords": [ + "auth", + "json-web-token", + "jwt", + "jwt-auth", + "jwt-php", + "token" + ], + "support": { + "issues": "https://github.com/adhocore/php-jwt/issues", + "source": "https://github.com/adhocore/php-jwt/tree/1.1.2" + }, + "funding": [ + { + "url": "https://paypal.me/ji10", + "type": "custom" + } + ], + "time": "2021-02-20T09:56:44+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "a878d45c1914464426dc94da61c9e1d36ae262a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/a878d45c1914464426dc94da61c9e1d36ae262a8", + "reference": "a878d45c1914464426dc94da61c9e1d36ae262a8", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.28 || ^9.5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2022-07-30T15:56:11+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", + "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8", + "phpunit/phpunit": "^8.5.28 || ^9.5.21" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2022-07-30T15:51:26+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.27.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-03T14:55:06+00:00" + }, + { + "name": "utopia-php/framework", + "version": "0.27.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/framework.git", + "reference": "b8d0447f5c98291d7759db05460ecced29a0f9ee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/b8d0447f5c98291d7759db05460ecced29a0f9ee", + "reference": "b8d0447f5c98291d7759db05460ecced29a0f9ee", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "require-dev": { + "laravel/pint": "^1.2", + "phpunit/phpunit": "^9.5.25", + "vimeo/psalm": "4.27.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple, light and advanced PHP framework", + "keywords": [ + "framework", + "php", + "upf" + ], + "support": { + "issues": "https://github.com/utopia-php/framework/issues", + "source": "https://github.com/utopia-php/framework/tree/0.27.0" + }, + "time": "2023-01-29T05:36:17+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.5.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", + "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.0.2", + "php": "^7.1.3 || ^8.0", + "phpoption/phpoption": "^1.8", + "symfony/polyfill-ctype": "^1.23", + "symfony/polyfill-mbstring": "^1.23.1", + "symfony/polyfill-php80": "^1.23.1" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-filter": "*", + "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + }, + "branch-alias": { + "dev-master": "5.5-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2022-10-16T01:01:54+00:00" + } + ], "packages-dev": [ { "name": "doctrine/instantiator", diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index d1fe18ec..d018ba99 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -3,6 +3,7 @@ namespace Utopia\VCS\Adapter\Git; use Exception; +use Ahc\Jwt\JWT; use Utopia\VCS\Adapter\Git; class GitHub extends Git @@ -22,6 +23,65 @@ class GitHub extends Git */ protected $accessToken; + /** + * @var string + */ + protected $installationId; + + /** + * Global Headers + * + * @var array + */ + protected $headers = ['content-type' => 'application/json']; + + /** + * GitHub constructor. + * + * @param user + * @param string $userName The username of account which has installed GitHub app + * @param string $installationId Installation ID of the GitHub App + */ + public function __construct(string $userName, string $installationId, string $privateKey, string $githubAppId) + { + // Set user name + $this->user = $userName; + + // Set installation id + $this->installationId = $installationId; + + $this->generateAccessToken($privateKey, $githubAppId); + } + + /** + * Generate Access Token + * + * @param string $userName The username of account which has installed GitHub app + * @param string $installationId Installation ID of the GitHub App + */ + protected function generateAccessToken(string $privateKey, string $githubAppId) + { + // fetch env variables from .env file + $privateKeyString = $privateKey; + $privateKey = openssl_pkey_get_private($privateKeyString); + $appIdentifier = $githubAppId; + + $iat = time(); + $exp = $iat + 10 * 60; + $payload = [ + 'iat' => $iat, + 'exp' => $exp, + 'iss' => $appIdentifier, + ]; + + // generate access token + $jwt = new JWT($privateKey, 'RS256'); + $token = $jwt->encode($payload); + $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); + $this->accessToken = $res['body']['token']; + var_dump($this->accessToken); + } + /** * Get Adapter Name * @@ -43,65 +103,51 @@ public function isGitFlow(): bool } /** - * Set access token - * - * @param string $accessToken - */ - public function setAccessToken(string $accessToken) - { - $this->accessToken = $accessToken; - } - - /** - * Get access token + * Get user * - * @return string + * @return array + * @throws Exception */ - public function getAccessToken(): string + public function getUser(): array { - return $this->accessToken; + $response = $this->call(self::METHOD_GET, '/users/' . $this->user); + return $response; } /** - * Get user + * List repositories * - * @param string $owner * @return array * @throws Exception */ - public function getUser(string $owner): array + public function listRepositoriesForGitHubApp(): array { - $response = $this->call(self::METHOD_GET, '/users/' . urlencode($owner), ['content-type' => 'application/json']); + $response = $this->call(self::METHOD_GET, '/installation/repositories', ["Authorization" => "Bearer $this->accessToken"]); - return $response; + return $response['body']['repositories']; } /** - * List repositories + * Add Comment to Pull Request * - * @param string $owner * @return array * @throws Exception */ - public function listRepositories(string $owner): array + public function addComment($repoName, $pullRequestNumber) { - $response = $this->call(self::METHOD_GET, '/users/'. urlencode($owner) .'/repos', ['content-type' => 'application/json']); - - return $response; + $this->call(self::METHOD_POST, '/repos/' . $this->user . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments', ["Authorization" => "Bearer $this->accessToken"], ["body" => "hello from Utopia!"]); + return; } /** - * Get repository + * Update Pull Request Comment * - * @param string $owner - * @param string $repo * @return array * @throws Exception */ - public function getRepository(string $owner, string $repo): array + public function updateComment($repoName, $commentId) { - $response = $this->call(self::METHOD_GET, '/repos/' . urlencode($owner) . '/' . urlencode($repo), ['content-type' => 'application/json']); - - return $response; + $this->call(self::METHOD_PATCH, '/repos/' . $this->user . '/' . $repoName . '/issues/comments/' . $commentId, ["Authorization" => "Bearer $this->accessToken"], ["body" => "update from Utopia!"]); + return; } } \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 3c1ec34b..a2071b10 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -3,26 +3,43 @@ namespace Utopia\Tests; use PHPUnit\Framework\TestCase; +use Utopia\App; use Utopia\VCS\Adapter\Git\GitHub; -class GitHubTest extends TestCase +class GitHubTest extends TestCase { + protected $github; + + public function setUp(): void + { + $privateKey = App::getEnv("GITHUB_PRIVATE_KEY"); + $githubAppId = App::getEnv("GITHUB_APP_IDENTIFIER"); + $installationId = "1234"; + $this->github = new GitHub("vermakhushboo", $installationId, $privateKey, $githubAppId); + } + public function testGetUser(): void { - $github = new GitHub(); - $userDetails = $github->getUser("vermakhushboo"); + $this->github->getUser(); } - public function testListRepositories(): void + public function testListRepositoriesForGitHubApp(): void { - $github = new GitHub(); - $repos = $github->listRepositories("vermakhushboo"); + $this->github->listRepositoriesForGitHubApp(); } public function testGetRepository(): void { - $github = new GitHub(); - $repoDetails = $github->getRepository("vermakhushboo", "TodoApp"); - var_dump($repoDetails); + $this->github->getRepository("TodoApp"); + } + + public function testAddComment(): void + { + $this->github->addComment("basic-js-crud", 1); + } + + public function testUpdateComment(): void + { + $this->github->updateComment("basic-js-crud", 1431560395); } } \ No newline at end of file From f09655f2efe7e3cb63df926c4fcc9658e9a8c1f7 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 16 Feb 2023 00:02:14 +0530 Subject: [PATCH 005/147] Added dockerfile --- Dockerfile | 25 +++++++++++++++++++++++++ README.md | 6 +++++- docker-compose.yml | 14 ++++++++++++++ src/VCS/Adapter/Git/GitHub.php | 5 +---- tests/VCS/GitHubTest.php | 4 ++-- 5 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..19d90e3a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,25 @@ +FROM composer:2.0 as composer + +ARG TESTING=false +ENV TESTING=$TESTING + +WORKDIR /usr/local/src/ + +COPY composer.lock /usr/local/src/ +COPY composer.json /usr/local/src/ + +RUN composer install \ + --ignore-platform-reqs \ + --optimize-autoloader \ + --no-plugins \ + --no-scripts \ + --prefer-dist + +FROM php:8.0-cli-alpine + +WORKDIR /usr/local/src/ + +COPY --from=composer /usr/local/src/vendor /usr/local/src/vendor +COPY . /usr/local/src/ + +CMD [ "tail", "-f", "/dev/null" ] \ No newline at end of file diff --git a/README.md b/README.md index 476c2ec9..fa157c00 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,8 @@ Utopia VCS is a simple and lite library to integrate version control systems like GitHub, GitLab etc. to receive webhook events like push, new pull request etc. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io). -Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project, it is dependency free and can be used as standalone with any other PHP project or framework. \ No newline at end of file +Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project, it is dependency free and can be used as standalone with any other PHP project or framework. + +Run tests using the following command: + +`docker compose exec tests ./vendor/bin/phpunit` \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..7c279b21 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3.9' + +services: + tests: + build: + context: . + volumes: + - ./src:/usr/local/src/src + - ./tests:/usr/local/src/tests + - ./phpunit.xml:/usr/local/src/phpunit.xml + environment: + - GITHUB_PRIVATE_KEY + - GITHUB_APP_IDENTIFIER + - GITHUB_WEBHOOK_SECRET \ No newline at end of file diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index d018ba99..2f705c3b 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -38,9 +38,6 @@ class GitHub extends Git /** * GitHub constructor. * - * @param user - * @param string $userName The username of account which has installed GitHub app - * @param string $installationId Installation ID of the GitHub App */ public function __construct(string $userName, string $installationId, string $privateKey, string $githubAppId) { @@ -115,7 +112,7 @@ public function getUser(): array } /** - * List repositories + * List repositories for GitHub App * * @return array * @throws Exception diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index a2071b10..264b4ea1 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -14,7 +14,7 @@ public function setUp(): void { $privateKey = App::getEnv("GITHUB_PRIVATE_KEY"); $githubAppId = App::getEnv("GITHUB_APP_IDENTIFIER"); - $installationId = "1234"; + $installationId = "1234"; //your GitHub App Installation ID here $this->github = new GitHub("vermakhushboo", $installationId, $privateKey, $githubAppId); } @@ -25,7 +25,7 @@ public function testGetUser(): void public function testListRepositoriesForGitHubApp(): void { - $this->github->listRepositoriesForGitHubApp(); + $repos = $this->github->listRepositoriesForGitHubApp(); } public function testGetRepository(): void From 5e130c49c733ec504bff69e29a5f4e03119d29a2 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Fri, 17 Feb 2023 20:21:55 +0530 Subject: [PATCH 006/147] Add download repository zip method --- src/VCS/Adapter/Git/GitHub.php | 38 +++++++++++++++++++++++++++++++--- tests/VCS/GitHubTest.php | 14 ++++++++----- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 2f705c3b..b1953875 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -119,7 +119,9 @@ public function getUser(): array */ public function listRepositoriesForGitHubApp(): array { - $response = $this->call(self::METHOD_GET, '/installation/repositories', ["Authorization" => "Bearer $this->accessToken"]); + $url = '/installation/repositories'; + + $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); return $response['body']['repositories']; } @@ -132,7 +134,10 @@ public function listRepositoriesForGitHubApp(): array */ public function addComment($repoName, $pullRequestNumber) { - $this->call(self::METHOD_POST, '/repos/' . $this->user . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments', ["Authorization" => "Bearer $this->accessToken"], ["body" => "hello from Utopia!"]); + $url = '/repos/' . $this->user . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments'; + + $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => "hello from Utopia!"]); + return; } @@ -144,7 +149,34 @@ public function addComment($repoName, $pullRequestNumber) */ public function updateComment($repoName, $commentId) { - $this->call(self::METHOD_PATCH, '/repos/' . $this->user . '/' . $repoName . '/issues/comments/' . $commentId, ["Authorization" => "Bearer $this->accessToken"], ["body" => "update from Utopia!"]); + $url = '/repos/' . $this->user . '/' . $repoName . '/issues/comments/' . $commentId; + + $this->call(self::METHOD_PATCH, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => "update from Utopia!"]); + return; } + + /** + * Downloads a ZIP archive of a repository. + * + * @param string $repo The name of the repository. + * @param string $ref The name of the commit, branch, or tag to download. + * @param string $path The path of the file or directory to download. Optional. + * @return string The contents of the ZIP archive as a string. + */ + public function downloadRepositoryZip(string $repoName, string $ref, string $path = ''): string + { + // Build the URL for the API request + $url = "/repos/" . $this->user . "/{$repoName}/zipball/{$ref}"; + + // Add the path parameter to the URL query parameters, if specified + if (!empty($path)) { + $url .= "?path={$path}"; + } + + $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + + // Return the contents of the ZIP archive + return $response['body']; + } } \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 264b4ea1..53e0551d 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -28,11 +28,6 @@ public function testListRepositoriesForGitHubApp(): void $repos = $this->github->listRepositoriesForGitHubApp(); } - public function testGetRepository(): void - { - $this->github->getRepository("TodoApp"); - } - public function testAddComment(): void { $this->github->addComment("basic-js-crud", 1); @@ -42,4 +37,13 @@ public function testUpdateComment(): void { $this->github->updateComment("basic-js-crud", 1431560395); } + + public function testDownloadRepositoryZip(): void + { + // download the zip archive of the repo + $zipContents = $this->github->downloadRepositoryZip("gatsby-ecommerce-theme", "main"); + + // Save the ZIP archive to a file + file_put_contents('hello-world.zip', $zipContents); + } } \ No newline at end of file From 68d1605defbe3ae8671ccd40998638669d885f69 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 21 Feb 2023 01:04:56 +0530 Subject: [PATCH 007/147] Add forkRepository() method --- .gitignore | 3 ++- docker-compose.yml | 1 + src/VCS/Adapter/Git/GitHub.php | 27 +++++++++++++++++++++++++++ tests/VCS/GitHubTest.php | 8 +++++++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8b8036b3..a8e3d840 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /vendor/ /.idea/ .phpunit.result.cache -.env \ No newline at end of file +.env +.DS_Store \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 7c279b21..aa5c6575 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,6 +8,7 @@ services: - ./src:/usr/local/src/src - ./tests:/usr/local/src/tests - ./phpunit.xml:/usr/local/src/phpunit.xml + - /Users/khushbooverma/desktop:/usr/local/src/desktop environment: - GITHUB_PRIVATE_KEY - GITHUB_APP_IDENTIFIER diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index b1953875..26a4a204 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -179,4 +179,31 @@ public function downloadRepositoryZip(string $repoName, string $ref, string $pat // Return the contents of the ZIP archive return $response['body']; } + + /** + * Forks a repository on GitHub. + * + * @param string $owner The owner of the repository to fork. + * @param string $repo The name of the repository to fork. + * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. + * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. + * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. + * + * @return array|null The data of the newly forked repository, or null if the fork operation failed. + */ + public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?array + { + $url = "/repos/$owner/$repo/forks"; + + // Create the payload data for the API request + $data = [ + 'organization' => $organization, + 'name' => $name, + 'default_branch_only' => $defaultBranchOnly, + ]; + + // Send the API request to fork the repository + $response = $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], $data); + return $response['body']; + } } \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 53e0551d..4b95a5dd 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -44,6 +44,12 @@ public function testDownloadRepositoryZip(): void $zipContents = $this->github->downloadRepositoryZip("gatsby-ecommerce-theme", "main"); // Save the ZIP archive to a file - file_put_contents('hello-world.zip', $zipContents); + file_put_contents('./desktop/hello-world.zip', $zipContents); + } + + public function testForkRepository(): void + { + // Fork a repository into authenticated user's account with custom name + $response = $this->github->forkRepository("appwrite", "demos-for-astro", name: "fork-api-test-clone"); } } \ No newline at end of file From d6efcf520f55ec657bc5778893fb68fb2d2ab6d6 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 21 Feb 2023 20:10:33 +0530 Subject: [PATCH 008/147] Add CONTRIBUTING.md, CODE_OF_CONDUCT.md and updated README --- CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++++++++ CONTRIBUTING.md | 105 +++++++++++++++++++++++++++++++++++++++++++++ README.md | 42 +++++++++++++++++- 3 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..e3974013 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity, expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at team@appwrite.io. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..72939afc --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,105 @@ +# Contributing + +We would ❤️ for you to contribute to Utopia-php and help make it better! We want contributing to Utopia-php to be fun, enjoyable, and educational for anyone and everyone. All contributions are welcome, including issues, new docs as well as updates and tweaks, blog posts, workshops, and more. + +## How to Start? + +If you are worried or don’t know where to start, check out our next section explaining what kind of help we could use and where can you get involved. You can reach out with questions to [Eldad Fux (@eldadfux)](https://twitter.com/eldadfux) or anyone from the [Appwrite team on Discord](https://appwrite.io/discord). You can also submit an issue, and a maintainer can guide you! + +## Code of Conduct + +Help us keep Utopia-php open and inclusive. Please read and follow our [Code of Conduct](https://github.com/utopia-php/abuse/blob/master/CODE_OF_CONDUCT.md). + +## Submit a Pull Request 🚀 + +Branch naming convention is as following + +``` +TYPE-ISSUE_ID-DESCRIPTION +``` + +example: + +``` +doc-548-submit-a-pull-request-section-to-contribution-guide +``` + +When `TYPE` can be: + +- **feat** - is a new feature +- **doc** - documentation only changes +- **cicd** - changes related to CI/CD system +- **fix** - a bug fix +- **refactor** - code change that neither fixes a bug nor adds a feature + +**All PRs must include a commit message with the changes description!** + +For the initial start, fork the project and use git clone command to download the repository to your computer. A standard procedure for working on an issue would be to: + +1. `git pull`, before creating a new branch, pull the changes from upstream. Your master needs to be up to date. + +``` +$ git pull +``` + +2. Create new branch from `master` like: `doc-548-submit-a-pull-request-section-to-contribution-guide` + +``` +$ git checkout -b [name_of_your_new_branch] +``` + +3. Work - commit - repeat ( be sure to be in your branch ) + +4. Push changes to GitHub + +``` +$ git push origin [name_of_your_new_branch] +``` + +6. Submit your changes for review If you go to your repository on GitHub, you'll see a `Compare & pull request` button. Click on that button. + +7. Start a Pull Request Now submit the pull request and click on `Create pull request`. + +8. Get a code review approval/reject + +9. After approval, merge your PR + +10. GitHub will automatically delete the branch after the merge is done. (they can still be restored). + +## Introducing New Features + +We would 💖 you to contribute to Utopia-php, but we would also like to make sure Utopia-php is as great as possible and loyal to its vision and mission statement 🙏. + +For us to find the right balance, please open an issue explaining your ideas before introducing a new pull request. + +This will allow the Utopia-php community to have sufficient discussion about the new feature value and how it fits in the product roadmap and vision. + +This is also important for the Utopia-php lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc). + +## Other Ways to Help + +Pull requests are great, but there are many other areas where you can help Utopia-php. + +### Blogging & Speaking + +Blogging, speaking about, or creating tutorials about one of Utopia-php’s many features is great way to contribute and help our project grow. + +### Presenting at Meetups + +Presenting at meetups and conferences about your Utopia-php projects. Your unique challenges and successes in building things with Utopia-php can provide great speaking material. We’d love to review your talk abstract/CFP, so get in touch with us if you’d like some help! + +### Sending Feedbacks & Reporting Bugs + +Sending feedback is a great way for us to understand your different use cases of Utopia-php better. If you had any issues, bugs, or want to share about your experience, feel free to do so on our GitHub issues page or at our [Discord channel](https://discord.gg/GSeTUeA). + +### Submitting New Ideas + +If you think Utopia-php could use a new feature, please open an issue on our GitHub repository, stating as much information as you can think about your new idea and it's implications. We would also use this issue to gather more information, get more feedback from the community, and have a proper discussion about the new feature. + +### Improving Documentation + +Submitting documentation updates, enhancements, designs, or bug fixes. Spelling or grammar fixes will be very much appreciated. + +### Helping Someone + +Searching for Utopia-php, GitHub or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Utopia-php's repo! \ No newline at end of file diff --git a/README.md b/README.md index fa157c00..4603d4f5 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,47 @@ # Utopia VCS +[![Build Status](https://travis-ci.org/utopia-php/vcs.svg?branch=master)](https://travis-ci.com/utopia-php/vcs) +![Total Downloads](https://img.shields.io/packagist/dt/utopia-php/vcs.svg) +[![Discord](https://img.shields.io/discord/564160730845151244?label=discord)](https://appwrite.io/discord) + Utopia VCS is a simple and lite library to integrate version control systems like GitHub, GitLab etc. to receive webhook events like push, new pull request etc. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io). Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project, it is dependency free and can be used as standalone with any other PHP project or framework. -Run tests using the following command: +## Getting Started + +Install using composer: +```bash +composer require utopia-php/vcs +``` + +## System Requirements + +Utopia Pay requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible. + + +## Contributing + +All code contributions - including those of people having commit access - must go through a pull request and approved by a core developer before being merged. This is to ensure proper review of all the code. + +Fork the project, create a feature branch, and send us a pull request. + +You can refer to the [Contributing Guide](CONTRIBUTING.md) for more info. + +## Tests + +To run tests, you first need to bring up the example Docker stack with the following command: + +```bash +docker compose up -d --build +``` + +To run all unit tests, use the following Docker command: + +```bash +docker compose exec tests ./vendor/bin/phpunit +``` + +## Copyright and license -`docker compose exec tests ./vendor/bin/phpunit` \ No newline at end of file +The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php) \ No newline at end of file From edfd361f58d2c25e23b24e70d11164700e7cf183 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 1 Mar 2023 18:24:22 +0530 Subject: [PATCH 009/147] Update Utopia-php/framework version --- composer.json | 2 +- composer.lock | 72 +++++++++++++++++++++++++-------------------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/composer.json b/composer.json index db9b7b70..4157be66 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "php": ">=8.0", "adhocore/jwt": "^1.1", "vlucas/phpdotenv": "^5.5", - "utopia-php/framework": "^0.27.0" + "utopia-php/framework": "^0.26.0" }, "require-dev": { "phpunit/phpunit": "^9.4", diff --git a/composer.lock b/composer.lock index 612158bc..d72ce2cd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c49686b712c6423390df3fde708a1d32", + "content-hash": "e245e08b1d60f7be615344c02c6f87a3", "packages": [ { "name": "adhocore/jwt", @@ -65,24 +65,24 @@ }, { "name": "graham-campbell/result-type", - "version": "v1.1.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "a878d45c1914464426dc94da61c9e1d36ae262a8" + "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/a878d45c1914464426dc94da61c9e1d36ae262a8", - "reference": "a878d45c1914464426dc94da61c9e1d36ae262a8", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", + "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9" + "phpoption/phpoption": "^1.9.1" }, "require-dev": { - "phpunit/phpunit": "^8.5.28 || ^9.5.21" + "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" }, "type": "library", "autoload": { @@ -111,7 +111,7 @@ ], "support": { "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.0" + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1" }, "funding": [ { @@ -123,28 +123,28 @@ "type": "tidelift" } ], - "time": "2022-07-30T15:56:11+00:00" + "time": "2023-02-25T20:23:15+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab" + "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", - "reference": "dc5ff11e274a90cc1c743f66c9ad700ce50db9ab", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", + "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.8", - "phpunit/phpunit": "^8.5.28 || ^9.5.21" + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" }, "type": "library", "extra": { @@ -186,7 +186,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.0" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" }, "funding": [ { @@ -198,7 +198,7 @@ "type": "tidelift" } ], - "time": "2022-07-30T15:51:26+00:00" + "time": "2023-02-25T19:38:58+00:00" }, { "name": "symfony/polyfill-ctype", @@ -450,16 +450,16 @@ }, { "name": "utopia-php/framework", - "version": "0.27.0", + "version": "0.26.0", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "b8d0447f5c98291d7759db05460ecced29a0f9ee" + "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/b8d0447f5c98291d7759db05460ecced29a0f9ee", - "reference": "b8d0447f5c98291d7759db05460ecced29a0f9ee", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/e8da5576370366d3bf9c574ec855f8c96fe4f34e", + "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e", "shasum": "" }, "require": { @@ -488,9 +488,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.27.0" + "source": "https://github.com/utopia-php/framework/tree/0.26.0" }, - "time": "2023-01-29T05:36:17+00:00" + "time": "2023-01-13T08:14:43+00:00" }, { "name": "vlucas/phpdotenv", @@ -942,23 +942,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.24", + "version": "9.2.25", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed" + "reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2cf940ebc6355a9d430462811b5aaa308b174bed", - "reference": "2cf940ebc6355a9d430462811b5aaa308b174bed", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e2b40518197a8c0d4b08bc34dfff1c99c508954", + "reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.15", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -1007,7 +1007,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.24" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.25" }, "funding": [ { @@ -1015,7 +1015,7 @@ "type": "github" } ], - "time": "2023-01-26T08:26:55+00:00" + "time": "2023-02-25T05:32:00+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1260,16 +1260,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.3", + "version": "9.6.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555" + "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7b1615e3e887d6c719121c6d4a44b0ab9645555", - "reference": "e7b1615e3e887d6c719121c6d4a44b0ab9645555", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9125ee085b6d95e78277dc07aa1f46f9e0607b8d", + "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d", "shasum": "" }, "require": { @@ -1342,7 +1342,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.3" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.4" }, "funding": [ { @@ -1358,7 +1358,7 @@ "type": "tidelift" } ], - "time": "2023-02-04T13:37:15+00:00" + "time": "2023-02-27T13:06:37+00:00" }, { "name": "sebastian/cli-parser", From 2d56fe819ae3dfae7af8141ed3a8e2e86b01bb0f Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 1 Mar 2023 22:52:14 +0530 Subject: [PATCH 010/147] Add download as tar method --- src/VCS/Adapter/Git/GitHub.php | 18 ++++++++++++++++++ tests/VCS/GitHubTest.php | 9 +++++++++ 2 files changed, 27 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 26a4a204..ce18eaa2 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -180,6 +180,24 @@ public function downloadRepositoryZip(string $repoName, string $ref, string $pat return $response['body']; } + /** + * Downloads a tar archive of a repository. + * + * @param string $repo The name of the repository. + * @param string $ref The name of the commit, branch, or tag to download. + * @return string The contents of the tar archive as a string. + */ + public function downloadRepositoryTar(string $repoName, string $ref): string + { + // Build the URL for the API request + $url = "/repos/" . $this->user . "/{$repoName}/tarball/{$ref}"; + + $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + + // Return the contents of the tar archive + return $response['body']; + } + /** * Forks a repository on GitHub. * diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 4b95a5dd..d55df4d5 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -47,6 +47,15 @@ public function testDownloadRepositoryZip(): void file_put_contents('./desktop/hello-world.zip', $zipContents); } + public function testDownloadRepositoryTar():void + { + // download the tar archive of the repo + $tarContents = $this->github->downloadRepositoryTar("gatsby-ecommerce-theme", "main"); + + // Save the ZIP archive to a file + file_put_contents('./desktop/hello-world1.tar', $tarContents); + } + public function testForkRepository(): void { // Fork a repository into authenticated user's account with custom name From 651c21ad8f5df5e16ee23959a31acc25823c85ff Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 15 Mar 2023 00:45:32 +0530 Subject: [PATCH 011/147] Make username the last and optional param in constructor --- src/VCS/Adapter/Git/GitHub.php | 2 +- tests/VCS/GitHubTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index ce18eaa2..6c627be6 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -39,7 +39,7 @@ class GitHub extends Git * GitHub constructor. * */ - public function __construct(string $userName, string $installationId, string $privateKey, string $githubAppId) + public function __construct(string $installationId, string $privateKey, string $githubAppId, string $userName = "") { // Set user name $this->user = $userName; diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index d55df4d5..c677f3cf 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -15,7 +15,7 @@ public function setUp(): void $privateKey = App::getEnv("GITHUB_PRIVATE_KEY"); $githubAppId = App::getEnv("GITHUB_APP_IDENTIFIER"); $installationId = "1234"; //your GitHub App Installation ID here - $this->github = new GitHub("vermakhushboo", $installationId, $privateKey, $githubAppId); + $this->github = new GitHub($installationId, $privateKey, $githubAppId, "vermakhushboo"); } public function testGetUser(): void @@ -52,7 +52,7 @@ public function testDownloadRepositoryTar():void // download the tar archive of the repo $tarContents = $this->github->downloadRepositoryTar("gatsby-ecommerce-theme", "main"); - // Save the ZIP archive to a file + // Save the TAR archive to a file file_put_contents('./desktop/hello-world1.tar', $tarContents); } From 8874fe09f488342c268da4fb6031e06b79621df3 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 15 Mar 2023 01:56:18 +0530 Subject: [PATCH 012/147] Added method to generate git clone command --- src/VCS/Adapter/Git/GitHub.php | 23 +++++++++++++++++++++++ tests/VCS/GitHubTest.php | 7 +++++++ 2 files changed, 30 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 6c627be6..e66c5e98 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -224,4 +224,27 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio $response = $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], $data); return $response['body']; } + + /** + * Generates a git clone command using app access token + * + * @param string $repoUrl The URL of the repo to be cloned + * + * @return string The git clone command as a string + */ + public function generateGitCloneCommand(string $repoUrl) { + // Split the repository URL into its parts + $parts = parse_url($repoUrl); + + // Get the owner and repository name from the URL + $pathParts = explode('/', $parts['path']); + + // Construct the clone URL with the access token + $cloneUrl = str_replace("https://", "https://{$this->accessToken}@", $repoUrl); + + // Construct the Git clone command with the clone URL + $command = "git clone {$cloneUrl}"; + + return $command; + } } \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index c677f3cf..9627a3e2 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -61,4 +61,11 @@ public function testForkRepository(): void // Fork a repository into authenticated user's account with custom name $response = $this->github->forkRepository("appwrite", "demos-for-astro", name: "fork-api-test-clone"); } + + public function testGenerateGitCloneCommand(): string + { + $repoUrl = "https://github.com/vermakhushboo/testing-fork.git"; + $gitCloneCommand = $this->github->generateGitCloneCommand($repoUrl); + return $gitCloneCommand; + } } \ No newline at end of file From aeb360f97f49f0e1c408800902f01bef922b28b8 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 22 Mar 2023 02:27:10 +0530 Subject: [PATCH 013/147] Updated git clone method --- src/VCS/Adapter/Git/GitHub.php | 14 +++++++------- tests/VCS/GitHubTest.php | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index e66c5e98..a1bc5847 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -228,16 +228,16 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio /** * Generates a git clone command using app access token * - * @param string $repoUrl The URL of the repo to be cloned + * @param string $repoId The ID of the repo to be cloned * * @return string The git clone command as a string */ - public function generateGitCloneCommand(string $repoUrl) { - // Split the repository URL into its parts - $parts = parse_url($repoUrl); - - // Get the owner and repository name from the URL - $pathParts = explode('/', $parts['path']); + public function generateGitCloneCommand(string $repoID) { + $url = "/repositories/{$repoID}"; + + $repoData = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + + $repoUrl = $repoData["body"]["html_url"]; // Construct the clone URL with the access token $cloneUrl = str_replace("https://", "https://{$this->accessToken}@", $repoUrl); diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 9627a3e2..2b134a2b 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -64,8 +64,8 @@ public function testForkRepository(): void public function testGenerateGitCloneCommand(): string { - $repoUrl = "https://github.com/vermakhushboo/testing-fork.git"; - $gitCloneCommand = $this->github->generateGitCloneCommand($repoUrl); + $repoId = "155386150"; + $gitCloneCommand = $this->github->generateGitCloneCommand($repoId); return $gitCloneCommand; } } \ No newline at end of file From 693e07685ca1c1953e91ac754d1080c498aa7261 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 30 Mar 2023 16:07:19 +0530 Subject: [PATCH 014/147] Added parsePayload method --- src/VCS/Adapter/Git/GitHub.php | 28 +++++++++++++++++++++++++++- tests/VCS/GitHubTest.php | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index a1bc5847..06c871a2 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -35,11 +35,16 @@ class GitHub extends Git */ protected $headers = ['content-type' => 'application/json']; + public function __construct() + { + + } + /** * GitHub constructor. * */ - public function __construct(string $installationId, string $privateKey, string $githubAppId, string $userName = "") + public function initialiseVariables(string $installationId, string $privateKey, string $githubAppId, string $userName = "") { // Set user name $this->user = $userName; @@ -247,4 +252,25 @@ public function generateGitCloneCommand(string $repoID) { return $command; } + + public function parseWebhookEventPayload(string $payload) { + $payload = json_decode($payload, true); + $event = $payload["event"]; + + $result = array(); + + if($event == "push") + { + $ref = $payload["payload"]["ref"]; + $branch = str_replace("refs/heads/", "", $ref); + $repositoryId = strval($payload["payload"]["repository"]["id"]); + $result = array( + "event" => $event, + "branch" => $branch, + "repositoryId" => $repositoryId + ); + } + + return json_encode($result); + } } \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 2b134a2b..29394e3a 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -12,10 +12,11 @@ class GitHubTest extends TestCase public function setUp(): void { + $this->github = new GitHub(); $privateKey = App::getEnv("GITHUB_PRIVATE_KEY"); $githubAppId = App::getEnv("GITHUB_APP_IDENTIFIER"); $installationId = "1234"; //your GitHub App Installation ID here - $this->github = new GitHub($installationId, $privateKey, $githubAppId, "vermakhushboo"); + $this->github->initialiseVariables($installationId, $privateKey, $githubAppId, "vermakhushboo"); } public function testGetUser(): void @@ -68,4 +69,34 @@ public function testGenerateGitCloneCommand(): string $gitCloneCommand = $this->github->generateGitCloneCommand($repoId); return $gitCloneCommand; } + + public function testParseWebhookEventPayload(): void + { + $payload = '{ + "event": "push", + "payload": { + "ref": "refs/heads/main", + "before": "d1691190ef54f329b41333273722f444edc937ab", + "after": "d06526f437939d1298f9dea15478665692ee4e69", + "repository": { + "id": 1234, + "node_id": "R_kgDOI_yRPA", + "name": "testing-fork", + "full_name": "vermakhushboo/testing-fork", + "private": true, + "html_url": "https://github.com/vermakhushboo/testing-fork" + }, + "pusher": { + "name": "vermakhushboo" + }, + "sender": { + "login": "vermakhushboo" + }, + "installation": { + "id": 1234 + } + } + }'; + $result = $this->github->parseWebhookEventPayload($payload); + } } \ No newline at end of file From 0209e6e364ea35df01842f5f162789b940c25124 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 3 Apr 2023 12:28:21 +0530 Subject: [PATCH 015/147] Modified parseWebhookEventPayload method --- src/VCS/Adapter/Git/GitHub.php | 9 +++------ tests/VCS/GitHubTest.php | 36 +++++++++++++--------------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 06c871a2..e73a9093 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -253,24 +253,21 @@ public function generateGitCloneCommand(string $repoID) { return $command; } - public function parseWebhookEventPayload(string $payload) { + public function parseWebhookEventPayload(string $event, string $payload) { $payload = json_decode($payload, true); - $event = $payload["event"]; $result = array(); if($event == "push") { - $ref = $payload["payload"]["ref"]; + $ref = $payload["ref"]; $branch = str_replace("refs/heads/", "", $ref); - $repositoryId = strval($payload["payload"]["repository"]["id"]); + $repositoryId = strval($payload["repository"]["id"]); $result = array( - "event" => $event, "branch" => $branch, "repositoryId" => $repositoryId ); } - return json_encode($result); } } \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 29394e3a..2546b908 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -73,30 +73,22 @@ public function testGenerateGitCloneCommand(): string public function testParseWebhookEventPayload(): void { $payload = '{ - "event": "push", - "payload": { - "ref": "refs/heads/main", - "before": "d1691190ef54f329b41333273722f444edc937ab", - "after": "d06526f437939d1298f9dea15478665692ee4e69", - "repository": { - "id": 1234, - "node_id": "R_kgDOI_yRPA", - "name": "testing-fork", - "full_name": "vermakhushboo/testing-fork", - "private": true, - "html_url": "https://github.com/vermakhushboo/testing-fork" - }, - "pusher": { - "name": "vermakhushboo" - }, - "sender": { - "login": "vermakhushboo" - }, - "installation": { - "id": 1234 + "ref": "refs/heads/main", + "before": "1234", + "after": "1234", + "repository": { + "id": 603754812, + "node_id": "R_kgDOI_yRPA", + "name": "testing-fork", + "full_name": "vermakhushboo/testing-fork", + "private": true, + "owner": { } + }, + "installation": { + "id": 1234 } }'; - $result = $this->github->parseWebhookEventPayload($payload); + $this->github->parseWebhookEventPayload("push", $payload); } } \ No newline at end of file From 8be42d2243f375d7f35612ba74e5353522cb3ab2 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 5 Apr 2023 17:05:50 +0530 Subject: [PATCH 016/147] Return installationId also in parsed payload --- src/VCS/Adapter/Git/GitHub.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index e73a9093..68793032 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -263,9 +263,11 @@ public function parseWebhookEventPayload(string $event, string $payload) { $ref = $payload["ref"]; $branch = str_replace("refs/heads/", "", $ref); $repositoryId = strval($payload["repository"]["id"]); + $installationId = strval($payload["installation"]["id"]); $result = array( "branch" => $branch, - "repositoryId" => $repositoryId + "repositoryId" => $repositoryId, + "installationId" => $installationId ); } return json_encode($result); From 9724b1ddee0548f0c28e156d6a7d44d897b78fc6 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 5 Apr 2023 20:15:16 +0530 Subject: [PATCH 017/147] Updated git clone command --- src/VCS/Adapter/Git/GitHub.php | 4 ++-- tests/VCS/GitHubTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 68793032..82e950e2 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -237,7 +237,7 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio * * @return string The git clone command as a string */ - public function generateGitCloneCommand(string $repoID) { + public function generateGitCloneCommand(string $repoID, string $branchName) { $url = "/repositories/{$repoID}"; $repoData = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); @@ -248,7 +248,7 @@ public function generateGitCloneCommand(string $repoID) { $cloneUrl = str_replace("https://", "https://{$this->accessToken}@", $repoUrl); // Construct the Git clone command with the clone URL - $command = "git clone {$cloneUrl}"; + $command = "git clone -b " . $branchName . " --depth=1 {$cloneUrl}"; return $command; } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 2546b908..ecc03519 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -66,7 +66,7 @@ public function testForkRepository(): void public function testGenerateGitCloneCommand(): string { $repoId = "155386150"; - $gitCloneCommand = $this->github->generateGitCloneCommand($repoId); + $gitCloneCommand = $this->github->generateGitCloneCommand($repoId, "main"); return $gitCloneCommand; } From 5b16cd73cc1a790c044c86e2053f519a7b89571a Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 5 Apr 2023 21:30:33 +0530 Subject: [PATCH 018/147] Add logic to parse pull request payload --- src/VCS/Adapter/Git/GitHub.php | 42 +++++++++++++++++++--------------- tests/VCS/GitHubTest.php | 28 +++++++++++++++++++---- 2 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 82e950e2..bca6e87d 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -37,7 +37,6 @@ class GitHub extends Git public function __construct() { - } /** @@ -217,14 +216,14 @@ public function downloadRepositoryTar(string $repoName, string $ref): string public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?array { $url = "/repos/$owner/$repo/forks"; - + // Create the payload data for the API request $data = [ 'organization' => $organization, 'name' => $name, 'default_branch_only' => $defaultBranchOnly, ]; - + // Send the API request to fork the repository $response = $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], $data); return $response['body']; @@ -237,39 +236,44 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio * * @return string The git clone command as a string */ - public function generateGitCloneCommand(string $repoID, string $branchName) { + public function generateGitCloneCommand(string $repoID, string $branchName) + { $url = "/repositories/{$repoID}"; $repoData = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); $repoUrl = $repoData["body"]["html_url"]; - + // Construct the clone URL with the access token $cloneUrl = str_replace("https://", "https://{$this->accessToken}@", $repoUrl); - + // Construct the Git clone command with the clone URL $command = "git clone -b " . $branchName . " --depth=1 {$cloneUrl}"; - + return $command; } - public function parseWebhookEventPayload(string $event, string $payload) { + public function parseWebhookEventPayload(string $event, string $payload) + { $payload = json_decode($payload, true); - $result = array(); + $repositoryId = strval($payload["repository"]["id"]); + $installationId = strval($payload["installation"]["id"]); + $branch = ""; - if($event == "push") - { + if ($event == "push") { $ref = $payload["ref"]; $branch = str_replace("refs/heads/", "", $ref); - $repositoryId = strval($payload["repository"]["id"]); - $installationId = strval($payload["installation"]["id"]); - $result = array( - "branch" => $branch, - "repositoryId" => $repositoryId, - "installationId" => $installationId - ); + } else if ($event == "pull_request") { + $branch = $payload["pull_request"]["head"]["ref"]; } + + $result = array( + "branch" => $branch, + "repositoryId" => $repositoryId, + "installationId" => $installationId + ); + return json_encode($result); } -} \ No newline at end of file +} diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index ecc03519..572e1c37 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -48,7 +48,7 @@ public function testDownloadRepositoryZip(): void file_put_contents('./desktop/hello-world.zip', $zipContents); } - public function testDownloadRepositoryTar():void + public function testDownloadRepositoryTar(): void { // download the tar archive of the repo $tarContents = $this->github->downloadRepositoryTar("gatsby-ecommerce-theme", "main"); @@ -72,7 +72,7 @@ public function testGenerateGitCloneCommand(): string public function testParseWebhookEventPayload(): void { - $payload = '{ + $payload_push = '{ "ref": "refs/heads/main", "before": "1234", "after": "1234", @@ -89,6 +89,26 @@ public function testParseWebhookEventPayload(): void "id": 1234 } }'; - $this->github->parseWebhookEventPayload("push", $payload); + + $payload_pull_request = '{ + "action": "opened", + "number": 1, + "pull_request": { + "id": 1303283688, + "state": "open", + "head": { + "ref": "test" + } + }, + "repository": { + "id": 3498 + }, + "installation": { + "id": 9876 + } + }'; + + $this->github->parseWebhookEventPayload("push", $payload_push); + $this->github->parseWebhookEventPayload("pull_request", $payload_pull_request); } -} \ No newline at end of file +} From 73e743b1a82255f61f09304ba9a7e6a28cbfaf67 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 6 Apr 2023 17:40:08 +0530 Subject: [PATCH 019/147] Updated git clone command --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index bca6e87d..c44492ba 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -245,7 +245,7 @@ public function generateGitCloneCommand(string $repoID, string $branchName) $repoUrl = $repoData["body"]["html_url"]; // Construct the clone URL with the access token - $cloneUrl = str_replace("https://", "https://{$this->accessToken}@", $repoUrl); + $cloneUrl = str_replace("https://", "https://{$this->user}:{$this->accessToken}@", $repoUrl); // Construct the Git clone command with the clone URL $command = "git clone -b " . $branchName . " --depth=1 {$cloneUrl}"; From fbc4071e2b503c1a6df06cebb008aed20d770405 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:06:36 +0530 Subject: [PATCH 020/147] Parse GitHub App Uninstallation payload --- src/VCS/Adapter/Git/GitHub.php | 45 ++++++++++++++++++++++------------ tests/VCS/GitHubTest.php | 9 +++++++ 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index c44492ba..dc590cda 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -256,24 +256,37 @@ public function generateGitCloneCommand(string $repoID, string $branchName) public function parseWebhookEventPayload(string $event, string $payload) { $payload = json_decode($payload, true); - - $repositoryId = strval($payload["repository"]["id"]); $installationId = strval($payload["installation"]["id"]); - $branch = ""; - if ($event == "push") { - $ref = $payload["ref"]; - $branch = str_replace("refs/heads/", "", $ref); - } else if ($event == "pull_request") { - $branch = $payload["pull_request"]["head"]["ref"]; + switch ($event) { + case "push": + $ref = $payload["ref"]; + $repositoryId = strval($payload["repository"]["id"]); + $branch = str_replace("refs/heads/", "", $ref); + return json_encode([ + "branch" => $branch, + "repositoryId" => $repositoryId, + "installationId" => $installationId + ]); + case "pull_request": + if ($payload["action"] == "opened") { + $repositoryId = strval($payload["repository"]["id"]); + $branch = $payload["pull_request"]["head"]["ref"]; + return json_encode([ + "branch" => $branch, + "repositoryId" => $repositoryId, + "installationId" => $installationId + ]); + } + break; + case "installation": + if ($payload["action"] == "deleted") { + return json_encode([ + "installationId" => $installationId + ]); + } + break; } - - $result = array( - "branch" => $branch, - "repositoryId" => $repositoryId, - "installationId" => $installationId - ); - - return json_encode($result); + return json_encode([]); } } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 572e1c37..cc4ecd87 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -108,7 +108,16 @@ public function testParseWebhookEventPayload(): void } }'; + $payload_uninstall = '{ + "action": "deleted", + "installation": { + "id": 1234 + } + } + '; + $this->github->parseWebhookEventPayload("push", $payload_push); $this->github->parseWebhookEventPayload("pull_request", $payload_pull_request); + $this->github->parseWebhookEventPayload("installation", $payload_uninstall); } } From ddc24efa376e9f6ab01824b0acf09c60d83743b6 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:12:10 +0530 Subject: [PATCH 021/147] Added description to parsePayload method --- src/VCS/Adapter/Git/GitHub.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index dc590cda..d9ecad6b 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -253,6 +253,14 @@ public function generateGitCloneCommand(string $repoID, string $branchName) return $command; } + /** + * Parses webhook event payload + * + * @param string $event Type of event: push, pull_request etc + * @param string $payload The webhook payload received from GitHub + * + * @return json Parsed payload as a json object + */ public function parseWebhookEventPayload(string $event, string $payload) { $payload = json_decode($payload, true); From e790e4bad005f426a8a9050eeaa9921b1d455b80 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Apr 2023 20:18:22 +0530 Subject: [PATCH 022/147] Added constants for push, PR and other events --- src/VCS/Adapter/Git/GitHub.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index d9ecad6b..4a2b100e 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -28,6 +28,12 @@ class GitHub extends Git */ protected $installationId; + const EVENT_PUSH = 'push'; + + const EVENT_PULL_REQUEST = 'pull_request'; + + const EVENT_INSTALLATION = 'installation'; + /** * Global Headers * From 6150faea0ffb469e458e283f66f020b2fc4ef4ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 14 Apr 2023 08:14:04 +0000 Subject: [PATCH 023/147] Remove unneeded dependency --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 4157be66..f2141d9a 100644 --- a/composer.json +++ b/composer.json @@ -19,8 +19,7 @@ "require": { "php": ">=8.0", "adhocore/jwt": "^1.1", - "vlucas/phpdotenv": "^5.5", - "utopia-php/framework": "^0.26.0" + "vlucas/phpdotenv": "^5.5" }, "require-dev": { "phpunit/phpunit": "^9.4", From 417f24442e43c50056c7af976b105442d2bb418c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 14 Apr 2023 08:14:59 +0000 Subject: [PATCH 024/147] Update lockfile --- composer.lock | 103 +++++++++++++++----------------------------------- 1 file changed, 30 insertions(+), 73 deletions(-) diff --git a/composer.lock b/composer.lock index d72ce2cd..722ff179 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e245e08b1d60f7be615344c02c6f87a3", + "content-hash": "3ef6dcc55189772116160ad790e60d56", "packages": [ { "name": "adhocore/jwt", @@ -448,50 +448,6 @@ ], "time": "2022-11-03T14:55:06+00:00" }, - { - "name": "utopia-php/framework", - "version": "0.26.0", - "source": { - "type": "git", - "url": "https://github.com/utopia-php/framework.git", - "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/e8da5576370366d3bf9c574ec855f8c96fe4f34e", - "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "require-dev": { - "laravel/pint": "^1.2", - "phpunit/phpunit": "^9.5.25", - "vimeo/psalm": "4.27.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Utopia\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A simple, light and advanced PHP framework", - "keywords": [ - "framework", - "php", - "upf" - ], - "support": { - "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.26.0" - }, - "time": "2023-01-13T08:14:43+00:00" - }, { "name": "vlucas/phpdotenv", "version": "v5.5.0", @@ -716,16 +672,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.0", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { @@ -763,7 +719,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -771,20 +727,20 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.3", + "version": "v4.15.4", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", - "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", "shasum": "" }, "require": { @@ -825,9 +781,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.3" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" }, - "time": "2023-01-16T22:05:37+00:00" + "time": "2023-03-05T19:49:14+00:00" }, { "name": "phar-io/manifest", @@ -942,16 +898,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.25", + "version": "9.2.26", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954" + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0e2b40518197a8c0d4b08bc34dfff1c99c508954", - "reference": "0e2b40518197a8c0d4b08bc34dfff1c99c508954", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", "shasum": "" }, "require": { @@ -973,8 +929,8 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { @@ -1007,7 +963,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.25" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" }, "funding": [ { @@ -1015,7 +971,7 @@ "type": "github" } ], - "time": "2023-02-25T05:32:00+00:00" + "time": "2023-03-06T12:58:08+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1260,16 +1216,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.4", + "version": "9.6.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d" + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9125ee085b6d95e78277dc07aa1f46f9e0607b8d", - "reference": "9125ee085b6d95e78277dc07aa1f46f9e0607b8d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115", + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115", "shasum": "" }, "require": { @@ -1302,8 +1258,8 @@ "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -1342,7 +1298,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.4" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6" }, "funding": [ { @@ -1358,7 +1315,7 @@ "type": "tidelift" } ], - "time": "2023-02-27T13:06:37+00:00" + "time": "2023-03-27T11:43:46+00:00" }, { "name": "sebastian/cli-parser", From 59e6f1c366aa1be244dcf8253b8d9cecca1a4963 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 18 Apr 2023 18:55:05 +0530 Subject: [PATCH 025/147] Added pullRequestNumber and repoName in PR payload --- src/VCS/Adapter/Git/GitHub.php | 9 ++++++--- tests/VCS/GitHubTest.php | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 4a2b100e..af94a58a 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -86,7 +86,6 @@ protected function generateAccessToken(string $privateKey, string $githubAppId) $token = $jwt->encode($payload); $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); $this->accessToken = $res['body']['token']; - var_dump($this->accessToken); } /** @@ -283,13 +282,17 @@ public function parseWebhookEventPayload(string $event, string $payload) "installationId" => $installationId ]); case "pull_request": - if ($payload["action"] == "opened") { + if ($payload["action"] == "opened" or $payload["action"] == "reopened") { $repositoryId = strval($payload["repository"]["id"]); $branch = $payload["pull_request"]["head"]["ref"]; + $repositoryName = $payload["repository"]["name"]; + $pullRequestNumber = $payload["number"]; return json_encode([ "branch" => $branch, "repositoryId" => $repositoryId, - "installationId" => $installationId + "installationId" => $installationId, + "repositoryName" => $repositoryName, + "pullRequestNumber" => $pullRequestNumber ]); } break; diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index cc4ecd87..c2befc35 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -101,7 +101,8 @@ public function testParseWebhookEventPayload(): void } }, "repository": { - "id": 3498 + "id": 3498, + "name": "functions-example" }, "installation": { "id": 9876 From 2fde15ea47e04c8e43520454935ff7242f6e67ec Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 18 Apr 2023 19:29:33 +0530 Subject: [PATCH 026/147] Update add and update comment methodd --- src/VCS/Adapter/Git/GitHub.php | 16 ++++++++-------- tests/VCS/GitHubTest.php | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index af94a58a..e88ef43e 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -141,13 +141,13 @@ public function listRepositoriesForGitHubApp(): array * @return array * @throws Exception */ - public function addComment($repoName, $pullRequestNumber) + public function addComment($repoName, $pullRequestNumber, $comment) { $url = '/repos/' . $this->user . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments'; - $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => "hello from Utopia!"]); - - return; + $response = $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => $comment]); + $commentId = $response["body"]["id"]; + return $commentId; } /** @@ -156,13 +156,13 @@ public function addComment($repoName, $pullRequestNumber) * @return array * @throws Exception */ - public function updateComment($repoName, $commentId) + public function updateComment($repoName, $commentId, $comment) { $url = '/repos/' . $this->user . '/' . $repoName . '/issues/comments/' . $commentId; - $this->call(self::METHOD_PATCH, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => "update from Utopia!"]); - - return; + $response = $this->call(self::METHOD_PATCH, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => $comment]); + $commentId = $response["body"]["id"]; + return $commentId; } /** diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index c2befc35..6ae4919f 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -31,12 +31,12 @@ public function testListRepositoriesForGitHubApp(): void public function testAddComment(): void { - $this->github->addComment("basic-js-crud", 1); + $commentId = $this->github->addComment("basic-js-crud", 1, "hello"); } public function testUpdateComment(): void { - $this->github->updateComment("basic-js-crud", 1431560395); + $commentId = $this->github->updateComment("basic-js-crud", 1431560395, "update"); } public function testDownloadRepositoryZip(): void From 297a6dccd3adadd0e20a33ad824f5e47a3ac9600 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 20 Apr 2023 00:56:56 +0530 Subject: [PATCH 027/147] Return action in parsed payload --- src/VCS/Adapter/Git/GitHub.php | 37 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index e88ef43e..1826da5a 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -281,27 +281,28 @@ public function parseWebhookEventPayload(string $event, string $payload) "repositoryId" => $repositoryId, "installationId" => $installationId ]); + break; case "pull_request": - if ($payload["action"] == "opened" or $payload["action"] == "reopened") { - $repositoryId = strval($payload["repository"]["id"]); - $branch = $payload["pull_request"]["head"]["ref"]; - $repositoryName = $payload["repository"]["name"]; - $pullRequestNumber = $payload["number"]; - return json_encode([ - "branch" => $branch, - "repositoryId" => $repositoryId, - "installationId" => $installationId, - "repositoryName" => $repositoryName, - "pullRequestNumber" => $pullRequestNumber - ]); - } + $repositoryId = strval($payload["repository"]["id"]); + $branch = $payload["pull_request"]["head"]["ref"]; + $repositoryName = $payload["repository"]["name"]; + $pullRequestNumber = $payload["number"]; + $action = $payload["action"]; + return json_encode([ + "action" => $action, + "branch" => $branch, + "repositoryId" => $repositoryId, + "installationId" => $installationId, + "repositoryName" => $repositoryName, + "pullRequestNumber" => $pullRequestNumber + ]); break; case "installation": - if ($payload["action"] == "deleted") { - return json_encode([ - "installationId" => $installationId - ]); - } + $action = $payload["action"]; + return json_encode([ + "action" => $action, + "installationId" => $installationId + ]); break; } return json_encode([]); From 18a6aa235362e0cc08e47670452dea89bcbb3548 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Apr 2023 01:04:53 +0530 Subject: [PATCH 028/147] Added getRepositoryName function --- src/VCS/Adapter/Git/GitHub.php | 8 +++++++- tests/VCS/GitHubTest.php | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 1826da5a..279cb924 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -307,4 +307,10 @@ public function parseWebhookEventPayload(string $event, string $payload) } return json_encode([]); } -} + + public function getRepositoryName(string $repoId) { + $url = "/repositories/$repoId"; + $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + return $response['body']['name']; + } +} \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 6ae4919f..0ddab701 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -121,4 +121,9 @@ public function testParseWebhookEventPayload(): void $this->github->parseWebhookEventPayload("pull_request", $payload_pull_request); $this->github->parseWebhookEventPayload("installation", $payload_uninstall); } + + public function testGetRepositoryName(): void + { + $repoName = $this->github->getRepositoryName("615825784"); + } } From 083d0a0c80d0dfbdc4fcdad86736363e4468c76f Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 3 May 2023 19:32:11 +0530 Subject: [PATCH 029/147] Added updateCommitStatus method --- src/VCS/Adapter/Git/GitHub.php | 25 +++++++++++++++++++++++++ tests/VCS/GitHubTest.php | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 279cb924..bb390318 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -308,9 +308,34 @@ public function parseWebhookEventPayload(string $event, string $payload) return json_encode([]); } + /** + * Fetches repository name using repository id + * + * @param string $repoId ID of GitHub Repository + * + * @return string name of GitHub repository + */ public function getRepositoryName(string $repoId) { $url = "/repositories/$repoId"; $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); return $response['body']['name']; } + + /** + * Updates status check of each commit + * state can be one of: error, failure, pending, success + */ + public function updateCommitStatus(string $repositoryName, string $commitSHA, string $state, string $description = "", string $target_url = "", string $context = "") { + $url = "/repos/$this->user/$repositoryName/statuses/$commitSHA"; + + $body = [ + "state" => $state, + "target_url" => $target_url, + "description" => $description, + "context" => $context + ]; + + $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], $body); + return; + } } \ No newline at end of file diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 0ddab701..715b7e14 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -126,4 +126,9 @@ public function testGetRepositoryName(): void { $repoName = $this->github->getRepositoryName("615825784"); } + + public function testUpdateCommitStatus(): void + { + $this->github->updateCommitStatus("functions-example", "a71dc759d5cbe5316c990f91f98de65d99f4ca64", "failure", "build failed", "", "Appwrite Deployment"); + } } From 5668309cc95c88a9d2718ba207833ba4cdc353d5 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 4 May 2023 18:45:19 +0530 Subject: [PATCH 030/147] Added commitSHA and repoName to push payload --- src/VCS/Adapter/Git/GitHub.php | 6 +++++- tests/VCS/GitHubTest.php | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index bb390318..7e371564 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -275,11 +275,15 @@ public function parseWebhookEventPayload(string $event, string $payload) case "push": $ref = $payload["ref"]; $repositoryId = strval($payload["repository"]["id"]); + $repositoryName = $payload["repository"]["name"]; + $commitSHA = $payload["after"]; $branch = str_replace("refs/heads/", "", $ref); return json_encode([ "branch" => $branch, "repositoryId" => $repositoryId, - "installationId" => $installationId + "installationId" => $installationId, + "repositoryName" => $repositoryName, + "commitSHA" => $commitSHA ]); break; case "pull_request": diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 715b7e14..f173226a 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -75,7 +75,7 @@ public function testParseWebhookEventPayload(): void $payload_push = '{ "ref": "refs/heads/main", "before": "1234", - "after": "1234", + "after": "4567", "repository": { "id": 603754812, "node_id": "R_kgDOI_yRPA", From 2b9da9ccc6732ca7278e711c26e807fc8955f335 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Fri, 5 May 2023 15:21:56 +0530 Subject: [PATCH 031/147] Use ownerName instead of App name in updateCommitStatus --- src/VCS/Adapter/Git/GitHub.php | 8 +++++--- tests/VCS/GitHubTest.php | 7 +++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 7e371564..61f98937 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -277,13 +277,15 @@ public function parseWebhookEventPayload(string $event, string $payload) $repositoryId = strval($payload["repository"]["id"]); $repositoryName = $payload["repository"]["name"]; $commitSHA = $payload["after"]; + $ownerName = $payload["repository"]["owner"]["name"]; $branch = str_replace("refs/heads/", "", $ref); return json_encode([ "branch" => $branch, "repositoryId" => $repositoryId, "installationId" => $installationId, "repositoryName" => $repositoryName, - "commitSHA" => $commitSHA + "commitSHA" => $commitSHA, + "ownerName" => $ownerName ]); break; case "pull_request": @@ -329,8 +331,8 @@ public function getRepositoryName(string $repoId) { * Updates status check of each commit * state can be one of: error, failure, pending, success */ - public function updateCommitStatus(string $repositoryName, string $commitSHA, string $state, string $description = "", string $target_url = "", string $context = "") { - $url = "/repos/$this->user/$repositoryName/statuses/$commitSHA"; + public function updateCommitStatus(string $repositoryName, string $commitSHA, string $ownerName, string $state, string $description = "", string $target_url = "", string $context = "") { + $url = "/repos/$ownerName/$repositoryName/statuses/$commitSHA"; $body = [ "state" => $state, diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index f173226a..d20eca35 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -102,7 +102,10 @@ public function testParseWebhookEventPayload(): void }, "repository": { "id": 3498, - "name": "functions-example" + "name": "functions-example", + "owner": { + "name": "vermakhushboo" + } }, "installation": { "id": 9876 @@ -129,6 +132,6 @@ public function testGetRepositoryName(): void public function testUpdateCommitStatus(): void { - $this->github->updateCommitStatus("functions-example", "a71dc759d5cbe5316c990f91f98de65d99f4ca64", "failure", "build failed", "", "Appwrite Deployment"); + $this->github->updateCommitStatus("functions-example", "a71dc759d5cbe5316c990f91f98de65d99f4ca64", "vermakhushboo", "failure", "build failed", "", "Appwrite Deployment"); } } From 018042e40350689d59bf5e31f973a76c1646d28d Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 9 May 2023 01:02:37 +0530 Subject: [PATCH 032/147] Added owner as param --- composer.json | 5 ++- composer.lock | 70 +++++++++++++++++++++++++++------- src/VCS/Adapter/Git/GitHub.php | 66 ++++++++++++++------------------ tests/VCS/GitHubTest.php | 15 ++++---- 4 files changed, 97 insertions(+), 59 deletions(-) diff --git a/composer.json b/composer.json index f2141d9a..7bc3e0be 100644 --- a/composer.json +++ b/composer.json @@ -19,10 +19,11 @@ "require": { "php": ">=8.0", "adhocore/jwt": "^1.1", - "vlucas/phpdotenv": "^5.5" + "vlucas/phpdotenv": "^5.5", + "utopia-php/framework": "^0.28.1" }, "require-dev": { "phpunit/phpunit": "^9.4", "laravel/pint": "1.2.*" } -} +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index 722ff179..26278765 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3ef6dcc55189772116160ad790e60d56", + "content-hash": "6a453a20aa07a52813264910470dd7d7", "packages": [ { "name": "adhocore/jwt", @@ -448,6 +448,50 @@ ], "time": "2022-11-03T14:55:06+00:00" }, + { + "name": "utopia-php/framework", + "version": "0.28.1", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/framework.git", + "reference": "7f22c556fc5991e54e5811a68fb39809b21bda55" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/7f22c556fc5991e54e5811a68fb39809b21bda55", + "reference": "7f22c556fc5991e54e5811a68fb39809b21bda55", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "require-dev": { + "laravel/pint": "^1.2", + "phpunit/phpunit": "^9.5.25", + "vimeo/psalm": "4.27.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple, light and advanced PHP framework", + "keywords": [ + "framework", + "php", + "upf" + ], + "support": { + "issues": "https://github.com/utopia-php/framework/issues", + "source": "https://github.com/utopia-php/framework/tree/0.28.1" + }, + "time": "2023-03-02T08:16:01+00:00" + }, { "name": "vlucas/phpdotenv", "version": "v5.5.0", @@ -1216,16 +1260,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.6", + "version": "9.6.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115" + "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115", - "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c993f0d3b0489ffc42ee2fe0bd645af1538a63b2", + "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2", "shasum": "" }, "require": { @@ -1299,7 +1343,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.7" }, "funding": [ { @@ -1315,7 +1359,7 @@ "type": "tidelift" } ], - "time": "2023-03-27T11:43:46+00:00" + "time": "2023-04-14T08:58:40+00:00" }, { "name": "sebastian/cli-parser", @@ -1617,16 +1661,16 @@ }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { @@ -1671,7 +1715,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" }, "funding": [ { @@ -1679,7 +1723,7 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 61f98937..be75d959 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -13,11 +13,6 @@ class GitHub extends Git */ protected $endpoint = 'https://api.github.com'; - /** - * @var string - */ - protected $user; - /** * @var string */ @@ -49,14 +44,9 @@ public function __construct() * GitHub constructor. * */ - public function initialiseVariables(string $installationId, string $privateKey, string $githubAppId, string $userName = "") + public function initialiseVariables(string $installationId, string $privateKey, string $githubAppId) { - // Set user name - $this->user = $userName; - - // Set installation id $this->installationId = $installationId; - $this->generateAccessToken($privateKey, $githubAppId); } @@ -114,9 +104,9 @@ public function isGitFlow(): bool * @return array * @throws Exception */ - public function getUser(): array + public function getUser(string $username): array { - $response = $this->call(self::METHOD_GET, '/users/' . $this->user); + $response = $this->call(self::METHOD_GET, '/users/' . $username); return $response; } @@ -141,9 +131,9 @@ public function listRepositoriesForGitHubApp(): array * @return array * @throws Exception */ - public function addComment($repoName, $pullRequestNumber, $comment) + public function addComment($owner, $repoName, $pullRequestNumber, $comment) { - $url = '/repos/' . $this->user . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments'; + $url = '/repos/' . $owner . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments'; $response = $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => $comment]); $commentId = $response["body"]["id"]; @@ -156,9 +146,9 @@ public function addComment($repoName, $pullRequestNumber, $comment) * @return array * @throws Exception */ - public function updateComment($repoName, $commentId, $comment) + public function updateComment($owner, $repoName, $commentId, $comment) { - $url = '/repos/' . $this->user . '/' . $repoName . '/issues/comments/' . $commentId; + $url = '/repos/' . $owner . '/' . $repoName . '/issues/comments/' . $commentId; $response = $this->call(self::METHOD_PATCH, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => $comment]); $commentId = $response["body"]["id"]; @@ -173,10 +163,10 @@ public function updateComment($repoName, $commentId, $comment) * @param string $path The path of the file or directory to download. Optional. * @return string The contents of the ZIP archive as a string. */ - public function downloadRepositoryZip(string $repoName, string $ref, string $path = ''): string + public function downloadRepositoryZip(string $owner, string $repoName, string $ref, string $path = ''): string { // Build the URL for the API request - $url = "/repos/" . $this->user . "/{$repoName}/zipball/{$ref}"; + $url = "/repos/" . $owner . "/{$repoName}/zipball/{$ref}"; // Add the path parameter to the URL query parameters, if specified if (!empty($path)) { @@ -196,10 +186,10 @@ public function downloadRepositoryZip(string $repoName, string $ref, string $pat * @param string $ref The name of the commit, branch, or tag to download. * @return string The contents of the tar archive as a string. */ - public function downloadRepositoryTar(string $repoName, string $ref): string + public function downloadRepositoryTar(string $owner, string $repoName, string $ref): string { // Build the URL for the API request - $url = "/repos/" . $this->user . "/{$repoName}/tarball/{$ref}"; + $url = "/repos/" . $owner . "/{$repoName}/tarball/{$ref}"; $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); @@ -241,7 +231,7 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio * * @return string The git clone command as a string */ - public function generateGitCloneCommand(string $repoID, string $branchName) + public function generateGitCloneCommand(string $owner, string $repoID, string $branchName) { $url = "/repositories/{$repoID}"; @@ -250,7 +240,7 @@ public function generateGitCloneCommand(string $repoID, string $branchName) $repoUrl = $repoData["body"]["html_url"]; // Construct the clone URL with the access token - $cloneUrl = str_replace("https://", "https://{$this->user}:{$this->accessToken}@", $repoUrl); + $cloneUrl = str_replace("https://", "https://{$owner}:{$this->accessToken}@", $repoUrl); // Construct the Git clone command with the clone URL $command = "git clone -b " . $branchName . " --depth=1 {$cloneUrl}"; @@ -276,17 +266,17 @@ public function parseWebhookEventPayload(string $event, string $payload) $ref = $payload["ref"]; $repositoryId = strval($payload["repository"]["id"]); $repositoryName = $payload["repository"]["name"]; - $commitSHA = $payload["after"]; - $ownerName = $payload["repository"]["owner"]["name"]; + $SHA = $payload["after"]; + $owner = $payload["repository"]["owner"]["name"]; $branch = str_replace("refs/heads/", "", $ref); - return json_encode([ + return [ "branch" => $branch, "repositoryId" => $repositoryId, "installationId" => $installationId, "repositoryName" => $repositoryName, - "commitSHA" => $commitSHA, - "ownerName" => $ownerName - ]); + "SHA" => $SHA, + "owner" => $owner + ]; break; case "pull_request": $repositoryId = strval($payload["repository"]["id"]); @@ -294,24 +284,26 @@ public function parseWebhookEventPayload(string $event, string $payload) $repositoryName = $payload["repository"]["name"]; $pullRequestNumber = $payload["number"]; $action = $payload["action"]; - return json_encode([ + $owner = $payload["repository"]["owner"]["login"]; + return [ "action" => $action, "branch" => $branch, "repositoryId" => $repositoryId, "installationId" => $installationId, "repositoryName" => $repositoryName, - "pullRequestNumber" => $pullRequestNumber - ]); + "pullRequestNumber" => $pullRequestNumber, + "owner" => $owner + ]; break; case "installation": $action = $payload["action"]; - return json_encode([ + return [ "action" => $action, "installationId" => $installationId - ]); + ]; break; } - return json_encode([]); + return []; } /** @@ -331,8 +323,8 @@ public function getRepositoryName(string $repoId) { * Updates status check of each commit * state can be one of: error, failure, pending, success */ - public function updateCommitStatus(string $repositoryName, string $commitSHA, string $ownerName, string $state, string $description = "", string $target_url = "", string $context = "") { - $url = "/repos/$ownerName/$repositoryName/statuses/$commitSHA"; + public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = "", string $target_url = "", string $context = "") { + $url = "/repos/$owner/$repositoryName/statuses/$SHA"; $body = [ "state" => $state, diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index d20eca35..680f2201 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -21,7 +21,7 @@ public function setUp(): void public function testGetUser(): void { - $this->github->getUser(); + $this->github->getUser("vermakhushboo"); } public function testListRepositoriesForGitHubApp(): void @@ -31,18 +31,18 @@ public function testListRepositoriesForGitHubApp(): void public function testAddComment(): void { - $commentId = $this->github->addComment("basic-js-crud", 1, "hello"); + $commentId = $this->github->addComment("vermakhushboo", "basic-js-crud", 1, "hello"); } public function testUpdateComment(): void { - $commentId = $this->github->updateComment("basic-js-crud", 1431560395, "update"); + $commentId = $this->github->updateComment("vermakhushboo", "basic-js-crud", 1431560395, "update"); } public function testDownloadRepositoryZip(): void { // download the zip archive of the repo - $zipContents = $this->github->downloadRepositoryZip("gatsby-ecommerce-theme", "main"); + $zipContents = $this->github->downloadRepositoryZip("vermakhushboo", "gatsby-ecommerce-theme", "main"); // Save the ZIP archive to a file file_put_contents('./desktop/hello-world.zip', $zipContents); @@ -51,7 +51,7 @@ public function testDownloadRepositoryZip(): void public function testDownloadRepositoryTar(): void { // download the tar archive of the repo - $tarContents = $this->github->downloadRepositoryTar("gatsby-ecommerce-theme", "main"); + $tarContents = $this->github->downloadRepositoryTar("vermakhushboo", "gatsby-ecommerce-theme", "main"); // Save the TAR archive to a file file_put_contents('./desktop/hello-world1.tar', $tarContents); @@ -66,7 +66,7 @@ public function testForkRepository(): void public function testGenerateGitCloneCommand(): string { $repoId = "155386150"; - $gitCloneCommand = $this->github->generateGitCloneCommand($repoId, "main"); + $gitCloneCommand = $this->github->generateGitCloneCommand("vermakhushboo", $repoId, "main"); return $gitCloneCommand; } @@ -83,6 +83,7 @@ public function testParseWebhookEventPayload(): void "full_name": "vermakhushboo/testing-fork", "private": true, "owner": { + "name": "vermakhushboo" } }, "installation": { @@ -104,7 +105,7 @@ public function testParseWebhookEventPayload(): void "id": 3498, "name": "functions-example", "owner": { - "name": "vermakhushboo" + "login": "vermakhushboo" } }, "installation": { From f46e635b88d93c8dc0df22b3a24f8a13c4a179e6 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 10 May 2023 21:38:13 +0530 Subject: [PATCH 033/147] Add searchRepos method --- src/VCS/Adapter/Git/GitHub.php | 21 +++++++++++++++++++-- tests/VCS/GitHubTest.php | 5 +++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index be75d959..5e5310b7 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -125,6 +125,21 @@ public function listRepositoriesForGitHubApp(): array return $response['body']['repositories']; } + /** + * Search repositories for specified user + * + * @return array + * @throws Exception + */ + public function searchRepositories($owner, $query, $page, $per_page): array + { + $url = '/search/repositories?q=' . $query . '+user%3A' . $owner . '&type=repositories&sort=updated&page=' . $page . '&per_page=' . $per_page; + + $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + + return $response['body']['items']; + } + /** * Add Comment to Pull Request * @@ -313,7 +328,8 @@ public function parseWebhookEventPayload(string $event, string $payload) * * @return string name of GitHub repository */ - public function getRepositoryName(string $repoId) { + public function getRepositoryName(string $repoId) + { $url = "/repositories/$repoId"; $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); return $response['body']['name']; @@ -323,7 +339,8 @@ public function getRepositoryName(string $repoId) { * Updates status check of each commit * state can be one of: error, failure, pending, success */ - public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = "", string $target_url = "", string $context = "") { + public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = "", string $target_url = "", string $context = "") + { $url = "/repos/$owner/$repositoryName/statuses/$SHA"; $body = [ diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 680f2201..1485af31 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -29,6 +29,11 @@ public function testListRepositoriesForGitHubApp(): void $repos = $this->github->listRepositoriesForGitHubApp(); } + public function testSearchRepositories() : void + { + $repos = $this->github->searchRepositories("vermakhushboo", "f", 1, 5); + } + public function testAddComment(): void { $commentId = $this->github->addComment("vermakhushboo", "basic-js-crud", 1, "hello"); From 5c1e622f65588c61e3e042ee391785f1540ddc09 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 10 May 2023 23:05:27 +0530 Subject: [PATCH 034/147] Parse name of user who installed app --- src/VCS/Adapter/Git/GitHub.php | 4 +++- tests/VCS/GitHubTest.php | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 5e5310b7..785bd262 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -312,9 +312,11 @@ public function parseWebhookEventPayload(string $event, string $payload) break; case "installation": $action = $payload["action"]; + $userName = $payload["installation"]["account"]["login"]; return [ "action" => $action, - "installationId" => $installationId + "installationId" => $installationId, + "userName" => $userName ]; break; } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 1485af31..1b8abb49 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -121,7 +121,10 @@ public function testParseWebhookEventPayload(): void $payload_uninstall = '{ "action": "deleted", "installation": { - "id": 1234 + "id": 1234, + "account": { + "login": "vermakhushboo" + } } } '; From a8c0ceebc3320544b7a5b21ca3f1b8754b9494d6 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Fri, 12 May 2023 16:08:15 +0530 Subject: [PATCH 035/147] Also parse payload on permission updated --- src/VCS/Adapter/Git/GitHub.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 785bd262..ea0a82ac 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -76,6 +76,7 @@ protected function generateAccessToken(string $privateKey, string $githubAppId) $token = $jwt->encode($payload); $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); $this->accessToken = $res['body']['token']; + var_dump($this->accessToken); } /** @@ -310,7 +311,7 @@ public function parseWebhookEventPayload(string $event, string $payload) "owner" => $owner ]; break; - case "installation": + case ("installation" || "installation_repositories"): $action = $payload["action"]; $userName = $payload["installation"]["account"]["login"]; return [ From 8a1e3b9b906e41a145b7cdb4c96be8979643cd8e Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Fri, 12 May 2023 16:55:55 +0530 Subject: [PATCH 036/147] Added var_dump --- src/VCS/Adapter/Git/GitHub.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index ea0a82ac..5d372559 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -135,6 +135,7 @@ public function listRepositoriesForGitHubApp(): array public function searchRepositories($owner, $query, $page, $per_page): array { $url = '/search/repositories?q=' . $query . '+user%3A' . $owner . '&type=repositories&sort=updated&page=' . $page . '&per_page=' . $per_page; + var_dump($url); $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); From 3f0b12bb5b80e8f8a563dfe0141ba2432d10e507 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 17 May 2023 13:58:51 +0530 Subject: [PATCH 037/147] Added page number and per_page query params to list repos --- src/VCS/Adapter/Git/GitHub.php | 20 ++------------------ tests/VCS/GitHubTest.php | 7 +------ 2 files changed, 3 insertions(+), 24 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 5d372559..b995b4bd 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -117,31 +117,15 @@ public function getUser(string $username): array * @return array * @throws Exception */ - public function listRepositoriesForGitHubApp(): array + public function listRepositoriesForGitHubApp($page, $per_page): array { - $url = '/installation/repositories'; + $url = '/installation/repositories?page=' . $page . '&per_page=' . $per_page; $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); return $response['body']['repositories']; } - /** - * Search repositories for specified user - * - * @return array - * @throws Exception - */ - public function searchRepositories($owner, $query, $page, $per_page): array - { - $url = '/search/repositories?q=' . $query . '+user%3A' . $owner . '&type=repositories&sort=updated&page=' . $page . '&per_page=' . $per_page; - var_dump($url); - - $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); - - return $response['body']['items']; - } - /** * Add Comment to Pull Request * diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 1b8abb49..8bc6a208 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -26,12 +26,7 @@ public function testGetUser(): void public function testListRepositoriesForGitHubApp(): void { - $repos = $this->github->listRepositoriesForGitHubApp(); - } - - public function testSearchRepositories() : void - { - $repos = $this->github->searchRepositories("vermakhushboo", "f", 1, 5); + $repos = $this->github->listRepositoriesForGitHubApp(1, 5); } public function testAddComment(): void From 93eeea20f0033202067a3e88c1fd5542651e7c0c Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 17 May 2023 15:54:19 +0530 Subject: [PATCH 038/147] Added getTotalReposCount method --- src/VCS/Adapter/Git/GitHub.php | 11 ++++++++++- tests/VCS/GitHubTest.php | 11 ++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index b995b4bd..c4859293 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -126,6 +126,15 @@ public function listRepositoriesForGitHubApp($page, $per_page): array return $response['body']['repositories']; } + public function getTotalReposCount(): int + { + $url = '/installation/repositories'; + + $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + + return $response['body']['total_count']; + } + /** * Add Comment to Pull Request * @@ -341,4 +350,4 @@ public function updateCommitStatus(string $repositoryName, string $SHA, string $ $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], $body); return; } -} \ No newline at end of file +} diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 8bc6a208..29398916 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -29,6 +29,11 @@ public function testListRepositoriesForGitHubApp(): void $repos = $this->github->listRepositoriesForGitHubApp(1, 5); } + public function testGetTotalReposCount(): void + { + $count = $this->github->getTotalReposCount(); + } + public function testAddComment(): void { $commentId = $this->github->addComment("vermakhushboo", "basic-js-crud", 1, "hello"); @@ -134,8 +139,8 @@ public function testGetRepositoryName(): void $repoName = $this->github->getRepositoryName("615825784"); } - public function testUpdateCommitStatus(): void - { + public function testUpdateCommitStatus(): void + { $this->github->updateCommitStatus("functions-example", "a71dc759d5cbe5316c990f91f98de65d99f4ca64", "vermakhushboo", "failure", "build failed", "", "Appwrite Deployment"); - } + } } From 774b6424a6d2d186d9713e863384857e3bb6ca0a Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 22 May 2023 15:57:30 +0530 Subject: [PATCH 039/147] Updated utopia framework version --- composer.json | 2 +- composer.lock | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/composer.json b/composer.json index 7bc3e0be..b5301bfa 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "php": ">=8.0", "adhocore/jwt": "^1.1", "vlucas/phpdotenv": "^5.5", - "utopia-php/framework": "^0.28.1" + "utopia-php/framework": "0.26.*" }, "require-dev": { "phpunit/phpunit": "^9.4", diff --git a/composer.lock b/composer.lock index 26278765..59517d96 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6a453a20aa07a52813264910470dd7d7", + "content-hash": "d13c62261f4722e3361d82b5f689e477", "packages": [ { "name": "adhocore/jwt", @@ -450,16 +450,16 @@ }, { "name": "utopia-php/framework", - "version": "0.28.1", + "version": "0.26.0", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "7f22c556fc5991e54e5811a68fb39809b21bda55" + "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/7f22c556fc5991e54e5811a68fb39809b21bda55", - "reference": "7f22c556fc5991e54e5811a68fb39809b21bda55", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/e8da5576370366d3bf9c574ec855f8c96fe4f34e", + "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e", "shasum": "" }, "require": { @@ -488,9 +488,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.28.1" + "source": "https://github.com/utopia-php/framework/tree/0.26.0" }, - "time": "2023-03-02T08:16:01+00:00" + "time": "2023-01-13T08:14:43+00:00" }, { "name": "vlucas/phpdotenv", @@ -775,16 +775,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.4", + "version": "v4.15.5", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290" + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/6bb5176bc4af8bcb7d926f88718db9b96a2d4290", - "reference": "6bb5176bc4af8bcb7d926f88718db9b96a2d4290", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", "shasum": "" }, "require": { @@ -825,9 +825,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" }, - "time": "2023-03-05T19:49:14+00:00" + "time": "2023-05-19T20:20:00+00:00" }, { "name": "phar-io/manifest", @@ -1260,16 +1260,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.7", + "version": "9.6.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2" + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c993f0d3b0489ffc42ee2fe0bd645af1538a63b2", - "reference": "c993f0d3b0489ffc42ee2fe0bd645af1538a63b2", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", "shasum": "" }, "require": { @@ -1343,7 +1343,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.7" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" }, "funding": [ { @@ -1359,7 +1359,7 @@ "type": "tidelift" } ], - "time": "2023-04-14T08:58:40+00:00" + "time": "2023-05-11T05:14:45+00:00" }, { "name": "sebastian/cli-parser", From a3f5d680e79431b661bde03774b8c4e4d71e6023 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 22 May 2023 18:26:31 +0530 Subject: [PATCH 040/147] Add getOwnerName method --- src/VCS/Adapter/Git/GitHub.php | 18 ++++++++++++++++++ tests/VCS/GitHubTest.php | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index c4859293..e567111f 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -18,6 +18,11 @@ class GitHub extends Git */ protected $accessToken; + /** + * @var string + */ + protected $jwtToken; + /** * @var string */ @@ -74,6 +79,7 @@ protected function generateAccessToken(string $privateKey, string $githubAppId) // generate access token $jwt = new JWT($privateKey, 'RS256'); $token = $jwt->encode($payload); + $this->jwtToken = $token; $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); $this->accessToken = $res['body']['token']; var_dump($this->accessToken); @@ -111,6 +117,18 @@ public function getUser(string $username): array return $response; } + /** + * Get owner name of the GitHub installation + * + * @return string + */ + public function getOwnerName($installationId): string + { + $url = '/app/installations/' . $installationId; + $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->jwtToken"]); + return $response['body']['account']['login']; + } + /** * List repositories for GitHub App * diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 29398916..b09f462d 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -24,6 +24,11 @@ public function testGetUser(): void $this->github->getUser("vermakhushboo"); } + public function testGetOwnerName(): void + { + $owner = $this->github->getOwnerName("37569846"); + } + public function testListRepositoriesForGitHubApp(): void { $repos = $this->github->listRepositoriesForGitHubApp(1, 5); From 198669f5b9a1eb984a4307030c07474e58776685 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 25 May 2023 19:51:28 +0530 Subject: [PATCH 041/147] Added listBranches method --- src/VCS/Adapter/Git/GitHub.php | 18 ++++++++++++++++++ tests/VCS/GitHubTest.php | 5 +++++ 2 files changed, 23 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index e567111f..295339cf 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -350,6 +350,24 @@ public function getRepositoryName(string $repoId) return $response['body']['name']; } + /** + * Lists branches for a given repository + * + * @param string $owner Owner name of the repository + * + * @param string $repositoryName Name of the GitHub repository + * + * @return array List of branch names as array + */ + public function listBranches(string $owner, string $repositoryName): array + { + $url = "/repos/$owner/$repositoryName/branches"; + + $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + + return $response['body']; + } + /** * Updates status check of each commit * state can be one of: error, failure, pending, success diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index b09f462d..2aef19c3 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -148,4 +148,9 @@ public function testUpdateCommitStatus(): void { $this->github->updateCommitStatus("functions-example", "a71dc759d5cbe5316c990f91f98de65d99f4ca64", "vermakhushboo", "failure", "build failed", "", "Appwrite Deployment"); } + + public function testListBranches(): void + { + $this->github->listBranches("vermakhushboo", "functions-example"); + } } From de473962979c1ebd9c98952a0c22ce3e29242002 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 25 May 2023 20:55:45 +0530 Subject: [PATCH 042/147] Return names of branches instead of payload --- src/VCS/Adapter/Git/GitHub.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 295339cf..b0f67750 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -364,8 +364,13 @@ public function listBranches(string $owner, string $repositoryName): array $url = "/repos/$owner/$repositoryName/branches"; $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + + $names = []; + foreach ($response['body'] as $subarray) { + $names[] = $subarray["name"]; + } - return $response['body']; + return $names; } /** From 220a93ed1fedcce23312f5b3cf2c557e54746f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 26 May 2023 10:26:42 +0200 Subject: [PATCH 043/147] Fixed formatting, added cache --- composer.json | 5 +- composer.lock | 51 ++++++- src/VCS/Adapter.php | 56 +++++--- src/VCS/Adapter/Git.php | 6 +- src/VCS/Adapter/Git/GitHub.php | 254 +++++++++++++++++---------------- tests/VCS/GitHubTest.php | 39 ++--- 6 files changed, 242 insertions(+), 169 deletions(-) diff --git a/composer.json b/composer.json index b5301bfa..ea1950eb 100644 --- a/composer.json +++ b/composer.json @@ -20,10 +20,11 @@ "php": ">=8.0", "adhocore/jwt": "^1.1", "vlucas/phpdotenv": "^5.5", - "utopia-php/framework": "0.26.*" + "utopia-php/framework": "0.26.*", + "utopia-php/cache": "^0.8.0" }, "require-dev": { "phpunit/phpunit": "^9.4", "laravel/pint": "1.2.*" } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index 59517d96..4c0638d9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d13c62261f4722e3361d82b5f689e477", + "content-hash": "defc15760be761695f6779d67d8bba72", "packages": [ { "name": "adhocore/jwt", @@ -448,6 +448,55 @@ ], "time": "2022-11-03T14:55:06+00:00" }, + { + "name": "utopia-php/cache", + "version": "0.8.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/cache.git", + "reference": "212e66100a1f32e674fca5d9bc317cc998303089" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/cache/zipball/212e66100a1f32e674fca5d9bc317cc998303089", + "reference": "212e66100a1f32e674fca5d9bc317cc998303089", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-memcached": "*", + "ext-redis": "*", + "php": ">=8.0" + }, + "require-dev": { + "laravel/pint": "1.2.*", + "phpunit/phpunit": "^9.3", + "vimeo/psalm": "4.13.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Cache\\": "src/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A simple cache library to manage application cache storing, loading and purging", + "keywords": [ + "cache", + "framework", + "php", + "upf", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/cache/issues", + "source": "https://github.com/utopia-php/cache/tree/0.8.0" + }, + "time": "2022-10-16T16:48:09+00:00" + }, { "name": "utopia-php/framework", "version": "0.26.0", diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 2e98dbed..e9785968 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -4,16 +4,24 @@ use Exception; -abstract class Adapter{ - +abstract class Adapter +{ public const METHOD_GET = 'GET'; + public const METHOD_POST = 'POST'; + public const METHOD_PUT = 'PUT'; + public const METHOD_PATCH = 'PATCH'; + public const METHOD_DELETE = 'DELETE'; + public const METHOD_HEAD = 'HEAD'; + public const METHOD_OPTIONS = 'OPTIONS'; + public const METHOD_CONNECT = 'CONNECT'; + public const METHOD_TRACE = 'TRACE'; /** @@ -42,22 +50,23 @@ abstract class Adapter{ * * Make an API call * - * @param string $method - * @param string $path - * @param array $params - * @param array $headers - * @param bool $decode + * @param string $method + * @param string $path + * @param array $params + * @param array $headers + * @param bool $decode * @return array|string + * * @throws Exception */ public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true) { - $headers = array_merge($this->headers, $headers); - $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); - $responseHeaders = []; - $responseStatus = -1; - $responseType = ''; - $responseBody = ''; + $headers = array_merge($this->headers, $headers); + $ch = curl_init($this->endpoint.$path.(($method == self::METHOD_GET && ! empty($params)) ? '?'.http_build_query($params) : '')); + $responseHeaders = []; + $responseStatus = -1; + $responseType = ''; + $responseBody = ''; switch ($headers['content-type']) { case 'application/json': @@ -78,7 +87,7 @@ public function call(string $method, string $path = '', array $headers = [], arr } foreach ($headers as $i => $header) { - $headers[] = $i . ':' . $header; + $headers[] = $i.':'.$header; unset($headers[$i]); } @@ -113,8 +122,8 @@ public function call(string $method, string $path = '', array $headers = [], arr curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - $responseBody = curl_exec($ch); - $responseType = $responseHeaders['content-type'] ?? ''; + $responseBody = curl_exec($ch); + $responseType = $responseHeaders['content-type'] ?? ''; $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($decode) { @@ -123,7 +132,7 @@ public function call(string $method, string $path = '', array $headers = [], arr $json = json_decode($responseBody, true); if ($json === null) { - throw new Exception('Failed to parse response: ' . $responseBody); + throw new Exception('Failed to parse response: '.$responseBody); } $responseBody = $json; @@ -133,7 +142,7 @@ public function call(string $method, string $path = '', array $headers = [], arr } if ((curl_errno($ch)/* || 200 != $responseStatus*/)) { - throw new Exception(curl_error($ch) . ' with status code ' . $responseStatus, $responseStatus); + throw new Exception(curl_error($ch).' with status code '.$responseStatus, $responseStatus); } curl_close($ch); @@ -141,20 +150,20 @@ public function call(string $method, string $path = '', array $headers = [], arr $responseHeaders['status-code'] = $responseStatus; if ($responseStatus === 500) { - echo 'Server error(' . $method . ': ' . $path . '. Params: ' . json_encode($params) . '): ' . json_encode($responseBody) . "\n"; + echo 'Server error('.$method.': '.$path.'. Params: '.json_encode($params).'): '.json_encode($responseBody)."\n"; } return [ 'headers' => $responseHeaders, - 'body' => $responseBody + 'body' => $responseBody, ]; } /** * Flatten params array to PHP multiple format * - * @param array $data - * @param string $prefix + * @param array $data + * @param string $prefix * @return array */ protected function flatten(array $data, string $prefix = ''): array @@ -170,6 +179,7 @@ protected function flatten(array $data, string $prefix = ''): array $output[$finalKey] = $value; } } + return $output; } -} \ No newline at end of file +} diff --git a/src/VCS/Adapter/Git.php b/src/VCS/Adapter/Git.php index dc69214f..21114f33 100644 --- a/src/VCS/Adapter/Git.php +++ b/src/VCS/Adapter/Git.php @@ -4,6 +4,6 @@ use Utopia\VCS\Adapter; -abstract class Git extends Adapter{ - -} \ No newline at end of file +abstract class Git extends Adapter +{ +} diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index b0f67750..ef38bcbb 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -2,64 +2,68 @@ namespace Utopia\VCS\Adapter\Git; -use Exception; use Ahc\Jwt\JWT; +use Exception; +use Utopia\Cache\Cache; use Utopia\VCS\Adapter\Git; class GitHub extends Git { - /** - * @var string - */ - protected $endpoint = 'https://api.github.com'; + const EVENT_PUSH = 'push'; - /** - * @var string - */ - protected $accessToken; + const EVENT_PULL_REQUEST = 'pull_request'; - /** - * @var string - */ - protected $jwtToken; + const EVENT_INSTALLATION = 'installation'; - /** - * @var string - */ - protected $installationId; + protected string $endpoint = 'https://api.github.com'; - const EVENT_PUSH = 'push'; + protected string $accessToken; - const EVENT_PULL_REQUEST = 'pull_request'; + protected string $jwtToken; - const EVENT_INSTALLATION = 'installation'; + protected string $installationId; + + protected Cache $cache; /** * Global Headers * - * @var array + * @var array */ protected $headers = ['content-type' => 'application/json']; - public function __construct() + public function __construct(Cache $cache) { + $this->cache = $cache; } /** * GitHub constructor. - * */ public function initialiseVariables(string $installationId, string $privateKey, string $githubAppId) { $this->installationId = $installationId; - $this->generateAccessToken($privateKey, $githubAppId); + + $response = $this->cache->load($installationId, 60 * 9); // 10 minutes, but 1 minute earlier to be safe + if (! $response) { + $this->generateAccessToken($privateKey, $githubAppId); + + $this->cache->save($installationId, \json_encode([ + 'jwtToken' => $this->jwtToken, + 'accessToken' => $this->accessToken, + ])); + } else { + $parsed = \json_decode($response, true); + $this->jwtToken = $parsed['jwtToken']; + $this->accessToken = $parsed['accessToken']; + } } /** * Generate Access Token * - * @param string $userName The username of account which has installed GitHub app - * @param string $installationId Installation ID of the GitHub App + * @param string $userName The username of account which has installed GitHub app + * @param string $installationId Installation ID of the GitHub App */ protected function generateAccessToken(string $privateKey, string $githubAppId) { @@ -80,24 +84,24 @@ protected function generateAccessToken(string $privateKey, string $githubAppId) $jwt = new JWT($privateKey, 'RS256'); $token = $jwt->encode($payload); $this->jwtToken = $token; - $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); + $res = $this->call(self::METHOD_POST, '/app/installations/'.$this->installationId.'/access_tokens', ['Authorization' => 'Bearer '.$token]); $this->accessToken = $res['body']['token']; var_dump($this->accessToken); } /** * Get Adapter Name - * + * * @return string */ public function getName(): string { - return "github"; + return 'github'; } /** * Is Git Flow - * + * * @return bool */ public function isGitFlow(): bool @@ -109,23 +113,26 @@ public function isGitFlow(): bool * Get user * * @return array + * * @throws Exception */ public function getUser(string $username): array { - $response = $this->call(self::METHOD_GET, '/users/' . $username); + $response = $this->call(self::METHOD_GET, '/users/'.$username); + return $response; } /** - * Get owner name of the GitHub installation + * Get owner name of the GitHub installation * * @return string */ public function getOwnerName($installationId): string { - $url = '/app/installations/' . $installationId; - $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->jwtToken"]); + $url = '/app/installations/'.$installationId; + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->jwtToken"]); + return $response['body']['account']['login']; } @@ -133,13 +140,14 @@ public function getOwnerName($installationId): string * List repositories for GitHub App * * @return array + * * @throws Exception */ public function listRepositoriesForGitHubApp($page, $per_page): array { - $url = '/installation/repositories?page=' . $page . '&per_page=' . $per_page; + $url = '/installation/repositories?page='.$page.'&per_page='.$per_page; - $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); return $response['body']['repositories']; } @@ -148,7 +156,7 @@ public function getTotalReposCount(): int { $url = '/installation/repositories'; - $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); return $response['body']['total_count']; } @@ -157,14 +165,16 @@ public function getTotalReposCount(): int * Add Comment to Pull Request * * @return array + * * @throws Exception */ public function addComment($owner, $repoName, $pullRequestNumber, $comment) { - $url = '/repos/' . $owner . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments'; + $url = '/repos/'.$owner.'/'.$repoName.'/issues/'.$pullRequestNumber.'/comments'; + + $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); + $commentId = $response['body']['id']; - $response = $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => $comment]); - $commentId = $response["body"]["id"]; return $commentId; } @@ -172,36 +182,38 @@ public function addComment($owner, $repoName, $pullRequestNumber, $comment) * Update Pull Request Comment * * @return array + * * @throws Exception */ public function updateComment($owner, $repoName, $commentId, $comment) { - $url = '/repos/' . $owner . '/' . $repoName . '/issues/comments/' . $commentId; + $url = '/repos/'.$owner.'/'.$repoName.'/issues/comments/'.$commentId; + + $response = $this->call(self::METHOD_PATCH, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); + $commentId = $response['body']['id']; - $response = $this->call(self::METHOD_PATCH, $url, ["Authorization" => "Bearer $this->accessToken"], ["body" => $comment]); - $commentId = $response["body"]["id"]; return $commentId; } /** * Downloads a ZIP archive of a repository. * - * @param string $repo The name of the repository. - * @param string $ref The name of the commit, branch, or tag to download. - * @param string $path The path of the file or directory to download. Optional. + * @param string $repo The name of the repository. + * @param string $ref The name of the commit, branch, or tag to download. + * @param string $path The path of the file or directory to download. Optional. * @return string The contents of the ZIP archive as a string. */ public function downloadRepositoryZip(string $owner, string $repoName, string $ref, string $path = ''): string { // Build the URL for the API request - $url = "/repos/" . $owner . "/{$repoName}/zipball/{$ref}"; + $url = '/repos/'.$owner."/{$repoName}/zipball/{$ref}"; // Add the path parameter to the URL query parameters, if specified - if (!empty($path)) { + if (! empty($path)) { $url .= "?path={$path}"; } - $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); // Return the contents of the ZIP archive return $response['body']; @@ -210,16 +222,16 @@ public function downloadRepositoryZip(string $owner, string $repoName, string $r /** * Downloads a tar archive of a repository. * - * @param string $repo The name of the repository. - * @param string $ref The name of the commit, branch, or tag to download. + * @param string $repo The name of the repository. + * @param string $ref The name of the commit, branch, or tag to download. * @return string The contents of the tar archive as a string. */ public function downloadRepositoryTar(string $owner, string $repoName, string $ref): string { // Build the URL for the API request - $url = "/repos/" . $owner . "/{$repoName}/tarball/{$ref}"; + $url = '/repos/'.$owner."/{$repoName}/tarball/{$ref}"; - $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); // Return the contents of the tar archive return $response['body']; @@ -228,12 +240,11 @@ public function downloadRepositoryTar(string $owner, string $repoName, string $r /** * Forks a repository on GitHub. * - * @param string $owner The owner of the repository to fork. - * @param string $repo The name of the repository to fork. - * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. - * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. - * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. - * + * @param string $owner The owner of the repository to fork. + * @param string $repo The name of the repository to fork. + * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. + * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. + * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. * @return array|null The data of the newly forked repository, or null if the fork operation failed. */ public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?array @@ -248,30 +259,30 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio ]; // Send the API request to fork the repository - $response = $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], $data); + $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $data); + return $response['body']; } /** * Generates a git clone command using app access token * - * @param string $repoId The ID of the repo to be cloned - * + * @param string $repoId The ID of the repo to be cloned * @return string The git clone command as a string */ public function generateGitCloneCommand(string $owner, string $repoID, string $branchName) { $url = "/repositories/{$repoID}"; - $repoData = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + $repoData = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - $repoUrl = $repoData["body"]["html_url"]; + $repoUrl = $repoData['body']['html_url']; // Construct the clone URL with the access token - $cloneUrl = str_replace("https://", "https://{$owner}:{$this->accessToken}@", $repoUrl); + $cloneUrl = str_replace('https://', "https://{$owner}:{$this->accessToken}@", $repoUrl); // Construct the Git clone command with the clone URL - $command = "git clone -b " . $branchName . " --depth=1 {$cloneUrl}"; + $command = 'git clone -b '.$branchName." --depth=1 {$cloneUrl}"; return $command; } @@ -279,97 +290,98 @@ public function generateGitCloneCommand(string $owner, string $repoID, string $b /** * Parses webhook event payload * - * @param string $event Type of event: push, pull_request etc - * @param string $payload The webhook payload received from GitHub - * + * @param string $event Type of event: push, pull_request etc + * @param string $payload The webhook payload received from GitHub * @return json Parsed payload as a json object */ public function parseWebhookEventPayload(string $event, string $payload) { $payload = json_decode($payload, true); - $installationId = strval($payload["installation"]["id"]); + $installationId = strval($payload['installation']['id']); switch ($event) { - case "push": - $ref = $payload["ref"]; - $repositoryId = strval($payload["repository"]["id"]); - $repositoryName = $payload["repository"]["name"]; - $SHA = $payload["after"]; - $owner = $payload["repository"]["owner"]["name"]; - $branch = str_replace("refs/heads/", "", $ref); + case 'push': + $ref = $payload['ref']; + $repositoryId = strval($payload['repository']['id']); + $repositoryName = $payload['repository']['name']; + $SHA = $payload['after']; + $owner = $payload['repository']['owner']['name']; + $branch = str_replace('refs/heads/', '', $ref); + return [ - "branch" => $branch, - "repositoryId" => $repositoryId, - "installationId" => $installationId, - "repositoryName" => $repositoryName, - "SHA" => $SHA, - "owner" => $owner + 'branch' => $branch, + 'repositoryId' => $repositoryId, + 'installationId' => $installationId, + 'repositoryName' => $repositoryName, + 'SHA' => $SHA, + 'owner' => $owner, ]; break; - case "pull_request": - $repositoryId = strval($payload["repository"]["id"]); - $branch = $payload["pull_request"]["head"]["ref"]; - $repositoryName = $payload["repository"]["name"]; - $pullRequestNumber = $payload["number"]; - $action = $payload["action"]; - $owner = $payload["repository"]["owner"]["login"]; + case 'pull_request': + $repositoryId = strval($payload['repository']['id']); + $branch = $payload['pull_request']['head']['ref']; + $repositoryName = $payload['repository']['name']; + $pullRequestNumber = $payload['number']; + $action = $payload['action']; + $owner = $payload['repository']['owner']['login']; + return [ - "action" => $action, - "branch" => $branch, - "repositoryId" => $repositoryId, - "installationId" => $installationId, - "repositoryName" => $repositoryName, - "pullRequestNumber" => $pullRequestNumber, - "owner" => $owner + 'action' => $action, + 'branch' => $branch, + 'repositoryId' => $repositoryId, + 'installationId' => $installationId, + 'repositoryName' => $repositoryName, + 'pullRequestNumber' => $pullRequestNumber, + 'owner' => $owner, ]; break; - case ("installation" || "installation_repositories"): - $action = $payload["action"]; - $userName = $payload["installation"]["account"]["login"]; + case 'installation' || 'installation_repositories': + $action = $payload['action']; + $userName = $payload['installation']['account']['login']; + return [ - "action" => $action, - "installationId" => $installationId, - "userName" => $userName + 'action' => $action, + 'installationId' => $installationId, + 'userName' => $userName, ]; break; } + return []; } /** * Fetches repository name using repository id * - * @param string $repoId ID of GitHub Repository - * + * @param string $repoId ID of GitHub Repository * @return string name of GitHub repository */ public function getRepositoryName(string $repoId) { $url = "/repositories/$repoId"; - $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + return $response['body']['name']; } /** * Lists branches for a given repository * - * @param string $owner Owner name of the repository - * - * @param string $repositoryName Name of the GitHub repository - * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository * @return array List of branch names as array */ public function listBranches(string $owner, string $repositoryName): array { $url = "/repos/$owner/$repositoryName/branches"; - - $response = $this->call(self::METHOD_GET, $url, ["Authorization" => "Bearer $this->accessToken"]); + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); $names = []; foreach ($response['body'] as $subarray) { - $names[] = $subarray["name"]; + $names[] = $subarray['name']; } - + return $names; } @@ -377,18 +389,18 @@ public function listBranches(string $owner, string $repositoryName): array * Updates status check of each commit * state can be one of: error, failure, pending, success */ - public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = "", string $target_url = "", string $context = "") + public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = '', string $target_url = '', string $context = '') { $url = "/repos/$owner/$repositoryName/statuses/$SHA"; $body = [ - "state" => $state, - "target_url" => $target_url, - "description" => $description, - "context" => $context + 'state' => $state, + 'target_url' => $target_url, + 'description' => $description, + 'context' => $context, ]; - $this->call(self::METHOD_POST, $url, ["Authorization" => "Bearer $this->accessToken"], $body); - return; + $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $body); + } } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 2aef19c3..e7dc6903 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -13,20 +13,20 @@ class GitHubTest extends TestCase public function setUp(): void { $this->github = new GitHub(); - $privateKey = App::getEnv("GITHUB_PRIVATE_KEY"); - $githubAppId = App::getEnv("GITHUB_APP_IDENTIFIER"); - $installationId = "1234"; //your GitHub App Installation ID here - $this->github->initialiseVariables($installationId, $privateKey, $githubAppId, "vermakhushboo"); + $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); + $installationId = '1234'; //your GitHub App Installation ID here + $this->github->initialiseVariables($installationId, $privateKey, $githubAppId, 'vermakhushboo'); } public function testGetUser(): void { - $this->github->getUser("vermakhushboo"); + $this->github->getUser('vermakhushboo'); } public function testGetOwnerName(): void { - $owner = $this->github->getOwnerName("37569846"); + $owner = $this->github->getOwnerName('37569846'); } public function testListRepositoriesForGitHubApp(): void @@ -41,18 +41,18 @@ public function testGetTotalReposCount(): void public function testAddComment(): void { - $commentId = $this->github->addComment("vermakhushboo", "basic-js-crud", 1, "hello"); + $commentId = $this->github->addComment('vermakhushboo', 'basic-js-crud', 1, 'hello'); } public function testUpdateComment(): void { - $commentId = $this->github->updateComment("vermakhushboo", "basic-js-crud", 1431560395, "update"); + $commentId = $this->github->updateComment('vermakhushboo', 'basic-js-crud', 1431560395, 'update'); } public function testDownloadRepositoryZip(): void { // download the zip archive of the repo - $zipContents = $this->github->downloadRepositoryZip("vermakhushboo", "gatsby-ecommerce-theme", "main"); + $zipContents = $this->github->downloadRepositoryZip('vermakhushboo', 'gatsby-ecommerce-theme', 'main'); // Save the ZIP archive to a file file_put_contents('./desktop/hello-world.zip', $zipContents); @@ -61,7 +61,7 @@ public function testDownloadRepositoryZip(): void public function testDownloadRepositoryTar(): void { // download the tar archive of the repo - $tarContents = $this->github->downloadRepositoryTar("vermakhushboo", "gatsby-ecommerce-theme", "main"); + $tarContents = $this->github->downloadRepositoryTar('vermakhushboo', 'gatsby-ecommerce-theme', 'main'); // Save the TAR archive to a file file_put_contents('./desktop/hello-world1.tar', $tarContents); @@ -70,13 +70,14 @@ public function testDownloadRepositoryTar(): void public function testForkRepository(): void { // Fork a repository into authenticated user's account with custom name - $response = $this->github->forkRepository("appwrite", "demos-for-astro", name: "fork-api-test-clone"); + $response = $this->github->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); } public function testGenerateGitCloneCommand(): string { - $repoId = "155386150"; - $gitCloneCommand = $this->github->generateGitCloneCommand("vermakhushboo", $repoId, "main"); + $repoId = '155386150'; + $gitCloneCommand = $this->github->generateGitCloneCommand('vermakhushboo', $repoId, 'main'); + return $gitCloneCommand; } @@ -134,23 +135,23 @@ public function testParseWebhookEventPayload(): void } '; - $this->github->parseWebhookEventPayload("push", $payload_push); - $this->github->parseWebhookEventPayload("pull_request", $payload_pull_request); - $this->github->parseWebhookEventPayload("installation", $payload_uninstall); + $this->github->parseWebhookEventPayload('push', $payload_push); + $this->github->parseWebhookEventPayload('pull_request', $payload_pull_request); + $this->github->parseWebhookEventPayload('installation', $payload_uninstall); } public function testGetRepositoryName(): void { - $repoName = $this->github->getRepositoryName("615825784"); + $repoName = $this->github->getRepositoryName('615825784'); } public function testUpdateCommitStatus(): void { - $this->github->updateCommitStatus("functions-example", "a71dc759d5cbe5316c990f91f98de65d99f4ca64", "vermakhushboo", "failure", "build failed", "", "Appwrite Deployment"); + $this->github->updateCommitStatus('functions-example', 'a71dc759d5cbe5316c990f91f98de65d99f4ca64', 'vermakhushboo', 'failure', 'build failed', '', 'Appwrite Deployment'); } public function testListBranches(): void { - $this->github->listBranches("vermakhushboo", "functions-example"); + $this->github->listBranches('vermakhushboo', 'functions-example'); } } From 1331193f6ba0443a87f4fd665a8f91dc07817370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 26 May 2023 10:41:54 +0200 Subject: [PATCH 044/147] Fix tests --- src/VCS/Adapter.php | 16 +++------------- src/VCS/Adapter/Git/GitHub.php | 3 +-- tests/VCS/GitHubTest.php | 4 +++- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index e9785968..a582d515 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -24,24 +24,14 @@ abstract class Adapter public const METHOD_TRACE = 'TRACE'; - /** - * Is Self Signed Certificates Allowed? - * - * @var bool - */ - protected $selfSigned = true; + protected bool $selfSigned = true; - /** - * Service host name - * - * @var string - */ - protected $endpoint; + protected string $endpoint; /** * Global Headers * - * @var array + * @var array */ protected $headers = []; diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index ef38bcbb..17c49788 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -45,7 +45,7 @@ public function initialiseVariables(string $installationId, string $privateKey, $this->installationId = $installationId; $response = $this->cache->load($installationId, 60 * 9); // 10 minutes, but 1 minute earlier to be safe - if (! $response) { + if ($response == false) { $this->generateAccessToken($privateKey, $githubAppId); $this->cache->save($installationId, \json_encode([ @@ -401,6 +401,5 @@ public function updateCommitStatus(string $repositoryName, string $SHA, string $ ]; $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $body); - } } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index e7dc6903..45967c79 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -4,6 +4,8 @@ use PHPUnit\Framework\TestCase; use Utopia\App; +use Utopia\Cache\Adapter\None; +use Utopia\Cache\Cache; use Utopia\VCS\Adapter\Git\GitHub; class GitHubTest extends TestCase @@ -12,7 +14,7 @@ class GitHubTest extends TestCase public function setUp(): void { - $this->github = new GitHub(); + $this->github = new GitHub(new Cache(new None())); $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); $installationId = '1234'; //your GitHub App Installation ID here From 9215381b4fde95e26ab1f01d5add6d2d428d6fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 28 May 2023 12:14:37 +0200 Subject: [PATCH 045/147] add getComment --- src/VCS/Adapter/Git/GitHub.php | 19 ++++++++++++++++++- tests/VCS/GitHubTest.php | 6 ++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 17c49788..cc50bfea 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -168,7 +168,7 @@ public function getTotalReposCount(): int * * @throws Exception */ - public function addComment($owner, $repoName, $pullRequestNumber, $comment) + public function createComment($owner, $repoName, $pullRequestNumber, $comment) { $url = '/repos/'.$owner.'/'.$repoName.'/issues/'.$pullRequestNumber.'/comments'; @@ -178,6 +178,23 @@ public function addComment($owner, $repoName, $pullRequestNumber, $comment) return $commentId; } + /** + * Get Comment of Pull Request + * + * @return string + * + * @throws Exception + */ + public function getComment($owner, $repoName, $commentId): string + { + $url = '/repos/'.$owner.'/'.$repoName.'/issues/comments/'.$commentId; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + $comment = $response['body']['body']; + + return $comment; + } + /** * Update Pull Request Comment * diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 45967c79..4d2df478 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -41,9 +41,11 @@ public function testGetTotalReposCount(): void $count = $this->github->getTotalReposCount(); } - public function testAddComment(): void + // TODO: testGetComment() + + public function testCreateComment(): void { - $commentId = $this->github->addComment('vermakhushboo', 'basic-js-crud', 1, 'hello'); + $commentId = $this->github->createComment('vermakhushboo', 'basic-js-crud', 1, 'hello'); } public function testUpdateComment(): void From 30b9c9193c5897d1bbb1937bdf734f1d9e653a94 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Sun, 4 Jun 2023 20:31:30 +0530 Subject: [PATCH 046/147] WIP: Auto-Runtime Detection --- src/Detector/Adapter/Dart.php | 59 ++++++++++++++++++++++++ src/Detector/Adapter/JavaScript.php | 69 +++++++++++++++++++++++++++++ src/Detector/Adapter/PHP.php | 52 ++++++++++++++++++++++ src/Detector/Adapter/Python.php | 52 ++++++++++++++++++++++ src/Detector/Adapter/Ruby.php | 65 +++++++++++++++++++++++++++ src/Detector/Detector.php | 25 +++++++++++ src/Detector/DetectorFactory.php | 27 +++++++++++ tests/Detector/DetectorTest.php | 35 +++++++++++++++ 8 files changed, 384 insertions(+) create mode 100644 src/Detector/Adapter/Dart.php create mode 100644 src/Detector/Adapter/JavaScript.php create mode 100644 src/Detector/Adapter/PHP.php create mode 100644 src/Detector/Adapter/Python.php create mode 100644 src/Detector/Adapter/Ruby.php create mode 100644 src/Detector/Detector.php create mode 100644 src/Detector/DetectorFactory.php create mode 100644 tests/Detector/DetectorTest.php diff --git a/src/Detector/Adapter/Dart.php b/src/Detector/Adapter/Dart.php new file mode 100644 index 00000000..83447962 --- /dev/null +++ b/src/Detector/Adapter/Dart.php @@ -0,0 +1,59 @@ +files)) { + return true; + } + + if (isset($this->languages[self::DETECTOR_DART])) { + return true; + } + + if ( + in_array('lib/main.dart', $this->files) || + in_array('pubspec.lock', $this->files) + ) { + return true; + } + + // foreach ($this->files as $file) { + // if (pathinfo($file, PATHINFO_EXTENSION) === 'dart') { + // return true; + // } + // } + + return false; + } +} diff --git a/src/Detector/Adapter/JavaScript.php b/src/Detector/Adapter/JavaScript.php new file mode 100644 index 00000000..4397b400 --- /dev/null +++ b/src/Detector/Adapter/JavaScript.php @@ -0,0 +1,69 @@ +files)) { + return true; + } + + if (isset($this->languages[self::DETECTOR_JAVASCRIPT])) { + return true; + } + + if ( + in_array('src/index.js', $this->files) || + in_array('webpack.config.js', $this->files) || + in_array('.babelrc', $this->files) || + in_array('.eslintrc.js', $this->files) + ) { + return true; + } + + if ( + in_array('package-lock.json', $this->files) || + in_array('yarn.lock', $this->files) + ) { + return true; + } + + // Check if any JavaScript files are present in the project + // foreach ($this->files as $file) { + // if (pathinfo($file, PATHINFO_EXTENSION) === 'js') { + // return true; + // } + // } + + return false; + } +} diff --git a/src/Detector/Adapter/PHP.php b/src/Detector/Adapter/PHP.php new file mode 100644 index 00000000..28f56c93 --- /dev/null +++ b/src/Detector/Adapter/PHP.php @@ -0,0 +1,52 @@ +files)) { + return true; + } + + if (isset($this->languages[self::DETECTOR_PHP])) { + return true; + } + + // foreach ($this->files as $file) { + // if (pathinfo($file, PATHINFO_EXTENSION) === 'php') { + // return $this; + // } + // } + + return false; + } +} diff --git a/src/Detector/Adapter/Python.php b/src/Detector/Adapter/Python.php new file mode 100644 index 00000000..2c8e53a2 --- /dev/null +++ b/src/Detector/Adapter/Python.php @@ -0,0 +1,52 @@ +files)) { + return true; + } + + if (isset($this->languages[self::DETECTOR_PYTHON])) { + return true; + } + + // foreach ($this->files as $file) { + // if (pathinfo($file, PATHINFO_EXTENSION) === 'py') { + // return true; + // } + // } + + return false; + } +} diff --git a/src/Detector/Adapter/Ruby.php b/src/Detector/Adapter/Ruby.php new file mode 100644 index 00000000..d5ca529a --- /dev/null +++ b/src/Detector/Adapter/Ruby.php @@ -0,0 +1,65 @@ +files) || in_array('Gemfile.lock', $this->files)) { + return true; + } + + if (isset($this->languages[self::DETECTOR_RUBY])) { + return true; + } + + if ( + in_array('config.ru', $this->files) || + in_array('Rakefile', $this->files) || + in_array('Gemspec', $this->files) || + in_array('Capfile', $this->files) + ) { + return true; + } + + if (in_array('Rakefile', $this->files) || in_array('Guardfile', $this->files)) { + return true; + } + + // foreach ($this->files as $file) { + // if (pathinfo($file, PATHINFO_EXTENSION) === 'rb') { + // return true; + // } + // } + + return false; + } +} diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php new file mode 100644 index 00000000..55497097 --- /dev/null +++ b/src/Detector/Detector.php @@ -0,0 +1,25 @@ +files = $files; + $this->languages = $languages; + } + + abstract public function getLanguage(): ?string; + + abstract public function getRuntime(): ?string; + + abstract public function getInstallCommand(): ?string; + + abstract public function getBuildCommand(): ?string; + + abstract public function getEntryPoint(): ?string; + + abstract public function detect(): ?bool; +} \ No newline at end of file diff --git a/src/Detector/DetectorFactory.php b/src/Detector/DetectorFactory.php new file mode 100644 index 00000000..c579ac12 --- /dev/null +++ b/src/Detector/DetectorFactory.php @@ -0,0 +1,27 @@ +detectors = $detectors; + } + + public function addDetector(Detector $detector): self + { + $this->detectors[] = $detector; + return $this; + } + + public function detect(): ?Detector + { + foreach ($this->detectors as $detector) { + if ($detector->detect()) { + return $detector->getRuntime(); + } + } + return null; + } +} \ No newline at end of file diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php new file mode 100644 index 00000000..13aff39d --- /dev/null +++ b/tests/Detector/DetectorTest.php @@ -0,0 +1,35 @@ +addDetector(new JavaScript($files, $languages)) + ->addDetector(new PHP($files, $languages)) + ->addDetector(new Python($files, $languages)) + ->addDetector(new Dart($files, $languages)) + ->addDetector(new Ruby($files, $languages)); + + + var_dump($detectorFactory->detect()); + + // // Ensure that detect() returns null when no detector matches + // $this->assertNull($detectorFactory->detect()); + } +} From f25e7497e9f5abf3141415963c58c2661ecd769b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 4 Jun 2023 17:12:21 +0200 Subject: [PATCH 047/147] Fix imports --- composer.json | 2 +- composer.lock | 12 ++++++------ src/Detector/Adapter/Dart.php | 4 ++++ src/Detector/Adapter/JavaScript.php | 4 ++++ src/Detector/Adapter/PHP.php | 4 ++++ src/Detector/Adapter/Python.php | 4 ++++ src/Detector/Adapter/Ruby.php | 4 ++++ src/Detector/Detector.php | 2 ++ src/Detector/DetectorFactory.php | 4 +++- tests/Detector/DetectorTest.php | 14 +++++++------- 10 files changed, 39 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index ea1950eb..52de7d73 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "test": "vendor/bin/phpunit --configuration phpunit.xml" }, "autoload": { - "psr-4": {"Utopia\\VCS\\": "src/VCS"} + "psr-4": {"Utopia\\VCS\\": "src/VCS", "Utopia\\Detector\\": "src/Detector"} }, "autoload-dev": { "psr-4": {"Utopia\\Tests\\": "tests/VCS"} diff --git a/composer.lock b/composer.lock index 4c0638d9..bd1fa8e9 100644 --- a/composer.lock +++ b/composer.lock @@ -499,16 +499,16 @@ }, { "name": "utopia-php/framework", - "version": "0.26.0", + "version": "0.26.3", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e" + "reference": "7a18a2b0d6c8dba878c926b73650fd2c4eeaa70d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/e8da5576370366d3bf9c574ec855f8c96fe4f34e", - "reference": "e8da5576370366d3bf9c574ec855f8c96fe4f34e", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/7a18a2b0d6c8dba878c926b73650fd2c4eeaa70d", + "reference": "7a18a2b0d6c8dba878c926b73650fd2c4eeaa70d", "shasum": "" }, "require": { @@ -537,9 +537,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.26.0" + "source": "https://github.com/utopia-php/framework/tree/0.26.3" }, - "time": "2023-01-13T08:14:43+00:00" + "time": "2023-06-03T14:01:15+00:00" }, { "name": "vlucas/phpdotenv", diff --git a/src/Detector/Adapter/Dart.php b/src/Detector/Adapter/Dart.php index 83447962..e083ce59 100644 --- a/src/Detector/Adapter/Dart.php +++ b/src/Detector/Adapter/Dart.php @@ -1,5 +1,9 @@ detectors as $detector) { if ($detector->detect()) { diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 13aff39d..cae1fb4e 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -3,16 +3,16 @@ namespace Utopia\Tests; use PHPUnit\Framework\TestCase; -use DetectorFactory; -use Dart; -use JavaScript; -use PHP; -use Python; -use Ruby; +use Utopia\Detector\Adapter\Dart; +use Utopia\Detector\Adapter\JavaScript; +use Utopia\Detector\Adapter\PHP; +use Utopia\Detector\Adapter\Python; +use Utopia\Detector\Adapter\Ruby; +use Utopia\Detector\DetectorFactory; class DetectorTest extends TestCase { - public function testDetect(){ + public function testDetect() { $files = ['package.json', 'src/index.js', 'src/components/main.svelte']; $languages = ['Javascript']; From 418df43419d6c388d0b98bfc73494d0fd320b4aa Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:35:44 +0530 Subject: [PATCH 048/147] Fix check languages array logic --- src/Detector/Adapter/Dart.php | 2 +- src/Detector/Adapter/JavaScript.php | 2 +- src/Detector/Adapter/PHP.php | 2 +- src/Detector/Adapter/Python.php | 2 +- src/Detector/Adapter/Ruby.php | 2 +- tests/Detector/DetectorTest.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Detector/Adapter/Dart.php b/src/Detector/Adapter/Dart.php index e083ce59..7e1ac1ad 100644 --- a/src/Detector/Adapter/Dart.php +++ b/src/Detector/Adapter/Dart.php @@ -41,7 +41,7 @@ public function detect(): bool return true; } - if (isset($this->languages[self::DETECTOR_DART])) { + if (in_array(self::DETECTOR_DART, $this->languages)) { return true; } diff --git a/src/Detector/Adapter/JavaScript.php b/src/Detector/Adapter/JavaScript.php index f4059db0..67784871 100644 --- a/src/Detector/Adapter/JavaScript.php +++ b/src/Detector/Adapter/JavaScript.php @@ -41,7 +41,7 @@ public function detect(): ?bool return true; } - if (isset($this->languages[self::DETECTOR_JAVASCRIPT])) { + if (in_array(self::DETECTOR_JAVASCRIPT, $this->languages)) { return true; } diff --git a/src/Detector/Adapter/PHP.php b/src/Detector/Adapter/PHP.php index a402f9c1..dccb6bfb 100644 --- a/src/Detector/Adapter/PHP.php +++ b/src/Detector/Adapter/PHP.php @@ -41,7 +41,7 @@ public function detect(): ?bool return true; } - if (isset($this->languages[self::DETECTOR_PHP])) { + if (in_array(self::DETECTOR_PHP, $this->languages)) { return true; } diff --git a/src/Detector/Adapter/Python.php b/src/Detector/Adapter/Python.php index 874733d3..66188594 100644 --- a/src/Detector/Adapter/Python.php +++ b/src/Detector/Adapter/Python.php @@ -41,7 +41,7 @@ public function detect(): ?bool return true; } - if (isset($this->languages[self::DETECTOR_PYTHON])) { + if (in_array(self::DETECTOR_PYTHON, $this->languages)) { return true; } diff --git a/src/Detector/Adapter/Ruby.php b/src/Detector/Adapter/Ruby.php index 9288b60c..c7f892de 100644 --- a/src/Detector/Adapter/Ruby.php +++ b/src/Detector/Adapter/Ruby.php @@ -41,7 +41,7 @@ public function detect(): ?bool return true; } - if (isset($this->languages[self::DETECTOR_RUBY])) { + if (in_array(self::DETECTOR_RUBY, $this->languages)) { return true; } diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index cae1fb4e..256756fc 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -29,7 +29,7 @@ public function testDetect() { var_dump($detectorFactory->detect()); - // // Ensure that detect() returns null when no detector matches + // Ensure that detect() returns null when no detector matches // $this->assertNull($detectorFactory->detect()); } } From 911900d661d9f0c5066ae3f9e8448c15b8545669 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:57:56 +0530 Subject: [PATCH 049/147] Add getRepositoryLanguages method --- src/VCS/Adapter/Git/GitHub.php | 20 ++++++++++++++++++++ tests/VCS/GitHubTest.php | 11 +++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index cc50bfea..116a5179 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -419,4 +419,24 @@ public function updateCommitStatus(string $repositoryName, string $SHA, string $ $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $body); } + + /** + * Get repository languages + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @return array|null List of repository languages or null if the request fails + */ + public function getRepositoryLanguages(string $owner, string $repositoryName): ?array + { + $url = "/repos/$owner/$repositoryName/languages"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + if (isset($response['body'])) { + return $response['body']; + } + + return null; + } } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 4d2df478..cc4b21f0 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -158,4 +158,15 @@ public function testListBranches(): void { $this->github->listBranches('vermakhushboo', 'functions-example'); } + + public function testGetRepositoryLanguages(): void + { + $languages = $this->github->getRepositoryLanguages('vermakhushboo', 'basic-js-crud'); + + $this->assertIsArray($languages); + + $this->assertArrayHasKey('JavaScript', $languages); + $this->assertArrayHasKey('HTML', $languages); + $this->assertArrayHasKey('CSS', $languages); + } } From e0246bbabe7a47136d8fb9a3bc94536b6b03ab06 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 6 Jun 2023 16:53:18 +0530 Subject: [PATCH 050/147] Add listRepositoryContents method --- src/VCS/Adapter/Git/GitHub.php | 19 +++++++++++++++++++ tests/VCS/GitHubTest.php | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 116a5179..0df0cbfe 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -439,4 +439,23 @@ public function getRepositoryLanguages(string $owner, string $repositoryName): ? return null; } + + /** + * List contents of the specified root directory. + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @param string $path Path to list contents from + * @return array List of contents at the specified path + */ + public function listRepositoryContents(string $owner, string $repositoryName, string $path): array + { + $url = "/repos/$owner/$repositoryName/contents/$path"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return array_map(static function ($item) { + return $item['name']; + }, $response['body']); + } } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index cc4b21f0..62f6745c 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -169,4 +169,9 @@ public function testGetRepositoryLanguages(): void $this->assertArrayHasKey('HTML', $languages); $this->assertArrayHasKey('CSS', $languages); } + + public function testListRepositoryContents(): void + { + $contents = $this-> github->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); + } } From 6a5e3aa2e7fc3f4f0d6b9efbdcfd02916b47a4b1 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 6 Jun 2023 17:15:34 +0530 Subject: [PATCH 051/147] Updated detector test --- src/VCS/Adapter/Git/GitHub.php | 9 ++++++--- tests/Detector/DetectorTest.php | 17 +++++++++++++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 0df0cbfe..21b4cb2a 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -448,14 +448,17 @@ public function getRepositoryLanguages(string $owner, string $repositoryName): ? * @param string $path Path to list contents from * @return array List of contents at the specified path */ - public function listRepositoryContents(string $owner, string $repositoryName, string $path): array + public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array { - $url = "/repos/$owner/$repositoryName/contents/$path"; + $url = "/repos/$owner/$repositoryName/contents"; + if (!empty($path)) { + $url .= "/$path"; + } $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); return array_map(static function ($item) { return $item['name']; - }, $response['body']); + }, $response['body']); } } diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 256756fc..1d31343c 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -9,13 +9,22 @@ use Utopia\Detector\Adapter\Python; use Utopia\Detector\Adapter\Ruby; use Utopia\Detector\DetectorFactory; +use Utopia\App; +use Utopia\Cache\Adapter\None; +use Utopia\Cache\Cache; +use Utopia\VCS\Adapter\Git\GitHub; class DetectorTest extends TestCase { public function testDetect() { - - $files = ['package.json', 'src/index.js', 'src/components/main.svelte']; - $languages = ['Javascript']; + $github = new GitHub(new Cache(new None())); + $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); + $installationId = '1234'; //your GitHub App Installation ID here + $github->initialiseVariables($installationId, $privateKey, $githubAppId, 'vermakhushboo'); + + $files = $github->listRepositoryContents('appwrite', 'appwrite'); + $languages = $github->getRepositoryLanguages('appwrite', 'appwrite'); $detectorFactory = new DetectorFactory(); // Add some detectors to the factory @@ -27,7 +36,7 @@ public function testDetect() { ->addDetector(new Ruby($files, $languages)); - var_dump($detectorFactory->detect()); + $runtime = $detectorFactory->detect(); // Ensure that detect() returns null when no detector matches // $this->assertNull($detectorFactory->detect()); From 27c6662ff207c1c1e85c7dc6de87059cda9ada03 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 7 Jun 2023 12:27:31 +0530 Subject: [PATCH 052/147] Update src/Detector/Adapter/JavaScript.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matej Bačo --- src/Detector/Adapter/JavaScript.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Detector/Adapter/JavaScript.php b/src/Detector/Adapter/JavaScript.php index 67784871..551f7c18 100644 --- a/src/Detector/Adapter/JavaScript.php +++ b/src/Detector/Adapter/JavaScript.php @@ -25,7 +25,7 @@ public function getBuildCommand(): string return 'npm build'; } - public function getEntryPoint(): string + public function getEntrypoint(): string { return 'src/index.js'; } From 832b165cf1843a920eaff81d97c7dcd5d2e4543c Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 7 Jun 2023 16:18:32 +0530 Subject: [PATCH 053/147] Removed vlucas dependency --- composer.json | 1 - composer.lock | 471 +-------------------------------------- src/VCS/Adapter.php | 2 +- tests/VCS/GitHubTest.php | 4 +- 4 files changed, 3 insertions(+), 475 deletions(-) diff --git a/composer.json b/composer.json index 52de7d73..d5729eea 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,6 @@ "require": { "php": ">=8.0", "adhocore/jwt": "^1.1", - "vlucas/phpdotenv": "^5.5", "utopia-php/framework": "0.26.*", "utopia-php/cache": "^0.8.0" }, diff --git a/composer.lock b/composer.lock index bd1fa8e9..de77eec3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "defc15760be761695f6779d67d8bba72", + "content-hash": "7427d56641753b0991ad05ef5c7a168f", "packages": [ { "name": "adhocore/jwt", @@ -63,391 +63,6 @@ ], "time": "2021-02-20T09:56:44+00:00" }, - { - "name": "graham-campbell/result-type", - "version": "v1.1.1", - "source": { - "type": "git", - "url": "https://github.com/GrahamCampbell/Result-Type.git", - "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", - "reference": "672eff8cf1d6fe1ef09ca0f89c4b287d6a3eb831", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0", - "phpoption/phpoption": "^1.9.1" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" - }, - "type": "library", - "autoload": { - "psr-4": { - "GrahamCampbell\\ResultType\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - } - ], - "description": "An Implementation Of The Result Type", - "keywords": [ - "Graham Campbell", - "GrahamCampbell", - "Result Type", - "Result-Type", - "result" - ], - "support": { - "issues": "https://github.com/GrahamCampbell/Result-Type/issues", - "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.1" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", - "type": "tidelift" - } - ], - "time": "2023-02-25T20:23:15+00:00" - }, - { - "name": "phpoption/phpoption", - "version": "1.9.1", - "source": { - "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", - "shasum": "" - }, - "require": { - "php": "^7.2.5 || ^8.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": true - }, - "branch-alias": { - "dev-master": "1.9-dev" - } - }, - "autoload": { - "psr-4": { - "PhpOption\\": "src/PhpOption/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh" - }, - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - } - ], - "description": "Option Type for PHP", - "keywords": [ - "language", - "option", - "php", - "type" - ], - "support": { - "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", - "type": "tidelift" - } - ], - "time": "2023-02-25T19:38:58+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, { "name": "utopia-php/cache", "version": "0.8.0", @@ -540,90 +155,6 @@ "source": "https://github.com/utopia-php/framework/tree/0.26.3" }, "time": "2023-06-03T14:01:15+00:00" - }, - { - "name": "vlucas/phpdotenv", - "version": "v5.5.0", - "source": { - "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", - "shasum": "" - }, - "require": { - "ext-pcre": "*", - "graham-campbell/result-type": "^1.0.2", - "php": "^7.1.3 || ^8.0", - "phpoption/phpoption": "^1.8", - "symfony/polyfill-ctype": "^1.23", - "symfony/polyfill-mbstring": "^1.23.1", - "symfony/polyfill-php80": "^1.23.1" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.4.1", - "ext-filter": "*", - "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25" - }, - "suggest": { - "ext-filter": "Required to use the boolean validator." - }, - "type": "library", - "extra": { - "bamarni-bin": { - "bin-links": true, - "forward-command": true - }, - "branch-alias": { - "dev-master": "5.5-dev" - } - }, - "autoload": { - "psr-4": { - "Dotenv\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Graham Campbell", - "email": "hello@gjcampbell.co.uk", - "homepage": "https://github.com/GrahamCampbell" - }, - { - "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "https://github.com/vlucas" - } - ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", - "keywords": [ - "dotenv", - "env", - "environment" - ], - "support": { - "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0" - }, - "funding": [ - { - "url": "https://github.com/GrahamCampbell", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", - "type": "tidelift" - } - ], - "time": "2022-10-16T01:01:54+00:00" } ], "packages-dev": [ diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index a582d515..0e6d66fb 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -49,7 +49,7 @@ abstract class Adapter * * @throws Exception */ - public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true) + protected function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true) { $headers = array_merge($this->headers, $headers); $ch = curl_init($this->endpoint.$path.(($method == self::METHOD_GET && ! empty($params)) ? '?'.http_build_query($params) : '')); diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 62f6745c..4b8b2aa8 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -77,12 +77,10 @@ public function testForkRepository(): void $response = $this->github->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); } - public function testGenerateGitCloneCommand(): string + public function testGenerateGitCloneCommand(): void { $repoId = '155386150'; $gitCloneCommand = $this->github->generateGitCloneCommand('vermakhushboo', $repoId, 'main'); - - return $gitCloneCommand; } public function testParseWebhookEventPayload(): void From d919ac9299acbf154c155bd46db9e171c839bc67 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 7 Jun 2023 16:37:16 +0530 Subject: [PATCH 054/147] Pass and to DetectorFactory --- src/Detector/Detector.php | 16 ++++++++++------ src/Detector/DetectorFactory.php | 9 +++++++-- tests/Detector/DetectorTest.php | 12 ++++++------ 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php index 214f690a..32abc403 100644 --- a/src/Detector/Detector.php +++ b/src/Detector/Detector.php @@ -7,12 +7,6 @@ abstract class Detector protected $files; protected $languages; - public function __construct(array $files, array $languages) - { - $this->files = $files; - $this->languages = $languages; - } - abstract public function getLanguage(): ?string; abstract public function getRuntime(): ?string; @@ -24,4 +18,14 @@ abstract public function getBuildCommand(): ?string; abstract public function getEntryPoint(): ?string; abstract public function detect(): ?bool; + + public function setFiles(array $files): void + { + $this->files = $files; + } + + public function setLanguages(array $languages): void + { + $this->languages = $languages; + } } \ No newline at end of file diff --git a/src/Detector/DetectorFactory.php b/src/Detector/DetectorFactory.php index ebc542de..76d71bdf 100644 --- a/src/Detector/DetectorFactory.php +++ b/src/Detector/DetectorFactory.php @@ -5,14 +5,19 @@ class DetectorFactory { protected $detectors = []; + protected $files; + protected $languages; - public function __construct(array $detectors = []) + public function __construct(array $files = [], array $languages = []) { - $this->detectors = $detectors; + $this->files = $files; + $this->languages = $languages; } public function addDetector(Detector $detector): self { + $detector->setFiles($this->files); + $detector->setLanguages($this->languages); $this->detectors[] = $detector; return $this; } diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 1d31343c..45c36eac 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -25,15 +25,15 @@ public function testDetect() { $files = $github->listRepositoryContents('appwrite', 'appwrite'); $languages = $github->getRepositoryLanguages('appwrite', 'appwrite'); - $detectorFactory = new DetectorFactory(); + $detectorFactory = new DetectorFactory($files, $languages); // Add some detectors to the factory $detectorFactory - ->addDetector(new JavaScript($files, $languages)) - ->addDetector(new PHP($files, $languages)) - ->addDetector(new Python($files, $languages)) - ->addDetector(new Dart($files, $languages)) - ->addDetector(new Ruby($files, $languages)); + ->addDetector(new JavaScript()) + ->addDetector(new PHP()) + ->addDetector(new Python()) + ->addDetector(new Dart()) + ->addDetector(new Ruby()); $runtime = $detectorFactory->detect(); From a13e2e3621ae45132cf89163aa7848c940367f9c Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 7 Jun 2023 16:51:22 +0530 Subject: [PATCH 055/147] Renamed files as per adapter pattern --- src/Detector/Adapter.php | 31 +++++++++++++++++++++++++ src/Detector/Adapter/Dart.php | 4 ++-- src/Detector/Adapter/JavaScript.php | 4 ++-- src/Detector/Adapter/PHP.php | 4 ++-- src/Detector/Adapter/Python.php | 4 ++-- src/Detector/Adapter/Ruby.php | 4 ++-- src/Detector/Detector.php | 35 ++++++++++++++++------------- src/Detector/DetectorFactory.php | 34 ---------------------------- tests/Detector/DetectorTest.php | 4 ++-- 9 files changed, 62 insertions(+), 62 deletions(-) create mode 100644 src/Detector/Adapter.php delete mode 100644 src/Detector/DetectorFactory.php diff --git a/src/Detector/Adapter.php b/src/Detector/Adapter.php new file mode 100644 index 00000000..f4c4bc97 --- /dev/null +++ b/src/Detector/Adapter.php @@ -0,0 +1,31 @@ +files = $files; + } + + public function setLanguages(array $languages): void + { + $this->languages = $languages; + } +} \ No newline at end of file diff --git a/src/Detector/Adapter/Dart.php b/src/Detector/Adapter/Dart.php index 7e1ac1ad..f371e0b0 100644 --- a/src/Detector/Adapter/Dart.php +++ b/src/Detector/Adapter/Dart.php @@ -2,9 +2,9 @@ namespace Utopia\Detector\Adapter; -use Utopia\Detector\Detector; +use Utopia\Detector\Adapter; -class Dart extends Detector +class Dart extends Adapter { const DETECTOR_DART = 'Dart'; diff --git a/src/Detector/Adapter/JavaScript.php b/src/Detector/Adapter/JavaScript.php index 551f7c18..e2f0b016 100644 --- a/src/Detector/Adapter/JavaScript.php +++ b/src/Detector/Adapter/JavaScript.php @@ -2,9 +2,9 @@ namespace Utopia\Detector\Adapter; -use Utopia\Detector\Detector; +use Utopia\Detector\Adapter; -class JavaScript extends Detector +class JavaScript extends Adapter { const DETECTOR_JAVASCRIPT = 'JavaScript'; diff --git a/src/Detector/Adapter/PHP.php b/src/Detector/Adapter/PHP.php index dccb6bfb..282fe96b 100644 --- a/src/Detector/Adapter/PHP.php +++ b/src/Detector/Adapter/PHP.php @@ -2,9 +2,9 @@ namespace Utopia\Detector\Adapter; -use Utopia\Detector\Detector; +use Utopia\Detector\Adapter; -class PHP extends Detector +class PHP extends Adapter { const DETECTOR_PHP = 'PHP'; diff --git a/src/Detector/Adapter/Python.php b/src/Detector/Adapter/Python.php index 66188594..65ce3b89 100644 --- a/src/Detector/Adapter/Python.php +++ b/src/Detector/Adapter/Python.php @@ -2,9 +2,9 @@ namespace Utopia\Detector\Adapter; -use Utopia\Detector\Detector; +use Utopia\Detector\Adapter; -class Python extends Detector +class Python extends Adapter { const DETECTOR_PYTHON = 'Python'; diff --git a/src/Detector/Adapter/Ruby.php b/src/Detector/Adapter/Ruby.php index c7f892de..ec09468c 100644 --- a/src/Detector/Adapter/Ruby.php +++ b/src/Detector/Adapter/Ruby.php @@ -2,9 +2,9 @@ namespace Utopia\Detector\Adapter; -use Utopia\Detector\Detector; +use Utopia\Detector\Adapter; -class Ruby extends Detector +class Ruby extends Adapter { const DETECTOR_RUBY = 'Ruby'; diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php index 32abc403..4d6f4a24 100644 --- a/src/Detector/Detector.php +++ b/src/Detector/Detector.php @@ -2,30 +2,33 @@ namespace Utopia\Detector; -abstract class Detector +class Detector { + protected $detectors = []; protected $files; protected $languages; - abstract public function getLanguage(): ?string; - - abstract public function getRuntime(): ?string; - - abstract public function getInstallCommand(): ?string; - - abstract public function getBuildCommand(): ?string; - - abstract public function getEntryPoint(): ?string; - - abstract public function detect(): ?bool; - - public function setFiles(array $files): void + public function __construct(array $files = [], array $languages = []) { $this->files = $files; + $this->languages = $languages; } - public function setLanguages(array $languages): void + public function addDetector(Adapter $detector): self { - $this->languages = $languages; + $detector->setFiles($this->files); + $detector->setLanguages($this->languages); + $this->detectors[] = $detector; + return $this; + } + + public function detect(): ?string + { + foreach ($this->detectors as $detector) { + if ($detector->detect()) { + return $detector->getRuntime(); + } + } + return null; } } \ No newline at end of file diff --git a/src/Detector/DetectorFactory.php b/src/Detector/DetectorFactory.php deleted file mode 100644 index 76d71bdf..00000000 --- a/src/Detector/DetectorFactory.php +++ /dev/null @@ -1,34 +0,0 @@ -files = $files; - $this->languages = $languages; - } - - public function addDetector(Detector $detector): self - { - $detector->setFiles($this->files); - $detector->setLanguages($this->languages); - $this->detectors[] = $detector; - return $this; - } - - public function detect(): ?string - { - foreach ($this->detectors as $detector) { - if ($detector->detect()) { - return $detector->getRuntime(); - } - } - return null; - } -} \ No newline at end of file diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 45c36eac..1333ad28 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -8,10 +8,10 @@ use Utopia\Detector\Adapter\PHP; use Utopia\Detector\Adapter\Python; use Utopia\Detector\Adapter\Ruby; -use Utopia\Detector\DetectorFactory; use Utopia\App; use Utopia\Cache\Adapter\None; use Utopia\Cache\Cache; +use Utopia\Detector\Detector; use Utopia\VCS\Adapter\Git\GitHub; class DetectorTest extends TestCase @@ -25,7 +25,7 @@ public function testDetect() { $files = $github->listRepositoryContents('appwrite', 'appwrite'); $languages = $github->getRepositoryLanguages('appwrite', 'appwrite'); - $detectorFactory = new DetectorFactory($files, $languages); + $detectorFactory = new Detector($files, $languages); // Add some detectors to the factory $detectorFactory From 023cc8cd76e51ae665421b840b723e47136fec53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 7 Jun 2023 15:52:16 +0200 Subject: [PATCH 056/147] Add getRepository --- src/VCS/Adapter/Git/GitHub.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 21b4cb2a..949506b9 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -152,6 +152,22 @@ public function listRepositoriesForGitHubApp($page, $per_page): array return $response['body']['repositories']; } + /** + * Get GitHub repository + * + * @return array + * + * @throws Exception + */ + public function getRepository(string $owner, string $repositoryName): array + { + $url = "/repos/{$owner}/{$repositoryName}"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return $response['body']; + } + public function getTotalReposCount(): int { $url = '/installation/repositories'; From 927140be98f87659ff24145f4d37686a5e0f5fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 7 Jun 2023 16:30:22 +0200 Subject: [PATCH 057/147] Add shallow clone and rootDirectory to clone --- src/VCS/Adapter/Git/GitHub.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 949506b9..3abb3548 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -303,7 +303,7 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio * @param string $repoId The ID of the repo to be cloned * @return string The git clone command as a string */ - public function generateGitCloneCommand(string $owner, string $repoID, string $branchName) + public function generateGitCloneCommand(string $owner, string $repoID, string $branchName, string $directory, string $rootDirectory) { $url = "/repositories/{$repoID}"; @@ -315,8 +315,7 @@ public function generateGitCloneCommand(string $owner, string $repoID, string $b $cloneUrl = str_replace('https://', "https://{$owner}:{$this->accessToken}@", $repoUrl); // Construct the Git clone command with the clone URL - $command = 'git clone -b '.$branchName." --depth=1 {$cloneUrl}"; - + $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparsecheckout true && echo \"{$rootDirectory}/*\" >> .git/info/sparse-checkout && git pull --depth=1 origin {$branchName}"; return $command; } From eefb16269e93134386080208c33fb443c143639d Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Sat, 10 Jun 2023 13:59:19 +0530 Subject: [PATCH 058/147] Added more detectors --- src/Detector/Adapter/Cpp.php | 61 ++++++++++++++++++++++++++++ src/Detector/Adapter/Deno.php | 54 +++++++++++++++++++++++++ src/Detector/Adapter/Dotnet.php | 62 +++++++++++++++++++++++++++++ src/Detector/Adapter/Java.php | 54 +++++++++++++++++++++++++ src/Detector/Adapter/Swift.php | 70 +++++++++++++++++++++++++++++++++ tests/Detector/DetectorTest.php | 26 ++++++++---- 6 files changed, 319 insertions(+), 8 deletions(-) create mode 100644 src/Detector/Adapter/Cpp.php create mode 100644 src/Detector/Adapter/Deno.php create mode 100644 src/Detector/Adapter/Dotnet.php create mode 100644 src/Detector/Adapter/Java.php create mode 100644 src/Detector/Adapter/Swift.php diff --git a/src/Detector/Adapter/Cpp.php b/src/Detector/Adapter/Cpp.php new file mode 100644 index 00000000..350414c3 --- /dev/null +++ b/src/Detector/Adapter/Cpp.php @@ -0,0 +1,61 @@ +files)) { + return true; + } + + if (in_array('Makefile', $this->files) || in_array('Solution', $this->files) || in_array('CMakeLists.txt', $this->files) || in_array('.clang-format', $this->files)) { + return true; + } + + if (in_array(self::DETECTOR_CPP, $this->languages)) { + return true; + } + + // foreach ($this->files as $file) { + // $extension = pathinfo($file, PATHINFO_EXTENSION); + // if (in_array($extension, ['cpp', 'cxx', 'cc', 'c++'])) { + // return true; + // } + // } + + return false; + } +} diff --git a/src/Detector/Adapter/Deno.php b/src/Detector/Adapter/Deno.php new file mode 100644 index 00000000..56388bcc --- /dev/null +++ b/src/Detector/Adapter/Deno.php @@ -0,0 +1,54 @@ +files)) { + return true; + } + + if (in_array('deps.ts', $this->files)) { + return true; + } + + if (in_array(self::DETECTOR_DENO, $this->languages)) { + return true; + } + + return false; + } +} diff --git a/src/Detector/Adapter/Dotnet.php b/src/Detector/Adapter/Dotnet.php new file mode 100644 index 00000000..02b682df --- /dev/null +++ b/src/Detector/Adapter/Dotnet.php @@ -0,0 +1,62 @@ +files)) { + return true; + } + + if (in_array('Function.csproj', $this->files)) { + return true; + } + + if (in_array('Solution.sln', $this->files)) { + return true; + } + + if (in_array('web.config', $this->files)) { + return true; + } + + if (in_array(self::DETECTOR_DOTNET, $this->languages)) { + return true; + } + + return false; + } +} diff --git a/src/Detector/Adapter/Java.php b/src/Detector/Adapter/Java.php new file mode 100644 index 00000000..2035b0cf --- /dev/null +++ b/src/Detector/Adapter/Java.php @@ -0,0 +1,54 @@ +files) || in_array('pmd.xml', $this->files)) { + return true; + } + + if (in_array('build.gradle', $this->files) || in_array('build.gradle.kts', $this->files)) { + return true; + } + + if (in_array(self::DETECTOR_JAVA, $this->languages)) { + return true; + } + + return false; + } +} diff --git a/src/Detector/Adapter/Swift.php b/src/Detector/Adapter/Swift.php new file mode 100644 index 00000000..68979aa7 --- /dev/null +++ b/src/Detector/Adapter/Swift.php @@ -0,0 +1,70 @@ +files)) { + return true; + } + + if (in_array(self::DETECTOR_SWIFT, $this->languages)) { + return true; + } + + if ( + in_array('.xcodeproj', $this->files) || + in_array('.xcworkspace', $this->files) + ) { + return true; + } + + if ( + in_array('project.pbxproj', $this->files) || + in_array('Podfile', $this->files) + ) { + return true; + } + + // foreach ($this->files as $file) { + // if (pathinfo($file, PATHINFO_EXTENSION) === 'swift') { + // return true; + // } + // } + + return false; + } +} diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 1333ad28..77b6eb69 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -3,14 +3,19 @@ namespace Utopia\Tests; use PHPUnit\Framework\TestCase; +use Utopia\App; +use Utopia\Cache\Adapter\None; +use Utopia\Cache\Cache; use Utopia\Detector\Adapter\Dart; use Utopia\Detector\Adapter\JavaScript; use Utopia\Detector\Adapter\PHP; use Utopia\Detector\Adapter\Python; use Utopia\Detector\Adapter\Ruby; -use Utopia\App; -use Utopia\Cache\Adapter\None; -use Utopia\Cache\Cache; +use Utopia\Detector\Adapter\CPP; +use Utopia\Detector\Adapter\Deno; +use Utopia\Detector\Adapter\Dotnet; +use Utopia\Detector\Adapter\Java; +use Utopia\Detector\Adapter\Swift; use Utopia\Detector\Detector; use Utopia\VCS\Adapter\Git\GitHub; @@ -20,11 +25,11 @@ public function testDetect() { $github = new GitHub(new Cache(new None())); $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); - $installationId = '1234'; //your GitHub App Installation ID here + $installationId = '37569846'; //your GitHub App Installation ID here $github->initialiseVariables($installationId, $privateKey, $githubAppId, 'vermakhushboo'); - $files = $github->listRepositoryContents('appwrite', 'appwrite'); - $languages = $github->getRepositoryLanguages('appwrite', 'appwrite'); + $files = $github->listRepositoryContents('joblib', 'joblib'); + $languages = $github->getRepositoryLanguages('joblib', 'joblib'); $detectorFactory = new Detector($files, $languages); // Add some detectors to the factory @@ -33,10 +38,15 @@ public function testDetect() { ->addDetector(new PHP()) ->addDetector(new Python()) ->addDetector(new Dart()) - ->addDetector(new Ruby()); - + ->addDetector(new Ruby()) + ->addDetector(new Swift()) + ->addDetector(new Java()) + ->addDetector(new CPP()) + ->addDetector(new Deno()) + ->addDetector(new Dotnet()); $runtime = $detectorFactory->detect(); + var_dump($runtime); // Ensure that detect() returns null when no detector matches // $this->assertNull($detectorFactory->detect()); From 3e606fb114f80a0702d3186939b67d77d6078c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 10 Jun 2023 11:27:04 +0200 Subject: [PATCH 059/147] New adapter approach PoC --- src/Detector/Adapter.php | 23 +++--------- src/Detector/Adapter/JavaScript.php | 58 +++++++++-------------------- src/Detector/Adapter/PHP.php | 1 - src/Detector/Adapter/Swift.php | 2 +- src/Detector/Detector.php | 47 +++++++++++++++++++---- src/VCS/Adapter/Git/GitHub.php | 11 +++--- tests/Detector/DetectorTest.php | 11 +++--- tests/VCS/GitHubTest.php | 2 +- 8 files changed, 78 insertions(+), 77 deletions(-) diff --git a/src/Detector/Adapter.php b/src/Detector/Adapter.php index f4c4bc97..f626ded5 100644 --- a/src/Detector/Adapter.php +++ b/src/Detector/Adapter.php @@ -4,28 +4,17 @@ abstract class Adapter { - protected $files; - protected $languages; + abstract public function getLanguage(): string; - abstract public function getLanguage(): ?string; + abstract public function getRuntime(): string; - abstract public function getRuntime(): ?string; + abstract public function getFileExtensions(): array; + + abstract public function getFiles(): array; abstract public function getInstallCommand(): ?string; abstract public function getBuildCommand(): ?string; abstract public function getEntryPoint(): ?string; - - abstract public function detect(): ?bool; - - public function setFiles(array $files): void - { - $this->files = $files; - } - - public function setLanguages(array $languages): void - { - $this->languages = $languages; - } -} \ No newline at end of file +} diff --git a/src/Detector/Adapter/JavaScript.php b/src/Detector/Adapter/JavaScript.php index e2f0b016..9075270d 100644 --- a/src/Detector/Adapter/JavaScript.php +++ b/src/Detector/Adapter/JavaScript.php @@ -10,64 +10,42 @@ class JavaScript extends Adapter const RUNTIME_NODE = 'node'; + const FILE_EXTENSIONS = ['js']; + + const FILES = ['pakcage.json', 'package-lock.json', 'yarn.lock']; + public function getLanguage(): string { return self::DETECTOR_JAVASCRIPT; } - public function getInstallCommand(): string + public function getRuntime(): string { - return 'npm install'; + return self::RUNTIME_NODE; } - public function getBuildCommand(): string + public function getFiles(): array { - return 'npm build'; + return self::FILES; } - public function getEntrypoint(): string + public function getFileExtensions(): array { - return 'src/index.js'; + return self::FILE_EXTENSIONS; } - public function getRuntime(): string + public function getInstallCommand(): string { - return self::RUNTIME_NODE; + return 'npm install'; } - public function detect(): ?bool + public function getBuildCommand(): string { - if (in_array('package.json', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_JAVASCRIPT, $this->languages)) { - return true; - } - - if ( - in_array('src/index.js', $this->files) || - in_array('webpack.config.js', $this->files) || - in_array('.babelrc', $this->files) || - in_array('.eslintrc.js', $this->files) - ) { - return true; - } - - if ( - in_array('package-lock.json', $this->files) || - in_array('yarn.lock', $this->files) - ) { - return true; - } - - // Check if any JavaScript files are present in the project - // foreach ($this->files as $file) { - // if (pathinfo($file, PATHINFO_EXTENSION) === 'js') { - // return true; - // } - // } + return 'npm build'; + } - return false; + public function getEntrypoint(): string + { + return 'src/index.js'; } } diff --git a/src/Detector/Adapter/PHP.php b/src/Detector/Adapter/PHP.php index 282fe96b..a2aad5f6 100644 --- a/src/Detector/Adapter/PHP.php +++ b/src/Detector/Adapter/PHP.php @@ -50,7 +50,6 @@ public function detect(): ?bool // return $this; // } // } - return false; } } diff --git a/src/Detector/Adapter/Swift.php b/src/Detector/Adapter/Swift.php index 68979aa7..5309e390 100644 --- a/src/Detector/Adapter/Swift.php +++ b/src/Detector/Adapter/Swift.php @@ -51,7 +51,7 @@ public function detect(): ?bool ) { return true; } - + if ( in_array('project.pbxproj', $this->files) || in_array('Podfile', $this->files) diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php index 4d6f4a24..93217da8 100644 --- a/src/Detector/Detector.php +++ b/src/Detector/Detector.php @@ -4,9 +4,20 @@ class Detector { - protected $detectors = []; - protected $files; - protected $languages; + /** + * @var Adapter[] + */ + protected array $detectors = []; + + /** + * @var string[] + */ + protected array $files; + + /** + * @var string[] + */ + protected array $languages; public function __construct(array $files = [], array $languages = []) { @@ -16,19 +27,41 @@ public function __construct(array $files = [], array $languages = []) public function addDetector(Adapter $detector): self { - $detector->setFiles($this->files); - $detector->setLanguages($this->languages); $this->detectors[] = $detector; + return $this; } public function detect(): ?string { + // 1. Look for specific files foreach ($this->detectors as $detector) { - if ($detector->detect()) { + $detectorFiles = $detector->getFiles(); + + $matches = \array_intersect($detectorFiles, $this->files); + if (\count($matches) > 0) { return $detector->getRuntime(); } } + + // 2. Look for files with extension + foreach ($this->detectors as $detector) { + foreach ($this->files as $file) { + if (\in_array(pathinfo($file, PATHINFO_EXTENSION), $detector->getFileExtensions())) { + return $detector->getRuntime(); + } + } + } + + // 3. Look for mathch with Git language + foreach ($this->languages as $language) { + foreach ($this->detectors as $detector) { + if ($language === $detector->getLanguage()) { + return $detector->getRuntime(); + } + } + } + return null; } -} \ No newline at end of file +} diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 3abb3548..02d27962 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -316,6 +316,7 @@ public function generateGitCloneCommand(string $owner, string $repoID, string $b // Construct the Git clone command with the clone URL $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparsecheckout true && echo \"{$rootDirectory}/*\" >> .git/info/sparse-checkout && git pull --depth=1 origin {$branchName}"; + return $command; } @@ -434,7 +435,7 @@ public function updateCommitStatus(string $repositoryName, string $SHA, string $ $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $body); } - + /** * Get repository languages * @@ -458,15 +459,15 @@ public function getRepositoryLanguages(string $owner, string $repositoryName): ? /** * List contents of the specified root directory. * - * @param string $owner Owner name of the repository - * @param string $repositoryName Name of the GitHub repository - * @param string $path Path to list contents from + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @param string $path Path to list contents from * @return array List of contents at the specified path */ public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array { $url = "/repos/$owner/$repositoryName/contents"; - if (!empty($path)) { + if (! empty($path)) { $url .= "/$path"; } diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 77b6eb69..1da1689e 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -6,22 +6,23 @@ use Utopia\App; use Utopia\Cache\Adapter\None; use Utopia\Cache\Cache; +use Utopia\Detector\Adapter\CPP; use Utopia\Detector\Adapter\Dart; +use Utopia\Detector\Adapter\Deno; +use Utopia\Detector\Adapter\Dotnet; +use Utopia\Detector\Adapter\Java; use Utopia\Detector\Adapter\JavaScript; use Utopia\Detector\Adapter\PHP; use Utopia\Detector\Adapter\Python; use Utopia\Detector\Adapter\Ruby; -use Utopia\Detector\Adapter\CPP; -use Utopia\Detector\Adapter\Deno; -use Utopia\Detector\Adapter\Dotnet; -use Utopia\Detector\Adapter\Java; use Utopia\Detector\Adapter\Swift; use Utopia\Detector\Detector; use Utopia\VCS\Adapter\Git\GitHub; class DetectorTest extends TestCase { - public function testDetect() { + public function testDetect() + { $github = new GitHub(new Cache(new None())); $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 4b8b2aa8..36fc5e3c 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -170,6 +170,6 @@ public function testGetRepositoryLanguages(): void public function testListRepositoryContents(): void { - $contents = $this-> github->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); + $contents = $this->github->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); } } From 7011a5918763f3a35caf52eaa26f401fb186d536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 10 Jun 2023 11:34:25 +0200 Subject: [PATCH 060/147] Better multi-extension support --- src/Detector/Adapter.php | 2 +- src/Detector/Adapter/Deno.php | 2 +- src/Detector/Adapter/JavaScript.php | 18 +++++------------- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/Detector/Adapter.php b/src/Detector/Adapter.php index f626ded5..07d12c61 100644 --- a/src/Detector/Adapter.php +++ b/src/Detector/Adapter.php @@ -4,7 +4,7 @@ abstract class Adapter { - abstract public function getLanguage(): string; + abstract public function getLanguages(): array; abstract public function getRuntime(): string; diff --git a/src/Detector/Adapter/Deno.php b/src/Detector/Adapter/Deno.php index 56388bcc..96228912 100644 --- a/src/Detector/Adapter/Deno.php +++ b/src/Detector/Adapter/Deno.php @@ -6,7 +6,7 @@ class Deno extends Adapter { - const DETECTOR_DENO = 'Deno'; + const DETECTOR_DENO = 'TypeScript'; const RUNTIME_DENO = 'deno'; diff --git a/src/Detector/Adapter/JavaScript.php b/src/Detector/Adapter/JavaScript.php index 9075270d..00ded046 100644 --- a/src/Detector/Adapter/JavaScript.php +++ b/src/Detector/Adapter/JavaScript.php @@ -6,32 +6,24 @@ class JavaScript extends Adapter { - const DETECTOR_JAVASCRIPT = 'JavaScript'; - - const RUNTIME_NODE = 'node'; - - const FILE_EXTENSIONS = ['js']; - - const FILES = ['pakcage.json', 'package-lock.json', 'yarn.lock']; - - public function getLanguage(): string + public function getLanguages(): array { - return self::DETECTOR_JAVASCRIPT; + return ['JavaScript', 'TypeScript']; } public function getRuntime(): string { - return self::RUNTIME_NODE; + return 'node'; } public function getFiles(): array { - return self::FILES; + return ['js', 'ts']; } public function getFileExtensions(): array { - return self::FILE_EXTENSIONS; + return ['pakcage.json', 'package-lock.json', 'yarn.lock', 'tsconfig.json']; } public function getInstallCommand(): string From a5ac92a59b636e4242aeca4f0c390135d6d98960 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Sat, 10 Jun 2023 17:28:55 +0530 Subject: [PATCH 061/147] New adapter approach --- src/Detector/Adapter/Cpp.php | 48 ++++++++---------------- src/Detector/Adapter/Dart.php | 50 ++++++++----------------- src/Detector/Adapter/Deno.php | 41 ++++++++------------- src/Detector/Adapter/Dotnet.php | 49 ++++++++----------------- src/Detector/Adapter/Java.php | 41 ++++++++------------- src/Detector/Adapter/JavaScript.php | 6 +-- src/Detector/Adapter/PHP.php | 42 ++++++++------------- src/Detector/Adapter/Python.php | 45 ++++++++--------------- src/Detector/Adapter/Ruby.php | 56 ++++++++-------------------- src/Detector/Adapter/Swift.php | 57 ++++++++--------------------- src/Detector/Detector.php | 2 +- 11 files changed, 140 insertions(+), 297 deletions(-) diff --git a/src/Detector/Adapter/Cpp.php b/src/Detector/Adapter/Cpp.php index 350414c3..acf6abb1 100644 --- a/src/Detector/Adapter/Cpp.php +++ b/src/Detector/Adapter/Cpp.php @@ -6,13 +6,24 @@ class CPP extends Adapter { - const DETECTOR_CPP = 'C++'; + public function getLanguages(): array + { + return ['C++']; + } + + public function getRuntime(): string + { + return 'cpp'; + } - const RUNTIME_CPP = 'cpp'; + public function getFileExtensions(): array + { + return ['cpp', 'h', 'hpp', 'cxx', 'cc']; + } - public function getLanguage(): string + public function getFiles(): array { - return self::DETECTOR_CPP; + return ['main.cpp', 'Solution', 'CMakeLists.txt', '.clang-format']; } public function getInstallCommand(): string @@ -29,33 +40,4 @@ public function getEntryPoint(): string { return ''; } - - public function getRuntime(): string - { - return self::RUNTIME_CPP; - } - - public function detect(): ?bool - { - if (in_array('main.cpp', $this->files)) { - return true; - } - - if (in_array('Makefile', $this->files) || in_array('Solution', $this->files) || in_array('CMakeLists.txt', $this->files) || in_array('.clang-format', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_CPP, $this->languages)) { - return true; - } - - // foreach ($this->files as $file) { - // $extension = pathinfo($file, PATHINFO_EXTENSION); - // if (in_array($extension, ['cpp', 'cxx', 'cc', 'c++'])) { - // return true; - // } - // } - - return false; - } } diff --git a/src/Detector/Adapter/Dart.php b/src/Detector/Adapter/Dart.php index f371e0b0..ba422bbf 100644 --- a/src/Detector/Adapter/Dart.php +++ b/src/Detector/Adapter/Dart.php @@ -6,13 +6,24 @@ class Dart extends Adapter { - const DETECTOR_DART = 'Dart'; + public function getLanguages(): array + { + return ['Dart']; + } + + public function getRuntime(): string + { + return 'dart'; + } - const RUNTIME_DART = 'dart'; + public function getFileExtensions(): array + { + return ['dart']; + } - public function getLanguage(): string + public function getFiles(): array { - return self::DETECTOR_DART; + return ['pubspec.yaml', 'pubspec.lock']; } public function getInstallCommand(): string @@ -29,35 +40,4 @@ public function getEntryPoint(): string { return 'lib/main.dart'; } - - public function getRuntime(): string - { - return self::RUNTIME_DART; - } - - public function detect(): bool - { - if (in_array('pubspec.yaml', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_DART, $this->languages)) { - return true; - } - - if ( - in_array('lib/main.dart', $this->files) || - in_array('pubspec.lock', $this->files) - ) { - return true; - } - - // foreach ($this->files as $file) { - // if (pathinfo($file, PATHINFO_EXTENSION) === 'dart') { - // return true; - // } - // } - - return false; - } } diff --git a/src/Detector/Adapter/Deno.php b/src/Detector/Adapter/Deno.php index 96228912..0bb5e7ef 100644 --- a/src/Detector/Adapter/Deno.php +++ b/src/Detector/Adapter/Deno.php @@ -6,13 +6,24 @@ class Deno extends Adapter { - const DETECTOR_DENO = 'TypeScript'; + public function getLanguages(): array + { + return ['TypeScript']; + } - const RUNTIME_DENO = 'deno'; + public function getRuntime(): string + { + return 'deno'; + } - public function getLanguage(): string + public function getFileExtensions(): array { - return self::DETECTOR_DENO; + return ['ts', 'tsx']; + } + + public function getFiles(): array + { + return ['mod.ts', 'deps.ts']; } public function getInstallCommand(): string @@ -29,26 +40,4 @@ public function getEntryPoint(): string { return 'mod.ts'; } - - public function getRuntime(): string - { - return self::RUNTIME_DENO; - } - - public function detect(): ?bool - { - if (in_array('mod.ts', $this->files)) { - return true; - } - - if (in_array('deps.ts', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_DENO, $this->languages)) { - return true; - } - - return false; - } } diff --git a/src/Detector/Adapter/Dotnet.php b/src/Detector/Adapter/Dotnet.php index 02b682df..7faf0a8e 100644 --- a/src/Detector/Adapter/Dotnet.php +++ b/src/Detector/Adapter/Dotnet.php @@ -6,13 +6,24 @@ class Dotnet extends Adapter { - const DETECTOR_DOTNET = '.NET'; + public function getLanguages(): array + { + return ['C#', 'Visual Basic .NET']; + } + + public function getRuntime(): string + { + return 'dotnet'; + } - const RUNTIME_DOTNET = 'dotnet'; + public function getFileExtensions(): array + { + return ['cs', 'vb', 'sln', 'csproj', 'vbproj']; + } - public function getLanguage(): string + public function getFiles(): array { - return self::DETECTOR_DOTNET; + return ['Program.cs', 'Solution.sln', 'Function.csproj', 'Program.vb']; } public function getInstallCommand(): string @@ -29,34 +40,4 @@ public function getEntryPoint(): string { return 'Program.cs'; } - - public function getRuntime(): string - { - return self::RUNTIME_DOTNET; - } - - public function detect(): ?bool - { - if (in_array('Program.cs', $this->files)) { - return true; - } - - if (in_array('Function.csproj', $this->files)) { - return true; - } - - if (in_array('Solution.sln', $this->files)) { - return true; - } - - if (in_array('web.config', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_DOTNET, $this->languages)) { - return true; - } - - return false; - } } diff --git a/src/Detector/Adapter/Java.php b/src/Detector/Adapter/Java.php index 2035b0cf..5304fbcc 100644 --- a/src/Detector/Adapter/Java.php +++ b/src/Detector/Adapter/Java.php @@ -6,13 +6,24 @@ class Java extends Adapter { - const DETECTOR_JAVA = 'Java'; + public function getLanguages(): array + { + return ['Java']; + } - const RUNTIME_JAVA = 'java'; + public function getRuntime(): string + { + return 'java'; + } - public function getLanguage(): string + public function getFileExtensions(): array { - return self::DETECTOR_JAVA; + return ['java', 'class', 'jar']; + } + + public function getFiles(): array + { + return ['pom.xml', 'pmd.xml', 'build.gradle', 'build.gradle.kts']; } public function getInstallCommand(): string @@ -29,26 +40,4 @@ public function getEntryPoint(): string { return 'Main.java'; } - - public function getRuntime(): string - { - return self::RUNTIME_JAVA; - } - - public function detect(): ?bool - { - if (in_array('pom.xml', $this->files) || in_array('pmd.xml', $this->files)) { - return true; - } - - if (in_array('build.gradle', $this->files) || in_array('build.gradle.kts', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_JAVA, $this->languages)) { - return true; - } - - return false; - } } diff --git a/src/Detector/Adapter/JavaScript.php b/src/Detector/Adapter/JavaScript.php index 00ded046..8dff5081 100644 --- a/src/Detector/Adapter/JavaScript.php +++ b/src/Detector/Adapter/JavaScript.php @@ -16,14 +16,14 @@ public function getRuntime(): string return 'node'; } - public function getFiles(): array + public function getFileExtensions(): array { return ['js', 'ts']; } - public function getFileExtensions(): array + public function getFiles(): array { - return ['pakcage.json', 'package-lock.json', 'yarn.lock', 'tsconfig.json']; + return ['package.json', 'package-lock.json', 'yarn.lock', 'tsconfig.json']; } public function getInstallCommand(): string diff --git a/src/Detector/Adapter/PHP.php b/src/Detector/Adapter/PHP.php index a2aad5f6..e109b84a 100644 --- a/src/Detector/Adapter/PHP.php +++ b/src/Detector/Adapter/PHP.php @@ -6,13 +6,24 @@ class PHP extends Adapter { - const DETECTOR_PHP = 'PHP'; + public function getLanguages(): array + { + return ['PHP']; + } + + public function getRuntime(): string + { + return 'php'; + } - const RUNTIME_PHP = 'php'; + public function getFileExtensions(): array + { + return ['php']; + } - public function getLanguage(): string + public function getFiles(): array { - return self::DETECTOR_PHP; + return ['composer.json', 'composer.lock']; } public function getInstallCommand(): string @@ -29,27 +40,4 @@ public function getEntryPoint(): string { return 'index.php'; } - - public function getRuntime(): string - { - return self::RUNTIME_PHP; - } - - public function detect(): ?bool - { - if (in_array('composer.json', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_PHP, $this->languages)) { - return true; - } - - // foreach ($this->files as $file) { - // if (pathinfo($file, PATHINFO_EXTENSION) === 'php') { - // return $this; - // } - // } - return false; - } } diff --git a/src/Detector/Adapter/Python.php b/src/Detector/Adapter/Python.php index 65ce3b89..4c357461 100644 --- a/src/Detector/Adapter/Python.php +++ b/src/Detector/Adapter/Python.php @@ -6,51 +6,38 @@ class Python extends Adapter { - const DETECTOR_PYTHON = 'Python'; - - const RUNTIME_PYTHON = 'python'; - - public function getLanguage(): string + public function getLanguages(): array { - return self::DETECTOR_PYTHON; + return ['Python']; } - public function getInstallCommand(): string + public function getRuntime(): string { - return 'pip install'; + return 'python'; } - public function getBuildCommand(): string + public function getFileExtensions(): array { - return ''; // No build command for Python + return ['py']; } - public function getEntryPoint(): string + public function getFiles(): array { - return 'main.py'; // Replace with your Python entry point file name + return ['requirements.txt', 'setup.py']; } - public function getRuntime(): string + public function getInstallCommand(): string { - return self::RUNTIME_PYTHON; + return 'pip install'; } - public function detect(): ?bool + public function getBuildCommand(): string { - if (in_array('requirements.txt', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_PYTHON, $this->languages)) { - return true; - } - - // foreach ($this->files as $file) { - // if (pathinfo($file, PATHINFO_EXTENSION) === 'py') { - // return true; - // } - // } + return ''; + } - return false; + public function getEntryPoint(): string + { + return 'main.py'; } } diff --git a/src/Detector/Adapter/Ruby.php b/src/Detector/Adapter/Ruby.php index ec09468c..6ec68162 100644 --- a/src/Detector/Adapter/Ruby.php +++ b/src/Detector/Adapter/Ruby.php @@ -6,13 +6,24 @@ class Ruby extends Adapter { - const DETECTOR_RUBY = 'Ruby'; + public function getLanguages(): array + { + return ['Ruby']; + } + + public function getRuntime(): string + { + return 'ruby'; + } - const RUNTIME_RUBY = 'ruby'; + public function getFileExtensions(): array + { + return ['rb']; + } - public function getLanguage(): string + public function getFiles(): array { - return self::DETECTOR_RUBY; + return ['Gemfile', 'Gemfile.lock', 'Rakefile', 'Guardfile']; } public function getInstallCommand(): string @@ -29,41 +40,4 @@ public function getEntryPoint(): string { return 'main.rb'; } - - public function getRuntime(): string - { - return self::RUNTIME_RUBY; - } - - public function detect(): ?bool - { - if (in_array('Gemfile', $this->files) || in_array('Gemfile.lock', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_RUBY, $this->languages)) { - return true; - } - - if ( - in_array('config.ru', $this->files) || - in_array('Rakefile', $this->files) || - in_array('Gemspec', $this->files) || - in_array('Capfile', $this->files) - ) { - return true; - } - - if (in_array('Rakefile', $this->files) || in_array('Guardfile', $this->files)) { - return true; - } - - // foreach ($this->files as $file) { - // if (pathinfo($file, PATHINFO_EXTENSION) === 'rb') { - // return true; - // } - // } - - return false; - } } diff --git a/src/Detector/Adapter/Swift.php b/src/Detector/Adapter/Swift.php index 5309e390..247d982d 100644 --- a/src/Detector/Adapter/Swift.php +++ b/src/Detector/Adapter/Swift.php @@ -6,13 +6,24 @@ class Swift extends Adapter { - const DETECTOR_SWIFT = 'Swift'; + public function getLanguages(): array + { + return ['Swift']; + } + + public function getRuntime(): string + { + return 'swift'; + } - const RUNTIME_SWIFT = 'swift'; + public function getFileExtensions(): array + { + return ['swift', 'xcodeproj', 'xcworkspace']; + } - public function getLanguage(): string + public function getFiles(): array { - return self::DETECTOR_SWIFT; + return ['Package.swift', 'Podfile', 'project.pbxproj']; } public function getInstallCommand(): string @@ -29,42 +40,4 @@ public function getEntryPoint(): string { return 'main.swift'; } - - public function getRuntime(): string - { - return self::RUNTIME_SWIFT; - } - - public function detect(): ?bool - { - if (in_array('Package.swift', $this->files)) { - return true; - } - - if (in_array(self::DETECTOR_SWIFT, $this->languages)) { - return true; - } - - if ( - in_array('.xcodeproj', $this->files) || - in_array('.xcworkspace', $this->files) - ) { - return true; - } - - if ( - in_array('project.pbxproj', $this->files) || - in_array('Podfile', $this->files) - ) { - return true; - } - - // foreach ($this->files as $file) { - // if (pathinfo($file, PATHINFO_EXTENSION) === 'swift') { - // return true; - // } - // } - - return false; - } } diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php index 93217da8..70b069f8 100644 --- a/src/Detector/Detector.php +++ b/src/Detector/Detector.php @@ -56,7 +56,7 @@ public function detect(): ?string // 3. Look for mathch with Git language foreach ($this->languages as $language) { foreach ($this->detectors as $detector) { - if ($language === $detector->getLanguage()) { + if ($language === $detector->getLanguages()) { return $detector->getRuntime(); } } From 416405c4dba707ea76d67edca19fdfc4a31f83e1 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Sat, 10 Jun 2023 18:02:59 +0530 Subject: [PATCH 062/147] Return languages as strings instead of pair --- src/Detector/Detector.php | 6 +++--- src/VCS/Adapter/Git/GitHub.php | 2 +- tests/Detector/DetectorTest.php | 7 ++++--- tests/VCS/GitHubTest.php | 6 +++--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php index 70b069f8..9130ba11 100644 --- a/src/Detector/Detector.php +++ b/src/Detector/Detector.php @@ -54,9 +54,9 @@ public function detect(): ?string } // 3. Look for mathch with Git language - foreach ($this->languages as $language) { - foreach ($this->detectors as $detector) { - if ($language === $detector->getLanguages()) { + foreach ($this->detectors as $detector) { + foreach ($this->languages as $language) { + if (\in_array($language, $detector->getLanguages())) { return $detector->getRuntime(); } } diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 02d27962..9a0e602d 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -450,7 +450,7 @@ public function getRepositoryLanguages(string $owner, string $repositoryName): ? $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); if (isset($response['body'])) { - return $response['body']; + return array_keys($response['body']); } return null; diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 1da1689e..3263b84d 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -29,8 +29,9 @@ public function testDetect() $installationId = '37569846'; //your GitHub App Installation ID here $github->initialiseVariables($installationId, $privateKey, $githubAppId, 'vermakhushboo'); - $files = $github->listRepositoryContents('joblib', 'joblib'); - $languages = $github->getRepositoryLanguages('joblib', 'joblib'); + $files = $github->listRepositoryContents('mxcl', 'PromiseKit'); + $languages = $github->getRepositoryLanguages('mxcl', 'PromiseKit'); + $detectorFactory = new Detector($files, $languages); // Add some detectors to the factory @@ -39,8 +40,8 @@ public function testDetect() ->addDetector(new PHP()) ->addDetector(new Python()) ->addDetector(new Dart()) - ->addDetector(new Ruby()) ->addDetector(new Swift()) + ->addDetector(new Ruby()) ->addDetector(new Java()) ->addDetector(new CPP()) ->addDetector(new Deno()) diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 36fc5e3c..6f3e08a7 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -163,9 +163,9 @@ public function testGetRepositoryLanguages(): void $this->assertIsArray($languages); - $this->assertArrayHasKey('JavaScript', $languages); - $this->assertArrayHasKey('HTML', $languages); - $this->assertArrayHasKey('CSS', $languages); + $this->assertContains('JavaScript', $languages); + $this->assertContains('HTML', $languages); + $this->assertContains('CSS', $languages); } public function testListRepositoryContents(): void From 19df1db1ed35cede8be047c52f57ad768ebdd22a Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Sat, 10 Jun 2023 19:34:55 +0530 Subject: [PATCH 063/147] Add tests for all detectors --- tests/Detector/DetectorTest.php | 49 +++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 3263b84d..013e5256 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -21,20 +21,12 @@ class DetectorTest extends TestCase { - public function testDetect() - { - $github = new GitHub(new Cache(new None())); - $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); - $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); - $installationId = '37569846'; //your GitHub App Installation ID here - $github->initialiseVariables($installationId, $privateKey, $githubAppId, 'vermakhushboo'); - - $files = $github->listRepositoryContents('mxcl', 'PromiseKit'); - $languages = $github->getRepositoryLanguages('mxcl', 'PromiseKit'); + protected $github; + public function detect($files, $languages): string + { $detectorFactory = new Detector($files, $languages); - // Add some detectors to the factory $detectorFactory ->addDetector(new JavaScript()) ->addDetector(new PHP()) @@ -48,9 +40,38 @@ public function testDetect() ->addDetector(new Dotnet()); $runtime = $detectorFactory->detect(); - var_dump($runtime); + return $runtime; + } + + public function setUp(): void + { + $this->github = new GitHub(new Cache(new None())); + $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); + $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); + $installationId = '1234'; //your GitHub App Installation ID here + $this->github->initialiseVariables($installationId, $privateKey, $githubAppId, 'vermakhushboo'); + } + + public function testLanguageDetection() + { + $languageMap = [ + ['vermakhushboo', 'basic-js-crud', 'node'], + ['appwrite', 'appwrite', 'php'], + ['joblib', 'joblib', 'python'], + ['smartherd', 'DartTutorial', 'dart'], + ['realm', 'realm-swift', 'swift'], + ['aws', 'aws-sdk-ruby', 'ruby'], + ['functionaljava', 'functionaljava', 'java'], + ['Dobiasd', 'FunctionalPlus', 'cpp'], + ['anthonychu', 'azure-functions-deno-worker', 'deno'], + ['mono', 'mono-basic', 'dotnet'] + ]; - // Ensure that detect() returns null when no detector matches - // $this->assertNull($detectorFactory->detect()); + foreach ($languageMap as [$owner, $repositoryName, $expectedRuntime]) { + $files = $this->github->listRepositoryContents($owner, $repositoryName); + $languages = $this->github->getRepositoryLanguages($owner, $repositoryName); + $runtime = $this->detect($files, $languages); + $this->assertEquals($expectedRuntime, $runtime); + } } } From 46f4de30652a057a0c19a6975276a6be8e12606f Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 12 Jun 2023 18:18:43 +0530 Subject: [PATCH 064/147] Rename Cpp.php to CPP.php --- src/Detector/Adapter/{Cpp.php => CPP.php} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Detector/Adapter/{Cpp.php => CPP.php} (100%) diff --git a/src/Detector/Adapter/Cpp.php b/src/Detector/Adapter/CPP.php similarity index 100% rename from src/Detector/Adapter/Cpp.php rename to src/Detector/Adapter/CPP.php From 01afc324865613f7b34ca9981745bfaaec8ec363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 15 Jun 2023 12:13:29 +0200 Subject: [PATCH 065/147] Add validateWebhook --- src/VCS/Adapter/Git/GitHub.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 9a0e602d..56f0f755 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -320,6 +320,19 @@ public function generateGitCloneCommand(string $owner, string $repoID, string $b return $command; } + /** + * Parses webhook event payload + * + * @param string $payload Raw body of HTTP request + * @param string $signature Signature provided by GitHub in header + * @param string $signatureKey Webhook secret configured on GitHub + * @return bool + */ + public function validateWebhook(string $payload, string $signature, string $signatureKey) + { + return $signature === ('sha256=' . hash_hmac('sha256', $payload, $signatureKey)); + } + /** * Parses webhook event payload * From f34e6e5b0b78c5f8971a7d2e5bd8bb50744e5edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 16 Jun 2023 12:50:37 +0200 Subject: [PATCH 066/147] Add getPullRequest --- src/VCS/Adapter/Git/GitHub.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 56f0f755..7c9a0354 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -152,6 +152,18 @@ public function listRepositoriesForGitHubApp($page, $per_page): array return $response['body']['repositories']; } + /** + * Get latest opened pull request with specific base branch + */ + public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array + { + $url = "/repos/{$owner}/{$repositoryName}/pulls?base={$branch}&state=open&sort=updated&per_page=1"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return $response['body'][0] ?? null; + } + /** * Get GitHub repository * From 2f1ecff11d16413a2247b2f21de6d9f086b8324f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 16 Jun 2023 12:55:33 +0200 Subject: [PATCH 067/147] add debugs --- src/VCS/Adapter/Git/GitHub.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 7c9a0354..89a963ab 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -157,11 +157,16 @@ public function listRepositoriesForGitHubApp($page, $per_page): array */ public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array { + \var_dump($owner); + \var_dump($repositoryName); + \var_dump($branch); + $url = "/repos/{$owner}/{$repositoryName}/pulls?base={$branch}&state=open&sort=updated&per_page=1"; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + \var_dump($response); - return $response['body'][0] ?? null; + return $response['body'][0] ?? []; } /** From 2966e482920a9dd028a237083a81de723a9bcbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 16 Jun 2023 13:02:30 +0200 Subject: [PATCH 068/147] Fix method --- src/VCS/Adapter/Git/GitHub.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 89a963ab..c7ea3132 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -157,14 +157,10 @@ public function listRepositoriesForGitHubApp($page, $per_page): array */ public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array { - \var_dump($owner); - \var_dump($repositoryName); - \var_dump($branch); - - $url = "/repos/{$owner}/{$repositoryName}/pulls?base={$branch}&state=open&sort=updated&per_page=1"; + $head = "{$owner}:{$branch}"; + $url = "/repos/{$owner}/{$repositoryName}/pulls?head={$head}&state=open&sort=updated&per_page=1"; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - \var_dump($response); return $response['body'][0] ?? []; } From 06e0f27c4a4f267bce83dd68d43bac273eac0aee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 17 Jun 2023 16:16:44 +0200 Subject: [PATCH 069/147] Add createRepository --- src/VCS/Adapter/Git/GitHub.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index c7ea3132..92aa957f 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -181,6 +181,18 @@ public function getRepository(string $owner, string $repositoryName): array return $response['body']; } + public function createRepository(string $owner, string $repositoryName, bool $private): array + { + $url = "/orgs/{$owner}/{$repositoryName}"; + + $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], [ + 'name' => $repositoryName, + 'private' => $private, + ]); + + return $response['body']; + } + public function getTotalReposCount(): int { $url = '/installation/repositories'; From 7fb5b733ab0676b257d8bc8fc4e0c4cafd4c756c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 17 Jun 2023 16:27:48 +0200 Subject: [PATCH 070/147] Fix endpoint --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 92aa957f..b6ce2f36 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -183,7 +183,7 @@ public function getRepository(string $owner, string $repositoryName): array public function createRepository(string $owner, string $repositoryName, bool $private): array { - $url = "/orgs/{$owner}/{$repositoryName}"; + $url = "/orgs/{$owner}/repos"; $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], [ 'name' => $repositoryName, From 4e031248bc2ac6b7bd33548f8ca8a1844bafd34b Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 19 Jun 2023 17:40:18 +0530 Subject: [PATCH 071/147] Updated git clone command --- src/VCS/Adapter/Git/GitHub.php | 19 +++++-------------- tests/VCS/GitHubTest.php | 3 +-- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index b6ce2f36..64a7def2 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -324,20 +324,11 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio /** * Generates a git clone command using app access token - * - * @param string $repoId The ID of the repo to be cloned - * @return string The git clone command as a string */ - public function generateGitCloneCommand(string $owner, string $repoID, string $branchName, string $directory, string $rootDirectory) + public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory) { - $url = "/repositories/{$repoID}"; - - $repoData = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - $repoUrl = $repoData['body']['html_url']; - // Construct the clone URL with the access token - $cloneUrl = str_replace('https://', "https://{$owner}:{$this->accessToken}@", $repoUrl); + $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; // Construct the Git clone command with the clone URL $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparsecheckout true && echo \"{$rootDirectory}/*\" >> .git/info/sparse-checkout && git pull --depth=1 origin {$branchName}"; @@ -424,12 +415,12 @@ public function parseWebhookEventPayload(string $event, string $payload) /** * Fetches repository name using repository id * - * @param string $repoId ID of GitHub Repository + * @param string $repository ID of GitHub Repository * @return string name of GitHub repository */ - public function getRepositoryName(string $repoId) + public function getRepositoryName(string $repositoryId) { - $url = "/repositories/$repoId"; + $url = "/repositories/$repositoryId"; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); return $response['body']['name']; diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 6f3e08a7..c0fe1e78 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -79,8 +79,7 @@ public function testForkRepository(): void public function testGenerateGitCloneCommand(): void { - $repoId = '155386150'; - $gitCloneCommand = $this->github->generateGitCloneCommand('vermakhushboo', $repoId, 'main'); + $gitCloneCommand = $this->github->generateGitCloneCommand('vermakhushboo', 'Amigo', 'main', '', ''); } public function testParseWebhookEventPayload(): void From df56d0eecf308e0c8b1e86c6801bb44c7c363052 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 19 Jun 2023 22:24:01 +0530 Subject: [PATCH 072/147] Added var_dump --- src/VCS/Adapter/Git/GitHub.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 64a7def2..50451afa 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -330,6 +330,8 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s // Construct the clone URL with the access token $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; + var_dump($cloneUrl); + // Construct the Git clone command with the clone URL $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparsecheckout true && echo \"{$rootDirectory}/*\" >> .git/info/sparse-checkout && git pull --depth=1 origin {$branchName}"; From 36e0bff5b1add767e5c4b594dd9fb7e767600819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 21 Jun 2023 09:43:56 +0200 Subject: [PATCH 073/147] Fix clone command --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 50451afa..33c3568f 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -333,7 +333,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s var_dump($cloneUrl); // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparsecheckout true && echo \"{$rootDirectory}/*\" >> .git/info/sparse-checkout && git pull --depth=1 origin {$branchName}"; + $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git pull origin {$branchName}"; return $command; } From 8eb6558f2dc1660de6e900efc0b97c8310e23df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 21 Jun 2023 10:44:23 +0200 Subject: [PATCH 074/147] Fix missing branch edge case --- src/VCS/Adapter/Git/GitHub.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 33c3568f..163005ab 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -330,10 +330,8 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s // Construct the clone URL with the access token $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; - var_dump($cloneUrl); - // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git pull origin {$branchName}"; + $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git checkout -b {$branchName} && git pull origin {$branchName} 2>/dev/null"; return $command; } From 3d517a691e95180283ef8aba831b8fa3a700abbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 21 Jun 2023 14:18:56 +0200 Subject: [PATCH 075/147] Prevent warning --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 163005ab..adf86088 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -331,7 +331,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git checkout -b {$branchName} && git pull origin {$branchName} 2>/dev/null"; + $command = "mkdir -p {$directory} && cd {$directory} && git init --initial-branch=main && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git checkout -b {$branchName} && git pull origin {$branchName} 2>/dev/null"; return $command; } From 64e6769b00fa896f50406ebd2c86b940d22a1233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 21 Jun 2023 14:35:05 +0200 Subject: [PATCH 076/147] Fix branch warning --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index adf86088..77f8746d 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -331,7 +331,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git init --initial-branch=main && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git checkout -b {$branchName} && git pull origin {$branchName} 2>/dev/null"; + $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git checkout -b {$branchName} && git pull origin {$branchName} 2>/dev/null"; return $command; } From ee673c8e6ab7fe05ec65681461b2bf7ce47abb9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 21 Jun 2023 14:45:52 +0200 Subject: [PATCH 077/147] Update GitHub.php --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 77f8746d..142dda2a 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -331,7 +331,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git checkout -b {$branchName} && git pull origin {$branchName} 2>/dev/null"; + $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git pull origin {$branchName} 2>/dev/null && git checkout -b {$branchName}"; return $command; } From f39f18e4b13bd51ffd7cb026a00afef3773eed90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 21 Jun 2023 15:00:55 +0200 Subject: [PATCH 078/147] Fix exit code --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 142dda2a..77e59734 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -331,7 +331,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git pull origin {$branchName} 2>/dev/null && git checkout -b {$branchName}"; + $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git pull origin {$branchName} 2>/dev/null && true && git checkout -b {$branchName}"; return $command; } From bc20bfb9ef352112aad793625e8ad288f527efc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 21 Jun 2023 15:06:13 +0200 Subject: [PATCH 079/147] Disable empty repos in git clone --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 77e59734..420ad85b 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -331,7 +331,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git pull origin {$branchName} 2>/dev/null && true && git checkout -b {$branchName}"; + $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git pull origin {$branchName} && git checkout {$branchName}"; return $command; } From 6131630cdc48f0fde2207fc0efcce503e7967272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 22 Jun 2023 08:40:49 +0200 Subject: [PATCH 080/147] Existing repo support --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 420ad85b..be27fe71 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -331,7 +331,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && git pull origin {$branchName} && git checkout {$branchName}"; + $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && if git ls-remote --exit-code --heads origin {$branchName}; then git pull origin {$branchName} && git checkout {$branchName}; else git checkout -b {$branchName}; fi"; return $command; } From e20c41135323a72c256541ebc9357baaf225f11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 26 Jun 2023 12:06:06 +0200 Subject: [PATCH 081/147] Add SHA to PR event --- src/VCS/Adapter/Git/GitHub.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index be27fe71..9d75e4e4 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -386,6 +386,7 @@ public function parseWebhookEventPayload(string $event, string $payload) $pullRequestNumber = $payload['number']; $action = $payload['action']; $owner = $payload['repository']['owner']['login']; + $SHA = $payload['pull_request']['head']['sha']; return [ 'action' => $action, @@ -394,6 +395,7 @@ public function parseWebhookEventPayload(string $event, string $payload) 'installationId' => $installationId, 'repositoryName' => $repositoryName, 'pullRequestNumber' => $pullRequestNumber, + 'SHA' => $SHA, 'owner' => $owner, ]; break; From 764cff092c948382b5918103e6d8e5aa6d3d2463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 27 Jun 2023 12:15:37 +0200 Subject: [PATCH 082/147] Add isExternal to PR --- src/VCS/Adapter/Git/GitHub.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 9d75e4e4..1d9db819 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -387,6 +387,7 @@ public function parseWebhookEventPayload(string $event, string $payload) $action = $payload['action']; $owner = $payload['repository']['owner']['login']; $SHA = $payload['pull_request']['head']['sha']; + $external = $payload['pull_request']['head']['label'] !== $payload['pull_request']['base']['label']; return [ 'action' => $action, @@ -397,6 +398,7 @@ public function parseWebhookEventPayload(string $event, string $payload) 'pullRequestNumber' => $pullRequestNumber, 'SHA' => $SHA, 'owner' => $owner, + 'external' => $external ]; break; case 'installation' || 'installation_repositories': From 80d1fa3022c20c6b391473c22265760a8551c5ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 28 Jun 2023 10:07:04 +0200 Subject: [PATCH 083/147] Add getPullRequest() --- src/VCS/Adapter/Git/GitHub.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 1d9db819..0eba1ca1 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -202,6 +202,15 @@ public function getTotalReposCount(): int return $response['body']['total_count']; } + public function getPullRequest(string $owner, string $repoName, $pullRequestNumber): array + { + $url = "/repos/{$owner}/{$repoName}/pulls/{$pullRequestNumber}"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return $response['body']; + } + /** * Add Comment to Pull Request * @@ -209,7 +218,7 @@ public function getTotalReposCount(): int * * @throws Exception */ - public function createComment($owner, $repoName, $pullRequestNumber, $comment) + public function createComment(string $owner, string $repoName, $pullRequestNumber, $comment) { $url = '/repos/'.$owner.'/'.$repoName.'/issues/'.$pullRequestNumber.'/comments'; From 580474fcbc5a88a908a1df3e124e47ebad2c014f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 28 Jun 2023 12:54:07 +0200 Subject: [PATCH 084/147] Add placehollders for consistency --- src/VCS/Adapter/Git/GitHub.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 0eba1ca1..2a97b1c3 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -386,6 +386,9 @@ public function parseWebhookEventPayload(string $event, string $payload) 'repositoryName' => $repositoryName, 'SHA' => $SHA, 'owner' => $owner, + 'external' => false, + 'pullRequestNumber' => '', + 'action' => '' ]; break; case 'pull_request': From abb9fccaf084dfc4b12d82a8cb77c4ddc78fcc2b Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 6 Jul 2023 16:59:32 +0530 Subject: [PATCH 085/147] Update README.md --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4603d4f5..eef7359f 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![Total Downloads](https://img.shields.io/packagist/dt/utopia-php/vcs.svg) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord)](https://appwrite.io/discord) -Utopia VCS is a simple and lite library to integrate version control systems like GitHub, GitLab etc. to receive webhook events like push, new pull request etc. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io). +Utopia VCS is a simple and lite library for interacting with version control systems (VCS) in Utopia-PHP using adapters for different providers like GitHub, GitLab etc. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io). Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project, it is dependency free and can be used as standalone with any other PHP project or framework. @@ -15,9 +15,63 @@ Install using composer: composer require utopia-php/vcs ``` +Init in your application: +```php +initialiseVariables($installationId, $privateKey, $githubAppId, 'github-username'); + +// Perform the actions that you want +$repository = $github->createRepository($owner, $name, $private); +``` + +### Supported Adapters + +VCS Adapters: + +| Adapter | Status | +|---------|---------| +| GitHub | ✅ | +| GitLab | | +| Bitbucket | | +| Azure DevOps | | + +Detector Adapters: + +| Adapter | Status | +|---------|---------| +| CPP | ✅ | +| Dart | ✅ | +| Deno | ✅ | +| Dotnet | ✅ | +| Java | ✅ | +| JavaScript | ✅ | +| PHP | ✅ | +| Python | ✅ | +| Ruby | ✅ | +| Swift | ✅ | + +`✅ - supported, 🛠 - work in progress` + ## System Requirements -Utopia Pay requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible. +Utopia VCS requires PHP 8.0 or later. We recommend using the latest PHP version whenever possible. ## Contributing @@ -44,4 +98,4 @@ docker compose exec tests ./vendor/bin/phpunit ## Copyright and license -The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php) \ No newline at end of file +The MIT License (MIT) [http://www.opensource.org/licenses/mit-license.php](http://www.opensource.org/licenses/mit-license.php) From 1f9c5e908cd6340b6aaae5d574394beecfe442cc Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:27:16 +0530 Subject: [PATCH 086/147] Add assertions to existing tests --- src/VCS/Adapter/Git/GitHub.php | 2 +- tests/VCS/GitHubTest.php | 55 ++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 2a97b1c3..448ea6ab 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -38,7 +38,7 @@ public function __construct(Cache $cache) } /** - * GitHub constructor. + * GitHub Initialisation with access token generation. */ public function initialiseVariables(string $installationId, string $privateKey, string $githubAppId) { diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index c0fe1e78..c348326c 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -23,22 +23,26 @@ public function setUp(): void public function testGetUser(): void { - $this->github->getUser('vermakhushboo'); + $user = $this->github->getUser('vermakhushboo'); + $this->assertEquals('vermakhushboo', $user['body']['login']); } public function testGetOwnerName(): void { $owner = $this->github->getOwnerName('37569846'); + $this->assertEquals('vermakhushboo', $owner); } public function testListRepositoriesForGitHubApp(): void { - $repos = $this->github->listRepositoriesForGitHubApp(1, 5); + $repos = $this->github->listRepositoriesForGitHubApp(1, 3); + $this->assertCount(3, $repos); } public function testGetTotalReposCount(): void { $count = $this->github->getTotalReposCount(); + $this->assertGreaterThanOrEqual(0, $count); } // TODO: testGetComment() @@ -46,11 +50,13 @@ public function testGetTotalReposCount(): void public function testCreateComment(): void { $commentId = $this->github->createComment('vermakhushboo', 'basic-js-crud', 1, 'hello'); + $this->assertNotEmpty($commentId); } public function testUpdateComment(): void { $commentId = $this->github->updateComment('vermakhushboo', 'basic-js-crud', 1431560395, 'update'); + $this->assertNotEmpty($commentId); } public function testDownloadRepositoryZip(): void @@ -60,6 +66,9 @@ public function testDownloadRepositoryZip(): void // Save the ZIP archive to a file file_put_contents('./desktop/hello-world.zip', $zipContents); + + // Assert that the file was saved successfully + $this->assertFileExists('./desktop/hello-world.zip'); } public function testDownloadRepositoryTar(): void @@ -69,17 +78,24 @@ public function testDownloadRepositoryTar(): void // Save the TAR archive to a file file_put_contents('./desktop/hello-world1.tar', $tarContents); + + // Assert that the file was saved successfully + $this->assertFileExists('./desktop/hello-world1.tar'); } public function testForkRepository(): void { // Fork a repository into authenticated user's account with custom name $response = $this->github->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); + // Assert that the forked repo has the expected name + $this->assertEquals('fork-api-test-clone', $response['name']); } public function testGenerateGitCloneCommand(): void { $gitCloneCommand = $this->github->generateGitCloneCommand('vermakhushboo', 'Amigo', 'main', '', ''); + $this->assertNotEmpty($gitCloneCommand); + $this->assertStringContainsString('sparse-checkout', $gitCloneCommand); } public function testParseWebhookEventPayload(): void @@ -110,7 +126,12 @@ public function testParseWebhookEventPayload(): void "id": 1303283688, "state": "open", "head": { - "ref": "test" + "ref": "test", + "sha": "08e857a3ee1d1b0156502239798f558c996a664f", + "label": "vermakhushboo:test" + }, + "base": { + "label": "vermakhushboo:main" } }, "repository": { @@ -136,24 +157,30 @@ public function testParseWebhookEventPayload(): void } '; - $this->github->parseWebhookEventPayload('push', $payload_push); - $this->github->parseWebhookEventPayload('pull_request', $payload_pull_request); - $this->github->parseWebhookEventPayload('installation', $payload_uninstall); - } + $pushResult = $this->github->parseWebhookEventPayload('push', $payload_push); + $this->assertEquals('main', $pushResult['branch']); + $this->assertEquals('603754812', $pushResult['repositoryId']); - public function testGetRepositoryName(): void - { - $repoName = $this->github->getRepositoryName('615825784'); + $pullRequestResult = $this->github->parseWebhookEventPayload('pull_request', $payload_pull_request); + $this->assertEquals('opened', $pullRequestResult['action']); + $this->assertEquals(1, $pullRequestResult['pullRequestNumber']); + + $uninstallResult = $this->github->parseWebhookEventPayload('installation', $payload_uninstall); + $this->assertEquals('deleted', $uninstallResult['action']); + $this->assertEquals(1234, $uninstallResult['installationId']); } - public function testUpdateCommitStatus(): void + public function testGetRepositoryName(): void { - $this->github->updateCommitStatus('functions-example', 'a71dc759d5cbe5316c990f91f98de65d99f4ca64', 'vermakhushboo', 'failure', 'build failed', '', 'Appwrite Deployment'); + $repoName = $this->github->getRepositoryName('432284323'); + $this->assertEquals('basic-js-crud', $repoName); } public function testListBranches(): void { - $this->github->listBranches('vermakhushboo', 'functions-example'); + $branches = $this->github->listBranches('vermakhushboo', 'basic-js-crud'); + $this->assertIsArray($branches); + $this->assertNotEmpty($branches); } public function testGetRepositoryLanguages(): void @@ -170,5 +197,7 @@ public function testGetRepositoryLanguages(): void public function testListRepositoryContents(): void { $contents = $this->github->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); + $this->assertIsArray($contents); + $this->assertNotEmpty($contents); } } From 5bd035402a15c4d629f027ff6d2a8517fa9b326e Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 6 Jul 2023 18:29:25 +0530 Subject: [PATCH 087/147] Fixed formatting --- src/VCS/Adapter/Git/GitHub.php | 6 +++--- tests/Detector/DetectorTest.php | 3 ++- tests/VCS/GitHubTest.php | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 448ea6ab..06026458 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -355,7 +355,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s */ public function validateWebhook(string $payload, string $signature, string $signatureKey) { - return $signature === ('sha256=' . hash_hmac('sha256', $payload, $signatureKey)); + return $signature === ('sha256='.hash_hmac('sha256', $payload, $signatureKey)); } /** @@ -388,7 +388,7 @@ public function parseWebhookEventPayload(string $event, string $payload) 'owner' => $owner, 'external' => false, 'pullRequestNumber' => '', - 'action' => '' + 'action' => '', ]; break; case 'pull_request': @@ -410,7 +410,7 @@ public function parseWebhookEventPayload(string $event, string $payload) 'pullRequestNumber' => $pullRequestNumber, 'SHA' => $SHA, 'owner' => $owner, - 'external' => $external + 'external' => $external, ]; break; case 'installation' || 'installation_repositories': diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 013e5256..4a9e37ff 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -40,6 +40,7 @@ public function detect($files, $languages): string ->addDetector(new Dotnet()); $runtime = $detectorFactory->detect(); + return $runtime; } @@ -64,7 +65,7 @@ public function testLanguageDetection() ['functionaljava', 'functionaljava', 'java'], ['Dobiasd', 'FunctionalPlus', 'cpp'], ['anthonychu', 'azure-functions-deno-worker', 'deno'], - ['mono', 'mono-basic', 'dotnet'] + ['mono', 'mono-basic', 'dotnet'], ]; foreach ($languageMap as [$owner, $repositoryName, $expectedRuntime]) { diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index c348326c..e786e5e9 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -30,7 +30,7 @@ public function testGetUser(): void public function testGetOwnerName(): void { $owner = $this->github->getOwnerName('37569846'); - $this->assertEquals('vermakhushboo', $owner); + $this->assertEquals('vermakhushboo', $owner); } public function testListRepositoriesForGitHubApp(): void From 65b4365cd45408c6c3e2df9eb8042ce2f5c46b34 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 6 Jul 2023 20:01:58 +0530 Subject: [PATCH 088/147] Add tests for more methods --- tests/VCS/GitHubTest.php | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index e786e5e9..cef11a89 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -45,8 +45,6 @@ public function testGetTotalReposCount(): void $this->assertGreaterThanOrEqual(0, $count); } - // TODO: testGetComment() - public function testCreateComment(): void { $commentId = $this->github->createComment('vermakhushboo', 'basic-js-crud', 1, 'hello'); @@ -200,4 +198,38 @@ public function testListRepositoryContents(): void $this->assertIsArray($contents); $this->assertNotEmpty($contents); } + + public function testGetBranchPullRequest(): void + { + $result = $this->github->getBranchPullRequest("vermakhushboo", "basic-js-crud", "test"); + $this->assertIsArray($result); + $this->assertNotEmpty($result); + } + + public function testGetPullRequest(): void + { + $owner = 'vermakhushboo'; + $repositoryName = 'basic-js-crud'; + $pullRequestNumber = 1; + + $result = $this->github->getPullRequest($owner, $repositoryName, $pullRequestNumber); + + $this->assertIsArray($result); + $this->assertNotEmpty($result); + $this->assertEquals($pullRequestNumber, $result['number']); + $this->assertEquals($owner, $result['base']['user']['login']); + $this->assertEquals($repositoryName, $result['base']['repo']['name']); + } + + public function testGetComment(): void + { + $owner = 'vermakhushboo'; + $repositoryName = 'basic-js-crud'; + $commentId = '1431560395'; + + $result = $this->github->getComment($owner, $repositoryName, $commentId); + + $this->assertIsString($result); + $this->assertNotEmpty($result); + } } From 14cec759cb311d67b33c41b529d10d05352402a5 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Fri, 7 Jul 2023 14:05:24 +0530 Subject: [PATCH 089/147] Create add-new-adapter.md --- docs/add-new-adapter.md | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 docs/add-new-adapter.md diff --git a/docs/add-new-adapter.md b/docs/add-new-adapter.md new file mode 100644 index 00000000..c45e336d --- /dev/null +++ b/docs/add-new-adapter.md @@ -0,0 +1,46 @@ +# Add new Detector Adapter + +To get started with implementing a new adapter, start by reviewing the [README](/README.md) to understand the goals of this library. + +### File Structure + +Below are outlined the most useful files for adding a new detector adapter: + +```bash +. +├── src # Source code +│ └── Detector +│ ├── Adapter/ # Where your new adapter goes! +│ ├── Adapter.php # Parent class for individual adapters +│ └── Detector.php # Detector class - calls individual adapter methods +└── tests + └── Detector + └── DetectorTest.php # Test class that holds all tests +``` + + +### Extend the Adapter + +Create your `NewDetector.php` file in `src/Detector/Adapter/` and extend the parent class: + +```php + Date: Fri, 7 Jul 2023 14:07:17 +0530 Subject: [PATCH 090/147] Add steps to add new detector --- CONTRIBUTING.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72939afc..ce035008 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,6 +76,10 @@ This will allow the Utopia-php community to have sufficient discussion about the This is also important for the Utopia-php lead developers to be able to give technical input and different emphasis regarding the feature design and architecture. Some bigger features might need to go through our [RFC process](https://github.com/appwrite/rfc). +## Adding A New Adapter + +You can follow our [Adding new Detector Adapter](docs/add-new-adapter.md) tutorial to add new detector support in this library. + ## Other Ways to Help Pull requests are great, but there are many other areas where you can help Utopia-php. @@ -102,4 +106,4 @@ Submitting documentation updates, enhancements, designs, or bug fixes. Spelling ### Helping Someone -Searching for Utopia-php, GitHub or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Utopia-php's repo! \ No newline at end of file +Searching for Utopia-php, GitHub or StackOverflow and helping someone else who needs help. You can also help by teaching others how to contribute to Utopia-php's repo! From c4cbcce6f5e5f192795e58e799a926c58a450382 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:01:00 +0530 Subject: [PATCH 091/147] Fixed formatting --- composer.json | 62 ++++++++++++++++++++-------------- docker-compose.yml | 1 - src/Detector/Detector.php | 2 +- src/VCS/Adapter.php | 10 +++--- src/VCS/Adapter/Git/GitHub.php | 24 ++++++------- tests/VCS/GitHubTest.php | 4 +-- 6 files changed, 56 insertions(+), 47 deletions(-) diff --git a/composer.json b/composer.json index d5729eea..eca93ad4 100644 --- a/composer.json +++ b/composer.json @@ -1,29 +1,39 @@ { - "name": "utopia-php/vcs", - "description": "A simple library to integrate version control systems like GitHub, GitLab etc. to receive webhook events", - "type": "library", - "keywords": ["php","framework", "utopia", "vcs"], - "license": "MIT", - "minimum-stability": "stable", - "scripts": { - "lint": "./vendor/bin/pint --test", - "format": "./vendor/bin/pint", - "test": "vendor/bin/phpunit --configuration phpunit.xml" - }, - "autoload": { - "psr-4": {"Utopia\\VCS\\": "src/VCS", "Utopia\\Detector\\": "src/Detector"} - }, - "autoload-dev": { - "psr-4": {"Utopia\\Tests\\": "tests/VCS"} - }, - "require": { - "php": ">=8.0", - "adhocore/jwt": "^1.1", - "utopia-php/framework": "0.26.*", - "utopia-php/cache": "^0.8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.4", - "laravel/pint": "1.2.*" + "name": "utopia-php/vcs", + "description": "A simple library to integrate version control systems like GitHub, GitLab etc. to receive webhook events", + "type": "library", + "keywords": [ + "php", + "framework", + "utopia", + "vcs" + ], + "license": "MIT", + "minimum-stability": "stable", + "scripts": { + "lint": "./vendor/bin/pint --test", + "format": "./vendor/bin/pint", + "test": "vendor/bin/phpunit --configuration phpunit.xml" + }, + "autoload": { + "psr-4": { + "Utopia\\VCS\\": "src/VCS", + "Utopia\\Detector\\": "src/Detector" } + }, + "autoload-dev": { + "psr-4": { + "Utopia\\Tests\\": "tests/VCS" + } + }, + "require": { + "php": ">=8.0", + "adhocore/jwt": "^1.1", + "utopia-php/framework": "0.26.*", + "utopia-php/cache": "^0.8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.4", + "laravel/pint": "1.2.*" + } } diff --git a/docker-compose.yml b/docker-compose.yml index aa5c6575..7c279b21 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,6 @@ services: - ./src:/usr/local/src/src - ./tests:/usr/local/src/tests - ./phpunit.xml:/usr/local/src/phpunit.xml - - /Users/khushbooverma/desktop:/usr/local/src/desktop environment: - GITHUB_PRIVATE_KEY - GITHUB_APP_IDENTIFIER diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php index 9130ba11..8c1ef242 100644 --- a/src/Detector/Detector.php +++ b/src/Detector/Detector.php @@ -53,7 +53,7 @@ public function detect(): ?string } } - // 3. Look for mathch with Git language + // 3. Look for match with language detected by Git foreach ($this->detectors as $detector) { foreach ($this->languages as $language) { if (\in_array($language, $detector->getLanguages())) { diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 0e6d66fb..f12baa1f 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -52,7 +52,7 @@ abstract class Adapter protected function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true) { $headers = array_merge($this->headers, $headers); - $ch = curl_init($this->endpoint.$path.(($method == self::METHOD_GET && ! empty($params)) ? '?'.http_build_query($params) : '')); + $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); $responseHeaders = []; $responseStatus = -1; $responseType = ''; @@ -77,7 +77,7 @@ protected function call(string $method, string $path = '', array $headers = [], } foreach ($headers as $i => $header) { - $headers[] = $i.':'.$header; + $headers[] = $i . ':' . $header; unset($headers[$i]); } @@ -122,7 +122,7 @@ protected function call(string $method, string $path = '', array $headers = [], $json = json_decode($responseBody, true); if ($json === null) { - throw new Exception('Failed to parse response: '.$responseBody); + throw new Exception('Failed to parse response: ' . $responseBody); } $responseBody = $json; @@ -132,7 +132,7 @@ protected function call(string $method, string $path = '', array $headers = [], } if ((curl_errno($ch)/* || 200 != $responseStatus*/)) { - throw new Exception(curl_error($ch).' with status code '.$responseStatus, $responseStatus); + throw new Exception(curl_error($ch) . ' with status code ' . $responseStatus, $responseStatus); } curl_close($ch); @@ -140,7 +140,7 @@ protected function call(string $method, string $path = '', array $headers = [], $responseHeaders['status-code'] = $responseStatus; if ($responseStatus === 500) { - echo 'Server error('.$method.': '.$path.'. Params: '.json_encode($params).'): '.json_encode($responseBody)."\n"; + echo 'Server error(' . $method . ': ' . $path . '. Params: ' . json_encode($params) . '): ' . json_encode($responseBody) . "\n"; } return [ diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 06026458..cfb99fb4 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -84,7 +84,7 @@ protected function generateAccessToken(string $privateKey, string $githubAppId) $jwt = new JWT($privateKey, 'RS256'); $token = $jwt->encode($payload); $this->jwtToken = $token; - $res = $this->call(self::METHOD_POST, '/app/installations/'.$this->installationId.'/access_tokens', ['Authorization' => 'Bearer '.$token]); + $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); $this->accessToken = $res['body']['token']; var_dump($this->accessToken); } @@ -118,7 +118,7 @@ public function isGitFlow(): bool */ public function getUser(string $username): array { - $response = $this->call(self::METHOD_GET, '/users/'.$username); + $response = $this->call(self::METHOD_GET, '/users/' . $username); return $response; } @@ -130,7 +130,7 @@ public function getUser(string $username): array */ public function getOwnerName($installationId): string { - $url = '/app/installations/'.$installationId; + $url = '/app/installations/' . $installationId; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->jwtToken"]); return $response['body']['account']['login']; @@ -145,7 +145,7 @@ public function getOwnerName($installationId): string */ public function listRepositoriesForGitHubApp($page, $per_page): array { - $url = '/installation/repositories?page='.$page.'&per_page='.$per_page; + $url = '/installation/repositories?page=' . $page . '&per_page=' . $per_page; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); @@ -220,7 +220,7 @@ public function getPullRequest(string $owner, string $repoName, $pullRequestNumb */ public function createComment(string $owner, string $repoName, $pullRequestNumber, $comment) { - $url = '/repos/'.$owner.'/'.$repoName.'/issues/'.$pullRequestNumber.'/comments'; + $url = '/repos/' . $owner . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments'; $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); $commentId = $response['body']['id']; @@ -237,7 +237,7 @@ public function createComment(string $owner, string $repoName, $pullRequestNumbe */ public function getComment($owner, $repoName, $commentId): string { - $url = '/repos/'.$owner.'/'.$repoName.'/issues/comments/'.$commentId; + $url = '/repos/' . $owner . '/' . $repoName . '/issues/comments/' . $commentId; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); $comment = $response['body']['body']; @@ -254,7 +254,7 @@ public function getComment($owner, $repoName, $commentId): string */ public function updateComment($owner, $repoName, $commentId, $comment) { - $url = '/repos/'.$owner.'/'.$repoName.'/issues/comments/'.$commentId; + $url = '/repos/' . $owner . '/' . $repoName . '/issues/comments/' . $commentId; $response = $this->call(self::METHOD_PATCH, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); $commentId = $response['body']['id']; @@ -273,10 +273,10 @@ public function updateComment($owner, $repoName, $commentId, $comment) public function downloadRepositoryZip(string $owner, string $repoName, string $ref, string $path = ''): string { // Build the URL for the API request - $url = '/repos/'.$owner."/{$repoName}/zipball/{$ref}"; + $url = '/repos/' . $owner . "/{$repoName}/zipball/{$ref}"; // Add the path parameter to the URL query parameters, if specified - if (! empty($path)) { + if (!empty($path)) { $url .= "?path={$path}"; } @@ -296,7 +296,7 @@ public function downloadRepositoryZip(string $owner, string $repoName, string $r public function downloadRepositoryTar(string $owner, string $repoName, string $ref): string { // Build the URL for the API request - $url = '/repos/'.$owner."/{$repoName}/tarball/{$ref}"; + $url = '/repos/' . $owner . "/{$repoName}/tarball/{$ref}"; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); @@ -355,7 +355,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s */ public function validateWebhook(string $payload, string $signature, string $signatureKey) { - return $signature === ('sha256='.hash_hmac('sha256', $payload, $signatureKey)); + return $signature === ('sha256=' . hash_hmac('sha256', $payload, $signatureKey)); } /** @@ -512,7 +512,7 @@ public function getRepositoryLanguages(string $owner, string $repositoryName): ? public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array { $url = "/repos/$owner/$repositoryName/contents"; - if (! empty($path)) { + if (!empty($path)) { $url .= "/$path"; } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index cef11a89..a8c9df8d 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -201,7 +201,7 @@ public function testListRepositoryContents(): void public function testGetBranchPullRequest(): void { - $result = $this->github->getBranchPullRequest("vermakhushboo", "basic-js-crud", "test"); + $result = $this->github->getBranchPullRequest('vermakhushboo', 'basic-js-crud', 'test'); $this->assertIsArray($result); $this->assertNotEmpty($result); } @@ -222,7 +222,7 @@ public function testGetPullRequest(): void } public function testGetComment(): void - { + { $owner = 'vermakhushboo'; $repositoryName = 'basic-js-crud'; $commentId = '1431560395'; From 40c4683de4d792e07dcdbe2d488f5d98973d6c67 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 10 Jul 2023 11:16:13 +0530 Subject: [PATCH 092/147] Update getting started steps --- README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index eef7359f..5eada256 100644 --- a/README.md +++ b/README.md @@ -22,22 +22,26 @@ Init in your application: require_once __DIR__ . '/../../vendor/autoload.php'; use Utopia\VCS\Adapter\Git\GitHub; -use Utopia\App; -use Utopia\Cache\Adapter\None; -use Utopia\Cache\Cache; // Initialise your adapter -$github = new GitHub(new Cache(new None())); +$github = new GitHub(); -// Set and read values from environment variables -$privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); -$githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); -$installationId = '1234'; //your GitHub App Installation ID here +// Your GitHub app private key. You can generate this from your GitHub App settings. +$privateKey = 'your-github-app-private-key'; + +// Your GitHub App ID. You can find this in the GitHub App dashboard. +$githubAppId = 'your-github-app-id'; + +// Your GitHub App installation ID. You can find this in the GitHub App installation settings. +$installationId = 'your-github-app-installation-id'; // Initialise variables $github->initialiseVariables($installationId, $privateKey, $githubAppId, 'github-username'); -// Perform the actions that you want +// Perform the actions that you want, ex: create repository +$owner = ''; +$name = ''; +$isPrivate = true; // Set to false if you want to create a public repository $repository = $github->createRepository($owner, $name, $private); ``` From 65f75d16f55d08efe0f509eab7bfc3d92c1daadf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Jul 2023 09:18:34 +0200 Subject: [PATCH 093/147] Add CI/CD --- .github/workflows/codeql-analysis.yml | 16 ++++++++++++++++ .github/workflows/linter.yml | 16 ++++++++++++++++ composer.json | 7 ++++--- phpstan.neon | 5 +++++ pint.json | 6 ++++++ 5 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/linter.yml create mode 100644 phpstan.neon create mode 100644 pint.json diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..3253e2c3 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,16 @@ +name: "CodeQL" + +on: [pull_request] +jobs: + lint: + name: CodeQL + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Run CodeQL + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer check" \ No newline at end of file diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml new file mode 100644 index 00000000..28f4c6a0 --- /dev/null +++ b/.github/workflows/linter.yml @@ -0,0 +1,16 @@ +name: "Linter" + +on: [pull_request] +jobs: + lint: + name: Linter + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Run Linter + run: | + docker run --rm -v $PWD:/app composer sh -c \ + "composer install --profile --ignore-platform-reqs && composer lint" \ No newline at end of file diff --git a/composer.json b/composer.json index eca93ad4..0f95df2f 100644 --- a/composer.json +++ b/composer.json @@ -11,9 +11,10 @@ "license": "MIT", "minimum-stability": "stable", "scripts": { - "lint": "./vendor/bin/pint --test", - "format": "./vendor/bin/pint", - "test": "vendor/bin/phpunit --configuration phpunit.xml" + "lint": "./vendor/bin/pint --test --config pint.json", + "format": "./vendor/bin/pint --config pint.json", + "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon app src tests", + "test": "./vendor/bin/phpunit --configuration phpunit.xml --debug" }, "autoload": { "psr-4": { diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..c41461e4 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,5 @@ +parameters: + scanDirectories: + - vendor/swoole/ide-helper + excludePaths: + - tests/resources \ No newline at end of file diff --git a/pint.json b/pint.json new file mode 100644 index 00000000..70add709 --- /dev/null +++ b/pint.json @@ -0,0 +1,6 @@ +{ + "preset": "psr12", + "exclude": [ + "tests/resources" + ] +} \ No newline at end of file From 3136a4587d6838417100b9fd31f6371052d1d9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Jul 2023 09:20:52 +0200 Subject: [PATCH 094/147] Fix phpstan --- composer.json | 5 +- composer.lock | 85 ++++++++++++++++++++++++++++------ phpstan.neon | 2 - src/VCS/Adapter/Git/GitHub.php | 6 +-- 4 files changed, 78 insertions(+), 20 deletions(-) diff --git a/composer.json b/composer.json index 0f95df2f..10bb5da7 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "scripts": { "lint": "./vendor/bin/pint --test --config pint.json", "format": "./vendor/bin/pint --config pint.json", - "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon app src tests", + "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon src tests", "test": "./vendor/bin/phpunit --configuration phpunit.xml --debug" }, "autoload": { @@ -35,6 +35,7 @@ }, "require-dev": { "phpunit/phpunit": "^9.4", - "laravel/pint": "1.2.*" + "laravel/pint": "1.2.*", + "phpstan/phpstan": "1.8.*" } } diff --git a/composer.lock b/composer.lock index de77eec3..442378af 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7427d56641753b0991ad05ef5c7a168f", + "content-hash": "6212d04d6bd97ce55995cc4fe998686e", "packages": [ { "name": "adhocore/jwt", @@ -355,16 +355,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.15.5", + "version": "v4.16.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e" + "reference": "19526a33fb561ef417e822e85f08a00db4059c17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/11e2663a5bc9db5d714eedb4277ee300403b4a9e", - "reference": "11e2663a5bc9db5d714eedb4277ee300403b4a9e", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/19526a33fb561ef417e822e85f08a00db4059c17", + "reference": "19526a33fb561ef417e822e85f08a00db4059c17", "shasum": "" }, "require": { @@ -405,9 +405,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.5" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.16.0" }, - "time": "2023-05-19T20:20:00+00:00" + "time": "2023-06-25T14:52:30+00:00" }, { "name": "phar-io/manifest", @@ -520,6 +520,65 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/phpstan", + "version": "1.8.11", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "46e223dd68a620da18855c23046ddb00940b4014" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/46e223dd68a620da18855c23046ddb00940b4014", + "reference": "46e223dd68a620da18855c23046ddb00940b4014", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/1.8.11" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2022-10-24T15:45:13+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.26", @@ -840,16 +899,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.8", + "version": "9.6.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e" + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/17d621b3aff84d0c8b62539e269e87d8d5baa76e", - "reference": "17d621b3aff84d0c8b62539e269e87d8d5baa76e", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a6d351645c3fe5a30f5e86be6577d946af65a328", + "reference": "a6d351645c3fe5a30f5e86be6577d946af65a328", "shasum": "" }, "require": { @@ -923,7 +982,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.8" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.10" }, "funding": [ { @@ -939,7 +998,7 @@ "type": "tidelift" } ], - "time": "2023-05-11T05:14:45+00:00" + "time": "2023-07-10T04:04:23+00:00" }, { "name": "sebastian/cli-parser", diff --git a/phpstan.neon b/phpstan.neon index c41461e4..8b576c6f 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,3 @@ parameters: - scanDirectories: - - vendor/swoole/ide-helper excludePaths: - tests/resources \ No newline at end of file diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index cfb99fb4..56d74443 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -9,11 +9,11 @@ class GitHub extends Git { - const EVENT_PUSH = 'push'; + public const EVENT_PUSH = 'push'; - const EVENT_PULL_REQUEST = 'pull_request'; + public const EVENT_PULL_REQUEST = 'pull_request'; - const EVENT_INSTALLATION = 'installation'; + public const EVENT_INSTALLATION = 'installation'; protected string $endpoint = 'https://api.github.com'; From 59f6c51e22beb6bcd93224849e7fa216c2a41040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Jul 2023 09:48:19 +0200 Subject: [PATCH 095/147] Fix some code QL errors --- src/Detector/Adapter.php | 9 +++++++++ src/Detector/Adapter/CPP.php | 9 +++++++++ src/Detector/Adapter/Dart.php | 9 +++++++++ src/Detector/Adapter/Deno.php | 9 +++++++++ src/Detector/Adapter/Dotnet.php | 9 +++++++++ src/Detector/Adapter/Java.php | 9 +++++++++ src/Detector/Adapter/JavaScript.php | 9 +++++++++ src/Detector/Adapter/PHP.php | 9 +++++++++ src/Detector/Adapter/Python.php | 9 +++++++++ src/Detector/Adapter/Ruby.php | 9 +++++++++ src/Detector/Adapter/Swift.php | 9 +++++++++ src/Detector/Detector.php | 4 ++++ src/VCS/Adapter.php | 11 ++++++++--- src/VCS/Adapter/Git/GitHub.php | 5 +---- 14 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/Detector/Adapter.php b/src/Detector/Adapter.php index 07d12c61..2c73f344 100644 --- a/src/Detector/Adapter.php +++ b/src/Detector/Adapter.php @@ -4,12 +4,21 @@ abstract class Adapter { + /** + * @return string[] + */ abstract public function getLanguages(): array; abstract public function getRuntime(): string; + /** + * @return string[] + */ abstract public function getFileExtensions(): array; + /** + * @return string[] + */ abstract public function getFiles(): array; abstract public function getInstallCommand(): ?string; diff --git a/src/Detector/Adapter/CPP.php b/src/Detector/Adapter/CPP.php index acf6abb1..1ec5f1fb 100644 --- a/src/Detector/Adapter/CPP.php +++ b/src/Detector/Adapter/CPP.php @@ -6,6 +6,9 @@ class CPP extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['C++']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'cpp'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['cpp', 'h', 'hpp', 'cxx', 'cc']; } + /** + * @return string[] + */ public function getFiles(): array { return ['main.cpp', 'Solution', 'CMakeLists.txt', '.clang-format']; diff --git a/src/Detector/Adapter/Dart.php b/src/Detector/Adapter/Dart.php index ba422bbf..271d69f1 100644 --- a/src/Detector/Adapter/Dart.php +++ b/src/Detector/Adapter/Dart.php @@ -6,6 +6,9 @@ class Dart extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['Dart']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'dart'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['dart']; } + /** + * @return string[] + */ public function getFiles(): array { return ['pubspec.yaml', 'pubspec.lock']; diff --git a/src/Detector/Adapter/Deno.php b/src/Detector/Adapter/Deno.php index 0bb5e7ef..3f0cc8b9 100644 --- a/src/Detector/Adapter/Deno.php +++ b/src/Detector/Adapter/Deno.php @@ -6,6 +6,9 @@ class Deno extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['TypeScript']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'deno'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['ts', 'tsx']; } + /** + * @return string[] + */ public function getFiles(): array { return ['mod.ts', 'deps.ts']; diff --git a/src/Detector/Adapter/Dotnet.php b/src/Detector/Adapter/Dotnet.php index 7faf0a8e..8719c7e9 100644 --- a/src/Detector/Adapter/Dotnet.php +++ b/src/Detector/Adapter/Dotnet.php @@ -6,6 +6,9 @@ class Dotnet extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['C#', 'Visual Basic .NET']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'dotnet'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['cs', 'vb', 'sln', 'csproj', 'vbproj']; } + /** + * @return string[] + */ public function getFiles(): array { return ['Program.cs', 'Solution.sln', 'Function.csproj', 'Program.vb']; diff --git a/src/Detector/Adapter/Java.php b/src/Detector/Adapter/Java.php index 5304fbcc..a4b50900 100644 --- a/src/Detector/Adapter/Java.php +++ b/src/Detector/Adapter/Java.php @@ -6,6 +6,9 @@ class Java extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['Java']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'java'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['java', 'class', 'jar']; } + /** + * @return string[] + */ public function getFiles(): array { return ['pom.xml', 'pmd.xml', 'build.gradle', 'build.gradle.kts']; diff --git a/src/Detector/Adapter/JavaScript.php b/src/Detector/Adapter/JavaScript.php index 8dff5081..f33b099a 100644 --- a/src/Detector/Adapter/JavaScript.php +++ b/src/Detector/Adapter/JavaScript.php @@ -6,6 +6,9 @@ class JavaScript extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['JavaScript', 'TypeScript']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'node'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['js', 'ts']; } + /** + * @return string[] + */ public function getFiles(): array { return ['package.json', 'package-lock.json', 'yarn.lock', 'tsconfig.json']; diff --git a/src/Detector/Adapter/PHP.php b/src/Detector/Adapter/PHP.php index e109b84a..523b2880 100644 --- a/src/Detector/Adapter/PHP.php +++ b/src/Detector/Adapter/PHP.php @@ -6,6 +6,9 @@ class PHP extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['PHP']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'php'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['php']; } + /** + * @return string[] + */ public function getFiles(): array { return ['composer.json', 'composer.lock']; diff --git a/src/Detector/Adapter/Python.php b/src/Detector/Adapter/Python.php index 4c357461..406931aa 100644 --- a/src/Detector/Adapter/Python.php +++ b/src/Detector/Adapter/Python.php @@ -6,6 +6,9 @@ class Python extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['Python']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'python'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['py']; } + /** + * @return string[] + */ public function getFiles(): array { return ['requirements.txt', 'setup.py']; diff --git a/src/Detector/Adapter/Ruby.php b/src/Detector/Adapter/Ruby.php index 6ec68162..2ac17985 100644 --- a/src/Detector/Adapter/Ruby.php +++ b/src/Detector/Adapter/Ruby.php @@ -6,6 +6,9 @@ class Ruby extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['Ruby']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'ruby'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['rb']; } + /** + * @return string[] + */ public function getFiles(): array { return ['Gemfile', 'Gemfile.lock', 'Rakefile', 'Guardfile']; diff --git a/src/Detector/Adapter/Swift.php b/src/Detector/Adapter/Swift.php index 247d982d..a1ae80ab 100644 --- a/src/Detector/Adapter/Swift.php +++ b/src/Detector/Adapter/Swift.php @@ -6,6 +6,9 @@ class Swift extends Adapter { + /** + * @return string[] + */ public function getLanguages(): array { return ['Swift']; @@ -16,11 +19,17 @@ public function getRuntime(): string return 'swift'; } + /** + * @return string[] + */ public function getFileExtensions(): array { return ['swift', 'xcodeproj', 'xcworkspace']; } + /** + * @return string[] + */ public function getFiles(): array { return ['Package.swift', 'Podfile', 'project.pbxproj']; diff --git a/src/Detector/Detector.php b/src/Detector/Detector.php index 8c1ef242..4e967ad2 100644 --- a/src/Detector/Detector.php +++ b/src/Detector/Detector.php @@ -19,6 +19,10 @@ class Detector */ protected array $languages; + /** + * @param string[] $files + * @param string[] $languages + */ public function __construct(array $files = [], array $languages = []) { $this->files = $files; diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index f12baa1f..7383e5bf 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -42,10 +42,10 @@ abstract class Adapter * * @param string $method * @param string $path - * @param array $params - * @param array $headers + * @param array $params + * @param array $headers * @param bool $decode - * @return array|string + * @return array|string * * @throws Exception */ @@ -53,6 +53,11 @@ protected function call(string $method, string $path = '', array $headers = [], { $headers = array_merge($this->headers, $headers); $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); + + if(!$ch) { + throw new Exception('Curl failed to initialize'); + } + $responseHeaders = []; $responseStatus = -1; $responseType = ''; diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 56d74443..a40ad1e1 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -40,7 +40,7 @@ public function __construct(Cache $cache) /** * GitHub Initialisation with access token generation. */ - public function initialiseVariables(string $installationId, string $privateKey, string $githubAppId) + public function initialiseVariables(string $installationId, string $privateKey, string $githubAppId): void { $this->installationId = $installationId; @@ -61,9 +61,6 @@ public function initialiseVariables(string $installationId, string $privateKey, /** * Generate Access Token - * - * @param string $userName The username of account which has installed GitHub app - * @param string $installationId Installation ID of the GitHub App */ protected function generateAccessToken(string $privateKey, string $githubAppId) { From ecfe36f71affb251a606be640d0dbf9e475cd7ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Jul 2023 09:52:31 +0200 Subject: [PATCH 096/147] Add tests CI/CD --- .github/workflows/tests.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..96e68e0c --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,33 @@ +name: "Tests" + +on: [pull_request] +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + + steps: + - name: Check out the repo + uses: actions/checkout@v2 + + - name: Start Test Stack + run: | + export COMPOSE_INTERACTIVE_NO_CLI + export DOCKER_BUILDKIT=1 + export COMPOSE_DOCKER_CLI_BUILD=1 + export BUILDKIT_PROGRESS=plain + docker pull composer:2.0 + docker compose build + docker compose up -d + sleep 15 + + - name: Doctor + run: | + docker compose logs + docker ps + docker network ls + + - name: Run Tests + run: | + docker run --rm -v $PWD:/app --network openruntimes-runtimes -w /app phpswoole/swoole:4.8.12-php8.0-alpine sh -c \ + "composer install --profile --ignore-platform-reqs && composer test" \ No newline at end of file From 86cda7a3217c3eba213c6f334f2545cf8fbf4405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Jul 2023 09:53:46 +0200 Subject: [PATCH 097/147] Fix test --- .github/workflows/tests.yml | 3 +-- src/VCS/Adapter.php | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 96e68e0c..aa339a1e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -29,5 +29,4 @@ jobs: - name: Run Tests run: | - docker run --rm -v $PWD:/app --network openruntimes-runtimes -w /app phpswoole/swoole:4.8.12-php8.0-alpine sh -c \ - "composer install --profile --ignore-platform-reqs && composer test" \ No newline at end of file + docker-compose exec tests vendor/bin/phpunit --configuration phpunit.xml tests \ No newline at end of file diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 7383e5bf..88c68a0c 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -54,7 +54,7 @@ protected function call(string $method, string $path = '', array $headers = [], $headers = array_merge($this->headers, $headers); $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); - if(!$ch) { + if (!$ch) { throw new Exception('Curl failed to initialize'); } From de469271fefcdfcfdee3cc59753bbc00381b0129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Jul 2023 09:55:34 +0200 Subject: [PATCH 098/147] Simplify CI/CD test --- .github/workflows/tests.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index aa339a1e..7f2f30a5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,12 +12,6 @@ jobs: - name: Start Test Stack run: | - export COMPOSE_INTERACTIVE_NO_CLI - export DOCKER_BUILDKIT=1 - export COMPOSE_DOCKER_CLI_BUILD=1 - export BUILDKIT_PROGRESS=plain - docker pull composer:2.0 - docker compose build docker compose up -d sleep 15 From da63540aabee44cb75bdbbe861275afe48ecbefc Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 10 Jul 2023 13:26:29 +0530 Subject: [PATCH 099/147] Update add-new-adapter.md --- docs/add-new-adapter.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/add-new-adapter.md b/docs/add-new-adapter.md index c45e336d..6ab818b3 100644 --- a/docs/add-new-adapter.md +++ b/docs/add-new-adapter.md @@ -1,6 +1,18 @@ # Add new Detector Adapter -To get started with implementing a new adapter, start by reviewing the [README](/README.md) to understand the goals of this library. +To get started with implementing a new detector adapter, start by reviewing the [README](/README.md) to understand the goals of this library. + +### Introduction +- A `detector` is a class that defines the files, extensions, and languages that are associated with a specific runtime environment, such as Node.js, PHP, Ruby, or Python. The presence of these files, extensions, or languages can help automatically detect that runtime environment. +- To add a new detector adapter, you need to extend the Adapter parent class and define the following methods: + + - `getFiles()`: This method returns an array of files that are known to be associated with the runtime environment. + - `getFileExtensions()`: This method returns an array of file extensions that are known to be associated with the runtime environment. + - `getLanguages()`: This method returns an array of languages that are known to be associated with the runtime environment. + - `getInstallCommand()`: This method returns the command that can be used to install the runtime environment. + - `getBuildCommand()`: This method returns the command that can be used to build the project for the runtime environment. + - `getEntryPoint()`: This method returns the entry point for the project in the runtime environment. + ### File Structure @@ -32,8 +44,19 @@ use Utopia\Detector\Adapter; class NewDetector extends Adapter { + ...override all relevant methods +} +``` + +Once you have created a new detector adapter class, you can register it with the Appwrite runtime detector by calling the addDetector() method on the Detector class. + +```php +$detector = new Detector(); +$detector->addDetector(new NewDetector()); ``` +Once the `NewDetector` class is registered, the Appwrite runtime detector will be able to detect the new runtime to detect the runtime environment for the given files. + Only include dependencies strictly necessary for the detector, preferably official PHP libraries, if available. ### Testing with Docker From ecf407cece7fd225bb4adf54b333305c55178c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Jul 2023 09:57:16 +0200 Subject: [PATCH 100/147] Fix missing logs --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7f2f30a5..3224b2c9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,4 +23,4 @@ jobs: - name: Run Tests run: | - docker-compose exec tests vendor/bin/phpunit --configuration phpunit.xml tests \ No newline at end of file + docker-compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml tests \ No newline at end of file From de6e83f6334c6528eb29e7b871dedf6c85e9950d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Jul 2023 10:15:38 +0200 Subject: [PATCH 101/147] Fix empty rootDirectory --- src/VCS/Adapter/Git/GitHub.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index a40ad1e1..e1517464 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -333,6 +333,10 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio */ public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory) { + if (empty($rootDirectory)) { + $rootDirectory = '*'; + } + // Construct the clone URL with the access token $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; From 930cf1a5897e5f120178e71a09afde0a665dc5b9 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 10 Jul 2023 14:03:37 +0530 Subject: [PATCH 102/147] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 5eada256..9757e308 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ Utopia VCS is a simple and lite library for interacting with version control systems (VCS) in Utopia-PHP using adapters for different providers like GitHub, GitLab etc. This library is aiming to be as simple and easy to learn and use. This library is maintained by the [Appwrite team](https://appwrite.io). -Although this library is part of the [Utopia Framework](https://github.com/utopia-php/framework) project, it is dependency free and can be used as standalone with any other PHP project or framework. - ## Getting Started Install using composer: From d0e3582358a53b1e578af9e5598637f33a853300 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:19:55 +0530 Subject: [PATCH 103/147] Fixed PHPStan errors --- docker-compose.yml | 3 +- src/VCS/Adapter.php | 2 +- src/VCS/Adapter/Git/GitHub.php | 100 ++++++++++++++++++-------------- tests/Detector/DetectorTest.php | 18 +++--- tests/VCS/GitHubTest.php | 23 ++++---- 5 files changed, 83 insertions(+), 63 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7c279b21..f2df0ec6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,4 +11,5 @@ services: environment: - GITHUB_PRIVATE_KEY - GITHUB_APP_IDENTIFIER - - GITHUB_WEBHOOK_SECRET \ No newline at end of file + - GITHUB_WEBHOOK_SECRET + - GITHUB_INSTALLATION_ID \ No newline at end of file diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 88c68a0c..3ad9b0fa 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -45,7 +45,7 @@ abstract class Adapter * @param array $params * @param array $headers * @param bool $decode - * @return array|string + * @return array * * @throws Exception */ diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index e1517464..6466c685 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -62,11 +62,10 @@ public function initialiseVariables(string $installationId, string $privateKey, /** * Generate Access Token */ - protected function generateAccessToken(string $privateKey, string $githubAppId) + protected function generateAccessToken(string $privateKey, string $githubAppId): void { // fetch env variables from .env file - $privateKeyString = $privateKey; - $privateKey = openssl_pkey_get_private($privateKeyString); + $privateKey = openssl_pkey_get_private($privateKey); $appIdentifier = $githubAppId; $iat = time(); @@ -109,7 +108,7 @@ public function isGitFlow(): bool /** * Get user * - * @return array + * @return array * * @throws Exception */ @@ -125,7 +124,7 @@ public function getUser(string $username): array * * @return string */ - public function getOwnerName($installationId): string + public function getOwnerName(string $installationId): string { $url = '/app/installations/' . $installationId; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->jwtToken"]); @@ -135,8 +134,9 @@ public function getOwnerName($installationId): string /** * List repositories for GitHub App - * - * @return array + * @param int $page page number + * @param int $per_page number of results per page + * @return array * * @throws Exception */ @@ -151,6 +151,7 @@ public function listRepositoriesForGitHubApp($page, $per_page): array /** * Get latest opened pull request with specific base branch + * @return array */ public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array { @@ -165,7 +166,7 @@ public function getBranchPullRequest(string $owner, string $repositoryName, stri /** * Get GitHub repository * - * @return array + * @return array * * @throws Exception */ @@ -178,6 +179,11 @@ public function getRepository(string $owner, string $repositoryName): array return $response['body']; } + /** + * Create new repository + * + * @return array Details of new repository + */ public function createRepository(string $owner, string $repositoryName, bool $private): array { $url = "/orgs/{$owner}/repos"; @@ -199,9 +205,14 @@ public function getTotalReposCount(): int return $response['body']['total_count']; } - public function getPullRequest(string $owner, string $repoName, $pullRequestNumber): array + /** + * Get Pull Request + * + * @return array The retrieved pull request + */ + public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array { - $url = "/repos/{$owner}/{$repoName}/pulls/{$pullRequestNumber}"; + $url = "/repos/{$owner}/{$repositoryName}/pulls/{$pullRequestNumber}"; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); @@ -211,13 +222,13 @@ public function getPullRequest(string $owner, string $repoName, $pullRequestNumb /** * Add Comment to Pull Request * - * @return array + * @return string * * @throws Exception */ - public function createComment(string $owner, string $repoName, $pullRequestNumber, $comment) + public function createComment(string $owner, string $repositoryName, int $pullRequestNumber, string $comment): string { - $url = '/repos/' . $owner . '/' . $repoName . '/issues/' . $pullRequestNumber . '/comments'; + $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/' . $pullRequestNumber . '/comments'; $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); $commentId = $response['body']['id']; @@ -228,13 +239,16 @@ public function createComment(string $owner, string $repoName, $pullRequestNumbe /** * Get Comment of Pull Request * - * @return string + * @param string $owner The owner of the repository + * @param string $repositoryName The name of the repository + * @param string $commentId The ID of the comment to retrieve + * @return string The retrieved comment * * @throws Exception */ - public function getComment($owner, $repoName, $commentId): string + public function getComment($owner, $repositoryName, $commentId): string { - $url = '/repos/' . $owner . '/' . $repoName . '/issues/comments/' . $commentId; + $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/comments/' . $commentId; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); $comment = $response['body']['body']; @@ -245,13 +259,17 @@ public function getComment($owner, $repoName, $commentId): string /** * Update Pull Request Comment * - * @return array + * @param string $owner The owner of the repository + * @param string $repositoryName The name of the repository + * @param string $commentId The ID of the comment to update + * @param string $comment The updated comment content + * @return string The ID of the updated comment * * @throws Exception */ - public function updateComment($owner, $repoName, $commentId, $comment) + public function updateComment($owner, $repositoryName, $commentId, $comment): string { - $url = '/repos/' . $owner . '/' . $repoName . '/issues/comments/' . $commentId; + $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/comments/' . $commentId; $response = $this->call(self::METHOD_PATCH, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); $commentId = $response['body']['id']; @@ -262,15 +280,15 @@ public function updateComment($owner, $repoName, $commentId, $comment) /** * Downloads a ZIP archive of a repository. * - * @param string $repo The name of the repository. + * @param string $repositoryName The name of the repository. * @param string $ref The name of the commit, branch, or tag to download. * @param string $path The path of the file or directory to download. Optional. * @return string The contents of the ZIP archive as a string. */ - public function downloadRepositoryZip(string $owner, string $repoName, string $ref, string $path = ''): string + public function downloadRepositoryZip(string $owner, string $repositoryName, string $ref, string $path = ''): string { // Build the URL for the API request - $url = '/repos/' . $owner . "/{$repoName}/zipball/{$ref}"; + $url = '/repos/' . $owner . "/{$repositoryName}/zipball/{$ref}"; // Add the path parameter to the URL query parameters, if specified if (!empty($path)) { @@ -286,14 +304,12 @@ public function downloadRepositoryZip(string $owner, string $repoName, string $r /** * Downloads a tar archive of a repository. * - * @param string $repo The name of the repository. - * @param string $ref The name of the commit, branch, or tag to download. * @return string The contents of the tar archive as a string. */ - public function downloadRepositoryTar(string $owner, string $repoName, string $ref): string + public function downloadRepositoryTar(string $owner, string $repositoryName, string $ref): string { // Build the URL for the API request - $url = '/repos/' . $owner . "/{$repoName}/tarball/{$ref}"; + $url = '/repos/' . $owner . "/{$repositoryName}/tarball/{$ref}"; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); @@ -309,7 +325,7 @@ public function downloadRepositoryTar(string $owner, string $repoName, string $r * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. - * @return array|null The data of the newly forked repository, or null if the fork operation failed. + * @return array|null The data of the newly forked repository, or null if the fork operation failed. */ public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?array { @@ -331,7 +347,7 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio /** * Generates a git clone command using app access token */ - public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory) + public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string { if (empty($rootDirectory)) { $rootDirectory = '*'; @@ -354,7 +370,7 @@ public function generateGitCloneCommand(string $owner, string $repositoryName, s * @param string $signatureKey Webhook secret configured on GitHub * @return bool */ - public function validateWebhook(string $payload, string $signature, string $signatureKey) + public function validateWebhook(string $payload, string $signature, string $signatureKey): bool { return $signature === ('sha256=' . hash_hmac('sha256', $payload, $signatureKey)); } @@ -364,9 +380,9 @@ public function validateWebhook(string $payload, string $signature, string $sign * * @param string $event Type of event: push, pull_request etc * @param string $payload The webhook payload received from GitHub - * @return json Parsed payload as a json object + * @return array Parsed payload as a json object */ - public function parseWebhookEventPayload(string $event, string $payload) + public function parseWebhookEventPayload(string $event, string $payload): array { $payload = json_decode($payload, true); $installationId = strval($payload['installation']['id']); @@ -391,7 +407,6 @@ public function parseWebhookEventPayload(string $event, string $payload) 'pullRequestNumber' => '', 'action' => '', ]; - break; case 'pull_request': $repositoryId = strval($payload['repository']['id']); $branch = $payload['pull_request']['head']['ref']; @@ -413,8 +428,8 @@ public function parseWebhookEventPayload(string $event, string $payload) 'owner' => $owner, 'external' => $external, ]; - break; - case 'installation' || 'installation_repositories': + case 'installation': + case 'installation_repositories': $action = $payload['action']; $userName = $payload['installation']['account']['login']; @@ -423,7 +438,6 @@ public function parseWebhookEventPayload(string $event, string $payload) 'installationId' => $installationId, 'userName' => $userName, ]; - break; } return []; @@ -432,10 +446,10 @@ public function parseWebhookEventPayload(string $event, string $payload) /** * Fetches repository name using repository id * - * @param string $repository ID of GitHub Repository + * @param string $repositoryId ID of GitHub Repository * @return string name of GitHub repository */ - public function getRepositoryName(string $repositoryId) + public function getRepositoryName(string $repositoryId): string { $url = "/repositories/$repositoryId"; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); @@ -448,7 +462,7 @@ public function getRepositoryName(string $repositoryId) * * @param string $owner Owner name of the repository * @param string $repositoryName Name of the GitHub repository - * @return array List of branch names as array + * @return array List of branch names as array */ public function listBranches(string $owner, string $repositoryName): array { @@ -468,7 +482,7 @@ public function listBranches(string $owner, string $repositoryName): array * Updates status check of each commit * state can be one of: error, failure, pending, success */ - public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = '', string $target_url = '', string $context = '') + public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = '', string $target_url = '', string $context = ''): void { $url = "/repos/$owner/$repositoryName/statuses/$SHA"; @@ -487,9 +501,9 @@ public function updateCommitStatus(string $repositoryName, string $SHA, string $ * * @param string $owner Owner name of the repository * @param string $repositoryName Name of the GitHub repository - * @return array|null List of repository languages or null if the request fails + * @return array List of repository languages */ - public function getRepositoryLanguages(string $owner, string $repositoryName): ?array + public function getRepositoryLanguages(string $owner, string $repositoryName): array { $url = "/repos/$owner/$repositoryName/languages"; @@ -499,7 +513,7 @@ public function getRepositoryLanguages(string $owner, string $repositoryName): ? return array_keys($response['body']); } - return null; + return []; } /** @@ -508,7 +522,7 @@ public function getRepositoryLanguages(string $owner, string $repositoryName): ? * @param string $owner Owner name of the repository * @param string $repositoryName Name of the GitHub repository * @param string $path Path to list contents from - * @return array List of contents at the specified path + * @return array List of contents at the specified path */ public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array { diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 4a9e37ff..4d7c4447 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -21,9 +21,13 @@ class DetectorTest extends TestCase { - protected $github; + protected GitHub $github; - public function detect($files, $languages): string + /** + * @param array $files + * @param array $languages + */ + public function detect($files, $languages): ?string { $detectorFactory = new Detector($files, $languages); @@ -47,13 +51,13 @@ public function detect($files, $languages): string public function setUp(): void { $this->github = new GitHub(new Cache(new None())); - $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); - $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); - $installationId = '1234'; //your GitHub App Installation ID here - $this->github->initialiseVariables($installationId, $privateKey, $githubAppId, 'vermakhushboo'); + $privateKey = App::getEnv('GITHUB_PRIVATE_KEY') ?? ''; + $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER') ?? ''; + $installationId = App::getEnv('GITHUB_INSTALLATION_ID') ?? ''; + $this->github->initialiseVariables($installationId, $privateKey, $githubAppId); } - public function testLanguageDetection() + public function testLanguageDetection(): void { $languageMap = [ ['vermakhushboo', 'basic-js-crud', 'node'], diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index a8c9df8d..eaafa59e 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -10,15 +10,15 @@ class GitHubTest extends TestCase { - protected $github; + protected GitHub $github; public function setUp(): void { $this->github = new GitHub(new Cache(new None())); - $privateKey = App::getEnv('GITHUB_PRIVATE_KEY'); - $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER'); - $installationId = '1234'; //your GitHub App Installation ID here - $this->github->initialiseVariables($installationId, $privateKey, $githubAppId, 'vermakhushboo'); + $privateKey = App::getEnv('GITHUB_PRIVATE_KEY') ?? ''; + $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER') ?? ''; + $installationId = App::getEnv('GITHUB_INSTALLATION_ID') ?? ''; + $this->github->initialiseVariables($installationId, $privateKey, $githubAppId); } public function testGetUser(): void @@ -29,8 +29,9 @@ public function testGetUser(): void public function testGetOwnerName(): void { - $owner = $this->github->getOwnerName('37569846'); - $this->assertEquals('vermakhushboo', $owner); + $installationId = App::getEnv('GITHUB_INSTALLATION_ID') ?? ''; + $owner = $this->github->getOwnerName($installationId); + $this->assertEquals('appwrite', $owner); } public function testListRepositoriesForGitHubApp(): void @@ -60,7 +61,7 @@ public function testUpdateComment(): void public function testDownloadRepositoryZip(): void { // download the zip archive of the repo - $zipContents = $this->github->downloadRepositoryZip('vermakhushboo', 'gatsby-ecommerce-theme', 'main'); + $zipContents = $this->github->downloadRepositoryZip('appwrite', 'demos-for-react', 'main'); // Save the ZIP archive to a file file_put_contents('./desktop/hello-world.zip', $zipContents); @@ -72,7 +73,7 @@ public function testDownloadRepositoryZip(): void public function testDownloadRepositoryTar(): void { // download the tar archive of the repo - $tarContents = $this->github->downloadRepositoryTar('vermakhushboo', 'gatsby-ecommerce-theme', 'main'); + $tarContents = $this->github->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); // Save the TAR archive to a file file_put_contents('./desktop/hello-world1.tar', $tarContents); @@ -170,8 +171,8 @@ public function testParseWebhookEventPayload(): void public function testGetRepositoryName(): void { - $repoName = $this->github->getRepositoryName('432284323'); - $this->assertEquals('basic-js-crud', $repoName); + $repositoryName = $this->github->getRepositoryName('432284323'); + $this->assertEquals('basic-js-crud', $repositoryName); } public function testListBranches(): void From 10678901779e44d7f776ae8137330fdfb683e156 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 11 Jul 2023 10:08:41 +0200 Subject: [PATCH 104/147] Resolve warnings --- src/VCS/Adapter.php | 18 ++++++++++++------ src/VCS/Adapter/Git/GitHub.php | 19 ++++++++++++------- tests/VCS/GitHubTest.php | 6 +++--- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 3ad9b0fa..7c30870f 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -117,14 +117,20 @@ protected function call(string $method, string $path = '', array $headers = [], curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); } - $responseBody = curl_exec($ch); + $responseBody = \curl_exec($ch) ?: ''; + + if ($responseBody === true) { + $responseBody = ''; + } + $responseType = $responseHeaders['content-type'] ?? ''; - $responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $responseStatus = \curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($decode) { - switch (substr($responseType, 0, strpos($responseType, ';'))) { + $length = strpos($responseType, ';') ?: 0; + switch (substr($responseType, 0, $length)) { case 'application/json': - $json = json_decode($responseBody, true); + $json = \json_decode($responseBody, true); if ($json === null) { throw new Exception('Failed to parse response: ' . $responseBody); @@ -157,9 +163,9 @@ protected function call(string $method, string $path = '', array $headers = [], /** * Flatten params array to PHP multiple format * - * @param array $data + * @param array $data * @param string $prefix - * @return array + * @return array */ protected function flatten(array $data, string $prefix = ''): array { diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 6466c685..3632e45e 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -48,10 +48,12 @@ public function initialiseVariables(string $installationId, string $privateKey, if ($response == false) { $this->generateAccessToken($privateKey, $githubAppId); - $this->cache->save($installationId, \json_encode([ + $tokens = \json_encode([ 'jwtToken' => $this->jwtToken, 'accessToken' => $this->accessToken, - ])); + ]) ?: '{}'; + + $this->cache->save($installationId, $tokens); } else { $parsed = \json_decode($response, true); $this->jwtToken = $parsed['jwtToken']; @@ -64,8 +66,11 @@ public function initialiseVariables(string $installationId, string $privateKey, */ protected function generateAccessToken(string $privateKey, string $githubAppId): void { - // fetch env variables from .env file - $privateKey = openssl_pkey_get_private($privateKey); + /** + * @var resource $privateKeyObj + */ + $privateKeyObj = \openssl_pkey_get_private($privateKey); + $appIdentifier = $githubAppId; $iat = time(); @@ -77,7 +82,7 @@ protected function generateAccessToken(string $privateKey, string $githubAppId): ]; // generate access token - $jwt = new JWT($privateKey, 'RS256'); + $jwt = new JWT($privateKeyObj, 'RS256'); $token = $jwt->encode($payload); $this->jwtToken = $token; $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); @@ -226,7 +231,7 @@ public function getPullRequest(string $owner, string $repositoryName, int $pullR * * @throws Exception */ - public function createComment(string $owner, string $repositoryName, int $pullRequestNumber, string $comment): string + public function createComment(string $owner, string $repositoryName, string $pullRequestNumber, string $comment): string { $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/' . $pullRequestNumber . '/comments'; @@ -267,7 +272,7 @@ public function getComment($owner, $repositoryName, $commentId): string * * @throws Exception */ - public function updateComment($owner, $repositoryName, $commentId, $comment): string + public function updateComment(string $owner, string $repositoryName, string $commentId, string $comment): string { $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/comments/' . $commentId; diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index eaafa59e..151a6927 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -48,13 +48,13 @@ public function testGetTotalReposCount(): void public function testCreateComment(): void { - $commentId = $this->github->createComment('vermakhushboo', 'basic-js-crud', 1, 'hello'); + $commentId = $this->github->createComment('vermakhushboo', 'basic-js-crud', '1', 'hello'); $this->assertNotEmpty($commentId); } public function testUpdateComment(): void { - $commentId = $this->github->updateComment('vermakhushboo', 'basic-js-crud', 1431560395, 'update'); + $commentId = $this->github->updateComment('vermakhushboo', 'basic-js-crud', '1431560395', 'update'); $this->assertNotEmpty($commentId); } @@ -87,7 +87,7 @@ public function testForkRepository(): void // Fork a repository into authenticated user's account with custom name $response = $this->github->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); // Assert that the forked repo has the expected name - $this->assertEquals('fork-api-test-clone', $response['name']); + $this->assertEquals('fork-api-test-clone', $response['name'] ?? ''); } public function testGenerateGitCloneCommand(): void From 1dda6d46cf6611dc5ef2f268b5e531759e99f37f Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Jul 2023 13:49:00 +0530 Subject: [PATCH 105/147] Fixed tests --- src/VCS/Adapter/Git/GitHub.php | 11 +++++++++-- tests/VCS/GitHubTest.php | 29 ++++++++++++----------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 6466c685..5ef34d3f 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -196,6 +196,13 @@ public function createRepository(string $owner, string $repositoryName, bool $pr return $response['body']; } + public function deleteRepository(string $owner, string $repositoryName): void + { + $url = "/repos/{$owner}/{$repositoryName}"; + + $this->call(self::METHOD_DELETE, $url, ['Authorization' => "Bearer $this->accessToken"]); + } + public function getTotalReposCount(): int { $url = '/installation/repositories'; @@ -261,7 +268,7 @@ public function getComment($owner, $repositoryName, $commentId): string * * @param string $owner The owner of the repository * @param string $repositoryName The name of the repository - * @param string $commentId The ID of the comment to update + * @param int $commentId The ID of the comment to update * @param string $comment The updated comment content * @return string The ID of the updated comment * @@ -325,7 +332,7 @@ public function downloadRepositoryTar(string $owner, string $repositoryName, str * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. - * @return array|null The data of the newly forked repository, or null if the fork operation failed. + * @return array The data of the newly forked repository */ public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?array { diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index eaafa59e..06ebbfce 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -21,23 +21,17 @@ public function setUp(): void $this->github->initialiseVariables($installationId, $privateKey, $githubAppId); } - public function testGetUser(): void - { - $user = $this->github->getUser('vermakhushboo'); - $this->assertEquals('vermakhushboo', $user['body']['login']); - } - public function testGetOwnerName(): void { $installationId = App::getEnv('GITHUB_INSTALLATION_ID') ?? ''; $owner = $this->github->getOwnerName($installationId); - $this->assertEquals('appwrite', $owner); + $this->assertEquals('test-kh', $owner); } public function testListRepositoriesForGitHubApp(): void { - $repos = $this->github->listRepositoriesForGitHubApp(1, 3); - $this->assertCount(3, $repos); + $repos = $this->github->listRepositoriesForGitHubApp(1, 2); + $this->assertCount(2, $repos); } public function testGetTotalReposCount(): void @@ -48,26 +42,26 @@ public function testGetTotalReposCount(): void public function testCreateComment(): void { - $commentId = $this->github->createComment('vermakhushboo', 'basic-js-crud', 1, 'hello'); + $commentId = $this->github->createComment('test-kh', 'test2', 1, 'hello'); $this->assertNotEmpty($commentId); } public function testUpdateComment(): void { - $commentId = $this->github->updateComment('vermakhushboo', 'basic-js-crud', 1431560395, 'update'); + $commentId = $this->github->updateComment('test-kh', 'test2', 1630320767, 'update'); $this->assertNotEmpty($commentId); } public function testDownloadRepositoryZip(): void { // download the zip archive of the repo - $zipContents = $this->github->downloadRepositoryZip('appwrite', 'demos-for-react', 'main'); + $zipContents = $this->github->downloadRepositoryZip('test-kh', 'test2', 'main'); // Save the ZIP archive to a file - file_put_contents('./desktop/hello-world.zip', $zipContents); + file_put_contents('./hello-world.zip', $zipContents); // Assert that the file was saved successfully - $this->assertFileExists('./desktop/hello-world.zip'); + $this->assertFileExists('./hello-world.zip'); } public function testDownloadRepositoryTar(): void @@ -76,10 +70,10 @@ public function testDownloadRepositoryTar(): void $tarContents = $this->github->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); // Save the TAR archive to a file - file_put_contents('./desktop/hello-world1.tar', $tarContents); + file_put_contents('./hello-world.tar', $tarContents); // Assert that the file was saved successfully - $this->assertFileExists('./desktop/hello-world1.tar'); + $this->assertFileExists('./hello-world.tar'); } public function testForkRepository(): void @@ -88,11 +82,12 @@ public function testForkRepository(): void $response = $this->github->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); // Assert that the forked repo has the expected name $this->assertEquals('fork-api-test-clone', $response['name']); + $this->github->deleteRepository("test-kh", "fork-api-test-clone"); } public function testGenerateGitCloneCommand(): void { - $gitCloneCommand = $this->github->generateGitCloneCommand('vermakhushboo', 'Amigo', 'main', '', ''); + $gitCloneCommand = $this->github->generateGitCloneCommand('test-kh', 'test2', 'main', '', ''); $this->assertNotEmpty($gitCloneCommand); $this->assertStringContainsString('sparse-checkout', $gitCloneCommand); } From 8cf9268a7ec0e8f17ccfb9c4f7861f6615d09a8c Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Jul 2023 14:09:51 +0530 Subject: [PATCH 106/147] Fixed PHPStan errors --- src/VCS/Adapter/Git/GitHub.php | 10 +++++----- tests/VCS/GitHubTest.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index e693eba3..bbc9f7bf 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -238,7 +238,7 @@ public function getPullRequest(string $owner, string $repositoryName, int $pullR * * @throws Exception */ - public function createComment(string $owner, string $repositoryName, string $pullRequestNumber, string $comment): string + public function createComment(string $owner, string $repositoryName, int $pullRequestNumber, string $comment): string { $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/' . $pullRequestNumber . '/comments'; @@ -279,7 +279,7 @@ public function getComment($owner, $repositoryName, $commentId): string * * @throws Exception */ - public function updateComment(string $owner, string $repositoryName, string $commentId, string $comment): string + public function updateComment(string $owner, string $repositoryName, int $commentId, string $comment): string { $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/comments/' . $commentId; @@ -337,9 +337,9 @@ public function downloadRepositoryTar(string $owner, string $repositoryName, str * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. - * @return array The data of the newly forked repository + * @return string The name of the newly forked repository */ - public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?array + public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?string { $url = "/repos/$owner/$repo/forks"; @@ -353,7 +353,7 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio // Send the API request to fork the repository $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $data); - return $response['body']; + return $response['body']['name']; } /** diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 06ebbfce..76916bc5 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -81,7 +81,7 @@ public function testForkRepository(): void // Fork a repository into authenticated user's account with custom name $response = $this->github->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); // Assert that the forked repo has the expected name - $this->assertEquals('fork-api-test-clone', $response['name']); + $this->assertEquals('fork-api-test-clone', $response); $this->github->deleteRepository("test-kh", "fork-api-test-clone"); } From de8a37636261d29e54356e048bfa68f27cab2dcc Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:29:42 +0530 Subject: [PATCH 107/147] Updated secret names --- docker-compose.yml | 8 ++++---- tests/Detector/DetectorTest.php | 6 +++--- tests/VCS/GitHubTest.php | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f2df0ec6..c42ddb31 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ services: - ./tests:/usr/local/src/tests - ./phpunit.xml:/usr/local/src/phpunit.xml environment: - - GITHUB_PRIVATE_KEY - - GITHUB_APP_IDENTIFIER - - GITHUB_WEBHOOK_SECRET - - GITHUB_INSTALLATION_ID \ No newline at end of file + - PRIVATE_KEY + - APP_IDENTIFIER + - WEBHOOK_SECRET + - INSTALLATION_ID \ No newline at end of file diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index 4d7c4447..e75d42de 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -51,9 +51,9 @@ public function detect($files, $languages): ?string public function setUp(): void { $this->github = new GitHub(new Cache(new None())); - $privateKey = App::getEnv('GITHUB_PRIVATE_KEY') ?? ''; - $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER') ?? ''; - $installationId = App::getEnv('GITHUB_INSTALLATION_ID') ?? ''; + $privateKey = App::getEnv('PRIVATE_KEY') ?? ''; + $githubAppId = App::getEnv('APP_IDENTIFIER') ?? ''; + $installationId = App::getEnv('INSTALLATION_ID') ?? ''; $this->github->initialiseVariables($installationId, $privateKey, $githubAppId); } diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/GitHubTest.php index 76916bc5..24e3f1b1 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/GitHubTest.php @@ -15,15 +15,15 @@ class GitHubTest extends TestCase public function setUp(): void { $this->github = new GitHub(new Cache(new None())); - $privateKey = App::getEnv('GITHUB_PRIVATE_KEY') ?? ''; - $githubAppId = App::getEnv('GITHUB_APP_IDENTIFIER') ?? ''; - $installationId = App::getEnv('GITHUB_INSTALLATION_ID') ?? ''; + $privateKey = App::getEnv('PRIVATE_KEY') ?? ''; + $githubAppId = App::getEnv('APP_IDENTIFIER') ?? ''; + $installationId = App::getEnv('INSTALLATION_ID') ?? ''; $this->github->initialiseVariables($installationId, $privateKey, $githubAppId); } public function testGetOwnerName(): void { - $installationId = App::getEnv('GITHUB_INSTALLATION_ID') ?? ''; + $installationId = App::getEnv('INSTALLATION_ID') ?? ''; $owner = $this->github->getOwnerName($installationId); $this->assertEquals('test-kh', $owner); } From cda0728a8cc5250b06320ea9627c22591c1ed055 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:41:30 +0530 Subject: [PATCH 108/147] Add env variables to CI/CD workflow --- .github/workflows/tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3224b2c9..a172ad80 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,5 +22,9 @@ jobs: docker network ls - name: Run Tests + env: + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }} + INSTALLATION_ID: ${{ secrets.INSTALLATION_ID }} run: | docker-compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml tests \ No newline at end of file From 2fa461eb0bf56424a886765805bae47b9a73e115 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Jul 2023 16:33:27 +0530 Subject: [PATCH 109/147] Debugging --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a172ad80..e999a402 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,6 +12,7 @@ jobs: - name: Start Test Stack run: | + echo $PRIVATE_KEY docker compose up -d sleep 15 From 827fdf375571769ba5817171512f59a335898c61 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Jul 2023 16:39:17 +0530 Subject: [PATCH 110/147] More debugging --- .github/workflows/tests.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e999a402..a4cdba69 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,6 +11,10 @@ jobs: uses: actions/checkout@v2 - name: Start Test Stack + env: + PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} + APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }} + INSTALLATION_ID: ${{ secrets.INSTALLATION_ID }} run: | echo $PRIVATE_KEY docker compose up -d @@ -23,9 +27,5 @@ jobs: docker network ls - name: Run Tests - env: - PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }} - APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }} - INSTALLATION_ID: ${{ secrets.INSTALLATION_ID }} run: | docker-compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml tests \ No newline at end of file From 7b5c7f074006f2b956d82e1a8671b0c6d2317c00 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Tue, 11 Jul 2023 16:41:14 +0530 Subject: [PATCH 111/147] Tests passing --- .github/workflows/tests.yml | 1 - src/VCS/Adapter/Git/GitHub.php | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a4cdba69..f17f711f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,7 +16,6 @@ jobs: APP_IDENTIFIER: ${{ secrets.APP_IDENTIFIER }} INSTALLATION_ID: ${{ secrets.INSTALLATION_ID }} run: | - echo $PRIVATE_KEY docker compose up -d sleep 15 diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index bbc9f7bf..2640689c 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -87,7 +87,6 @@ protected function generateAccessToken(string $privateKey, string $githubAppId): $this->jwtToken = $token; $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); $this->accessToken = $res['body']['token']; - var_dump($this->accessToken); } /** From 778a1041ce0c11cc41d330f301e9f1aaa04e621d Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:00:30 +0530 Subject: [PATCH 112/147] Updated logic for empty root directory --- src/VCS/Adapter/Git/GitHub.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 2640689c..b9d0ca8e 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -360,7 +360,7 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio */ public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string { - if (empty($rootDirectory)) { + if ($rootDirectory === "./") { $rootDirectory = '*'; } From 1d2d648f10cbca20177d3cee0d894a39eb6aad1a Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:13:34 +0530 Subject: [PATCH 113/147] Testing --- src/VCS/Adapter/Git/GitHub.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index b9d0ca8e..d64d28d6 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -7,6 +7,8 @@ use Utopia\Cache\Cache; use Utopia\VCS\Adapter\Git; +use function PHPUnit\Framework\isEmpty; + class GitHub extends Git { public const EVENT_PUSH = 'push'; @@ -360,10 +362,16 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio */ public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string { - if ($rootDirectory === "./") { + var_dump("root " . $rootDirectory); + + var_dump(isEmpty($rootDirectory)); + + if (empty($rootDirectory)) { $rootDirectory = '*'; } + var_dump($rootDirectory); + // Construct the clone URL with the access token $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; From 57eba51dcbf9c69e8ca50229c2caf8ecdf6362e5 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 17 Jul 2023 14:19:29 +0530 Subject: [PATCH 114/147] Fixed and tested --- src/VCS/Adapter/Git/GitHub.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index d64d28d6..2640689c 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -7,8 +7,6 @@ use Utopia\Cache\Cache; use Utopia\VCS\Adapter\Git; -use function PHPUnit\Framework\isEmpty; - class GitHub extends Git { public const EVENT_PUSH = 'push'; @@ -362,16 +360,10 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio */ public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string { - var_dump("root " . $rootDirectory); - - var_dump(isEmpty($rootDirectory)); - if (empty($rootDirectory)) { $rootDirectory = '*'; } - var_dump($rootDirectory); - // Construct the clone URL with the access token $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; From 9611f7d5818b70a989ae2496be397151ae2f970a Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 19 Jul 2023 13:21:58 +0530 Subject: [PATCH 115/147] Added base.php to make tests extensible --- tests/VCS/{ => Adapter}/GitHubTest.php | 56 +++++++++++++------------- tests/VCS/Base.php | 51 +++++++++++++++++++++++ 2 files changed, 80 insertions(+), 27 deletions(-) rename tests/VCS/{ => Adapter}/GitHubTest.php (71%) create mode 100644 tests/VCS/Base.php diff --git a/tests/VCS/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php similarity index 71% rename from tests/VCS/GitHubTest.php rename to tests/VCS/Adapter/GitHubTest.php index 24e3f1b1..37c4b0ab 100644 --- a/tests/VCS/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -2,60 +2,62 @@ namespace Utopia\Tests; -use PHPUnit\Framework\TestCase; use Utopia\App; use Utopia\Cache\Adapter\None; use Utopia\Cache\Cache; use Utopia\VCS\Adapter\Git\GitHub; -class GitHubTest extends TestCase +class GitHubTest extends Base { - protected GitHub $github; + protected function createVCSAdapter() + { + return new GitHub(new Cache(new None())); + } public function setUp(): void { - $this->github = new GitHub(new Cache(new None())); + $this->vcsAdapter = new GitHub(new Cache(new None())); $privateKey = App::getEnv('PRIVATE_KEY') ?? ''; $githubAppId = App::getEnv('APP_IDENTIFIER') ?? ''; $installationId = App::getEnv('INSTALLATION_ID') ?? ''; - $this->github->initialiseVariables($installationId, $privateKey, $githubAppId); + $this->vcsAdapter->initialiseVariables($installationId, $privateKey, $githubAppId); } public function testGetOwnerName(): void { $installationId = App::getEnv('INSTALLATION_ID') ?? ''; - $owner = $this->github->getOwnerName($installationId); + $owner = $this->vcsAdapter->getOwnerName($installationId); $this->assertEquals('test-kh', $owner); } - public function testListRepositoriesForGitHubApp(): void + public function testListRepositories(): void { - $repos = $this->github->listRepositoriesForGitHubApp(1, 2); + $repos = $this->vcsAdapter->listRepositoriesForGitHubApp(1, 2); $this->assertCount(2, $repos); } public function testGetTotalReposCount(): void { - $count = $this->github->getTotalReposCount(); + $count = $this->vcsAdapter->getTotalReposCount(); $this->assertGreaterThanOrEqual(0, $count); } public function testCreateComment(): void { - $commentId = $this->github->createComment('test-kh', 'test2', 1, 'hello'); + $commentId = $this->vcsAdapter->createComment('test-kh', 'test2', 1, 'hello'); $this->assertNotEmpty($commentId); } public function testUpdateComment(): void { - $commentId = $this->github->updateComment('test-kh', 'test2', 1630320767, 'update'); + $commentId = $this->vcsAdapter->updateComment('test-kh', 'test2', 1630320767, 'update'); $this->assertNotEmpty($commentId); } public function testDownloadRepositoryZip(): void { // download the zip archive of the repo - $zipContents = $this->github->downloadRepositoryZip('test-kh', 'test2', 'main'); + $zipContents = $this->vcsAdapter->downloadRepositoryZip('test-kh', 'test2', 'main'); // Save the ZIP archive to a file file_put_contents('./hello-world.zip', $zipContents); @@ -67,7 +69,7 @@ public function testDownloadRepositoryZip(): void public function testDownloadRepositoryTar(): void { // download the tar archive of the repo - $tarContents = $this->github->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); + $tarContents = $this->vcsAdapter->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); // Save the TAR archive to a file file_put_contents('./hello-world.tar', $tarContents); @@ -79,15 +81,15 @@ public function testDownloadRepositoryTar(): void public function testForkRepository(): void { // Fork a repository into authenticated user's account with custom name - $response = $this->github->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); + $response = $this->vcsAdapter->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); // Assert that the forked repo has the expected name $this->assertEquals('fork-api-test-clone', $response); - $this->github->deleteRepository("test-kh", "fork-api-test-clone"); + $this->vcsAdapter->deleteRepository("test-kh", "fork-api-test-clone"); } - public function testGenerateGitCloneCommand(): void + public function testGenerateCloneCommand(): void { - $gitCloneCommand = $this->github->generateGitCloneCommand('test-kh', 'test2', 'main', '', ''); + $gitCloneCommand = $this->vcsAdapter->generateGitCloneCommand('test-kh', 'test2', 'main', '', ''); $this->assertNotEmpty($gitCloneCommand); $this->assertStringContainsString('sparse-checkout', $gitCloneCommand); } @@ -151,35 +153,35 @@ public function testParseWebhookEventPayload(): void } '; - $pushResult = $this->github->parseWebhookEventPayload('push', $payload_push); + $pushResult = $this->vcsAdapter->parseWebhookEventPayload('push', $payload_push); $this->assertEquals('main', $pushResult['branch']); $this->assertEquals('603754812', $pushResult['repositoryId']); - $pullRequestResult = $this->github->parseWebhookEventPayload('pull_request', $payload_pull_request); + $pullRequestResult = $this->vcsAdapter->parseWebhookEventPayload('pull_request', $payload_pull_request); $this->assertEquals('opened', $pullRequestResult['action']); $this->assertEquals(1, $pullRequestResult['pullRequestNumber']); - $uninstallResult = $this->github->parseWebhookEventPayload('installation', $payload_uninstall); + $uninstallResult = $this->vcsAdapter->parseWebhookEventPayload('installation', $payload_uninstall); $this->assertEquals('deleted', $uninstallResult['action']); $this->assertEquals(1234, $uninstallResult['installationId']); } public function testGetRepositoryName(): void { - $repositoryName = $this->github->getRepositoryName('432284323'); + $repositoryName = $this->vcsAdapter->getRepositoryName('432284323'); $this->assertEquals('basic-js-crud', $repositoryName); } public function testListBranches(): void { - $branches = $this->github->listBranches('vermakhushboo', 'basic-js-crud'); + $branches = $this->vcsAdapter->listBranches('vermakhushboo', 'basic-js-crud'); $this->assertIsArray($branches); $this->assertNotEmpty($branches); } public function testGetRepositoryLanguages(): void { - $languages = $this->github->getRepositoryLanguages('vermakhushboo', 'basic-js-crud'); + $languages = $this->vcsAdapter->getRepositoryLanguages('vermakhushboo', 'basic-js-crud'); $this->assertIsArray($languages); @@ -190,14 +192,14 @@ public function testGetRepositoryLanguages(): void public function testListRepositoryContents(): void { - $contents = $this->github->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); + $contents = $this->vcsAdapter->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); $this->assertIsArray($contents); $this->assertNotEmpty($contents); } public function testGetBranchPullRequest(): void { - $result = $this->github->getBranchPullRequest('vermakhushboo', 'basic-js-crud', 'test'); + $result = $this->vcsAdapter->getBranchPullRequest('vermakhushboo', 'basic-js-crud', 'test'); $this->assertIsArray($result); $this->assertNotEmpty($result); } @@ -208,7 +210,7 @@ public function testGetPullRequest(): void $repositoryName = 'basic-js-crud'; $pullRequestNumber = 1; - $result = $this->github->getPullRequest($owner, $repositoryName, $pullRequestNumber); + $result = $this->vcsAdapter->getPullRequest($owner, $repositoryName, $pullRequestNumber); $this->assertIsArray($result); $this->assertNotEmpty($result); @@ -223,7 +225,7 @@ public function testGetComment(): void $repositoryName = 'basic-js-crud'; $commentId = '1431560395'; - $result = $this->github->getComment($owner, $repositoryName, $commentId); + $result = $this->vcsAdapter->getComment($owner, $repositoryName, $commentId); $this->assertIsString($result); $this->assertNotEmpty($result); diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php new file mode 100644 index 00000000..53bb9f0b --- /dev/null +++ b/tests/VCS/Base.php @@ -0,0 +1,51 @@ +vcsAdapter = $this->createVCSAdapter(); + } + + abstract protected function createVCSAdapter(); + + abstract public function testGetOwnerName(): void; + + abstract public function testListRepositories(): void; + + abstract public function testGetTotalReposCount(): void; + + abstract public function testCreateComment(): void; + + abstract public function testUpdateComment(): void; + + abstract public function testDownloadRepositoryZip(): void; + + abstract public function testDownloadRepositoryTar(): void; + + abstract public function testForkRepository(): void; + + abstract public function testGenerateCloneCommand(): void; + + abstract public function testParseWebhookEventPayload(): void; + + abstract public function testGetRepositoryName(): void; + + abstract public function testListBranches(): void; + + abstract public function testGetRepositoryLanguages(): void; + + abstract public function testListRepositoryContents(): void; + + abstract public function testGetBranchPullRequest(): void; + + abstract public function testGetPullRequest(): void; + + abstract public function testGetComment(): void; +} From 431a27fbada7e518916961fbb3ea79389191ae02 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 19 Jul 2023 16:07:03 +0530 Subject: [PATCH 116/147] Add interface for Git methods --- src/VCS/Adapter/Git.php | 221 +++++++++++++++++++++++++++++++ src/VCS/Adapter/Git/GitHub.php | 2 +- tests/VCS/Adapter/GitHubTest.php | 5 +- tests/VCS/Base.php | 5 +- 4 files changed, 228 insertions(+), 5 deletions(-) diff --git a/src/VCS/Adapter/Git.php b/src/VCS/Adapter/Git.php index 21114f33..cbc3c50c 100644 --- a/src/VCS/Adapter/Git.php +++ b/src/VCS/Adapter/Git.php @@ -3,7 +3,228 @@ namespace Utopia\VCS\Adapter; use Utopia\VCS\Adapter; +use Utopia\Cache\Cache; abstract class Git extends Adapter { + protected string $endpoint; + + protected string $accessToken; + + protected Cache $cache; + + /** + * Global Headers + * + * @var array + */ + protected $headers = ['content-type' => 'application/json']; + + public function __construct(Cache $cache) + { + $this->cache = $cache; + } + + /** + * Get Adapter Name + * + * @return string + */ + abstract public function getName(): string; + + /** + * Is Git Flow + * + * @return bool + */ + abstract public function isGitFlow(): bool; + + /** + * Get user + * + * @return array + * + */ + abstract public function getUser(string $username): array; + + /** + * Get owner name of the installation + * + * @return string + */ + abstract public function getOwnerName(string $installationId): string; + + /** + * List repositories for Git App + * @param int $page page number + * @param int $per_page number of results per page + * @return array + */ + abstract public function listRepositoriesForGitApp($page, $per_page): array; + + /** + * Get latest opened pull request with specific base branch + * @return array + */ + abstract public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array; + + /** + * Get repository + * + * @return array + */ + abstract public function getRepository(string $owner, string $repositoryName): array; + + /** + * Create new repository + * + * @return array Details of new repository + */ + abstract public function createRepository(string $owner, string $repositoryName, bool $private): array; + + /** + * Delete repository + */ + abstract public function deleteRepository(string $owner, string $repositoryName): void; + + /** + * Get total repositories count + * + * @return int + */ + abstract public function getTotalReposCount(): int; + + /** + * Get Pull Request + * + * @return array The retrieved pull request + */ + abstract public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array; + + /** + * Add Comment to Pull Request + * + * @return string + */ + abstract public function createComment(string $owner, string $repositoryName, int $pullRequestNumber, string $comment): string; + + /** + * Get Comment of Pull Request + * + * @param string $owner The owner of the repository + * @param string $repositoryName The name of the repository + * @param string $commentId The ID of the comment to retrieve + * @return string The retrieved comment + */ + abstract public function getComment($owner, $repositoryName, $commentId): string; + + /** + * Update Pull Request Comment + * + * @param string $owner The owner of the repository + * @param string $repositoryName The name of the repository + * @param int $commentId The ID of the comment to update + * @param string $comment The updated comment content + * @return string The ID of the updated comment + */ + abstract public function updateComment(string $owner, string $repositoryName, int $commentId, string $comment): string; + + /** + * Downloads a ZIP archive of a repository. + * + * @param string $owner The owner of the repository. + * @param string $repositoryName The name of the repository. + * @param string $ref The name of the commit, branch, or tag to download. + * @param string $path The path of the file or directory to download. Optional. + * @return string The contents of the ZIP archive as a string. + */ + abstract public function downloadRepositoryZip(string $owner, string $repositoryName, string $ref, string $path = ''): string; + + /** + * Downloads a tar archive of a repository. + * + * @param string $owner The owner of the repository. + * @param string $repositoryName The name of the repository. + * @param string $ref The name of the commit, branch, or tag to download. + * @return string The contents of the tar archive as a string. + */ + abstract public function downloadRepositoryTar(string $owner, string $repositoryName, string $ref): string; + + /** + * Forks a repository. + * + * @param string $owner The owner of the repository to fork. + * @param string $repo The name of the repository to fork. + * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. + * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. + * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. + * @return string The name of the newly forked repository + */ + abstract public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?string; + + /** + * Generates a git clone command using app access token + */ + abstract public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string; + + /** + * Parses webhook event payload + * + * @param string $payload Raw body of HTTP request + * @param string $signature Signature provided by Git provider in header + * @param string $signatureKey Webhook secret configured on Git provider + * @return bool + */ + abstract public function validateWebhook(string $payload, string $signature, string $signatureKey): bool; + + /** + * Parses webhook event payload + * + * @param string $event Type of event: push, pull_request etc + * @param string $payload The webhook payload received from Git provider + * @return array Parsed payload as a json object + */ + abstract public function parseWebhookEventPayload(string $event, string $payload): array; + + /** + * Fetches repository name using repository id + * + * @param string $repositoryId ID of the repository + * @return string name of the repository + */ + abstract public function getRepositoryName(string $repositoryId): string; + + /** + * Lists branches for a given repository + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the repository + * @return array List of branch names as array + */ + abstract public function listBranches(string $owner, string $repositoryName): array; + + /** + * Updates status check of each commit + * state can be one of: error, failure, pending, success + */ + abstract public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = '', string $target_url = '', string $context = ''): void; + + /** + * Get repository languages + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the repository + * @return array List of repository languages + */ + abstract public function getRepositoryLanguages(string $owner, string $repositoryName): array; + + /** + * List contents of the specified root directory. + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the repository + * @param string $path Path to list contents from + * @return array List of contents at the specified path + */ + abstract public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array; } diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 2640689c..f249a379 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -144,7 +144,7 @@ public function getOwnerName(string $installationId): string * * @throws Exception */ - public function listRepositoriesForGitHubApp($page, $per_page): array + public function listRepositoriesForGitApp($page, $per_page): array { $url = '/installation/repositories?page=' . $page . '&per_page=' . $per_page; diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index 37c4b0ab..7b324eb8 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -5,11 +5,12 @@ use Utopia\App; use Utopia\Cache\Adapter\None; use Utopia\Cache\Cache; +use Utopia\VCS\Adapter\Git; use Utopia\VCS\Adapter\Git\GitHub; class GitHubTest extends Base { - protected function createVCSAdapter() + protected function createVCSAdapter(): Git { return new GitHub(new Cache(new None())); } @@ -32,7 +33,7 @@ public function testGetOwnerName(): void public function testListRepositories(): void { - $repos = $this->vcsAdapter->listRepositoriesForGitHubApp(1, 2); + $repos = $this->vcsAdapter->listRepositoriesForGitApp(1, 2); $this->assertCount(2, $repos); } diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index 53bb9f0b..ce20ebc3 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -3,17 +3,18 @@ namespace Utopia\Tests; use PHPUnit\Framework\TestCase; +use Utopia\VCS\Adapter\Git; abstract class Base extends TestCase { - protected $vcsAdapter; + protected Git $vcsAdapter; protected function setUp(): void { $this->vcsAdapter = $this->createVCSAdapter(); } - abstract protected function createVCSAdapter(); + abstract protected function createVCSAdapter(): Git; abstract public function testGetOwnerName(): void; From 6bf14fc31f53fe375786c56c09121746cc39985e Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 20 Jul 2023 13:59:32 +0530 Subject: [PATCH 117/147] Moved method signatures to adapter.php --- src/VCS/Adapter.php | 203 +++++++++++++++++++++++++++++++ src/VCS/Adapter/Git.php | 201 +----------------------------- src/VCS/Adapter/Git/GitHub.php | 16 +-- tests/VCS/Adapter/GitHubTest.php | 4 +- 4 files changed, 212 insertions(+), 212 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 7c30870f..342925c0 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -35,6 +35,209 @@ abstract class Adapter */ protected $headers = []; + /** + * Get Adapter Name + * + * @return string + */ + abstract public function getName(): string; + + /** + * Is Git Flow + * + * @return bool + */ + abstract public function isGitFlow(): bool; + + /** + * Get user + * + * @return array + * + */ + abstract public function getUser(string $username): array; + + /** + * Get owner name of the installation + * + * @return string + */ + abstract public function getOwnerName(string $installationId): string; + + /** + * List repositories for Git App + * @param int $page page number + * @param int $per_page number of results per page + * @return array + */ + abstract public function listRepositoriesForVCSApp($page, $per_page): array; + + /** + * Get latest opened pull request with specific base branch + * @return array + */ + abstract public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array; + + /** + * Get repository + * + * @return array + */ + abstract public function getRepository(string $owner, string $repositoryName): array; + + /** + * Create new repository + * + * @return array Details of new repository + */ + abstract public function createRepository(string $owner, string $repositoryName, bool $private): array; + + /** + * Delete repository + */ + abstract public function deleteRepository(string $owner, string $repositoryName): void; + + /** + * Get total repositories count + * + * @return int + */ + abstract public function getTotalReposCount(): int; + + /** + * Get Pull Request + * + * @return array The retrieved pull request + */ + abstract public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array; + + /** + * Add Comment to Pull Request + * + * @return string + */ + abstract public function createComment(string $owner, string $repositoryName, int $pullRequestNumber, string $comment): string; + + /** + * Get Comment of Pull Request + * + * @param string $owner The owner of the repository + * @param string $repositoryName The name of the repository + * @param string $commentId The ID of the comment to retrieve + * @return string The retrieved comment + */ + abstract public function getComment($owner, $repositoryName, $commentId): string; + + /** + * Update Pull Request Comment + * + * @param string $owner The owner of the repository + * @param string $repositoryName The name of the repository + * @param int $commentId The ID of the comment to update + * @param string $comment The updated comment content + * @return string The ID of the updated comment + */ + abstract public function updateComment(string $owner, string $repositoryName, int $commentId, string $comment): string; + + /** + * Downloads a ZIP archive of a repository. + * + * @param string $owner The owner of the repository. + * @param string $repositoryName The name of the repository. + * @param string $ref The name of the commit, branch, or tag to download. + * @param string $path The path of the file or directory to download. Optional. + * @return string The contents of the ZIP archive as a string. + */ + abstract public function downloadRepositoryZip(string $owner, string $repositoryName, string $ref, string $path = ''): string; + + /** + * Downloads a tar archive of a repository. + * + * @param string $owner The owner of the repository. + * @param string $repositoryName The name of the repository. + * @param string $ref The name of the commit, branch, or tag to download. + * @return string The contents of the tar archive as a string. + */ + abstract public function downloadRepositoryTar(string $owner, string $repositoryName, string $ref): string; + + /** + * Forks a repository. + * + * @param string $owner The owner of the repository to fork. + * @param string $repo The name of the repository to fork. + * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. + * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. + * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. + * @return string The name of the newly forked repository + */ + abstract public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?string; + + /** + * Generates a clone command using app access token + */ + abstract public function generateCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string; + + /** + * Parses webhook event payload + * + * @param string $payload Raw body of HTTP request + * @param string $signature Signature provided by Git provider in header + * @param string $signatureKey Webhook secret configured on Git provider + * @return bool + */ + abstract public function validateWebhook(string $payload, string $signature, string $signatureKey): bool; + + /** + * Parses webhook event payload + * + * @param string $event Type of event: push, pull_request etc + * @param string $payload The webhook payload received from Git provider + * @return array Parsed payload as a json object + */ + abstract public function parseWebhookEventPayload(string $event, string $payload): array; + + /** + * Fetches repository name using repository id + * + * @param string $repositoryId ID of the repository + * @return string name of the repository + */ + abstract public function getRepositoryName(string $repositoryId): string; + + /** + * Lists branches for a given repository + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the repository + * @return array List of branch names as array + */ + abstract public function listBranches(string $owner, string $repositoryName): array; + + /** + * Updates status check of each commit + * state can be one of: error, failure, pending, success + */ + abstract public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = '', string $target_url = '', string $context = ''): void; + + /** + * Get repository languages + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the repository + * @return array List of repository languages + */ + abstract public function getRepositoryLanguages(string $owner, string $repositoryName): array; + + /** + * List contents of the specified root directory. + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the repository + * @param string $path Path to list contents from + * @return array List of contents at the specified path + */ + abstract public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array; + /** * Call * diff --git a/src/VCS/Adapter/Git.php b/src/VCS/Adapter/Git.php index cbc3c50c..7b8f5f1c 100644 --- a/src/VCS/Adapter/Git.php +++ b/src/VCS/Adapter/Git.php @@ -25,206 +25,13 @@ public function __construct(Cache $cache) $this->cache = $cache; } - /** - * Get Adapter Name - * - * @return string - */ - abstract public function getName(): string; - /** * Is Git Flow * * @return bool */ - abstract public function isGitFlow(): bool; - - /** - * Get user - * - * @return array - * - */ - abstract public function getUser(string $username): array; - - /** - * Get owner name of the installation - * - * @return string - */ - abstract public function getOwnerName(string $installationId): string; - - /** - * List repositories for Git App - * @param int $page page number - * @param int $per_page number of results per page - * @return array - */ - abstract public function listRepositoriesForGitApp($page, $per_page): array; - - /** - * Get latest opened pull request with specific base branch - * @return array - */ - abstract public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array; - - /** - * Get repository - * - * @return array - */ - abstract public function getRepository(string $owner, string $repositoryName): array; - - /** - * Create new repository - * - * @return array Details of new repository - */ - abstract public function createRepository(string $owner, string $repositoryName, bool $private): array; - - /** - * Delete repository - */ - abstract public function deleteRepository(string $owner, string $repositoryName): void; - - /** - * Get total repositories count - * - * @return int - */ - abstract public function getTotalReposCount(): int; - - /** - * Get Pull Request - * - * @return array The retrieved pull request - */ - abstract public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array; - - /** - * Add Comment to Pull Request - * - * @return string - */ - abstract public function createComment(string $owner, string $repositoryName, int $pullRequestNumber, string $comment): string; - - /** - * Get Comment of Pull Request - * - * @param string $owner The owner of the repository - * @param string $repositoryName The name of the repository - * @param string $commentId The ID of the comment to retrieve - * @return string The retrieved comment - */ - abstract public function getComment($owner, $repositoryName, $commentId): string; - - /** - * Update Pull Request Comment - * - * @param string $owner The owner of the repository - * @param string $repositoryName The name of the repository - * @param int $commentId The ID of the comment to update - * @param string $comment The updated comment content - * @return string The ID of the updated comment - */ - abstract public function updateComment(string $owner, string $repositoryName, int $commentId, string $comment): string; - - /** - * Downloads a ZIP archive of a repository. - * - * @param string $owner The owner of the repository. - * @param string $repositoryName The name of the repository. - * @param string $ref The name of the commit, branch, or tag to download. - * @param string $path The path of the file or directory to download. Optional. - * @return string The contents of the ZIP archive as a string. - */ - abstract public function downloadRepositoryZip(string $owner, string $repositoryName, string $ref, string $path = ''): string; - - /** - * Downloads a tar archive of a repository. - * - * @param string $owner The owner of the repository. - * @param string $repositoryName The name of the repository. - * @param string $ref The name of the commit, branch, or tag to download. - * @return string The contents of the tar archive as a string. - */ - abstract public function downloadRepositoryTar(string $owner, string $repositoryName, string $ref): string; - - /** - * Forks a repository. - * - * @param string $owner The owner of the repository to fork. - * @param string $repo The name of the repository to fork. - * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. - * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. - * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. - * @return string The name of the newly forked repository - */ - abstract public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?string; - - /** - * Generates a git clone command using app access token - */ - abstract public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string; - - /** - * Parses webhook event payload - * - * @param string $payload Raw body of HTTP request - * @param string $signature Signature provided by Git provider in header - * @param string $signatureKey Webhook secret configured on Git provider - * @return bool - */ - abstract public function validateWebhook(string $payload, string $signature, string $signatureKey): bool; - - /** - * Parses webhook event payload - * - * @param string $event Type of event: push, pull_request etc - * @param string $payload The webhook payload received from Git provider - * @return array Parsed payload as a json object - */ - abstract public function parseWebhookEventPayload(string $event, string $payload): array; - - /** - * Fetches repository name using repository id - * - * @param string $repositoryId ID of the repository - * @return string name of the repository - */ - abstract public function getRepositoryName(string $repositoryId): string; - - /** - * Lists branches for a given repository - * - * @param string $owner Owner name of the repository - * @param string $repositoryName Name of the repository - * @return array List of branch names as array - */ - abstract public function listBranches(string $owner, string $repositoryName): array; - - /** - * Updates status check of each commit - * state can be one of: error, failure, pending, success - */ - abstract public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = '', string $target_url = '', string $context = ''): void; - - /** - * Get repository languages - * - * @param string $owner Owner name of the repository - * @param string $repositoryName Name of the repository - * @return array List of repository languages - */ - abstract public function getRepositoryLanguages(string $owner, string $repositoryName): array; - - /** - * List contents of the specified root directory. - * - * @param string $owner Owner name of the repository - * @param string $repositoryName Name of the repository - * @param string $path Path to list contents from - * @return array List of contents at the specified path - */ - abstract public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array; + public function isGitFlow(): bool + { + return true; + } } diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index f249a379..39cbae09 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -99,16 +99,6 @@ public function getName(): string return 'github'; } - /** - * Is Git Flow - * - * @return bool - */ - public function isGitFlow(): bool - { - return true; // false for manual adapter - flow is way simpler. No auth, no branch selecting, ... - } - /** * Get user * @@ -144,7 +134,7 @@ public function getOwnerName(string $installationId): string * * @throws Exception */ - public function listRepositoriesForGitApp($page, $per_page): array + public function listRepositoriesForVCSApp($page, $per_page): array { $url = '/installation/repositories?page=' . $page . '&per_page=' . $per_page; @@ -356,9 +346,9 @@ public function forkRepository(string $owner, string $repo, ?string $organizatio } /** - * Generates a git clone command using app access token + * Generates a clone command using app access token */ - public function generateGitCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string + public function generateCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string { if (empty($rootDirectory)) { $rootDirectory = '*'; diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index 7b324eb8..0e799270 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -33,7 +33,7 @@ public function testGetOwnerName(): void public function testListRepositories(): void { - $repos = $this->vcsAdapter->listRepositoriesForGitApp(1, 2); + $repos = $this->vcsAdapter->listRepositoriesForVCSApp(1, 2); $this->assertCount(2, $repos); } @@ -90,7 +90,7 @@ public function testForkRepository(): void public function testGenerateCloneCommand(): void { - $gitCloneCommand = $this->vcsAdapter->generateGitCloneCommand('test-kh', 'test2', 'main', '', ''); + $gitCloneCommand = $this->vcsAdapter->generateCloneCommand('test-kh', 'test2', 'main', '', ''); $this->assertNotEmpty($gitCloneCommand); $this->assertStringContainsString('sparse-checkout', $gitCloneCommand); } From c836cb55c2d3e0e28506228c55a6c6efcb16ddbd Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 20 Jul 2023 18:12:56 +0530 Subject: [PATCH 118/147] Standardise method names --- src/VCS/Adapter.php | 6 +++--- src/VCS/Adapter/Git/GitHub.php | 6 +++--- tests/VCS/Adapter/GitHubTest.php | 8 ++++---- tests/VCS/Base.php | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 342925c0..1c3f6453 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -126,7 +126,7 @@ abstract public function createComment(string $owner, string $repositoryName, in * @param string $commentId The ID of the comment to retrieve * @return string The retrieved comment */ - abstract public function getComment($owner, $repositoryName, $commentId): string; + abstract public function getComment(string $owner, string $repositoryName, string $commentId): string; /** * Update Pull Request Comment @@ -185,7 +185,7 @@ abstract public function generateCloneCommand(string $owner, string $repositoryN * @param string $signatureKey Webhook secret configured on Git provider * @return bool */ - abstract public function validateWebhook(string $payload, string $signature, string $signatureKey): bool; + abstract public function validateWebhookEvent(string $payload, string $signature, string $signatureKey): bool; /** * Parses webhook event payload @@ -194,7 +194,7 @@ abstract public function validateWebhook(string $payload, string $signature, str * @param string $payload The webhook payload received from Git provider * @return array Parsed payload as a json object */ - abstract public function parseWebhookEventPayload(string $event, string $payload): array; + abstract public function parseWebhookEvent(string $event, string $payload): array; /** * Fetches repository name using repository id diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 39cbae09..42a8012b 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -247,7 +247,7 @@ public function createComment(string $owner, string $repositoryName, int $pullRe * * @throws Exception */ - public function getComment($owner, $repositoryName, $commentId): string + public function getComment(string $owner, string $repositoryName, string $commentId): string { $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/comments/' . $commentId; @@ -371,7 +371,7 @@ public function generateCloneCommand(string $owner, string $repositoryName, stri * @param string $signatureKey Webhook secret configured on GitHub * @return bool */ - public function validateWebhook(string $payload, string $signature, string $signatureKey): bool + public function validateWebhookEvent(string $payload, string $signature, string $signatureKey): bool { return $signature === ('sha256=' . hash_hmac('sha256', $payload, $signatureKey)); } @@ -383,7 +383,7 @@ public function validateWebhook(string $payload, string $signature, string $sign * @param string $payload The webhook payload received from GitHub * @return array Parsed payload as a json object */ - public function parseWebhookEventPayload(string $event, string $payload): array + public function parseWebhookEvent(string $event, string $payload): array { $payload = json_decode($payload, true); $installationId = strval($payload['installation']['id']); diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index 0e799270..d4811a9e 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -95,7 +95,7 @@ public function testGenerateCloneCommand(): void $this->assertStringContainsString('sparse-checkout', $gitCloneCommand); } - public function testParseWebhookEventPayload(): void + public function testParseWebhookEvent(): void { $payload_push = '{ "ref": "refs/heads/main", @@ -154,15 +154,15 @@ public function testParseWebhookEventPayload(): void } '; - $pushResult = $this->vcsAdapter->parseWebhookEventPayload('push', $payload_push); + $pushResult = $this->vcsAdapter->parseWebhookEvent('push', $payload_push); $this->assertEquals('main', $pushResult['branch']); $this->assertEquals('603754812', $pushResult['repositoryId']); - $pullRequestResult = $this->vcsAdapter->parseWebhookEventPayload('pull_request', $payload_pull_request); + $pullRequestResult = $this->vcsAdapter->parseWebhookEvent('pull_request', $payload_pull_request); $this->assertEquals('opened', $pullRequestResult['action']); $this->assertEquals(1, $pullRequestResult['pullRequestNumber']); - $uninstallResult = $this->vcsAdapter->parseWebhookEventPayload('installation', $payload_uninstall); + $uninstallResult = $this->vcsAdapter->parseWebhookEvent('installation', $payload_uninstall); $this->assertEquals('deleted', $uninstallResult['action']); $this->assertEquals(1234, $uninstallResult['installationId']); } diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index ce20ebc3..7ea667e6 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -34,7 +34,7 @@ abstract public function testForkRepository(): void; abstract public function testGenerateCloneCommand(): void; - abstract public function testParseWebhookEventPayload(): void; + abstract public function testParseWebhookEvent(): void; abstract public function testGetRepositoryName(): void; From 20d39035360f757da355374b59d374fc4dc80a5a Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Fri, 21 Jul 2023 17:01:42 +0530 Subject: [PATCH 119/147] Fix external contributions property --- src/VCS/Adapter/Git/GitHub.php | 2 +- tests/VCS/Adapter/GitHubTest.php | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 42a8012b..79a9aa05 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -416,7 +416,7 @@ public function parseWebhookEvent(string $event, string $payload): array $action = $payload['action']; $owner = $payload['repository']['owner']['login']; $SHA = $payload['pull_request']['head']['sha']; - $external = $payload['pull_request']['head']['label'] !== $payload['pull_request']['base']['label']; + $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; return [ 'action' => $action, diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index d4811a9e..3757a785 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -125,10 +125,16 @@ public function testParseWebhookEvent(): void "head": { "ref": "test", "sha": "08e857a3ee1d1b0156502239798f558c996a664f", - "label": "vermakhushboo:test" + "label": "vermakhushboo:test", + "user": { + "login": "vermakhushboo" + } }, "base": { - "label": "vermakhushboo:main" + "label": "vermakhushboo:main", + "user": { + "login": "vermakhushboo" + } } }, "repository": { From e64e93d103a2e6ec9b9c853919f3e1c13e4f3986 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 01:27:35 +0530 Subject: [PATCH 120/147] WIP: Move definitions to base git class --- tests/VCS/Adapter/{ => Git}/GitHubTest.php | 130 ++++----------------- tests/VCS/Adapter/GitTest.php | 101 ++++++++++++++++ 2 files changed, 121 insertions(+), 110 deletions(-) rename tests/VCS/Adapter/{ => Git}/GitHubTest.php (60%) create mode 100644 tests/VCS/Adapter/GitTest.php diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/Git/GitHubTest.php similarity index 60% rename from tests/VCS/Adapter/GitHubTest.php rename to tests/VCS/Adapter/Git/GitHubTest.php index 3757a785..e7b0a062 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/Git/GitHubTest.php @@ -8,7 +8,7 @@ use Utopia\VCS\Adapter\Git; use Utopia\VCS\Adapter\Git\GitHub; -class GitHubTest extends Base +class GitHubTest extends GitTest { protected function createVCSAdapter(): Git { @@ -24,77 +24,6 @@ public function setUp(): void $this->vcsAdapter->initialiseVariables($installationId, $privateKey, $githubAppId); } - public function testGetOwnerName(): void - { - $installationId = App::getEnv('INSTALLATION_ID') ?? ''; - $owner = $this->vcsAdapter->getOwnerName($installationId); - $this->assertEquals('test-kh', $owner); - } - - public function testListRepositories(): void - { - $repos = $this->vcsAdapter->listRepositoriesForVCSApp(1, 2); - $this->assertCount(2, $repos); - } - - public function testGetTotalReposCount(): void - { - $count = $this->vcsAdapter->getTotalReposCount(); - $this->assertGreaterThanOrEqual(0, $count); - } - - public function testCreateComment(): void - { - $commentId = $this->vcsAdapter->createComment('test-kh', 'test2', 1, 'hello'); - $this->assertNotEmpty($commentId); - } - - public function testUpdateComment(): void - { - $commentId = $this->vcsAdapter->updateComment('test-kh', 'test2', 1630320767, 'update'); - $this->assertNotEmpty($commentId); - } - - public function testDownloadRepositoryZip(): void - { - // download the zip archive of the repo - $zipContents = $this->vcsAdapter->downloadRepositoryZip('test-kh', 'test2', 'main'); - - // Save the ZIP archive to a file - file_put_contents('./hello-world.zip', $zipContents); - - // Assert that the file was saved successfully - $this->assertFileExists('./hello-world.zip'); - } - - public function testDownloadRepositoryTar(): void - { - // download the tar archive of the repo - $tarContents = $this->vcsAdapter->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); - - // Save the TAR archive to a file - file_put_contents('./hello-world.tar', $tarContents); - - // Assert that the file was saved successfully - $this->assertFileExists('./hello-world.tar'); - } - - public function testForkRepository(): void - { - // Fork a repository into authenticated user's account with custom name - $response = $this->vcsAdapter->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); - // Assert that the forked repo has the expected name - $this->assertEquals('fork-api-test-clone', $response); - $this->vcsAdapter->deleteRepository("test-kh", "fork-api-test-clone"); - } - - public function testGenerateCloneCommand(): void - { - $gitCloneCommand = $this->vcsAdapter->generateCloneCommand('test-kh', 'test2', 'main', '', ''); - $this->assertNotEmpty($gitCloneCommand); - $this->assertStringContainsString('sparse-checkout', $gitCloneCommand); - } - public function testParseWebhookEvent(): void { $payload_push = '{ @@ -173,42 +102,22 @@ public function testParseWebhookEvent(): void $this->assertEquals(1234, $uninstallResult['installationId']); } - public function testGetRepositoryName(): void - { - $repositoryName = $this->vcsAdapter->getRepositoryName('432284323'); - $this->assertEquals('basic-js-crud', $repositoryName); - } - - public function testListBranches(): void - { - $branches = $this->vcsAdapter->listBranches('vermakhushboo', 'basic-js-crud'); - $this->assertIsArray($branches); - $this->assertNotEmpty($branches); - } - - public function testGetRepositoryLanguages(): void + public function testGetComment(): void { - $languages = $this->vcsAdapter->getRepositoryLanguages('vermakhushboo', 'basic-js-crud'); - - $this->assertIsArray($languages); + $owner = 'vermakhushboo'; + $repositoryName = 'basic-js-crud'; + $commentId = '1431560395'; - $this->assertContains('JavaScript', $languages); - $this->assertContains('HTML', $languages); - $this->assertContains('CSS', $languages); - } + $result = $this->vcsAdapter->getComment($owner, $repositoryName, $commentId); - public function testListRepositoryContents(): void - { - $contents = $this->vcsAdapter->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); - $this->assertIsArray($contents); - $this->assertNotEmpty($contents); + $this->assertIsString($result); + $this->assertNotEmpty($result); } - public function testGetBranchPullRequest(): void + public function testGetRepositoryName(): void { - $result = $this->vcsAdapter->getBranchPullRequest('vermakhushboo', 'basic-js-crud', 'test'); - $this->assertIsArray($result); - $this->assertNotEmpty($result); + $repositoryName = $this->vcsAdapter->getRepositoryName('432284323'); + $this->assertEquals('basic-js-crud', $repositoryName); } public function testGetPullRequest(): void @@ -226,15 +135,16 @@ public function testGetPullRequest(): void $this->assertEquals($repositoryName, $result['base']['repo']['name']); } - public function testGetComment(): void + public function testGenerateCloneCommand(): void { - $owner = 'vermakhushboo'; - $repositoryName = 'basic-js-crud'; - $commentId = '1431560395'; - - $result = $this->vcsAdapter->getComment($owner, $repositoryName, $commentId); + $gitCloneCommand = $this->vcsAdapter->generateCloneCommand('test-kh', 'test2', 'main', '', ''); + $this->assertNotEmpty($gitCloneCommand); + $this->assertStringContainsString('sparse-checkout', $gitCloneCommand); + } - $this->assertIsString($result); - $this->assertNotEmpty($result); + public function testUpdateComment(): void + { + $commentId = $this->vcsAdapter->updateComment('test-kh', 'test2', 1630320767, 'update'); + $this->assertNotEmpty($commentId); } } diff --git a/tests/VCS/Adapter/GitTest.php b/tests/VCS/Adapter/GitTest.php new file mode 100644 index 00000000..7ca17963 --- /dev/null +++ b/tests/VCS/Adapter/GitTest.php @@ -0,0 +1,101 @@ +vcsAdapter->getOwnerName($installationId); + $this->assertEquals('test-kh', $owner); + } + + public function testListRepositories(): void + { + $repos = $this->vcsAdapter->listRepositoriesForVCSApp(1, 2); + $this->assertCount(2, $repos); + } + + public function testGetTotalReposCount(): void + { + $count = $this->vcsAdapter->getTotalReposCount(); + $this->assertGreaterThanOrEqual(0, $count); + } + + public function testCreateComment(): void + { + $commentId = $this->vcsAdapter->createComment('test-kh', 'test2', 1, 'hello'); + $this->assertNotEmpty($commentId); + } + + public function testDownloadRepositoryZip(): void + { + // download the zip archive of the repo + $zipContents = $this->vcsAdapter->downloadRepositoryZip('test-kh', 'test2', 'main'); + + // Save the ZIP archive to a file + file_put_contents('./hello-world.zip', $zipContents); + + // Assert that the file was saved successfully + $this->assertFileExists('./hello-world.zip'); + } + + public function testDownloadRepositoryTar(): void + { + // download the tar archive of the repo + $tarContents = $this->vcsAdapter->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); + + // Save the TAR archive to a file + file_put_contents('./hello-world.tar', $tarContents); + + // Assert that the file was saved successfully + $this->assertFileExists('./hello-world.tar'); + } + + public function testForkRepository(): void + { + // Fork a repository into authenticated user's account with custom name + $response = $this->vcsAdapter->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); + // Assert that the forked repo has the expected name + $this->assertEquals('fork-api-test-clone', $response); + $this->vcsAdapter->deleteRepository("test-kh", "fork-api-test-clone"); + } + + public function testListBranches(): void + { + $branches = $this->vcsAdapter->listBranches('vermakhushboo', 'basic-js-crud'); + $this->assertIsArray($branches); + $this->assertNotEmpty($branches); + } + + public function testGetRepositoryLanguages(): void + { + $languages = $this->vcsAdapter->getRepositoryLanguages('vermakhushboo', 'basic-js-crud'); + + $this->assertIsArray($languages); + + $this->assertContains('JavaScript', $languages); + $this->assertContains('HTML', $languages); + $this->assertContains('CSS', $languages); + } + + public function testListRepositoryContents(): void + { + $contents = $this->vcsAdapter->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); + $this->assertIsArray($contents); + $this->assertNotEmpty($contents); + } + + public function testGetBranchPullRequest(): void + { + $result = $this->vcsAdapter->getBranchPullRequest('vermakhushboo', 'basic-js-crud', 'test'); + $this->assertIsArray($result); + $this->assertNotEmpty($result); + } +} From 9c9c0e829f7af013b99587270cb1cd472ab274ec Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 02:04:20 +0530 Subject: [PATCH 121/147] Moved definitions to base test class --- tests/VCS/Adapter/{Git => }/GitHubTest.php | 5 +- tests/VCS/Adapter/GitTest.php | 101 -------------------- tests/VCS/Base.php | 103 +++++++++++++++++---- 3 files changed, 89 insertions(+), 120 deletions(-) rename tests/VCS/Adapter/{Git => }/GitHubTest.php (98%) delete mode 100644 tests/VCS/Adapter/GitTest.php diff --git a/tests/VCS/Adapter/Git/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php similarity index 98% rename from tests/VCS/Adapter/Git/GitHubTest.php rename to tests/VCS/Adapter/GitHubTest.php index e7b0a062..dd5952b8 100644 --- a/tests/VCS/Adapter/Git/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -1,14 +1,15 @@ vcsAdapter->getOwnerName($installationId); - $this->assertEquals('test-kh', $owner); - } - - public function testListRepositories(): void - { - $repos = $this->vcsAdapter->listRepositoriesForVCSApp(1, 2); - $this->assertCount(2, $repos); - } - - public function testGetTotalReposCount(): void - { - $count = $this->vcsAdapter->getTotalReposCount(); - $this->assertGreaterThanOrEqual(0, $count); - } - - public function testCreateComment(): void - { - $commentId = $this->vcsAdapter->createComment('test-kh', 'test2', 1, 'hello'); - $this->assertNotEmpty($commentId); - } - - public function testDownloadRepositoryZip(): void - { - // download the zip archive of the repo - $zipContents = $this->vcsAdapter->downloadRepositoryZip('test-kh', 'test2', 'main'); - - // Save the ZIP archive to a file - file_put_contents('./hello-world.zip', $zipContents); - - // Assert that the file was saved successfully - $this->assertFileExists('./hello-world.zip'); - } - - public function testDownloadRepositoryTar(): void - { - // download the tar archive of the repo - $tarContents = $this->vcsAdapter->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); - - // Save the TAR archive to a file - file_put_contents('./hello-world.tar', $tarContents); - - // Assert that the file was saved successfully - $this->assertFileExists('./hello-world.tar'); - } - - public function testForkRepository(): void - { - // Fork a repository into authenticated user's account with custom name - $response = $this->vcsAdapter->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); - // Assert that the forked repo has the expected name - $this->assertEquals('fork-api-test-clone', $response); - $this->vcsAdapter->deleteRepository("test-kh", "fork-api-test-clone"); - } - - public function testListBranches(): void - { - $branches = $this->vcsAdapter->listBranches('vermakhushboo', 'basic-js-crud'); - $this->assertIsArray($branches); - $this->assertNotEmpty($branches); - } - - public function testGetRepositoryLanguages(): void - { - $languages = $this->vcsAdapter->getRepositoryLanguages('vermakhushboo', 'basic-js-crud'); - - $this->assertIsArray($languages); - - $this->assertContains('JavaScript', $languages); - $this->assertContains('HTML', $languages); - $this->assertContains('CSS', $languages); - } - - public function testListRepositoryContents(): void - { - $contents = $this->vcsAdapter->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); - $this->assertIsArray($contents); - $this->assertNotEmpty($contents); - } - - public function testGetBranchPullRequest(): void - { - $result = $this->vcsAdapter->getBranchPullRequest('vermakhushboo', 'basic-js-crud', 'test'); - $this->assertIsArray($result); - $this->assertNotEmpty($result); - } -} diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index 7ea667e6..9194c3e8 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -3,6 +3,7 @@ namespace Utopia\Tests; use PHPUnit\Framework\TestCase; +use Utopia\App; use Utopia\VCS\Adapter\Git; abstract class Base extends TestCase @@ -16,37 +17,105 @@ protected function setUp(): void abstract protected function createVCSAdapter(): Git; - abstract public function testGetOwnerName(): void; + abstract public function testUpdateComment(): void; - abstract public function testListRepositories(): void; + abstract public function testGenerateCloneCommand(): void; - abstract public function testGetTotalReposCount(): void; + abstract public function testParseWebhookEvent(): void; - abstract public function testCreateComment(): void; + abstract public function testGetRepositoryName(): void; - abstract public function testUpdateComment(): void; + abstract public function testGetPullRequest(): void; + + abstract public function testGetComment(): void; - abstract public function testDownloadRepositoryZip(): void; + public function testGetOwnerName(): void + { + $installationId = App::getEnv('INSTALLATION_ID') ?? ''; + $owner = $this->vcsAdapter->getOwnerName($installationId); + $this->assertEquals('test-kh', $owner); + } - abstract public function testDownloadRepositoryTar(): void; + public function testListRepositories(): void + { + $repos = $this->vcsAdapter->listRepositoriesForVCSApp(1, 2); + $this->assertCount(2, $repos); + } - abstract public function testForkRepository(): void; + public function testGetTotalReposCount(): void + { + $count = $this->vcsAdapter->getTotalReposCount(); + $this->assertGreaterThanOrEqual(0, $count); + } - abstract public function testGenerateCloneCommand(): void; + public function testCreateComment(): void + { + $commentId = $this->vcsAdapter->createComment('test-kh', 'test2', 1, 'hello'); + $this->assertNotEmpty($commentId); + } - abstract public function testParseWebhookEvent(): void; + public function testDownloadRepositoryZip(): void + { + // download the zip archive of the repo + $zipContents = $this->vcsAdapter->downloadRepositoryZip('test-kh', 'test2', 'main'); - abstract public function testGetRepositoryName(): void; + // Save the ZIP archive to a file + file_put_contents('./hello-world.zip', $zipContents); - abstract public function testListBranches(): void; + // Assert that the file was saved successfully + $this->assertFileExists('./hello-world.zip'); + } - abstract public function testGetRepositoryLanguages(): void; + public function testDownloadRepositoryTar(): void + { + // download the tar archive of the repo + $tarContents = $this->vcsAdapter->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); - abstract public function testListRepositoryContents(): void; + // Save the TAR archive to a file + file_put_contents('./hello-world.tar', $tarContents); - abstract public function testGetBranchPullRequest(): void; + // Assert that the file was saved successfully + $this->assertFileExists('./hello-world.tar'); + } - abstract public function testGetPullRequest(): void; + public function testForkRepository(): void + { + // Fork a repository into authenticated user's account with custom name + $response = $this->vcsAdapter->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); + // Assert that the forked repo has the expected name + $this->assertEquals('fork-api-test-clone', $response); + $this->vcsAdapter->deleteRepository("test-kh", "fork-api-test-clone"); + } - abstract public function testGetComment(): void; + public function testListBranches(): void + { + $branches = $this->vcsAdapter->listBranches('vermakhushboo', 'basic-js-crud'); + $this->assertIsArray($branches); + $this->assertNotEmpty($branches); + } + + public function testGetRepositoryLanguages(): void + { + $languages = $this->vcsAdapter->getRepositoryLanguages('vermakhushboo', 'basic-js-crud'); + + $this->assertIsArray($languages); + + $this->assertContains('JavaScript', $languages); + $this->assertContains('HTML', $languages); + $this->assertContains('CSS', $languages); + } + + public function testListRepositoryContents(): void + { + $contents = $this->vcsAdapter->listRepositoryContents('appwrite', 'appwrite', 'src/Appwrite'); + $this->assertIsArray($contents); + $this->assertNotEmpty($contents); + } + + public function testGetBranchPullRequest(): void + { + $result = $this->vcsAdapter->getBranchPullRequest('vermakhushboo', 'basic-js-crud', 'test'); + $this->assertIsArray($result); + $this->assertNotEmpty($result); + } } From 4c9bf5a884f359e2146dba69dcc6eddb50f7d6fe Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 13:06:55 +0530 Subject: [PATCH 122/147] Change parseWebhookEvent to getEvent --- src/VCS/Adapter.php | 2 +- src/VCS/Adapter/Git/GitHub.php | 2 +- tests/VCS/Adapter/GitHubTest.php | 8 ++++---- tests/VCS/Base.php | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 1c3f6453..755f40f6 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -194,7 +194,7 @@ abstract public function validateWebhookEvent(string $payload, string $signature * @param string $payload The webhook payload received from Git provider * @return array Parsed payload as a json object */ - abstract public function parseWebhookEvent(string $event, string $payload): array; + abstract public function getEvent(string $event, string $payload): array; /** * Fetches repository name using repository id diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 79a9aa05..d28693bf 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -383,7 +383,7 @@ public function validateWebhookEvent(string $payload, string $signature, string * @param string $payload The webhook payload received from GitHub * @return array Parsed payload as a json object */ - public function parseWebhookEvent(string $event, string $payload): array + public function getEvent(string $event, string $payload): array { $payload = json_decode($payload, true); $installationId = strval($payload['installation']['id']); diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index dd5952b8..7bcdf989 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -25,7 +25,7 @@ public function setUp(): void $this->vcsAdapter->initialiseVariables($installationId, $privateKey, $githubAppId); } - public function testParseWebhookEvent(): void + public function testgetEvent(): void { $payload_push = '{ "ref": "refs/heads/main", @@ -90,15 +90,15 @@ public function testParseWebhookEvent(): void } '; - $pushResult = $this->vcsAdapter->parseWebhookEvent('push', $payload_push); + $pushResult = $this->vcsAdapter->getEvent('push', $payload_push); $this->assertEquals('main', $pushResult['branch']); $this->assertEquals('603754812', $pushResult['repositoryId']); - $pullRequestResult = $this->vcsAdapter->parseWebhookEvent('pull_request', $payload_pull_request); + $pullRequestResult = $this->vcsAdapter->getEvent('pull_request', $payload_pull_request); $this->assertEquals('opened', $pullRequestResult['action']); $this->assertEquals(1, $pullRequestResult['pullRequestNumber']); - $uninstallResult = $this->vcsAdapter->parseWebhookEvent('installation', $payload_uninstall); + $uninstallResult = $this->vcsAdapter->getEvent('installation', $payload_uninstall); $this->assertEquals('deleted', $uninstallResult['action']); $this->assertEquals(1234, $uninstallResult['installationId']); } diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index 9194c3e8..a214fd28 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -21,7 +21,7 @@ abstract public function testUpdateComment(): void; abstract public function testGenerateCloneCommand(): void; - abstract public function testParseWebhookEvent(): void; + abstract public function testgetEvent(): void; abstract public function testGetRepositoryName(): void; From 6fc2f0d2d101d48629a315887b869a3f725b7bf0 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:53:13 +0530 Subject: [PATCH 123/147] Rename add-new-adapter.md to add-new-detector-adapter.md --- docs/{add-new-adapter.md => add-new-detector-adapter.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{add-new-adapter.md => add-new-detector-adapter.md} (100%) diff --git a/docs/add-new-adapter.md b/docs/add-new-detector-adapter.md similarity index 100% rename from docs/add-new-adapter.md rename to docs/add-new-detector-adapter.md From 9babb9b5a9edca84c5f84ce344a17036af668a61 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:53:53 +0530 Subject: [PATCH 124/147] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce035008..f69790fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,7 +78,7 @@ This is also important for the Utopia-php lead developers to be able to give tec ## Adding A New Adapter -You can follow our [Adding new Detector Adapter](docs/add-new-adapter.md) tutorial to add new detector support in this library. +You can follow our [Adding new Detector Adapter](docs/add-new-detector-adapter.md) tutorial to add new detector support in this library. ## Other Ways to Help From a069030d5ed6b7bd826177510a69727f8db04b5c Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 22:44:21 +0530 Subject: [PATCH 125/147] Create add-new-vcs-adapter.md --- docs/add-new-vcs-adapter.md | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 docs/add-new-vcs-adapter.md diff --git a/docs/add-new-vcs-adapter.md b/docs/add-new-vcs-adapter.md new file mode 100644 index 00000000..43fec91c --- /dev/null +++ b/docs/add-new-vcs-adapter.md @@ -0,0 +1,86 @@ +# Add new VCS Adapter + +To get started with implementing a new VCS adapter, start by reviewing the [README](/README.md) to understand the goals of this library. ❤ + +### Introduction 📝 +- A `VCS (version control system)` is a software tool that helps you track changes to your code over time. +- A `VCS adapter` is a class that provides an interface to a specific VCS like GitHub, Bitbucket etc. It provides methods for interacting with the VCS user account and repositories, such as listing repositories, adding a comment on a pull request, cloning the repository etc. +- To add a new VCS adapter, you need to extend the `Adapter` parent class and define the required methods. + +### File Structure 📂 + +Below are outlined the most useful files for adding a new VCS adapter: + +```bash +. +├── src # Source code +│   └── VCS +│   ├── Adapter/ # Where your new adapter goes! +│  │  ├── Git/ # Where your new Git-based adapter goes! +│  │  └── Git.php # Parent class for Git-based adapters +│   └── Adapter.php # Parent class for individual adapters +└── tests + └── VCS + ├── Adapter/ # Where tests of your new adapter go! + └── Base.php # Parent class that holds all tests +``` +### Extend the Adapter 💻 + +Create your Git-based adapter `NewGitAdapter.php` file in `src/VCS/Adapter/Git` and extend the parent class: + +```php +initialiseVariables($installationId, $privateKey, $appId); +``` + +Only include dependencies strictly necessary for the adapter, preferably official PHP libraries, if available. + +### Testing with Docker + +The existing test suite is helpful when developing a new VCS adapter. Use official Docker images from trusted sources. Add new tests for your new VCS adapter in `tests/VCS/Adapter/VCSTest.php` test class. The specific `docker-compose` command for testing can be found in the [README](/README.md#tests). + +### Tips and Tricks + +- Keep it simple :) +- Prioritize code performance. From 7e129dc00b4b15ff1057803e5731912b2b0409b9 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 22:45:11 +0530 Subject: [PATCH 126/147] Update add-new-vcs-adapter.md --- docs/add-new-vcs-adapter.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/add-new-vcs-adapter.md b/docs/add-new-vcs-adapter.md index 43fec91c..08f79060 100644 --- a/docs/add-new-vcs-adapter.md +++ b/docs/add-new-vcs-adapter.md @@ -76,11 +76,11 @@ $vcs->initialiseVariables($installationId, $privateKey, $appId); Only include dependencies strictly necessary for the adapter, preferably official PHP libraries, if available. -### Testing with Docker +### Testing with Docker 🛠️ The existing test suite is helpful when developing a new VCS adapter. Use official Docker images from trusted sources. Add new tests for your new VCS adapter in `tests/VCS/Adapter/VCSTest.php` test class. The specific `docker-compose` command for testing can be found in the [README](/README.md#tests). -### Tips and Tricks +### Tips and Tricks 💡 - Keep it simple :) - Prioritize code performance. From 61a2c13f819e4fe348c088375de756b61dfc344b Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 22:47:24 +0530 Subject: [PATCH 127/147] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9757e308..7998c9d3 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ $githubAppId = 'your-github-app-id'; $installationId = 'your-github-app-installation-id'; // Initialise variables -$github->initialiseVariables($installationId, $privateKey, $githubAppId, 'github-username'); +$github->initialiseVariables($installationId, $privateKey, $githubAppId); // Perform the actions that you want, ex: create repository $owner = ''; From 059f0d3078192a17318344080d5c83c7d022362e Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 24 Jul 2023 22:49:36 +0530 Subject: [PATCH 128/147] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f69790fa..c986fbab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -78,7 +78,7 @@ This is also important for the Utopia-php lead developers to be able to give tec ## Adding A New Adapter -You can follow our [Adding new Detector Adapter](docs/add-new-detector-adapter.md) tutorial to add new detector support in this library. +You can follow our [Adding new VCS Adapter](docs/add-new-vcs-adapter.md) tutorial to add a new VCS adapter like GitLab, Bitbucket etc. and [Adding new Detector Adapter](docs/add-new-detector-adapter.md) tutorial to add new detector support in this library. ## Other Ways to Help From 81150e6373c8ac28e7eb44449400eb6d8e1dcfcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 6 Aug 2023 07:35:08 +0000 Subject: [PATCH 129/147] Upgrade libs --- composer.json | 2 +- composer.lock | 46 ++++++++++++++++++++++++---------------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/composer.json b/composer.json index 10bb5da7..9e0d695a 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "require": { "php": ">=8.0", "adhocore/jwt": "^1.1", - "utopia-php/framework": "0.26.*", + "utopia-php/framework": "0.29.*", "utopia-php/cache": "^0.8.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 442378af..d69a70ce 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6212d04d6bd97ce55995cc4fe998686e", + "content-hash": "0deccf467a5fbfe002781eba369b7eaf", "packages": [ { "name": "adhocore/jwt", @@ -114,25 +114,26 @@ }, { "name": "utopia-php/framework", - "version": "0.26.3", + "version": "0.29", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "7a18a2b0d6c8dba878c926b73650fd2c4eeaa70d" + "reference": "1c8ed95fb73531b0508ad69f85dafc4c78a64414" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/7a18a2b0d6c8dba878c926b73650fd2c4eeaa70d", - "reference": "7a18a2b0d6c8dba878c926b73650fd2c4eeaa70d", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/1c8ed95fb73531b0508ad69f85dafc4c78a64414", + "reference": "1c8ed95fb73531b0508ad69f85dafc4c78a64414", "shasum": "" }, "require": { - "php": ">=8.0.0" + "php": ">=8.0" }, "require-dev": { "laravel/pint": "^1.2", - "phpunit/phpunit": "^9.5.25", - "vimeo/psalm": "4.27.0" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.25" }, "type": "library", "autoload": { @@ -152,9 +153,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.26.3" + "source": "https://github.com/utopia-php/framework/tree/0.29" }, - "time": "2023-06-03T14:01:15+00:00" + "time": "2023-07-30T07:56:23+00:00" } ], "packages-dev": [ @@ -581,16 +582,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.26", + "version": "9.2.27", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1" + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", - "reference": "443bc6912c9bd5b409254a40f4b0f4ced7c80ea1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b0a88255cb70d52653d80c890bd7f38740ea50d1", + "reference": "b0a88255cb70d52653d80c890bd7f38740ea50d1", "shasum": "" }, "require": { @@ -646,7 +647,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.26" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.27" }, "funding": [ { @@ -654,7 +656,7 @@ "type": "github" } ], - "time": "2023-03-06T12:58:08+00:00" + "time": "2023-07-26T13:44:30+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1506,16 +1508,16 @@ }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { @@ -1558,7 +1560,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" }, "funding": [ { @@ -1566,7 +1568,7 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2023-08-02T09:26:13+00:00" }, { "name": "sebastian/lines-of-code", From 3b1138fd655cdf116c5848d8b966f2ffcd3c623d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 7 Aug 2023 10:00:44 +0000 Subject: [PATCH 130/147] Upgrade framework lib --- composer.json | 2 +- composer.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 9e0d695a..60c9d274 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ "require": { "php": ">=8.0", "adhocore/jwt": "^1.1", - "utopia-php/framework": "0.29.*", + "utopia-php/framework": "0.30.*", "utopia-php/cache": "^0.8.0" }, "require-dev": { diff --git a/composer.lock b/composer.lock index d69a70ce..1a941264 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0deccf467a5fbfe002781eba369b7eaf", + "content-hash": "0514888858a68ac038aaa4f60dc65203", "packages": [ { "name": "adhocore/jwt", @@ -114,16 +114,16 @@ }, { "name": "utopia-php/framework", - "version": "0.29", + "version": "0.30.0", "source": { "type": "git", "url": "https://github.com/utopia-php/framework.git", - "reference": "1c8ed95fb73531b0508ad69f85dafc4c78a64414" + "reference": "0969d429997996ceade53e477fce31221b415651" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/framework/zipball/1c8ed95fb73531b0508ad69f85dafc4c78a64414", - "reference": "1c8ed95fb73531b0508ad69f85dafc4c78a64414", + "url": "https://api.github.com/repos/utopia-php/framework/zipball/0969d429997996ceade53e477fce31221b415651", + "reference": "0969d429997996ceade53e477fce31221b415651", "shasum": "" }, "require": { @@ -153,9 +153,9 @@ ], "support": { "issues": "https://github.com/utopia-php/framework/issues", - "source": "https://github.com/utopia-php/framework/tree/0.29" + "source": "https://github.com/utopia-php/framework/tree/0.30.0" }, - "time": "2023-07-30T07:56:23+00:00" + "time": "2023-08-07T07:55:48+00:00" } ], "packages-dev": [ From b43af0b11f0de8e173add292fce636a61ba2fa4a Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Mon, 7 Aug 2023 20:47:42 +0530 Subject: [PATCH 131/147] Add additional information to deployments --- src/VCS/Adapter.php | 10 ++++++ src/VCS/Adapter/Git/GitHub.php | 54 ++++++++++++++++++++++++++------ tests/VCS/Adapter/GitHubTest.php | 17 +++++++++- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 755f40f6..5927012c 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -238,6 +238,16 @@ abstract public function getRepositoryLanguages(string $owner, string $repositor */ abstract public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array; + /** + * Get details of a commit + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @param string $commitHash SHA of the commit + * @return array Details of the commit + */ + abstract public function getCommit(string $owner, string $repositoryName, string $commitHash): array; + /** * Call * diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index d28693bf..3c45ebe2 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -376,6 +376,26 @@ public function validateWebhookEvent(string $payload, string $signature, string return $signature === ('sha256=' . hash_hmac('sha256', $payload, $signatureKey)); } + /** + * Get details of a commit + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @param string $commitHash SHA of the commit + * @return array Details of the commit + */ + public function getCommit(string $owner, string $repositoryName, string $commitHash): array + { + $url = "/repos/$owner/$repositoryName/commits/$commitHash"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return [ + 'commitAuthor' => $response['body']['commit']['author']['name'], + 'commitMessage' => $response['body']['commit']['message'], + ]; + } + /** * Parses webhook event payload * @@ -393,17 +413,25 @@ public function getEvent(string $event, string $payload): array $ref = $payload['ref']; $repositoryId = strval($payload['repository']['id']); $repositoryName = $payload['repository']['name']; - $SHA = $payload['after']; + $repositoryUrl = $payload['repository']['url']; + $commitHash = $payload['after']; $owner = $payload['repository']['owner']['name']; + $headCommitAuthor = $payload['head_commit']['author']['name']; + $headCommitMessage = $payload['head_commit']['message']; + $headCommitUrl = $payload['head_commit']['url']; $branch = str_replace('refs/heads/', '', $ref); return [ 'branch' => $branch, 'repositoryId' => $repositoryId, - 'installationId' => $installationId, 'repositoryName' => $repositoryName, - 'SHA' => $SHA, + 'repositoryUrl' => $repositoryUrl, + 'installationId' => $installationId, + 'commitHash' => $commitHash, 'owner' => $owner, + 'headCommitAuthor' => $headCommitAuthor, + 'headCommitMessage' => $headCommitMessage, + 'headCommitUrl' => $headCommitUrl, 'external' => false, 'pullRequestNumber' => '', 'action' => '', @@ -412,22 +440,28 @@ public function getEvent(string $event, string $payload): array $repositoryId = strval($payload['repository']['id']); $branch = $payload['pull_request']['head']['ref']; $repositoryName = $payload['repository']['name']; + $repositoryUrl = $payload['repository']['url']; + $branchUrl = "https://api.github.com/repos/vermakhushboo/g4-node-function/branches/$branch"; $pullRequestNumber = $payload['number']; $action = $payload['action']; $owner = $payload['repository']['owner']['login']; - $SHA = $payload['pull_request']['head']['sha']; + $commitHash = $payload['pull_request']['head']['sha']; + $headCommitUrl = "https://api.github.com/repos/vermakhushboo/g4-node-function/git/commits/$commitHash"; $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; return [ - 'action' => $action, 'branch' => $branch, + 'branchUrl' => $branchUrl, 'repositoryId' => $repositoryId, - 'installationId' => $installationId, 'repositoryName' => $repositoryName, - 'pullRequestNumber' => $pullRequestNumber, - 'SHA' => $SHA, + 'repositoryUrl' => $repositoryUrl, + 'installationId' => $installationId, + 'commitHash' => $commitHash, 'owner' => $owner, + 'headCommitUrl' => $headCommitUrl, 'external' => $external, + 'pullRequestNumber' => $pullRequestNumber, + 'action' => $action, ]; case 'installation': case 'installation_repositories': @@ -483,9 +517,9 @@ public function listBranches(string $owner, string $repositoryName): array * Updates status check of each commit * state can be one of: error, failure, pending, success */ - public function updateCommitStatus(string $repositoryName, string $SHA, string $owner, string $state, string $description = '', string $target_url = '', string $context = ''): void + public function updateCommitStatus(string $repositoryName, string $commitHash, string $owner, string $state, string $description = '', string $target_url = '', string $context = ''): void { - $url = "/repos/$owner/$repositoryName/statuses/$SHA"; + $url = "/repos/$owner/$repositoryName/statuses/$commitHash"; $body = [ 'state' => $state, diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index 7bcdf989..5a45a83f 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -37,12 +37,20 @@ public function testgetEvent(): void "name": "testing-fork", "full_name": "vermakhushboo/testing-fork", "private": true, + "url": "https://github.com/vermakhushboo/g4-node-function", "owner": { "name": "vermakhushboo" } }, "installation": { "id": 1234 + }, + "head_commit": { + "author": { + "name": "Khushboo Verma" + }, + "message": "Update index.js", + "url": "https://github.com/vermakhushboo/g4-node-function/commit/b787f03343171ff5a477627796140bfa1d02da09" } }'; @@ -72,7 +80,8 @@ public function testgetEvent(): void "name": "functions-example", "owner": { "login": "vermakhushboo" - } + }, + "url": "https://github.com/vermakhushboo/g4-node-function" }, "installation": { "id": 9876 @@ -148,4 +157,10 @@ public function testUpdateComment(): void $commentId = $this->vcsAdapter->updateComment('test-kh', 'test2', 1630320767, 'update'); $this->assertNotEmpty($commentId); } + + public function testGetCommit(): void + { + $commitDetails = $this->vcsAdapter->getCommit('test-kh', 'test1', '7ae65094d56edafc48596ffbb77950e741e56412'); + $this->assertIsArray($commitDetails); + } } From 051b973b5ac218c498a88489ce8380d0dc986407 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:49:15 +0530 Subject: [PATCH 132/147] Updated payloads --- src/VCS/Adapter/Git/GitHub.php | 28 +++++++++++++--------------- tests/VCS/Adapter/GitHubTest.php | 3 ++- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 3c45ebe2..aee93fbc 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -413,13 +413,13 @@ public function getEvent(string $event, string $payload): array $ref = $payload['ref']; $repositoryId = strval($payload['repository']['id']); $repositoryName = $payload['repository']['name']; - $repositoryUrl = $payload['repository']['url']; + $branch = str_replace('refs/heads/', '', $ref); + $repositoryUrl = $payload['repository']['url'] . "/tree/" . $branch; $commitHash = $payload['after']; $owner = $payload['repository']['owner']['name']; $headCommitAuthor = $payload['head_commit']['author']['name']; $headCommitMessage = $payload['head_commit']['message']; $headCommitUrl = $payload['head_commit']['url']; - $branch = str_replace('refs/heads/', '', $ref); return [ 'branch' => $branch, @@ -436,22 +436,20 @@ public function getEvent(string $event, string $payload): array 'pullRequestNumber' => '', 'action' => '', ]; - case 'pull_request': - $repositoryId = strval($payload['repository']['id']); - $branch = $payload['pull_request']['head']['ref']; - $repositoryName = $payload['repository']['name']; - $repositoryUrl = $payload['repository']['url']; - $branchUrl = "https://api.github.com/repos/vermakhushboo/g4-node-function/branches/$branch"; - $pullRequestNumber = $payload['number']; - $action = $payload['action']; - $owner = $payload['repository']['owner']['login']; - $commitHash = $payload['pull_request']['head']['sha']; - $headCommitUrl = "https://api.github.com/repos/vermakhushboo/g4-node-function/git/commits/$commitHash"; - $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; + case 'pull_request': + $repositoryId = strval($payload['repository']['id']); + $branch = $payload['pull_request']['head']['ref']; + $repositoryName = $payload['repository']['name']; + $repositoryUrl = $payload['pull_request']['html_url']; + $pullRequestNumber = $payload['number']; + $action = $payload['action']; + $owner = $payload['repository']['owner']['login']; + $commitHash = $payload['pull_request']['head']['sha']; + $headCommitUrl = $repositoryUrl . "/commits/" . $commitHash; + $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; return [ 'branch' => $branch, - 'branchUrl' => $branchUrl, 'repositoryId' => $repositoryId, 'repositoryName' => $repositoryName, 'repositoryUrl' => $repositoryUrl, diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index 5a45a83f..978afffa 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -60,9 +60,10 @@ public function testgetEvent(): void "pull_request": { "id": 1303283688, "state": "open", + "html_url": "https://github.com/vermakhushboo/g4-node-function/pull/17", "head": { "ref": "test", - "sha": "08e857a3ee1d1b0156502239798f558c996a664f", + "sha": "a27dbe54b17032ee35a16c24bac151e5c2b33328", "label": "vermakhushboo:test", "user": { "login": "vermakhushboo" From 315ea5d206bda8e2dcabd0451851d5c0a49d83eb Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 9 Aug 2023 15:52:00 +0530 Subject: [PATCH 133/147] Fixed formatting --- src/VCS/Adapter/Git/GitHub.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index aee93fbc..4368734e 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -436,17 +436,17 @@ public function getEvent(string $event, string $payload): array 'pullRequestNumber' => '', 'action' => '', ]; - case 'pull_request': - $repositoryId = strval($payload['repository']['id']); - $branch = $payload['pull_request']['head']['ref']; - $repositoryName = $payload['repository']['name']; - $repositoryUrl = $payload['pull_request']['html_url']; - $pullRequestNumber = $payload['number']; - $action = $payload['action']; - $owner = $payload['repository']['owner']['login']; - $commitHash = $payload['pull_request']['head']['sha']; - $headCommitUrl = $repositoryUrl . "/commits/" . $commitHash; - $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; + case 'pull_request': + $repositoryId = strval($payload['repository']['id']); + $branch = $payload['pull_request']['head']['ref']; + $repositoryName = $payload['repository']['name']; + $repositoryUrl = $payload['pull_request']['html_url']; + $pullRequestNumber = $payload['number']; + $action = $payload['action']; + $owner = $payload['repository']['owner']['login']; + $commitHash = $payload['pull_request']['head']['sha']; + $headCommitUrl = $repositoryUrl . "/commits/" . $commitHash; + $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; return [ 'branch' => $branch, From 214619ae39f56b2b35bfded40631ee21cc9c0ca5 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 9 Aug 2023 20:33:01 +0530 Subject: [PATCH 134/147] Add method to fetch latest commit on brancg --- src/VCS/Adapter.php | 45 ++++------------ src/VCS/Adapter/Git/GitHub.php | 93 +++++++++----------------------- tests/VCS/Adapter/GitHubTest.php | 6 +++ tests/VCS/Base.php | 33 ------------ 4 files changed, 42 insertions(+), 135 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 5927012c..b85edafa 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -139,39 +139,6 @@ abstract public function getComment(string $owner, string $repositoryName, strin */ abstract public function updateComment(string $owner, string $repositoryName, int $commentId, string $comment): string; - /** - * Downloads a ZIP archive of a repository. - * - * @param string $owner The owner of the repository. - * @param string $repositoryName The name of the repository. - * @param string $ref The name of the commit, branch, or tag to download. - * @param string $path The path of the file or directory to download. Optional. - * @return string The contents of the ZIP archive as a string. - */ - abstract public function downloadRepositoryZip(string $owner, string $repositoryName, string $ref, string $path = ''): string; - - /** - * Downloads a tar archive of a repository. - * - * @param string $owner The owner of the repository. - * @param string $repositoryName The name of the repository. - * @param string $ref The name of the commit, branch, or tag to download. - * @return string The contents of the tar archive as a string. - */ - abstract public function downloadRepositoryTar(string $owner, string $repositoryName, string $ref): string; - - /** - * Forks a repository. - * - * @param string $owner The owner of the repository to fork. - * @param string $repo The name of the repository to fork. - * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. - * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. - * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. - * @return string The name of the newly forked repository - */ - abstract public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?string; - /** * Generates a clone command using app access token */ @@ -239,7 +206,7 @@ abstract public function getRepositoryLanguages(string $owner, string $repositor abstract public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array; /** - * Get details of a commit + * Get details of a commit using commit hash * * @param string $owner Owner name of the repository * @param string $repositoryName Name of the GitHub repository @@ -248,6 +215,16 @@ abstract public function listRepositoryContents(string $owner, string $repositor */ abstract public function getCommit(string $owner, string $repositoryName, string $commitHash): array; + /** + * Get latest commit of a branch + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @param string $branch Name of the branch + * @return array Details of the commit + */ + abstract public function getLatestCommit(string $owner, string $repositoryName, string $branch): array; + /** * Call * diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 4368734e..4b1bd217 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -278,73 +278,6 @@ public function updateComment(string $owner, string $repositoryName, int $commen return $commentId; } - /** - * Downloads a ZIP archive of a repository. - * - * @param string $repositoryName The name of the repository. - * @param string $ref The name of the commit, branch, or tag to download. - * @param string $path The path of the file or directory to download. Optional. - * @return string The contents of the ZIP archive as a string. - */ - public function downloadRepositoryZip(string $owner, string $repositoryName, string $ref, string $path = ''): string - { - // Build the URL for the API request - $url = '/repos/' . $owner . "/{$repositoryName}/zipball/{$ref}"; - - // Add the path parameter to the URL query parameters, if specified - if (!empty($path)) { - $url .= "?path={$path}"; - } - - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - // Return the contents of the ZIP archive - return $response['body']; - } - - /** - * Downloads a tar archive of a repository. - * - * @return string The contents of the tar archive as a string. - */ - public function downloadRepositoryTar(string $owner, string $repositoryName, string $ref): string - { - // Build the URL for the API request - $url = '/repos/' . $owner . "/{$repositoryName}/tarball/{$ref}"; - - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - // Return the contents of the tar archive - return $response['body']; - } - - /** - * Forks a repository on GitHub. - * - * @param string $owner The owner of the repository to fork. - * @param string $repo The name of the repository to fork. - * @param string|null $organization The name of the organization to fork the repository into. If not provided, the repository will be forked into the authenticated user's account. - * @param string|null $name The name of the new forked repository. If not provided, the name will be the same as the original repository. - * @param bool $defaultBranchOnly Whether to include only the default branch in the forked repository. Defaults to false. - * @return string The name of the newly forked repository - */ - public function forkRepository(string $owner, string $repo, ?string $organization = null, ?string $name = null, bool $defaultBranchOnly = false): ?string - { - $url = "/repos/$owner/$repo/forks"; - - // Create the payload data for the API request - $data = [ - 'organization' => $organization, - 'name' => $name, - 'default_branch_only' => $defaultBranchOnly, - ]; - - // Send the API request to fork the repository - $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $data); - - return $response['body']['name']; - } - /** * Generates a clone command using app access token */ @@ -377,7 +310,7 @@ public function validateWebhookEvent(string $payload, string $signature, string } /** - * Get details of a commit + * Get details of a commit using commit hash * * @param string $owner Owner name of the repository * @param string $repositoryName Name of the GitHub repository @@ -410,6 +343,7 @@ public function getEvent(string $event, string $payload): array switch ($event) { case 'push': + $branchCreated = $payload['created']; $ref = $payload['ref']; $repositoryId = strval($payload['repository']['id']); $repositoryName = $payload['repository']['name']; @@ -422,6 +356,7 @@ public function getEvent(string $event, string $payload): array $headCommitUrl = $payload['head_commit']['url']; return [ + 'branchCreated' => $branchCreated, 'branch' => $branch, 'repositoryId' => $repositoryId, 'repositoryName' => $repositoryName, @@ -570,4 +505,26 @@ public function listRepositoryContents(string $owner, string $repositoryName, st return $item['name']; }, $response['body']); } + + /** + * Get latest commit of a branch + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @param string $branch Name of the branch + * @return array Details of the commit + */ + public function getLatestCommit(string $owner, string $repositoryName, string $branch): array + { + $url = "/repos/$owner/$repositoryName/commits/$branch?per_page=1"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return [ + 'commitAuthor' => $response['body']['commit']['author']['name'], + 'commitMessage' => $response['body']['commit']['message'], + 'commitHash' => $response['body']['sha'], + 'commitUrl' => $response['body']['html_url'] + ]; + } } diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index 978afffa..55803cf1 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -164,4 +164,10 @@ public function testGetCommit(): void $commitDetails = $this->vcsAdapter->getCommit('test-kh', 'test1', '7ae65094d56edafc48596ffbb77950e741e56412'); $this->assertIsArray($commitDetails); } + + public function testGetLatestCommit(): void + { + $commitDetails = $this->vcsAdapter->getLatestCommit('test-kh', 'test1', 'test'); + $this->assertEquals('Khushboo Verma', $commitDetails['commitAuthor']); + } } diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index a214fd28..3bef7650 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -54,39 +54,6 @@ public function testCreateComment(): void $this->assertNotEmpty($commentId); } - public function testDownloadRepositoryZip(): void - { - // download the zip archive of the repo - $zipContents = $this->vcsAdapter->downloadRepositoryZip('test-kh', 'test2', 'main'); - - // Save the ZIP archive to a file - file_put_contents('./hello-world.zip', $zipContents); - - // Assert that the file was saved successfully - $this->assertFileExists('./hello-world.zip'); - } - - public function testDownloadRepositoryTar(): void - { - // download the tar archive of the repo - $tarContents = $this->vcsAdapter->downloadRepositoryTar('appwrite', 'demos-for-react', 'main'); - - // Save the TAR archive to a file - file_put_contents('./hello-world.tar', $tarContents); - - // Assert that the file was saved successfully - $this->assertFileExists('./hello-world.tar'); - } - - public function testForkRepository(): void - { - // Fork a repository into authenticated user's account with custom name - $response = $this->vcsAdapter->forkRepository('appwrite', 'demos-for-astro', name: 'fork-api-test-clone'); - // Assert that the forked repo has the expected name - $this->assertEquals('fork-api-test-clone', $response); - $this->vcsAdapter->deleteRepository("test-kh", "fork-api-test-clone"); - } - public function testListBranches(): void { $branches = $this->vcsAdapter->listBranches('vermakhushboo', 'basic-js-crud'); From 6ee80b55a3cef5a8d29ab6a9b2af2db278789e38 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 9 Aug 2023 20:37:12 +0530 Subject: [PATCH 135/147] Check if new branch is created --- tests/VCS/Adapter/GitHubTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index 55803cf1..6ad8e555 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -28,6 +28,7 @@ public function setUp(): void public function testgetEvent(): void { $payload_push = '{ + "created": false, "ref": "refs/heads/main", "before": "1234", "after": "4567", From 048af6b90fd667aaadb3da76fde7a2403656bdeb Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 9 Aug 2023 16:32:36 +0100 Subject: [PATCH 136/147] Organize Code and rename "listRepositoriesForVCSApp" to "listRepositories" --- src/VCS/Adapter.php | 2 +- src/VCS/Adapter/Git/GitHub.php | 436 ++++++++++++++++----------------- tests/VCS/Base.php | 2 +- 3 files changed, 220 insertions(+), 220 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index b85edafa..c79c2d64 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -70,7 +70,7 @@ abstract public function getOwnerName(string $installationId): string; * @param int $per_page number of results per page * @return array */ - abstract public function listRepositoriesForVCSApp($page, $per_page): array; + abstract public function listRepositories($page, $per_page): array; /** * Get latest opened pull request with specific base branch diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 4b1bd217..6af838bf 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -37,6 +37,16 @@ public function __construct(Cache $cache) $this->cache = $cache; } + /** + * Get Adapter Name + * + * @return string + */ + public function getName(): string + { + return 'github'; + } + /** * GitHub Initialisation with access token generation. */ @@ -62,68 +72,20 @@ public function initialiseVariables(string $installationId, string $privateKey, } /** - * Generate Access Token - */ - protected function generateAccessToken(string $privateKey, string $githubAppId): void - { - /** - * @var resource $privateKeyObj - */ - $privateKeyObj = \openssl_pkey_get_private($privateKey); - - $appIdentifier = $githubAppId; - - $iat = time(); - $exp = $iat + 10 * 60; - $payload = [ - 'iat' => $iat, - 'exp' => $exp, - 'iss' => $appIdentifier, - ]; - - // generate access token - $jwt = new JWT($privateKeyObj, 'RS256'); - $token = $jwt->encode($payload); - $this->jwtToken = $token; - $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); - $this->accessToken = $res['body']['token']; - } - - /** - * Get Adapter Name - * - * @return string - */ - public function getName(): string - { - return 'github'; - } - - /** - * Get user - * - * @return array + * Create new repository * - * @throws Exception + * @return array Details of new repository */ - public function getUser(string $username): array + public function createRepository(string $owner, string $repositoryName, bool $private): array { - $response = $this->call(self::METHOD_GET, '/users/' . $username); - - return $response; - } + $url = "/orgs/{$owner}/repos"; - /** - * Get owner name of the GitHub installation - * - * @return string - */ - public function getOwnerName(string $installationId): string - { - $url = '/app/installations/' . $installationId; - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->jwtToken"]); + $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], [ + 'name' => $repositoryName, + 'private' => $private, + ]); - return $response['body']['account']['login']; + return $response['body']; } /** @@ -134,7 +96,7 @@ public function getOwnerName(string $installationId): string * * @throws Exception */ - public function listRepositoriesForVCSApp($page, $per_page): array + public function listRepositories($page, $per_page): array { $url = '/installation/repositories?page=' . $page . '&per_page=' . $per_page; @@ -143,20 +105,6 @@ public function listRepositoriesForVCSApp($page, $per_page): array return $response['body']['repositories']; } - /** - * Get latest opened pull request with specific base branch - * @return array - */ - public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array - { - $head = "{$owner}:{$branch}"; - $url = "/repos/{$owner}/{$repositoryName}/pulls?head={$head}&state=open&sort=updated&per_page=1"; - - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - return $response['body'][0] ?? []; - } - /** * Get GitHub repository * @@ -174,27 +122,37 @@ public function getRepository(string $owner, string $repositoryName): array } /** - * Create new repository + * Fetches repository name using repository id * - * @return array Details of new repository + * @param string $repositoryId ID of GitHub Repository + * @return string name of GitHub repository */ - public function createRepository(string $owner, string $repositoryName, bool $private): array + public function getRepositoryName(string $repositoryId): string { - $url = "/orgs/{$owner}/repos"; - - $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], [ - 'name' => $repositoryName, - 'private' => $private, - ]); + $url = "/repositories/$repositoryId"; + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - return $response['body']; + return $response['body']['name']; } - public function deleteRepository(string $owner, string $repositoryName): void + /** + * Get repository languages + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @return array List of repository languages + */ + public function getRepositoryLanguages(string $owner, string $repositoryName): array { - $url = "/repos/{$owner}/{$repositoryName}"; + $url = "/repos/$owner/$repositoryName/languages"; - $this->call(self::METHOD_DELETE, $url, ['Authorization' => "Bearer $this->accessToken"]); + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + if (isset($response['body'])) { + return array_keys($response['body']); + } + + return []; } public function getTotalReposCount(): int @@ -207,17 +165,32 @@ public function getTotalReposCount(): int } /** - * Get Pull Request + * List contents of the specified root directory. * - * @return array The retrieved pull request + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @param string $path Path to list contents from + * @return array List of contents at the specified path */ - public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array + public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array { - $url = "/repos/{$owner}/{$repositoryName}/pulls/{$pullRequestNumber}"; + $url = "/repos/$owner/$repositoryName/contents"; + if (!empty($path)) { + $url .= "/$path"; + } $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - return $response['body']; + return array_map(static function ($item) { + return $item['name']; + }, $response['body']); + } + + public function deleteRepository(string $owner, string $repositoryName): void + { + $url = "/repos/{$owner}/{$repositoryName}"; + + $this->call(self::METHOD_DELETE, $url, ['Authorization' => "Bearer $this->accessToken"]); } /** @@ -279,34 +252,107 @@ public function updateComment(string $owner, string $repositoryName, int $commen } /** - * Generates a clone command using app access token + * Generate Access Token */ - public function generateCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string + protected function generateAccessToken(string $privateKey, string $githubAppId): void { - if (empty($rootDirectory)) { - $rootDirectory = '*'; - } + /** + * @var resource $privateKeyObj + */ + $privateKeyObj = \openssl_pkey_get_private($privateKey); - // Construct the clone URL with the access token - $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; + $appIdentifier = $githubAppId; - // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && if git ls-remote --exit-code --heads origin {$branchName}; then git pull origin {$branchName} && git checkout {$branchName}; else git checkout -b {$branchName}; fi"; + $iat = time(); + $exp = $iat + 10 * 60; + $payload = [ + 'iat' => $iat, + 'exp' => $exp, + 'iss' => $appIdentifier, + ]; - return $command; + // generate access token + $jwt = new JWT($privateKeyObj, 'RS256'); + $token = $jwt->encode($payload); + $this->jwtToken = $token; + $res = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); + $this->accessToken = $res['body']['token']; } /** - * Parses webhook event payload + * Get user * - * @param string $payload Raw body of HTTP request - * @param string $signature Signature provided by GitHub in header - * @param string $signatureKey Webhook secret configured on GitHub - * @return bool + * @return array + * + * @throws Exception */ - public function validateWebhookEvent(string $payload, string $signature, string $signatureKey): bool + public function getUser(string $username): array { - return $signature === ('sha256=' . hash_hmac('sha256', $payload, $signatureKey)); + $response = $this->call(self::METHOD_GET, '/users/' . $username); + + return $response; + } + + /** + * Get owner name of the GitHub installation + * + * @return string + */ + public function getOwnerName(string $installationId): string + { + $url = '/app/installations/' . $installationId; + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->jwtToken"]); + + return $response['body']['account']['login']; + } + + /** + * Get Pull Request + * + * @return array The retrieved pull request + */ + public function getPullRequest(string $owner, string $repositoryName, int $pullRequestNumber): array + { + $url = "/repos/{$owner}/{$repositoryName}/pulls/{$pullRequestNumber}"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return $response['body']; + } + + /** + * Get latest opened pull request with specific base branch + * @return array + */ + public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array + { + $head = "{$owner}:{$branch}"; + $url = "/repos/{$owner}/{$repositoryName}/pulls?head={$head}&state=open&sort=updated&per_page=1"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return $response['body'][0] ?? []; + } + + /** + * Lists branches for a given repository + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @return array List of branch names as array + */ + public function listBranches(string $owner, string $repositoryName): array + { + $url = "/repos/$owner/$repositoryName/branches"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + $names = []; + foreach ($response['body'] as $subarray) { + $names[] = $subarray['name']; + } + + return $names; } /** @@ -329,6 +375,64 @@ public function getCommit(string $owner, string $repositoryName, string $commitH ]; } + /** + * Get latest commit of a branch + * + * @param string $owner Owner name of the repository + * @param string $repositoryName Name of the GitHub repository + * @param string $branch Name of the branch + * @return array Details of the commit + */ + public function getLatestCommit(string $owner, string $repositoryName, string $branch): array + { + $url = "/repos/$owner/$repositoryName/commits/$branch?per_page=1"; + + $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + + return [ + 'commitAuthor' => $response['body']['commit']['author']['name'], + 'commitMessage' => $response['body']['commit']['message'], + 'commitHash' => $response['body']['sha'], + 'commitUrl' => $response['body']['html_url'] + ]; + } + + /** + * Updates status check of each commit + * state can be one of: error, failure, pending, success + */ + public function updateCommitStatus(string $repositoryName, string $commitHash, string $owner, string $state, string $description = '', string $target_url = '', string $context = ''): void + { + $url = "/repos/$owner/$repositoryName/statuses/$commitHash"; + + $body = [ + 'state' => $state, + 'target_url' => $target_url, + 'description' => $description, + 'context' => $context, + ]; + + $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $body); + } + + /** + * Generates a clone command using app access token + */ + public function generateCloneCommand(string $owner, string $repositoryName, string $branchName, string $directory, string $rootDirectory): string + { + if (empty($rootDirectory)) { + $rootDirectory = '*'; + } + + // Construct the clone URL with the access token + $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; + + // Construct the Git clone command with the clone URL + $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && if git ls-remote --exit-code --heads origin {$branchName}; then git pull origin {$branchName} && git checkout {$branchName}; else git checkout -b {$branchName}; fi"; + + return $command; + } + /** * Parses webhook event payload * @@ -412,119 +516,15 @@ public function getEvent(string $event, string $payload): array } /** - * Fetches repository name using repository id - * - * @param string $repositoryId ID of GitHub Repository - * @return string name of GitHub repository - */ - public function getRepositoryName(string $repositoryId): string - { - $url = "/repositories/$repositoryId"; - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - return $response['body']['name']; - } - - /** - * Lists branches for a given repository - * - * @param string $owner Owner name of the repository - * @param string $repositoryName Name of the GitHub repository - * @return array List of branch names as array - */ - public function listBranches(string $owner, string $repositoryName): array - { - $url = "/repos/$owner/$repositoryName/branches"; - - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - $names = []; - foreach ($response['body'] as $subarray) { - $names[] = $subarray['name']; - } - - return $names; - } - - /** - * Updates status check of each commit - * state can be one of: error, failure, pending, success - */ - public function updateCommitStatus(string $repositoryName, string $commitHash, string $owner, string $state, string $description = '', string $target_url = '', string $context = ''): void - { - $url = "/repos/$owner/$repositoryName/statuses/$commitHash"; - - $body = [ - 'state' => $state, - 'target_url' => $target_url, - 'description' => $description, - 'context' => $context, - ]; - - $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], $body); - } - - /** - * Get repository languages - * - * @param string $owner Owner name of the repository - * @param string $repositoryName Name of the GitHub repository - * @return array List of repository languages - */ - public function getRepositoryLanguages(string $owner, string $repositoryName): array - { - $url = "/repos/$owner/$repositoryName/languages"; - - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - if (isset($response['body'])) { - return array_keys($response['body']); - } - - return []; - } - - /** - * List contents of the specified root directory. - * - * @param string $owner Owner name of the repository - * @param string $repositoryName Name of the GitHub repository - * @param string $path Path to list contents from - * @return array List of contents at the specified path - */ - public function listRepositoryContents(string $owner, string $repositoryName, string $path = ''): array - { - $url = "/repos/$owner/$repositoryName/contents"; - if (!empty($path)) { - $url .= "/$path"; - } - - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - return array_map(static function ($item) { - return $item['name']; - }, $response['body']); - } - - /** - * Get latest commit of a branch + * Parses webhook event payload * - * @param string $owner Owner name of the repository - * @param string $repositoryName Name of the GitHub repository - * @param string $branch Name of the branch - * @return array Details of the commit + * @param string $payload Raw body of HTTP request + * @param string $signature Signature provided by GitHub in header + * @param string $signatureKey Webhook secret configured on GitHub + * @return bool */ - public function getLatestCommit(string $owner, string $repositoryName, string $branch): array + public function validateWebhookEvent(string $payload, string $signature, string $signatureKey): bool { - $url = "/repos/$owner/$repositoryName/commits/$branch?per_page=1"; - - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - return [ - 'commitAuthor' => $response['body']['commit']['author']['name'], - 'commitMessage' => $response['body']['commit']['message'], - 'commitHash' => $response['body']['sha'], - 'commitUrl' => $response['body']['html_url'] - ]; + return $signature === ('sha256=' . hash_hmac('sha256', $payload, $signatureKey)); } } diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index 3bef7650..852b9346 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -38,7 +38,7 @@ public function testGetOwnerName(): void public function testListRepositories(): void { - $repos = $this->vcsAdapter->listRepositoriesForVCSApp(1, 2); + $repos = $this->vcsAdapter->listRepositories(1, 2); $this->assertCount(2, $repos); } From dfdfcd42521bc6093ece5bcae27bf3198038bf2f Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 9 Aug 2023 16:38:22 +0100 Subject: [PATCH 137/147] Continue renaming functions --- src/VCS/Adapter.php | 4 ++-- src/VCS/Adapter/Git/GitHub.php | 4 ++-- tests/Detector/DetectorTest.php | 2 +- tests/VCS/Base.php | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index c79c2d64..7ebaed38 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -102,7 +102,7 @@ abstract public function deleteRepository(string $owner, string $repositoryName) * * @return int */ - abstract public function getTotalReposCount(): int; + abstract public function getRepositoriesTotalCount(): int; /** * Get Pull Request @@ -193,7 +193,7 @@ abstract public function updateCommitStatus(string $repositoryName, string $SHA, * @param string $repositoryName Name of the repository * @return array List of repository languages */ - abstract public function getRepositoryLanguages(string $owner, string $repositoryName): array; + abstract public function listRepositoryLanguages(string $owner, string $repositoryName): array; /** * List contents of the specified root directory. diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 6af838bf..b96ac75c 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -142,7 +142,7 @@ public function getRepositoryName(string $repositoryId): string * @param string $repositoryName Name of the GitHub repository * @return array List of repository languages */ - public function getRepositoryLanguages(string $owner, string $repositoryName): array + public function listRepositoryLanguages(string $owner, string $repositoryName): array { $url = "/repos/$owner/$repositoryName/languages"; @@ -155,7 +155,7 @@ public function getRepositoryLanguages(string $owner, string $repositoryName): a return []; } - public function getTotalReposCount(): int + public function getRepositoriesTotalCount(): int { $url = '/installation/repositories'; diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index e75d42de..ec9b7c2c 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -74,7 +74,7 @@ public function testLanguageDetection(): void foreach ($languageMap as [$owner, $repositoryName, $expectedRuntime]) { $files = $this->github->listRepositoryContents($owner, $repositoryName); - $languages = $this->github->getRepositoryLanguages($owner, $repositoryName); + $languages = $this->github->listRepositoryLanguages($owner, $repositoryName); $runtime = $this->detect($files, $languages); $this->assertEquals($expectedRuntime, $runtime); } diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index 852b9346..83543255 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -42,9 +42,9 @@ public function testListRepositories(): void $this->assertCount(2, $repos); } - public function testGetTotalReposCount(): void + public function testGetRepositoriesTotalCount(): void { - $count = $this->vcsAdapter->getTotalReposCount(); + $count = $this->vcsAdapter->getRepositoriesTotalCount(); $this->assertGreaterThanOrEqual(0, $count); } @@ -61,9 +61,9 @@ public function testListBranches(): void $this->assertNotEmpty($branches); } - public function testGetRepositoryLanguages(): void + public function testListRepositoryLanguages(): void { - $languages = $this->vcsAdapter->getRepositoryLanguages('vermakhushboo', 'basic-js-crud'); + $languages = $this->vcsAdapter->listRepositoryLanguages('vermakhushboo', 'basic-js-crud'); $this->assertIsArray($languages); From c8164bd8ec92761e294f178cc9fc4e8324d0766a Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Wed, 9 Aug 2023 16:55:09 +0100 Subject: [PATCH 138/147] Update Func Names --- README.md | 2 +- docs/add-new-vcs-adapter.md | 4 ++-- src/VCS/Adapter.php | 19 +++++++++++++++++++ src/VCS/Adapter/Git/GitHub.php | 2 +- tests/Detector/DetectorTest.php | 2 +- tests/VCS/Adapter/GitHubTest.php | 2 +- 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7998c9d3..a43a5022 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ $githubAppId = 'your-github-app-id'; $installationId = 'your-github-app-installation-id'; // Initialise variables -$github->initialiseVariables($installationId, $privateKey, $githubAppId); +$github->initializeVariables($installationId, $privateKey, $githubAppId); // Perform the actions that you want, ex: create repository $owner = ''; diff --git a/docs/add-new-vcs-adapter.md b/docs/add-new-vcs-adapter.md index 08f79060..e0f1fb93 100644 --- a/docs/add-new-vcs-adapter.md +++ b/docs/add-new-vcs-adapter.md @@ -59,7 +59,7 @@ class NewVCSAdapter extends Adapter } ``` -Once you have created a new VCS adapter class, you can use it with the client by calling the `initialiseVariables()` method on the VCS class. +Once you have created a new VCS adapter class, you can use it with the client by calling the `initializeVariables()` method on the VCS class. ```php // Your VCS app private key. You can generate this from your VCS App settings. $privateKey = 'your-vcs-app-private-key'; @@ -71,7 +71,7 @@ $appId = 'your-vcs-app-id'; $installationId = 'your-vcs-app-installation-id'; // Initialise variables -$vcs->initialiseVariables($installationId, $privateKey, $appId); +$vcs->initializeVariables($installationId, $privateKey, $appId); ``` Only include dependencies strictly necessary for the adapter, preferably official PHP libraries, if available. diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 7ebaed38..9b896cf6 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -49,6 +49,25 @@ abstract public function getName(): string; */ abstract public function isGitFlow(): bool; + /** + * Initialize Variables + * + * @param string $installationId + * @param string $privateKey + * @param string $githubAppId + * @return void + */ + abstract public function initializeVariables(string $installationId, string $privateKey, string $githubAppId): void; + + /** + * Generate Access Token + * + * @param string $privateKey + * @param string $githubAppId + * @return void + */ + abstract protected function generateAccessToken(string $privateKey, string $githubAppId): void + /** * Get user * diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index b96ac75c..01445b32 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -50,7 +50,7 @@ public function getName(): string /** * GitHub Initialisation with access token generation. */ - public function initialiseVariables(string $installationId, string $privateKey, string $githubAppId): void + public function initializeVariables(string $installationId, string $privateKey, string $githubAppId): void { $this->installationId = $installationId; diff --git a/tests/Detector/DetectorTest.php b/tests/Detector/DetectorTest.php index ec9b7c2c..fd229bcd 100644 --- a/tests/Detector/DetectorTest.php +++ b/tests/Detector/DetectorTest.php @@ -54,7 +54,7 @@ public function setUp(): void $privateKey = App::getEnv('PRIVATE_KEY') ?? ''; $githubAppId = App::getEnv('APP_IDENTIFIER') ?? ''; $installationId = App::getEnv('INSTALLATION_ID') ?? ''; - $this->github->initialiseVariables($installationId, $privateKey, $githubAppId); + $this->github->initializeVariables($installationId, $privateKey, $githubAppId); } public function testLanguageDetection(): void diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index 6ad8e555..ac48c3e0 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -22,7 +22,7 @@ public function setUp(): void $privateKey = App::getEnv('PRIVATE_KEY') ?? ''; $githubAppId = App::getEnv('APP_IDENTIFIER') ?? ''; $installationId = App::getEnv('INSTALLATION_ID') ?? ''; - $this->vcsAdapter->initialiseVariables($installationId, $privateKey, $githubAppId); + $this->vcsAdapter->initializeVariables($installationId, $privateKey, $githubAppId); } public function testgetEvent(): void From 5cdcdf616fe10b548ea7c14c7f298a355d4ff0fc Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 9 Aug 2023 21:34:14 +0530 Subject: [PATCH 139/147] Fix failing tests --- src/VCS/Adapter.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index 9b896cf6..e096ecd3 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -51,8 +51,8 @@ abstract public function isGitFlow(): bool; /** * Initialize Variables - * - * @param string $installationId + * + * @param string $installationId * @param string $privateKey * @param string $githubAppId * @return void @@ -61,12 +61,12 @@ abstract public function initializeVariables(string $installationId, string $pri /** * Generate Access Token - * + * * @param string $privateKey * @param string $githubAppId * @return void */ - abstract protected function generateAccessToken(string $privateKey, string $githubAppId): void + abstract protected function generateAccessToken(string $privateKey, string $githubAppId): void; /** * Get user From 07d60e82496d1ce0b7d77c55174c84d055e085a0 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 9 Aug 2023 22:20:38 +0530 Subject: [PATCH 140/147] Added null safety checks --- src/VCS/Adapter.php | 6 +-- src/VCS/Adapter/Git.php | 10 ++-- src/VCS/Adapter/Git/GitHub.php | 91 +++++++++++++++++++++++++--------- 3 files changed, 77 insertions(+), 30 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index e096ecd3..e8b4cf65 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -43,11 +43,11 @@ abstract class Adapter abstract public function getName(): string; /** - * Is Git Flow + * Get Adapter Type * - * @return bool + * @return string */ - abstract public function isGitFlow(): bool; + abstract public function getType(): string; /** * Initialize Variables diff --git a/src/VCS/Adapter/Git.php b/src/VCS/Adapter/Git.php index 7b8f5f1c..b4b49e88 100644 --- a/src/VCS/Adapter/Git.php +++ b/src/VCS/Adapter/Git.php @@ -7,6 +7,8 @@ abstract class Git extends Adapter { + public const TYPE_GIT = 'git'; + protected string $endpoint; protected string $accessToken; @@ -26,12 +28,12 @@ public function __construct(Cache $cache) } /** - * Is Git Flow + * Get Adapter Type * - * @return bool + * @return string */ - public function isGitFlow(): bool + public function getType(): string { - return true; + return self::TYPE_GIT; } } diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 01445b32..591c976f 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -85,7 +85,7 @@ public function createRepository(string $owner, string $repositoryName, bool $pr 'private' => $private, ]); - return $response['body']; + return $response['body'] ?? []; } /** @@ -102,6 +102,10 @@ public function listRepositories($page, $per_page): array $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + if (!isset($response['body']['repositories'])) { + throw new Exception("Repositories list missing in the response."); + } + return $response['body']['repositories']; } @@ -118,7 +122,7 @@ public function getRepository(string $owner, string $repositoryName): array $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - return $response['body']; + return $response['body'] ?? []; } /** @@ -132,6 +136,10 @@ public function getRepositoryName(string $repositoryId): string $url = "/repositories/$repositoryId"; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + if (!isset($response['body']['name'])) { + throw new Exception("Repository name not found"); + } + return $response['body']['name']; } @@ -161,6 +169,10 @@ public function getRepositoriesTotalCount(): int $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + if (!isset($response['body']['total_count'])) { + throw new Exception("Total count of repositories missing in the response."); + } + return $response['body']['total_count']; } @@ -205,6 +217,11 @@ public function createComment(string $owner, string $repositoryName, int $pullRe $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/' . $pullRequestNumber . '/comments'; $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); + + if (!isset($response['body']['id'])) { + throw new Exception("Comment creation response is missing comment ID."); + } + $commentId = $response['body']['id']; return $commentId; @@ -225,7 +242,7 @@ public function getComment(string $owner, string $repositoryName, string $commen $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/comments/' . $commentId; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - $comment = $response['body']['body']; + $comment = $response['body']['body'] ?? ''; return $comment; } @@ -246,6 +263,11 @@ public function updateComment(string $owner, string $repositoryName, int $commen $url = '/repos/' . $owner . '/' . $repositoryName . '/issues/comments/' . $commentId; $response = $this->call(self::METHOD_PATCH, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); + + if (!isset($response['body']['id'])) { + throw new Exception("Comment update response is missing comment ID."); + } + $commentId = $response['body']['id']; return $commentId; @@ -303,6 +325,10 @@ public function getOwnerName(string $installationId): string $url = '/app/installations/' . $installationId; $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->jwtToken"]); + if (!isset($response['body']['account']['login'])) { + throw new Exception("Owner name retrieval response is missing account login."); + } + return $response['body']['account']['login']; } @@ -317,7 +343,7 @@ public function getPullRequest(string $owner, string $repositoryName, int $pullR $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - return $response['body']; + return $response['body'] ?? []; } /** @@ -369,6 +395,10 @@ public function getCommit(string $owner, string $repositoryName, string $commitH $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + if (!isset($response['body']['commit']['author']['name']) || !isset($response['body']['commit']['message'])) { + throw new Exception("Commit author or message information missing."); + } + return [ 'commitAuthor' => $response['body']['commit']['author']['name'], 'commitMessage' => $response['body']['commit']['message'], @@ -389,6 +419,15 @@ public function getLatestCommit(string $owner, string $repositoryName, string $b $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + if ( + !isset($response['body']['commit']['author']['name']) || + !isset($response['body']['commit']['message']) || + !isset($response['body']['sha']) || + !isset($response['body']['html_url']) + ) { + throw new Exception("Latest commit response is missing required information."); + } + return [ 'commitAuthor' => $response['body']['commit']['author']['name'], 'commitMessage' => $response['body']['commit']['message'], @@ -443,21 +482,26 @@ public function generateCloneCommand(string $owner, string $repositoryName, stri public function getEvent(string $event, string $payload): array { $payload = json_decode($payload, true); + + if ($payload === null || !is_array($payload)) { + throw new Exception("Invalid payload."); + } + $installationId = strval($payload['installation']['id']); switch ($event) { case 'push': - $branchCreated = $payload['created']; - $ref = $payload['ref']; - $repositoryId = strval($payload['repository']['id']); - $repositoryName = $payload['repository']['name']; + $branchCreated = isset($payload['created']) ? $payload['created'] : false; + $ref = $payload['ref'] ?? ''; + $repositoryId = strval($payload['repository']['id'] ?? ''); + $repositoryName = $payload['repository']['name'] ?? ''; $branch = str_replace('refs/heads/', '', $ref); $repositoryUrl = $payload['repository']['url'] . "/tree/" . $branch; - $commitHash = $payload['after']; - $owner = $payload['repository']['owner']['name']; - $headCommitAuthor = $payload['head_commit']['author']['name']; - $headCommitMessage = $payload['head_commit']['message']; - $headCommitUrl = $payload['head_commit']['url']; + $commitHash = $payload['after'] ?? ''; + $owner = $payload['repository']['owner']['name'] ?? ''; + $headCommitAuthor = $payload['head_commit']['author']['name'] ?? ''; + $headCommitMessage = $payload['head_commit']['message'] ?? ''; + $headCommitUrl = $payload['head_commit']['url'] ?? ''; return [ 'branchCreated' => $branchCreated, @@ -476,14 +520,14 @@ public function getEvent(string $event, string $payload): array 'action' => '', ]; case 'pull_request': - $repositoryId = strval($payload['repository']['id']); - $branch = $payload['pull_request']['head']['ref']; - $repositoryName = $payload['repository']['name']; - $repositoryUrl = $payload['pull_request']['html_url']; - $pullRequestNumber = $payload['number']; - $action = $payload['action']; - $owner = $payload['repository']['owner']['login']; - $commitHash = $payload['pull_request']['head']['sha']; + $repositoryId = strval($payload['repository']['id'] ?? ''); + $branch = $payload['pull_request']['head']['ref'] ?? ''; + $repositoryName = $payload['repository']['name'] ?? ''; + $repositoryUrl = $payload['pull_request']['html_url'] ?? ''; + $pullRequestNumber = $payload['number'] ?? ''; + $action = $payload['action'] ?? ''; + $owner = $payload['repository']['owner']['login'] ?? ''; + $commitHash = $payload['pull_request']['head']['sha'] ?? ''; $headCommitUrl = $repositoryUrl . "/commits/" . $commitHash; $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; @@ -502,8 +546,8 @@ public function getEvent(string $event, string $payload): array ]; case 'installation': case 'installation_repositories': - $action = $payload['action']; - $userName = $payload['installation']['account']['login']; + $action = $payload['action'] ?? ''; + $userName = $payload['installation']['account']['login'] ?? ''; return [ 'action' => $action, @@ -515,6 +559,7 @@ public function getEvent(string $event, string $payload): array return []; } + /** * Parses webhook event payload * From bc9da5670d636294f487177de229e294f33e3673 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 9 Aug 2023 22:38:46 +0530 Subject: [PATCH 141/147] Update urls --- src/VCS/Adapter/Git/GitHub.php | 11 +++++++++-- tests/VCS/Adapter/GitHubTest.php | 8 +++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 591c976f..642a61fe 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -496,9 +496,11 @@ public function getEvent(string $event, string $payload): array $repositoryId = strval($payload['repository']['id'] ?? ''); $repositoryName = $payload['repository']['name'] ?? ''; $branch = str_replace('refs/heads/', '', $ref); - $repositoryUrl = $payload['repository']['url'] . "/tree/" . $branch; + $branchUrl = $payload['repository']['url'] . "/tree/" . $branch; + $repositoryUrl = $payload['repository']['url']; $commitHash = $payload['after'] ?? ''; $owner = $payload['repository']['owner']['name'] ?? ''; + $authorUrl = $payload['sender']['html_url']; $headCommitAuthor = $payload['head_commit']['author']['name'] ?? ''; $headCommitMessage = $payload['head_commit']['message'] ?? ''; $headCommitUrl = $payload['head_commit']['url'] ?? ''; @@ -506,12 +508,14 @@ public function getEvent(string $event, string $payload): array return [ 'branchCreated' => $branchCreated, 'branch' => $branch, + 'branchUrl' => $branchUrl, 'repositoryId' => $repositoryId, 'repositoryName' => $repositoryName, 'repositoryUrl' => $repositoryUrl, 'installationId' => $installationId, 'commitHash' => $commitHash, 'owner' => $owner, + 'authorUrl' => $authorUrl, 'headCommitAuthor' => $headCommitAuthor, 'headCommitMessage' => $headCommitMessage, 'headCommitUrl' => $headCommitUrl, @@ -523,16 +527,19 @@ public function getEvent(string $event, string $payload): array $repositoryId = strval($payload['repository']['id'] ?? ''); $branch = $payload['pull_request']['head']['ref'] ?? ''; $repositoryName = $payload['repository']['name'] ?? ''; - $repositoryUrl = $payload['pull_request']['html_url'] ?? ''; + $repositoryUrl = $payload['repository']['html_url'] ?? ''; + $branchUrl = "$repositoryUrl/tree/$branch"; $pullRequestNumber = $payload['number'] ?? ''; $action = $payload['action'] ?? ''; $owner = $payload['repository']['owner']['login'] ?? ''; + $authorUrl = $payload['sender']['html_url']; $commitHash = $payload['pull_request']['head']['sha'] ?? ''; $headCommitUrl = $repositoryUrl . "/commits/" . $commitHash; $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; return [ 'branch' => $branch, + 'branchUrl' => $branchUrl, 'repositoryId' => $repositoryId, 'repositoryName' => $repositoryName, 'repositoryUrl' => $repositoryUrl, diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index ac48c3e0..a3783f6b 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -52,6 +52,9 @@ public function testgetEvent(): void }, "message": "Update index.js", "url": "https://github.com/vermakhushboo/g4-node-function/commit/b787f03343171ff5a477627796140bfa1d02da09" + }, + "sender": { + "html_url": "https://github.com/vermakhushboo" } }'; @@ -83,10 +86,13 @@ public function testgetEvent(): void "owner": { "login": "vermakhushboo" }, - "url": "https://github.com/vermakhushboo/g4-node-function" + "html_url": "https://github.com/vermakhushboo/g4-node-function" }, "installation": { "id": 9876 + }, + "sender": { + "html_url": "https://github.com/vermakhushboo" } }'; From 9f1665cb7818a05adf77c17972e560c2e43b7974 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Wed, 9 Aug 2023 22:52:48 +0530 Subject: [PATCH 142/147] Add authorUrl to pull request response --- src/VCS/Adapter/Git/GitHub.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 642a61fe..7f775156 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -546,6 +546,7 @@ public function getEvent(string $event, string $payload): array 'installationId' => $installationId, 'commitHash' => $commitHash, 'owner' => $owner, + 'authorUrl' => $authorUrl, 'headCommitUrl' => $headCommitUrl, 'external' => $external, 'pullRequestNumber' => $pullRequestNumber, From ce39443747ebc47f76e47563ed1703ac3bfc0eb4 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 10 Aug 2023 00:48:48 +0530 Subject: [PATCH 143/147] Resolve PR comments --- src/VCS/Adapter.php | 17 +++++++---------- src/VCS/Adapter/Git.php | 2 -- src/VCS/Adapter/Git/GitHub.php | 17 ++--------------- tests/VCS/Base.php | 22 ++++++++-------------- 4 files changed, 17 insertions(+), 41 deletions(-) diff --git a/src/VCS/Adapter.php b/src/VCS/Adapter.php index e8b4cf65..e46188c6 100644 --- a/src/VCS/Adapter.php +++ b/src/VCS/Adapter.php @@ -24,6 +24,10 @@ abstract class Adapter public const METHOD_TRACE = 'TRACE'; + public const TYPE_GIT = 'git'; + + public const TYPE_SVN = 'svn'; + protected bool $selfSigned = true; protected string $endpoint; @@ -91,12 +95,6 @@ abstract public function getOwnerName(string $installationId): string; */ abstract public function listRepositories($page, $per_page): array; - /** - * Get latest opened pull request with specific base branch - * @return array - */ - abstract public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array; - /** * Get repository * @@ -117,11 +115,10 @@ abstract public function createRepository(string $owner, string $repositoryName, abstract public function deleteRepository(string $owner, string $repositoryName): void; /** - * Get total repositories count - * - * @return int + * Get latest opened pull request with specific base branch + * @return array */ - abstract public function getRepositoriesTotalCount(): int; + abstract public function getPullRequestFromBranch(string $owner, string $repositoryName, string $branch): array; /** * Get Pull Request diff --git a/src/VCS/Adapter/Git.php b/src/VCS/Adapter/Git.php index b4b49e88..268f75b6 100644 --- a/src/VCS/Adapter/Git.php +++ b/src/VCS/Adapter/Git.php @@ -7,8 +7,6 @@ abstract class Git extends Adapter { - public const TYPE_GIT = 'git'; - protected string $endpoint; protected string $accessToken; diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 7f775156..4142f45d 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -163,19 +163,6 @@ public function listRepositoryLanguages(string $owner, string $repositoryName): return []; } - public function getRepositoriesTotalCount(): int - { - $url = '/installation/repositories'; - - $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - - if (!isset($response['body']['total_count'])) { - throw new Exception("Total count of repositories missing in the response."); - } - - return $response['body']['total_count']; - } - /** * List contents of the specified root directory. * @@ -350,7 +337,7 @@ public function getPullRequest(string $owner, string $repositoryName, int $pullR * Get latest opened pull request with specific base branch * @return array */ - public function getBranchPullRequest(string $owner, string $repositoryName, string $branch): array + public function getPullRequestFromBranch(string $owner, string $repositoryName, string $branch): array { $head = "{$owner}:{$branch}"; $url = "/repos/{$owner}/{$repositoryName}/pulls?head={$head}&state=open&sort=updated&per_page=1"; @@ -569,7 +556,7 @@ public function getEvent(string $event, string $payload): array /** - * Parses webhook event payload + * Validate webhook event * * @param string $payload Raw body of HTTP request * @param string $signature Signature provided by GitHub in header diff --git a/tests/VCS/Base.php b/tests/VCS/Base.php index 83543255..26c446a0 100644 --- a/tests/VCS/Base.php +++ b/tests/VCS/Base.php @@ -25,9 +25,16 @@ abstract public function testgetEvent(): void; abstract public function testGetRepositoryName(): void; + abstract public function testGetComment(): void; + abstract public function testGetPullRequest(): void; - abstract public function testGetComment(): void; + public function testGetPullRequestFromBranch(): void + { + $result = $this->vcsAdapter->getPullRequestFromBranch('vermakhushboo', 'basic-js-crud', 'test'); + $this->assertIsArray($result); + $this->assertNotEmpty($result); + } public function testGetOwnerName(): void { @@ -42,12 +49,6 @@ public function testListRepositories(): void $this->assertCount(2, $repos); } - public function testGetRepositoriesTotalCount(): void - { - $count = $this->vcsAdapter->getRepositoriesTotalCount(); - $this->assertGreaterThanOrEqual(0, $count); - } - public function testCreateComment(): void { $commentId = $this->vcsAdapter->createComment('test-kh', 'test2', 1, 'hello'); @@ -78,11 +79,4 @@ public function testListRepositoryContents(): void $this->assertIsArray($contents); $this->assertNotEmpty($contents); } - - public function testGetBranchPullRequest(): void - { - $result = $this->vcsAdapter->getBranchPullRequest('vermakhushboo', 'basic-js-crud', 'test'); - $this->assertIsArray($result); - $this->assertNotEmpty($result); - } } From 489e9561af474c23aea0837736b09e5ced5901ac Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 10 Aug 2023 01:00:54 +0530 Subject: [PATCH 144/147] Remove env variables not being used from docker-compose --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index c42ddb31..bf600426 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,5 +11,4 @@ services: environment: - PRIVATE_KEY - APP_IDENTIFIER - - WEBHOOK_SECRET - INSTALLATION_ID \ No newline at end of file From 66ce4af7f72ca63c763406b1bf97a49bbb901ead Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 10 Aug 2023 01:09:05 +0530 Subject: [PATCH 145/147] Update README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index a43a5022..596ee4c3 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,19 @@ $isPrivate = true; // Set to false if you want to create a public repository $repository = $github->createRepository($owner, $name, $private); ``` +### Environment Variables +To configure your GitHub App properly, you'll need to set up the following environment variables in your environment or configuration file. These values are crucial for authenticating and interacting with the GitHub API on behalf of your GitHub App. + +1. *PRIVATE_KEY*: You can generate this from your GitHub App settings. + > PRIVATE_KEY = your-github-app-private-key +2. *GITHUB_APP_ID*: You can find this in the GitHub App dashboard. + > GITHUB_APP_ID = your-github-app-id +3. *INSTALLATION_ID*: You can find this in the GitHub App installation settings after installation. +> INSTALLATION_ID = your-github-app-installation-id + +Remember to replace the placeholders (*your-github-app-private-key*, *your-github-app-id*, and *your-github-app-installation-id*) with the actual values from your GitHub App configuration. +By using these environment variables, you can ensure that sensitive information is kept separate from your codebase and can be easily managed across different environments without exposing sensitive data. + ### Supported Adapters VCS Adapters: From 482ff569dfced94419c23c48c92ea66ab8bfb952 Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 10 Aug 2023 01:10:35 +0530 Subject: [PATCH 146/147] Update README.md --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 596ee4c3..bda54586 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,17 @@ $repository = $github->createRepository($owner, $name, $private); To configure your GitHub App properly, you'll need to set up the following environment variables in your environment or configuration file. These values are crucial for authenticating and interacting with the GitHub API on behalf of your GitHub App. 1. *PRIVATE_KEY*: You can generate this from your GitHub App settings. - > PRIVATE_KEY = your-github-app-private-key +```bash +PRIVATE_KEY = your-github-app-private-key +``` 2. *GITHUB_APP_ID*: You can find this in the GitHub App dashboard. - > GITHUB_APP_ID = your-github-app-id +```bash +GITHUB_APP_ID = your-github-app-id +``` 3. *INSTALLATION_ID*: You can find this in the GitHub App installation settings after installation. -> INSTALLATION_ID = your-github-app-installation-id +```bash +INSTALLATION_ID = your-github-app-installation-id +``` Remember to replace the placeholders (*your-github-app-private-key*, *your-github-app-id*, and *your-github-app-installation-id*) with the actual values from your GitHub App configuration. By using these environment variables, you can ensure that sensitive information is kept separate from your codebase and can be easily managed across different environments without exposing sensitive data. From 488ddba7ab6ccb00c3cfa57db70a3fe2c5cea67f Mon Sep 17 00:00:00 2001 From: Khushboo Verma <43381712+vermakhushboo@users.noreply.github.com> Date: Thu, 10 Aug 2023 01:58:22 +0530 Subject: [PATCH 147/147] Fixed clone command to protect from shell injection --- src/VCS/Adapter/Git/GitHub.php | 27 ++++++++++++++++++++++----- tests/VCS/Adapter/GitHubTest.php | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 4142f45d..736792e8 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -450,13 +450,30 @@ public function generateCloneCommand(string $owner, string $repositoryName, stri $rootDirectory = '*'; } - // Construct the clone URL with the access token - $cloneUrl = "https://{$owner}:{$this->accessToken}@github.com/{$owner}/{$repositoryName}"; + // URL encode the components for the clone URL + $owner = urlencode($owner); + $repositoryName = urlencode($repositoryName); + $accessToken = urlencode($this->accessToken); + $cloneUrl = "https://{$owner}:{$accessToken}@github.com/{$owner}/{$repositoryName}"; + + $directory = escapeshellarg($directory); + $rootDirectory = escapeshellarg($rootDirectory); + $branchName = escapeshellarg($branchName); + + $commands = [ + "mkdir -p {$directory}", + "cd {$directory}", + "git config --global init.defaultBranch main", + "git init", + "git remote add origin {$cloneUrl}", + "git config core.sparseCheckout true", + "echo {$rootDirectory} >> .git/info/sparse-checkout", + "if git ls-remote --exit-code --heads origin {$branchName}; then git pull origin {$branchName} && git checkout {$branchName}; else git checkout -b {$branchName}; fi" + ]; - // Construct the Git clone command with the clone URL - $command = "mkdir -p {$directory} && cd {$directory} && git config --global init.defaultBranch main && git init && git remote add origin {$cloneUrl} && git config core.sparseCheckout true && echo \"{$rootDirectory}\" >> .git/info/sparse-checkout && if git ls-remote --exit-code --heads origin {$branchName}; then git pull origin {$branchName} && git checkout {$branchName}; else git checkout -b {$branchName}; fi"; + $fullCommand = implode(" && ", $commands); - return $command; + return $fullCommand; } /** diff --git a/tests/VCS/Adapter/GitHubTest.php b/tests/VCS/Adapter/GitHubTest.php index a3783f6b..56bc80ac 100644 --- a/tests/VCS/Adapter/GitHubTest.php +++ b/tests/VCS/Adapter/GitHubTest.php @@ -155,7 +155,7 @@ public function testGetPullRequest(): void public function testGenerateCloneCommand(): void { - $gitCloneCommand = $this->vcsAdapter->generateCloneCommand('test-kh', 'test2', 'main', '', ''); + $gitCloneCommand = $this->vcsAdapter->generateCloneCommand('test-kh', 'test2', 'main', 'test', '*'); $this->assertNotEmpty($gitCloneCommand); $this->assertStringContainsString('sparse-checkout', $gitCloneCommand); }