From e8c14263356b835ee1740e89951716a159b483d7 Mon Sep 17 00:00:00 2001 From: eldadfux Date: Sun, 22 Feb 2026 20:49:03 +0100 Subject: [PATCH 1/5] fix: Ensure installation ID is set correctly in GitHub payload handling --- 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 fdc4929..7656404 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -631,7 +631,7 @@ public function getEvent(string $event, string $payload): array throw new Exception("Invalid payload."); } - $installationId = strval($payload['installation']['id']); + $installationId = strval(isset($payload['installation']['id']) ? $payload['installation']['id'] : ''); switch ($event) { case 'push': From 4b6a37dd34512ea639840103a4cc16cbab16b0f6 Mon Sep 17 00:00:00 2001 From: eldadfux Date: Sun, 22 Feb 2026 21:03:27 +0100 Subject: [PATCH 2/5] Missing a lot of null safety checks --- src/VCS/Adapter/Git/GitHub.php | 48 ++++++++++++++++++---------------- src/VCS/Adapter/Git/Gitea.php | 4 +-- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 7656404..6678cb3 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -638,19 +638,19 @@ public function getEvent(string $event, string $payload): array $branchCreated = isset($payload['created']) ? $payload['created'] : false; $branchDeleted = isset($payload['deleted']) ? $payload['deleted'] : false; $ref = $payload['ref'] ?? ''; - $repositoryId = strval($payload['repository']['id'] ?? ''); - $repositoryName = $payload['repository']['name'] ?? ''; + $repositoryId = strval(isset($payload['repository']['id']) ? $payload['repository']['id'] : ''); + $repositoryName = isset($payload['repository']['name']) ? $payload['repository']['name'] : ''; $branch = str_replace('refs/heads/', '', $ref); - $branchUrl = $payload['repository']['html_url'] . "/tree/" . $branch; - $repositoryUrl = $payload['repository']['html_url']; + $repositoryUrl = isset($payload['repository']['html_url']) ? $payload['repository']['html_url'] : ''; + $branchUrl = $repositoryUrl ? $repositoryUrl . "/tree/" . $branch : ''; $commitHash = $payload['after'] ?? ''; - $owner = $payload['repository']['owner']['name'] ?? ''; - $authorUrl = $payload['sender']['html_url']; - $authorAvatarUrl = $payload['sender']['avatar_url'] ?? ''; - $headCommitAuthorName = $payload['head_commit']['author']['name'] ?? ''; - $headCommitAuthorEmail = $payload['head_commit']['author']['email'] ?? ''; - $headCommitMessage = $payload['head_commit']['message'] ?? ''; - $headCommitUrl = $payload['head_commit']['url'] ?? ''; + $owner = isset($payload['repository']['owner']['name']) ? $payload['repository']['owner']['name'] : ''; + $authorUrl = isset($payload['sender']['html_url']) ? $payload['sender']['html_url'] : ''; + $authorAvatarUrl = isset($payload['sender']['avatar_url']) ? $payload['sender']['avatar_url'] : ''; + $headCommitAuthorName = isset($payload['head_commit']['author']['name']) ? $payload['head_commit']['author']['name'] : ''; + $headCommitAuthorEmail = isset($payload['head_commit']['author']['email']) ? $payload['head_commit']['author']['email'] : ''; + $headCommitMessage = isset($payload['head_commit']['message']) ? $payload['head_commit']['message'] : ''; + $headCommitUrl = isset($payload['head_commit']['url']) ? $payload['head_commit']['url'] : ''; $affectedFiles = []; foreach (($payload['commits'] ?? []) as $commit) { @@ -690,19 +690,21 @@ public function getEvent(string $event, string $payload): array 'affectedFiles' => \array_keys($affectedFiles), ]; case 'pull_request': - $repositoryId = strval($payload['repository']['id'] ?? ''); - $branch = $payload['pull_request']['head']['ref'] ?? ''; - $repositoryName = $payload['repository']['name'] ?? ''; - $repositoryUrl = $payload['repository']['html_url'] ?? ''; - $branchUrl = "$repositoryUrl/tree/$branch"; + $repositoryId = strval(isset($payload['repository']['id']) ? $payload['repository']['id'] : ''); + $branch = isset($payload['pull_request']['head']['ref']) ? $payload['pull_request']['head']['ref'] : ''; + $repositoryName = isset($payload['repository']['name']) ? $payload['repository']['name'] : ''; + $repositoryUrl = isset($payload['repository']['html_url']) ? $payload['repository']['html_url'] : ''; + $branchUrl = $repositoryUrl ? "$repositoryUrl/tree/$branch" : ''; $pullRequestNumber = $payload['number'] ?? ''; $action = $payload['action'] ?? ''; - $owner = $payload['repository']['owner']['login'] ?? ''; - $authorUrl = $payload['sender']['html_url']; - $authorAvatarUrl = $payload['pull_request']['user']['avatar_url'] ?? ''; - $commitHash = $payload['pull_request']['head']['sha'] ?? ''; - $headCommitUrl = $repositoryUrl . "/commits/" . $commitHash; - $external = $payload['pull_request']['head']['user']['login'] !== $payload['pull_request']['base']['user']['login']; + $owner = isset($payload['repository']['owner']['login']) ? $payload['repository']['owner']['login'] : ''; + $authorUrl = isset($payload['sender']['html_url']) ? $payload['sender']['html_url'] : ''; + $authorAvatarUrl = isset($payload['pull_request']['user']['avatar_url']) ? $payload['pull_request']['user']['avatar_url'] : ''; + $commitHash = isset($payload['pull_request']['head']['sha']) ? $payload['pull_request']['head']['sha'] : ''; + $headCommitUrl = $repositoryUrl ? $repositoryUrl . "/commits/" . $commitHash : ''; + $headLogin = isset($payload['pull_request']['head']['user']['login']) ? $payload['pull_request']['head']['user']['login'] : ''; + $baseLogin = isset($payload['pull_request']['base']['user']['login']) ? $payload['pull_request']['base']['user']['login'] : ''; + $external = $headLogin !== $baseLogin; return [ 'branch' => $branch, @@ -723,7 +725,7 @@ public function getEvent(string $event, string $payload): array case 'installation': case 'installation_repositories': $action = $payload['action'] ?? ''; - $userName = $payload['installation']['account']['login'] ?? ''; + $userName = isset($payload['installation']['account']['login']) ? $payload['installation']['account']['login'] : ''; return [ 'action' => $action, diff --git a/src/VCS/Adapter/Git/Gitea.php b/src/VCS/Adapter/Git/Gitea.php index 944b87b..eea3524 100644 --- a/src/VCS/Adapter/Git/Gitea.php +++ b/src/VCS/Adapter/Git/Gitea.php @@ -124,7 +124,7 @@ public function getRepository(string $owner, string $repositoryName): array $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]); - $statusCode = $response['headers']['status-code'] ?? 0; + $statusCode = isset($response['headers']['status-code']) ? $response['headers']['status-code'] : 0; if ($statusCode >= 400) { throw new RepositoryNotFound("Repository not found"); } @@ -171,7 +171,7 @@ public function deleteRepository(string $owner, string $repositoryName): bool $response = $this->call(self::METHOD_DELETE, $url, ['Authorization' => "token $this->accessToken"]); - $statusCode = $response['headers']['status-code']; + $statusCode = isset($response['headers']['status-code']) ? $response['headers']['status-code'] : 0; if ($statusCode >= 400) { throw new Exception("Deleting repository {$repositoryName} failed with status code {$statusCode}"); From 9f65942a3813aa6f37dcf61e1e34473881ec8e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 5 Mar 2026 10:20:25 +0100 Subject: [PATCH 3/5] Improve null check quality --- src/VCS/Adapter/Git/GitHub.php | 224 ++++++++++++++++++++------------- src/VCS/Adapter/Git/Gitea.php | 25 ++-- 2 files changed, 156 insertions(+), 93 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 6678cb3..2282b7e 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -115,13 +115,15 @@ public function searchRepositories(string $owner, int $page, int $per_page, stri 'sort' => 'updated' ]); - if (!isset($response['body']['items'])) { + $responseBody = $response['body']; + + if (!array_key_exists('items', $responseBody)) { throw new Exception("Repositories list missing in the response."); } return [ - 'items' => $response['body']['items'], - 'total' => $response['body']['total_count'], + 'items' => $responseBody['items'] ?? [], + 'total' => $responseBody['total_count'] ?? 0, ]; } @@ -152,11 +154,13 @@ 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'])) { + $responseBody = $response['body'] ?? []; + + if (!array_key_exists('name', $responseBody)) { throw new RepositoryNotFound("Repository not found"); } - return $response['body']['name']; + return $responseBody['name'] ?? ''; } /** @@ -174,11 +178,15 @@ public function getRepositoryTree(string $owner, string $repositoryName, string $url = "/repos/$owner/$repositoryName/git/trees/$branch" . ($recursive ? '?recursive=1' : ''); $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - if ($response['headers']['status-code'] == 404) { + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode == 404) { return []; } - return array_column($response['body']['tree'], 'path'); + $responseBody = $response['body'] ?? []; + + return array_column($responseBody['tree'] ?? [], 'path'); } /** @@ -219,22 +227,26 @@ public function getRepositoryContent(string $owner, string $repositoryName, stri $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - if ($response['headers']['status-code'] !== 200) { + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode !== 200) { throw new FileNotFound(); } - $encoding = $response['body']['encoding']; + $responseBody = $response['body']; + + $encoding = $responseBody['encoding'] ?? ''; $content = ''; if ($encoding === 'base64') { - $content = base64_decode($response['body']['content']); + $content = base64_decode($responseBody['content'] ?? ''); } else { throw new FileNotFound(); } $output = [ - 'sha' => $response['body']['sha'], - 'size' => $response['body']['size'], + 'sha' => $responseBody['sha'] ?? '', + 'size' => $responseBody['size'] ?? 0, 'content' => $content ]; @@ -262,16 +274,20 @@ public function listRepositoryContents(string $owner, string $repositoryName, st $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - if (($response['headers']['status-code'] == 404)) { + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode == 404) { return []; } + $responseBody = $response['body'] ?? []; + $items = []; - if (!empty($response['body'][0])) { - $items = $response['body']; - } elseif (!empty($response['body'])) { - $items = [$response['body']]; + if (!empty($responseBody[0] ?? [])) { + $items = $responseBody; + } elseif (!empty($responseBody)) { + $items = [$responseBody]; } $contents = []; @@ -293,10 +309,10 @@ public function deleteRepository(string $owner, string $repositoryName): bool $response = $this->call(self::METHOD_DELETE, $url, ['Authorization' => "Bearer $this->accessToken"]); - $statusCode = $response['headers']['status-code']; - - if ($statusCode >= 400) { - throw new Exception("Deleting repository $repositoryName failed with status code $statusCode"); + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode >= 400) { + throw new Exception("Deleting repository $repositoryName failed with status code $responseHeadersStatusCode"); } return true; } @@ -314,11 +330,13 @@ public function createComment(string $owner, string $repositoryName, int $pullRe $response = $this->call(self::METHOD_POST, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); - if (!isset($response['body']['id'])) { + $responseBody = $response['body'] ?? []; + + if (!array_key_exists('id', $responseBody)) { throw new Exception("Comment creation response is missing comment ID."); } - $commentId = $response['body']['id']; + $commentId = $responseBody['id'] ?? ''; return $commentId; } @@ -338,7 +356,10 @@ 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'] ?? ''; + + $responseBody = $response['body'] ?? []; + + $comment = $responseBody['body'] ?? ''; return $comment; } @@ -360,11 +381,13 @@ public function updateComment(string $owner, string $repositoryName, int $commen $response = $this->call(self::METHOD_PATCH, $url, ['Authorization' => "Bearer $this->accessToken"], ['body' => $comment]); - if (!isset($response['body']['id'])) { + $responseBody = $response['body'] ?? []; + + if (!array_key_exists('id', $responseBody)) { throw new Exception("Comment update response is missing comment ID."); } - $commentId = $response['body']['id']; + $commentId = $responseBody['id'] ?? ''; return $commentId; } @@ -393,11 +416,12 @@ protected function generateAccessToken(string $privateKey, ?string $appId): void $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]); - if (!isset($res['body']['token'])) { + $response = $this->call(self::METHOD_POST, '/app/installations/' . $this->installationId . '/access_tokens', ['Authorization' => 'Bearer ' . $token]); + $responseBody = $response['body'] ?? []; + if (!array_key_exists('token', $responseBody)) { throw new Exception('Failed to retrieve access token from GitHub API.'); } - $this->accessToken = $res['body']['token']; + $this->accessToken = $responseBody['token'] ?? ''; } /** @@ -424,11 +448,14 @@ 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'])) { + $responseBody = $response['body'] ?? []; + $responseBodyAccount = $responseBody['account'] ?? []; + + if (!array_key_exists('login', $responseBodyAccount)) { throw new Exception("Owner name retrieval response is missing account login."); } - return $response['body']['account']['login']; + return $responseBodyAccount['login'] ?? ''; } /** @@ -456,7 +483,9 @@ public function getPullRequestFromBranch(string $owner, string $repositoryName, $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - return $response['body'][0] ?? []; + $responseBody = $response['body'] ?? []; + + return $responseBody[0] ?? []; } /** @@ -472,9 +501,11 @@ public function listBranches(string $owner, string $repositoryName): array $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + $responseBody = $response['body'] ?? []; + $names = []; - foreach ($response['body'] as $subarray) { - $names[] = $subarray['name']; + foreach ($responseBody as $subarray) { + $names[] = $subarray['name'] ?? ''; } return $names; @@ -494,18 +525,18 @@ public function getCommit(string $owner, string $repositoryName, string $commitH $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - $body = $response['body'] ?? []; - $author = $body['author'] ?? []; - $commit = $body['commit'] ?? []; - $commitAuthor = $commit['author'] ?? []; + $responseBody = $response['body'] ?? []; + $responseBodyAuthor = $responseBody['author'] ?? []; + $responseBodyCommit = $responseBody['commit'] ?? []; + $responseBodyCommitAuthor = $responseBodyCommit['author'] ?? []; return [ - 'commitAuthor' => $commitAuthor['name'] ?? 'Unknown', - 'commitMessage' => $commit['message'] ?? 'No message', - 'commitAuthorAvatar' => $author['avatar_url'] ?? '', - 'commitAuthorUrl' => $author['html_url'] ?? '', - 'commitHash' => $body['sha'] ?? '', - 'commitUrl' => $body['html_url'] ?? '', + 'commitAuthor' => $responseBodyCommitAuthor['name'] ?? 'Unknown', + 'commitMessage' => $responseBodyCommit['message'] ?? 'No message', + 'commitAuthorAvatar' => $responseBodyAuthor['avatar_url'] ?? '', + 'commitAuthorUrl' => $responseBodyAuthor['html_url'] ?? '', + 'commitHash' => $responseBody['sha'] ?? '', + 'commitUrl' => $responseBody['html_url'] ?? '', ]; } @@ -523,24 +554,29 @@ public function getLatestCommit(string $owner, string $repositoryName, string $b $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); + $responseBody = $response['body'] ?? []; + $responseBodyCommit = $responseBody['commit'] ?? []; + $responseBodyCommitAuthor = $responseBodyCommit['author'] ?? []; + $responseBodyAuthor = $responseBody['author'] ?? []; + if ( - !isset($response['body']['commit']['author']['name']) || - !isset($response['body']['commit']['message']) || - !isset($response['body']['sha']) || - !isset($response['body']['html_url']) || - !isset($response['body']['author']['avatar_url']) || - !isset($response['body']['author']['html_url']) + !array_key_exists('name', $responseBodyCommitAuthor) || + !array_key_exists('message', $responseBodyCommit) || + !array_key_exists('sha', $responseBody) || + !array_key_exists('html_url', $responseBody) || + !array_key_exists('avatar_url', $responseBodyAuthor) || + !array_key_exists('html_url', $responseBodyAuthor) ) { throw new Exception("Latest commit response is missing required information."); } return [ - 'commitAuthor' => $response['body']['commit']['author']['name'], - 'commitMessage' => $response['body']['commit']['message'], - 'commitHash' => $response['body']['sha'], - 'commitUrl' => $response['body']['html_url'], - 'commitAuthorAvatar' => $response['body']['author']['avatar_url'], - 'commitAuthorUrl' => $response['body']['author']['html_url'], + 'commitAuthor' => $responseBodyCommitAuthor['name'] ?? '', + 'commitMessage' => $responseBodyCommit['message'] ?? '', + 'commitHash' => $responseBody['sha'] ?? '', + 'commitUrl' => $responseBody['html_url'] ?? '', + 'commitAuthorAvatar' => $responseBodyAuthor['avatar_url'] ?? '', + 'commitAuthorUrl' => $responseBodyAuthor['html_url'] ?? '', ]; } @@ -631,26 +667,33 @@ public function getEvent(string $event, string $payload): array throw new Exception("Invalid payload."); } - $installationId = strval(isset($payload['installation']['id']) ? $payload['installation']['id'] : ''); + $payloadInstallation = $payload['installation'] ?? []; + + $installationId = strval($payloadInstallation['id'] ?? ''); switch ($event) { case 'push': - $branchCreated = isset($payload['created']) ? $payload['created'] : false; - $branchDeleted = isset($payload['deleted']) ? $payload['deleted'] : false; - $ref = $payload['ref'] ?? ''; - $repositoryId = strval(isset($payload['repository']['id']) ? $payload['repository']['id'] : ''); - $repositoryName = isset($payload['repository']['name']) ? $payload['repository']['name'] : ''; - $branch = str_replace('refs/heads/', '', $ref); - $repositoryUrl = isset($payload['repository']['html_url']) ? $payload['repository']['html_url'] : ''; - $branchUrl = $repositoryUrl ? $repositoryUrl . "/tree/" . $branch : ''; + $payloadRepository = $payload['repository'] ?? []; + $payloadRepositoryOwner = $payloadRepository['owner'] ?? []; + $payloadSender = $payload['sender'] ?? []; + $payloadHeadCommit = $payload['head_commit'] ?? []; + $payloadHeadCommitAuthor = $payloadHeadCommit['author'] ?? []; + + $branchCreated = $payload['created'] ?? false; + $branchDeleted = $payload['deleted'] ?? false; + $repositoryId = strval($payloadRepository['id'] ?? ''); + $repositoryName = $payloadRepository['name'] ?? ''; + $branch = str_replace('refs/heads/', '', $payload['ref'] ?? ''); + $repositoryUrl = $payloadRepository['html_url'] ?? ''; + $branchUrl = !empty($repositoryUrl) && !empty($branch) ? $repositoryUrl . "/tree/" . $branch : ''; $commitHash = $payload['after'] ?? ''; - $owner = isset($payload['repository']['owner']['name']) ? $payload['repository']['owner']['name'] : ''; - $authorUrl = isset($payload['sender']['html_url']) ? $payload['sender']['html_url'] : ''; - $authorAvatarUrl = isset($payload['sender']['avatar_url']) ? $payload['sender']['avatar_url'] : ''; - $headCommitAuthorName = isset($payload['head_commit']['author']['name']) ? $payload['head_commit']['author']['name'] : ''; - $headCommitAuthorEmail = isset($payload['head_commit']['author']['email']) ? $payload['head_commit']['author']['email'] : ''; - $headCommitMessage = isset($payload['head_commit']['message']) ? $payload['head_commit']['message'] : ''; - $headCommitUrl = isset($payload['head_commit']['url']) ? $payload['head_commit']['url'] : ''; + $owner = $payloadRepositoryOwner['name'] ?? ''; + $authorUrl = $payloadSender['html_url'] ?? ''; + $authorAvatarUrl = $payloadSender['avatar_url'] ?? ''; + $headCommitAuthorName = $payloadHeadCommitAuthor['name'] ?? ''; + $headCommitAuthorEmail = $payloadHeadCommitAuthor['email'] ?? ''; + $headCommitMessage = $payloadHeadCommit['message'] ?? ''; + $headCommitUrl = $payloadHeadCommit['url'] ?? ''; $affectedFiles = []; foreach (($payload['commits'] ?? []) as $commit) { @@ -690,20 +733,30 @@ public function getEvent(string $event, string $payload): array 'affectedFiles' => \array_keys($affectedFiles), ]; case 'pull_request': - $repositoryId = strval(isset($payload['repository']['id']) ? $payload['repository']['id'] : ''); - $branch = isset($payload['pull_request']['head']['ref']) ? $payload['pull_request']['head']['ref'] : ''; - $repositoryName = isset($payload['repository']['name']) ? $payload['repository']['name'] : ''; - $repositoryUrl = isset($payload['repository']['html_url']) ? $payload['repository']['html_url'] : ''; - $branchUrl = $repositoryUrl ? "$repositoryUrl/tree/$branch" : ''; + $payloadRepository = $payload['repository'] ?? []; + $payloadRepositoryOwner = $payloadRepository['owner'] ?? []; + $payloadSender = $payload['sender'] ?? []; + $payloadPullRequest = $payload['pull_request'] ?? []; + $payloadPullRequestHead = $payloadPullRequest['head'] ?? []; + $payloadPullRequestHeadUser = $payloadPullRequestHead['user'] ?? []; + $payloadPullRequestUser = $payloadPullRequest['user'] ?? []; + $payloadPullRequestBase = $payloadPullRequest['base'] ?? []; + $payloadPullRequestBaseUser = $payloadPullRequestBase['user'] ?? []; + + $repositoryId = strval($payloadRepository['id'] ?? ''); + $branch = $payloadPullRequestHead['ref'] ?? ''; + $repositoryName = $payloadRepository['name'] ?? ''; + $repositoryUrl = $payloadRepository['html_url'] ?? ''; + $branchUrl = !empty($repositoryUrl) && !empty($branch) ? $repositoryUrl . "/tree/" . $branch : ''; $pullRequestNumber = $payload['number'] ?? ''; $action = $payload['action'] ?? ''; - $owner = isset($payload['repository']['owner']['login']) ? $payload['repository']['owner']['login'] : ''; - $authorUrl = isset($payload['sender']['html_url']) ? $payload['sender']['html_url'] : ''; - $authorAvatarUrl = isset($payload['pull_request']['user']['avatar_url']) ? $payload['pull_request']['user']['avatar_url'] : ''; - $commitHash = isset($payload['pull_request']['head']['sha']) ? $payload['pull_request']['head']['sha'] : ''; + $owner = $payloadRepositoryOwner['login'] ?? ''; + $authorUrl = $payloadSender['html_url'] ?? ''; + $authorAvatarUrl = $payloadPullRequestUser['avatar_url'] ?? ''; + $commitHash = $payloadPullRequestHead['sha'] ?? ''; $headCommitUrl = $repositoryUrl ? $repositoryUrl . "/commits/" . $commitHash : ''; - $headLogin = isset($payload['pull_request']['head']['user']['login']) ? $payload['pull_request']['head']['user']['login'] : ''; - $baseLogin = isset($payload['pull_request']['base']['user']['login']) ? $payload['pull_request']['base']['user']['login'] : ''; + $headLogin = $payloadPullRequestHeadUser['login'] ?? ''; + $baseLogin = $payloadPullRequestBaseUser['login'] ?? ''; $external = $headLogin !== $baseLogin; return [ @@ -724,8 +777,11 @@ public function getEvent(string $event, string $payload): array ]; case 'installation': case 'installation_repositories': + $payloadInstallation = $payload['installation'] ?? []; + $payloadInstallationAccount = $payloadInstallation['account'] ?? []; + $action = $payload['action'] ?? ''; - $userName = isset($payload['installation']['account']['login']) ? $payload['installation']['account']['login'] : ''; + $userName = $payloadInstallationAccount['login'] ?? ''; return [ 'action' => $action, diff --git a/src/VCS/Adapter/Git/Gitea.php b/src/VCS/Adapter/Git/Gitea.php index eea3524..75e1520 100644 --- a/src/VCS/Adapter/Git/Gitea.php +++ b/src/VCS/Adapter/Git/Gitea.php @@ -107,7 +107,9 @@ public function createOrganization(string $orgName): string 'visibility' => 'public', ]); - return $response['body']['name'] ?? ''; + $responseBody = $response['body'] ?? []; + + return $responseBody['name'] ?? ''; } // Stub methods to satisfy abstract class requirements @@ -124,12 +126,14 @@ public function getRepository(string $owner, string $repositoryName): array $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]); - $statusCode = isset($response['headers']['status-code']) ? $response['headers']['status-code'] : 0; - if ($statusCode >= 400) { + + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode >= 400) { throw new RepositoryNotFound("Repository not found"); } - return $response['body']; + return $response['body'] ?? []; } public function getRepositoryName(string $repositoryId): string @@ -138,11 +142,13 @@ public function getRepositoryName(string $repositoryId): string $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]); - if (!isset($response['body']['name'])) { + $responseBody = $response['body'] ?? []; + + if (!array_key_exists('name', $responseBody)) { throw new RepositoryNotFound("Repository not found"); } - return $response['body']['name']; + return $responseBody['name'] ?? ''; } public function getRepositoryTree(string $owner, string $repositoryName, string $branch, bool $recursive = false): array @@ -171,10 +177,11 @@ public function deleteRepository(string $owner, string $repositoryName): bool $response = $this->call(self::METHOD_DELETE, $url, ['Authorization' => "token $this->accessToken"]); - $statusCode = isset($response['headers']['status-code']) ? $response['headers']['status-code'] : 0; - if ($statusCode >= 400) { - throw new Exception("Deleting repository {$repositoryName} failed with status code {$statusCode}"); + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode >= 400) { + throw new Exception("Deleting repository {$repositoryName} failed with status code {$responseHeadersStatusCode}"); } return true; From 4ee38f2bced7e30300108273c9c7378773bd7955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 5 Mar 2026 10:25:31 +0100 Subject: [PATCH 4/5] Fix leftover --- src/VCS/Adapter/Git/GitHub.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index 2282b7e..3de0be0 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -115,7 +115,7 @@ public function searchRepositories(string $owner, int $page, int $per_page, stri 'sort' => 'updated' ]); - $responseBody = $response['body']; + $responseBody = $response['body'] ?? []; if (!array_key_exists('items', $responseBody)) { throw new Exception("Repositories list missing in the response."); @@ -202,8 +202,10 @@ public function listRepositoryLanguages(string $owner, string $repositoryName): $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "Bearer $this->accessToken"]); - if (isset($response['body'])) { - return array_keys($response['body']); + $responseBody = $response['body'] ?? []; + + if (!empty($responseBody)) { + return array_keys($responseBody); } return []; @@ -233,7 +235,7 @@ public function getRepositoryContent(string $owner, string $repositoryName, stri throw new FileNotFound(); } - $responseBody = $response['body']; + $responseBody = $response['body'] ?? []; $encoding = $responseBody['encoding'] ?? ''; From a45c690ea7c3ca5e1916eacedc708a8ea097a3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 5 Mar 2026 10:36:40 +0100 Subject: [PATCH 5/5] More null fixes after merge --- src/VCS/Adapter/Git/GitHub.php | 12 ++++---- src/VCS/Adapter/Git/Gitea.php | 56 ++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/VCS/Adapter/Git/GitHub.php b/src/VCS/Adapter/Git/GitHub.php index cc5a0b4..a7394ea 100644 --- a/src/VCS/Adapter/Git/GitHub.php +++ b/src/VCS/Adapter/Git/GitHub.php @@ -174,9 +174,9 @@ public function searchRepositories(string $installationId, string $owner, int $p 'page' => $page, 'per_page' => $per_page, ]); - - $responseBody = $response['body']; - + + $responseBody = $response['body'] ?? []; + if (!array_key_exists('repositories', $responseBody)) { throw new Exception("Repositories list missing in the response."); } @@ -196,7 +196,7 @@ public function searchRepositories(string $installationId, string $owner, int $p ]); $responseBody = $response['body'] ?? []; - + if (!array_key_exists('repositories', $responseBody)) { throw new Exception("Repositories list missing in the response."); } @@ -208,7 +208,7 @@ public function searchRepositories(string $installationId, string $owner, int $p $repositories = array_merge($repositories, $filteredRepositories); // If less than 100 repositories are returned, we have fetched all repositories. - if (\count($responseBody['repositories'] ??[]) < 100) { + if (\count($responseBody['repositories'] ?? []) < 100) { break; } @@ -239,7 +239,7 @@ public function getInstallationRepository(string $repositoryName): array ]); $responseBody = $response['body'] ?? []; - + if (!array_key_exists('repositories', $responseBody)) { throw new Exception("Repositories list missing in the response."); } diff --git a/src/VCS/Adapter/Git/Gitea.php b/src/VCS/Adapter/Git/Gitea.php index 7f373b0..303f97a 100644 --- a/src/VCS/Adapter/Git/Gitea.php +++ b/src/VCS/Adapter/Git/Gitea.php @@ -167,11 +167,15 @@ public function getRepositoryTree(string $owner, string $repositoryName, string $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]); - if (($response['headers']['status-code'] ?? 0) === 404) { + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode === 404) { return []; } - return array_column($response['body']['tree'] ?? [], 'path'); + $responseBody = $response['body'] ?? []; + + return array_column($responseBody['tree'] ?? [], 'path'); } /** @@ -198,9 +202,10 @@ public function createFile(string $owner, string $repositoryName, string $filepa ] ); - $statusCode = $response['headers']['status-code'] ?? 0; - if ($statusCode >= 400) { - throw new Exception("Failed to create file {$filepath}: HTTP {$statusCode}"); + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode >= 400) { + throw new Exception("Failed to create file {$filepath}: HTTP {$responseHeadersStatusCode}"); } return $response['body'] ?? []; @@ -229,9 +234,10 @@ public function createBranch(string $owner, string $repositoryName, string $newB ] ); - $statusCode = $response['headers']['status-code'] ?? 0; - if ($statusCode >= 400) { - throw new Exception("Failed to create branch {$newBranchName}: HTTP {$statusCode}"); + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode >= 400) { + throw new Exception("Failed to create branch {$newBranchName}: HTTP {$responseHeadersStatusCode}"); } return $response['body'] ?? []; @@ -243,8 +249,10 @@ public function listRepositoryLanguages(string $owner, string $repositoryName): $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]); - if (isset($response['body'])) { - return array_keys($response['body']); + $responseBody = $response['body'] ?? []; + + if (!empty($responseBody)) { + return array_keys($responseBody); } return []; @@ -259,22 +267,26 @@ public function getRepositoryContent(string $owner, string $repositoryName, stri $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]); - if (($response['headers']['status-code'] ?? 0) !== 200) { + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode !== 200) { throw new FileNotFound(); } - $encoding = $response['body']['encoding'] ?? ''; + $responseBody = $response['body'] ?? []; + + $encoding = $responseBody['encoding'] ?? ''; $content = ''; if ($encoding === 'base64') { - $content = base64_decode($response['body']['content'] ?? ''); + $content = base64_decode($responseBody['content'] ?? ''); } else { throw new FileNotFound(); } return [ - 'sha' => $response['body']['sha'] ?? '', - 'size' => $response['body']['size'] ?? 0, + 'sha' => $responseBody['sha'] ?? '', + 'size' => $responseBody['size'] ?? 0, 'content' => $content ]; } @@ -291,15 +303,19 @@ public function listRepositoryContents(string $owner, string $repositoryName, st $response = $this->call(self::METHOD_GET, $url, ['Authorization' => "token $this->accessToken"]); - if (($response['headers']['status-code'] ?? 0) === 404) { + $responseHeaders = $response['headers'] ?? []; + $responseHeadersStatusCode = $responseHeaders['status-code'] ?? 0; + if ($responseHeadersStatusCode === 404) { return []; } + $responseBody = $response['body'] ?? []; + $items = []; - if (!empty($response['body'][0])) { - $items = $response['body']; - } elseif (!empty($response['body'])) { - $items = [$response['body']]; + if (!empty($responseBody[0] ?? [])) { + $items = $responseBody; + } elseif (!empty($responseBody)) { + $items = [$responseBody]; } $contents = [];