Skip to content

feat: Add rate limit and token permissions checking support#7

Merged
ralflang merged 5 commits intoFRAMEWORK_6_0from
feat/rate-limit-and-token-scopes
Feb 26, 2026
Merged

feat: Add rate limit and token permissions checking support#7
ralflang merged 5 commits intoFRAMEWORK_6_0from
feat/rate-limit-and-token-scopes

Conversation

@ralflang
Copy link
Member

Summary

This PR adds two essential features to the GitHub API client library:

  • Rate Limit Checking - Monitor API quota usage
  • Token Permissions/Scopes Checking - Verify what the access token can do

Features Added

1. Rate Limit Support

New Classes:

  • RateLimit - Value object for rate limit data
  • RateLimitRequestFactory - Creates requests for /rate_limit endpoint

API Method:

$rateLimit = $client->getRateLimit();
echo "Remaining: {$rateLimit->remaining}/{$rateLimit->limit}\n";
echo "Resets in: {$rateLimit->getSecondsUntilReset()} seconds\n";

Features:

  • Track limit, remaining, used, and reset timestamp
  • Helper methods: isExhausted(), getUsagePercentage(), getSecondsUntilReset(), getResetDateTime()

2. Token Permissions/Scopes Support

New Classes:

  • TokenScopes - Value object for OAuth scope list
  • AuthenticatedUserRequestFactory - Creates requests for /user endpoint

API Method:

$scopes = $client->getTokenScopes();
if ($scopes->canWriteRepositories()) {
    echo "Token has write access\n";
}
echo "Granted scopes: " . $scopes->toString() . "\n";

Features:

  • Parse X-OAuth-Scopes header from API response
  • Helper methods: has(), hasAny(), hasAll(), canReadRepositories(), canWriteRepositories(), canReadOrganizations()

3. Demo Script

Added bin/demo-token-info.php to demonstrate both features with formatted output.

Testing

Comprehensive PHPUnit test coverage

  • RateLimit: 10 tests, 22 assertions
  • TokenScopes: 19 tests, 27 assertions
  • Total: 29 new tests, 49 new assertions
  • All tests passing with 0 failures, 0 errors

PHPUnit 12 Compatible

  • Upgraded all deprecated annotations to attribute syntax
  • Zero deprecation warnings
  • Added missing PSR HTTP interface dependencies

Code Quality

  • ✅ All PHP syntax validated
  • ✅ Follows existing library patterns and conventions
  • ✅ Full type hints and doc blocks
  • ✅ PSR-compliant code style
  • ✅ Proper error handling with exceptions

Commits

  1. feat: Add rate limit and token permissions checking support
  2. fix: Add missing PSR HTTP interfaces and upgrade PHPUnit annotations
  3. fix: Convert remaining @Covers annotations to PHPUnit 12 attributes

Files Changed

  • 8 new files added (746 lines)
  • 2 test files upgraded (PHPUnit 12 compatibility)
  • 1 composer.json updated (PSR dependencies)

Usage Example

See bin/demo-token-info.php for a complete example.

This commit adds two new features to the GitHub API client:

RATE LIMIT SUPPORT:
- RateLimit value object to hold rate limit data
- RateLimitRequestFactory for creating /rate_limit endpoint requests
- GithubApiClient::getRateLimit() method
- Tracks limit, remaining, used, and reset timestamp
- Helper methods: isExhausted(), getUsagePercentage(), getSecondsUntilReset()
- Comprehensive PHPUnit tests (10 tests, 22 assertions)

TOKEN PERMISSIONS/SCOPES SUPPORT:
- TokenScopes value object to hold OAuth scope list
- AuthenticatedUserRequestFactory for creating /user endpoint requests
- GithubApiClient::getTokenScopes() method
- Parses X-OAuth-Scopes header from API response
- Helper methods: has(), hasAny(), hasAll(), canReadRepositories(), etc.
- Comprehensive PHPUnit tests (19 tests, 27 assertions)

DEMO SCRIPT:
- bin/demo-token-info.php demonstrates both features
- Displays formatted rate limit and scope information

All tests passing (29 tests, 49 assertions)
Follows existing library patterns and conventions
FIXES:
- Install psr/http-client, psr/http-message, psr/http-factory as dev dependencies
  to fix missing ClientInterface error in tests
- Upgrade deprecated @coversNothing annotation to PHPUnit 12 attribute syntax
  #[\PHPUnit\Framework\Attributes\CoversNothing]

RESULT:
- All tests now pass (30 tests, 50 assertions)
- No more deprecated annotation warnings
- Compatible with PHPUnit 12
Replace deprecated @Covers doc-comment annotations with
#[\PHPUnit\Framework\Attributes\CoversClass] attributes in:
- RateLimitTest.php
- TokenScopesTest.php

Result: All PHPUnit deprecation warnings eliminated
Tests: 30, Assertions: 50, No deprecations
FIXES:
- Upgrade deprecated @PHP82Migration to @PHP83Migration in .php-cs-fixer.dist.php
- Run php-cs-fixer fix on all source files
- Fix braces_position, single_line_empty_body, no_whitespace_in_blank_line issues
- Fix operator_linebreak and no_trailing_whitespace issues
- Add PHP ^8.3 requirement to composer.json (addresses CS Fixer warning)

AFFECTED FILES:
- .php-cs-fixer.dist.php (rule set updated)
- composer.json (PHP version requirement added)
- src/RateLimit.php (whitespace fixes)
- src/RateLimitRequestFactory.php (whitespace fixes)
- src/AuthenticatedUserRequestFactory.php (whitespace fixes)
- src/GithubRepository.php (operator linebreak fixes)
- src/GithubRepositoryList.php (operator linebreak fixes)
- tests/unit/RateLimitTest.php (whitespace fixes)
- tests/unit/TokenScopesTest.php (whitespace fixes)

RESULT:
- 0 CS violations remaining
- All tests still passing (30 tests, 50 assertions)
- No deprecation warnings from php-cs-fixer
Change constructor parameter type from array<string> to array<mixed>
since the implementation explicitly filters non-string values.

This fixes PHPStan error:
"Parameter #1 \ of class Horde\GithubApiClient\TokenScopes
constructor expects array<string>, array<int, int|string|null> given."

The constructor behavior remains unchanged - it filters out non-strings
using array_filter with is_string callback.

PHPStan now passes with 0 errors.
@ralflang ralflang merged commit 076fb19 into FRAMEWORK_6_0 Feb 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant