feat: integrate Monolog for enhanced logging across providers and controller
This commit is contained in:
@@ -84,6 +84,7 @@ Run vendor/bin/phpunit after each change to confirm tests stay green.
|
|||||||
| Combining Red + Green in one request | No failing baseline | Always separate the two phases |
|
| Combining Red + Green in one request | No failing baseline | Always separate the two phases |
|
||||||
|
|
||||||
### Running tests
|
### Running tests
|
||||||
|
Prever to use the tests in `docker compose exec graph`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run full suite
|
# Run full suite
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"symfony/console": "7.4.*",
|
"symfony/console": "7.4.*",
|
||||||
"symfony/framework-bundle": "7.4.*",
|
"symfony/framework-bundle": "7.4.*",
|
||||||
"symfony/http-client": "7.4.*",
|
"symfony/http-client": "7.4.*",
|
||||||
|
"symfony/monolog-bundle": "^4.0",
|
||||||
"symfony/runtime": "7.4.*",
|
"symfony/runtime": "7.4.*",
|
||||||
"symfony/yaml": "7.4.*"
|
"symfony/yaml": "7.4.*"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
|
||||||
|
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||||
EightPoints\Bundle\GuzzleBundle\EightPointsGuzzleBundle::class => ['all' => true],
|
EightPoints\Bundle\GuzzleBundle\EightPointsGuzzleBundle::class => ['all' => true],
|
||||||
IDCI\Bundle\GraphQLClientBundle\IDCIGraphQLClientBundle::class => ['all' => true],
|
IDCI\Bundle\GraphQLClientBundle\IDCIGraphQLClientBundle::class => ['all' => true],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
monolog:
|
||||||
|
channels:
|
||||||
|
- deprecation
|
||||||
|
|
||||||
|
when@dev:
|
||||||
|
monolog:
|
||||||
|
handlers:
|
||||||
|
main:
|
||||||
|
type: stream
|
||||||
|
path: '%kernel.logs_dir%/%kernel.environment%.log'
|
||||||
|
level: debug
|
||||||
|
channels: ['!event']
|
||||||
|
|
||||||
|
when@prod:
|
||||||
|
monolog:
|
||||||
|
handlers:
|
||||||
|
main:
|
||||||
|
type: stream
|
||||||
|
path: php://stderr
|
||||||
|
level: warning
|
||||||
|
channels: ['!event']
|
||||||
|
deprecation:
|
||||||
|
type: stream
|
||||||
|
channels: [deprecation]
|
||||||
|
path: '%kernel.logs_dir%/%kernel.environment%.deprecations.log'
|
||||||
|
level: info
|
||||||
@@ -690,6 +690,149 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* enabled?: bool|Param, // Default: false
|
* enabled?: bool|Param, // Default: false
|
||||||
* },
|
* },
|
||||||
* }
|
* }
|
||||||
|
* @psalm-type MonologConfig = array{
|
||||||
|
* use_microseconds?: scalar|Param|null, // Default: true
|
||||||
|
* channels?: list<scalar|Param|null>,
|
||||||
|
* handlers?: array<string, array{ // Default: []
|
||||||
|
* type?: scalar|Param|null,
|
||||||
|
* id?: scalar|Param|null,
|
||||||
|
* enabled?: bool|Param, // Default: true
|
||||||
|
* priority?: scalar|Param|null, // Default: 0
|
||||||
|
* level?: scalar|Param|null, // Default: "DEBUG"
|
||||||
|
* bubble?: bool|Param, // Default: true
|
||||||
|
* interactive_only?: bool|Param, // Default: false
|
||||||
|
* app_name?: scalar|Param|null, // Default: null
|
||||||
|
* include_stacktraces?: bool|Param, // Default: false
|
||||||
|
* process_psr_3_messages?: array{
|
||||||
|
* enabled?: bool|Param|null, // Default: null
|
||||||
|
* date_format?: scalar|Param|null,
|
||||||
|
* remove_used_context_fields?: bool|Param,
|
||||||
|
* },
|
||||||
|
* path?: scalar|Param|null, // Default: "%kernel.logs_dir%/%kernel.environment%.log"
|
||||||
|
* file_permission?: scalar|Param|null, // Default: null
|
||||||
|
* use_locking?: bool|Param, // Default: false
|
||||||
|
* filename_format?: scalar|Param|null, // Default: "{filename}-{date}"
|
||||||
|
* date_format?: scalar|Param|null, // Default: "Y-m-d"
|
||||||
|
* ident?: scalar|Param|null, // Default: false
|
||||||
|
* logopts?: scalar|Param|null, // Default: 1
|
||||||
|
* facility?: scalar|Param|null, // Default: "user"
|
||||||
|
* max_files?: scalar|Param|null, // Default: 0
|
||||||
|
* action_level?: scalar|Param|null, // Default: "WARNING"
|
||||||
|
* activation_strategy?: scalar|Param|null, // Default: null
|
||||||
|
* stop_buffering?: bool|Param, // Default: true
|
||||||
|
* passthru_level?: scalar|Param|null, // Default: null
|
||||||
|
* excluded_http_codes?: list<array{ // Default: []
|
||||||
|
* code?: scalar|Param|null,
|
||||||
|
* urls?: list<scalar|Param|null>,
|
||||||
|
* }>,
|
||||||
|
* accepted_levels?: list<scalar|Param|null>,
|
||||||
|
* min_level?: scalar|Param|null, // Default: "DEBUG"
|
||||||
|
* max_level?: scalar|Param|null, // Default: "EMERGENCY"
|
||||||
|
* buffer_size?: scalar|Param|null, // Default: 0
|
||||||
|
* flush_on_overflow?: bool|Param, // Default: false
|
||||||
|
* handler?: scalar|Param|null,
|
||||||
|
* url?: scalar|Param|null,
|
||||||
|
* exchange?: scalar|Param|null,
|
||||||
|
* exchange_name?: scalar|Param|null, // Default: "log"
|
||||||
|
* channel?: scalar|Param|null, // Default: null
|
||||||
|
* bot_name?: scalar|Param|null, // Default: "Monolog"
|
||||||
|
* use_attachment?: scalar|Param|null, // Default: true
|
||||||
|
* use_short_attachment?: scalar|Param|null, // Default: false
|
||||||
|
* include_extra?: scalar|Param|null, // Default: false
|
||||||
|
* icon_emoji?: scalar|Param|null, // Default: null
|
||||||
|
* webhook_url?: scalar|Param|null,
|
||||||
|
* exclude_fields?: list<scalar|Param|null>,
|
||||||
|
* token?: scalar|Param|null,
|
||||||
|
* region?: scalar|Param|null,
|
||||||
|
* source?: scalar|Param|null,
|
||||||
|
* use_ssl?: bool|Param, // Default: true
|
||||||
|
* user?: mixed,
|
||||||
|
* title?: scalar|Param|null, // Default: null
|
||||||
|
* host?: scalar|Param|null, // Default: null
|
||||||
|
* port?: scalar|Param|null, // Default: 514
|
||||||
|
* config?: list<scalar|Param|null>,
|
||||||
|
* members?: list<scalar|Param|null>,
|
||||||
|
* connection_string?: scalar|Param|null,
|
||||||
|
* timeout?: scalar|Param|null,
|
||||||
|
* time?: scalar|Param|null, // Default: 60
|
||||||
|
* deduplication_level?: scalar|Param|null, // Default: 400
|
||||||
|
* store?: scalar|Param|null, // Default: null
|
||||||
|
* connection_timeout?: scalar|Param|null,
|
||||||
|
* persistent?: bool|Param,
|
||||||
|
* message_type?: scalar|Param|null, // Default: 0
|
||||||
|
* parse_mode?: scalar|Param|null, // Default: null
|
||||||
|
* disable_webpage_preview?: bool|Param|null, // Default: null
|
||||||
|
* disable_notification?: bool|Param|null, // Default: null
|
||||||
|
* split_long_messages?: bool|Param, // Default: false
|
||||||
|
* delay_between_messages?: bool|Param, // Default: false
|
||||||
|
* topic?: int|Param, // Default: null
|
||||||
|
* factor?: int|Param, // Default: 1
|
||||||
|
* tags?: string|list<scalar|Param|null>,
|
||||||
|
* console_formatter_options?: mixed, // Default: []
|
||||||
|
* formatter?: scalar|Param|null,
|
||||||
|
* nested?: bool|Param, // Default: false
|
||||||
|
* publisher?: string|array{
|
||||||
|
* id?: scalar|Param|null,
|
||||||
|
* hostname?: scalar|Param|null,
|
||||||
|
* port?: scalar|Param|null, // Default: 12201
|
||||||
|
* chunk_size?: scalar|Param|null, // Default: 1420
|
||||||
|
* encoder?: "json"|"compressed_json"|Param,
|
||||||
|
* },
|
||||||
|
* mongodb?: string|array{
|
||||||
|
* id?: scalar|Param|null, // ID of a MongoDB\Client service
|
||||||
|
* uri?: scalar|Param|null,
|
||||||
|
* username?: scalar|Param|null,
|
||||||
|
* password?: scalar|Param|null,
|
||||||
|
* database?: scalar|Param|null, // Default: "monolog"
|
||||||
|
* collection?: scalar|Param|null, // Default: "logs"
|
||||||
|
* },
|
||||||
|
* elasticsearch?: string|array{
|
||||||
|
* id?: scalar|Param|null,
|
||||||
|
* hosts?: list<scalar|Param|null>,
|
||||||
|
* host?: scalar|Param|null,
|
||||||
|
* port?: scalar|Param|null, // Default: 9200
|
||||||
|
* transport?: scalar|Param|null, // Default: "Http"
|
||||||
|
* user?: scalar|Param|null, // Default: null
|
||||||
|
* password?: scalar|Param|null, // Default: null
|
||||||
|
* },
|
||||||
|
* index?: scalar|Param|null, // Default: "monolog"
|
||||||
|
* document_type?: scalar|Param|null, // Default: "logs"
|
||||||
|
* ignore_error?: scalar|Param|null, // Default: false
|
||||||
|
* redis?: string|array{
|
||||||
|
* id?: scalar|Param|null,
|
||||||
|
* host?: scalar|Param|null,
|
||||||
|
* password?: scalar|Param|null, // Default: null
|
||||||
|
* port?: scalar|Param|null, // Default: 6379
|
||||||
|
* database?: scalar|Param|null, // Default: 0
|
||||||
|
* key_name?: scalar|Param|null, // Default: "monolog_redis"
|
||||||
|
* },
|
||||||
|
* predis?: string|array{
|
||||||
|
* id?: scalar|Param|null,
|
||||||
|
* host?: scalar|Param|null,
|
||||||
|
* },
|
||||||
|
* from_email?: scalar|Param|null,
|
||||||
|
* to_email?: string|list<scalar|Param|null>,
|
||||||
|
* subject?: scalar|Param|null,
|
||||||
|
* content_type?: scalar|Param|null, // Default: null
|
||||||
|
* headers?: list<scalar|Param|null>,
|
||||||
|
* mailer?: scalar|Param|null, // Default: null
|
||||||
|
* email_prototype?: string|array{
|
||||||
|
* id?: scalar|Param|null,
|
||||||
|
* method?: scalar|Param|null, // Default: null
|
||||||
|
* },
|
||||||
|
* verbosity_levels?: array{
|
||||||
|
* VERBOSITY_QUIET?: scalar|Param|null, // Default: "ERROR"
|
||||||
|
* VERBOSITY_NORMAL?: scalar|Param|null, // Default: "WARNING"
|
||||||
|
* VERBOSITY_VERBOSE?: scalar|Param|null, // Default: "NOTICE"
|
||||||
|
* VERBOSITY_VERY_VERBOSE?: scalar|Param|null, // Default: "INFO"
|
||||||
|
* VERBOSITY_DEBUG?: scalar|Param|null, // Default: "DEBUG"
|
||||||
|
* },
|
||||||
|
* channels?: string|array{
|
||||||
|
* type?: scalar|Param|null,
|
||||||
|
* elements?: list<scalar|Param|null>,
|
||||||
|
* },
|
||||||
|
* }>,
|
||||||
|
* }
|
||||||
* @psalm-type EightPointsGuzzleConfig = array{
|
* @psalm-type EightPointsGuzzleConfig = array{
|
||||||
* clients?: array<string, array{ // Default: []
|
* clients?: array<string, array{ // Default: []
|
||||||
* class?: scalar|Param|null, // Default: "%eight_points_guzzle.http_client.class%"
|
* class?: scalar|Param|null, // Default: "%eight_points_guzzle.http_client.class%"
|
||||||
@@ -745,6 +888,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* parameters?: ParametersConfig,
|
* parameters?: ParametersConfig,
|
||||||
* services?: ServicesConfig,
|
* services?: ServicesConfig,
|
||||||
* framework?: FrameworkConfig,
|
* framework?: FrameworkConfig,
|
||||||
|
* monolog?: MonologConfig,
|
||||||
* eight_points_guzzle?: EightPointsGuzzleConfig,
|
* eight_points_guzzle?: EightPointsGuzzleConfig,
|
||||||
* idci_graphql_client?: IdciGraphqlClientConfig,
|
* idci_graphql_client?: IdciGraphqlClientConfig,
|
||||||
* "when@dev"?: array{
|
* "when@dev"?: array{
|
||||||
@@ -752,6 +896,16 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
|||||||
* parameters?: ParametersConfig,
|
* parameters?: ParametersConfig,
|
||||||
* services?: ServicesConfig,
|
* services?: ServicesConfig,
|
||||||
* framework?: FrameworkConfig,
|
* framework?: FrameworkConfig,
|
||||||
|
* monolog?: MonologConfig,
|
||||||
|
* eight_points_guzzle?: EightPointsGuzzleConfig,
|
||||||
|
* idci_graphql_client?: IdciGraphqlClientConfig,
|
||||||
|
* },
|
||||||
|
* "when@prod"?: array{
|
||||||
|
* imports?: ImportsConfig,
|
||||||
|
* parameters?: ParametersConfig,
|
||||||
|
* services?: ServicesConfig,
|
||||||
|
* framework?: FrameworkConfig,
|
||||||
|
* monolog?: MonologConfig,
|
||||||
* eight_points_guzzle?: EightPointsGuzzleConfig,
|
* eight_points_guzzle?: EightPointsGuzzleConfig,
|
||||||
* idci_graphql_client?: IdciGraphqlClientConfig,
|
* idci_graphql_client?: IdciGraphqlClientConfig,
|
||||||
* },
|
* },
|
||||||
@@ -838,6 +992,7 @@ namespace Symfony\Component\Routing\Loader\Configurator;
|
|||||||
* }
|
* }
|
||||||
* @psalm-type RoutesConfig = array{
|
* @psalm-type RoutesConfig = array{
|
||||||
* "when@dev"?: array<string, RouteConfig|ImportConfig|AliasConfig>,
|
* "when@dev"?: array<string, RouteConfig|ImportConfig|AliasConfig>,
|
||||||
|
* "when@prod"?: array<string, RouteConfig|ImportConfig|AliasConfig>,
|
||||||
* ...<string, RouteConfig|ImportConfig|AliasConfig>
|
* ...<string, RouteConfig|ImportConfig|AliasConfig>
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
@@ -39,18 +39,24 @@ class GraphController
|
|||||||
public function graph(Request $request): Response
|
public function graph(Request $request): Response
|
||||||
{
|
{
|
||||||
if ($this->allowedHosts !== [] && !in_array($request->getHost(), $this->allowedHosts, true)) {
|
if ($this->allowedHosts !== [] && !in_array($request->getHost(), $this->allowedHosts, true)) {
|
||||||
|
$this->logger->warning('GraphController: rejected request from disallowed host', ['host' => $request->getHost()]);
|
||||||
|
|
||||||
return new Response('Forbidden', 403);
|
return new Response('Forbidden', 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
$theme = $request->query->get('theme', 'dark');
|
$theme = $request->query->get('theme', 'dark');
|
||||||
$cacheKey = 'graph_' . $theme;
|
$cacheKey = 'graph_' . $theme;
|
||||||
|
|
||||||
$svg = $this->cache->get($cacheKey, function (ItemInterface $item) use ($theme): string {
|
$cacheMiss = false;
|
||||||
|
$svg = $this->cache->get($cacheKey, function (ItemInterface $item) use ($theme, &$cacheMiss): string {
|
||||||
|
$cacheMiss = true;
|
||||||
$item->expiresAfter(3600);
|
$item->expiresAfter(3600);
|
||||||
|
|
||||||
return $this->renderer->render($this->fetchAllContributions(), $theme);
|
return $this->renderer->render($this->fetchAllContributions(), $theme);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this->logger->debug('GraphController: cache ' . ($cacheMiss ? 'miss' : 'hit'), ['theme' => $theme]);
|
||||||
|
|
||||||
return new Response($svg, 200, [
|
return new Response($svg, 200, [
|
||||||
'Content-Type' => 'image/svg+xml',
|
'Content-Type' => 'image/svg+xml',
|
||||||
'Cache-Control' => 'public, max-age=3600',
|
'Cache-Control' => 'public, max-age=3600',
|
||||||
@@ -86,7 +92,7 @@ class GraphController
|
|||||||
try {
|
try {
|
||||||
$contributions = $this->merge($contributions, $provider->fetch());
|
$contributions = $this->merge($contributions, $provider->fetch());
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->logger->warning(sprintf('%s fetch failed: %s', $provider::class, $e->getMessage()));
|
$this->logger->warning(sprintf('%s fetch failed: %s', $provider::class, $e->getMessage()), ['exception' => $e]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace App\Service;
|
|||||||
|
|
||||||
use IDCI\Bundle\GraphQLClientBundle\Client\GraphQLApiClient;
|
use IDCI\Bundle\GraphQLClientBundle\Client\GraphQLApiClient;
|
||||||
use IDCI\Bundle\GraphQLClientBundle\Client\GraphQLApiClientRegistryInterface;
|
use IDCI\Bundle\GraphQLClientBundle\Client\GraphQLApiClientRegistryInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,6 +21,7 @@ class GitHubProvider implements ProviderInterface
|
|||||||
private readonly GraphQLApiClientRegistryInterface $registry,
|
private readonly GraphQLApiClientRegistryInterface $registry,
|
||||||
private readonly string $username,
|
private readonly string $username,
|
||||||
private readonly string $token,
|
private readonly string $token,
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function isConfigured(): bool
|
public function isConfigured(): bool
|
||||||
@@ -32,6 +34,8 @@ class GitHubProvider implements ProviderInterface
|
|||||||
*/
|
*/
|
||||||
public function fetch(): array
|
public function fetch(): array
|
||||||
{
|
{
|
||||||
|
$this->logger->debug('GitHubProvider: fetching contributions', ['user' => $this->username]);
|
||||||
|
|
||||||
$from = (new \DateTimeImmutable('-365 days'))->format('Y-m-d\T00:00:00\Z');
|
$from = (new \DateTimeImmutable('-365 days'))->format('Y-m-d\T00:00:00\Z');
|
||||||
$to = (new \DateTimeImmutable())->format('Y-m-d\T23:59:59\Z');
|
$to = (new \DateTimeImmutable())->format('Y-m-d\T23:59:59\Z');
|
||||||
|
|
||||||
@@ -79,6 +83,12 @@ class GitHubProvider implements ProviderInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger->info('GitHubProvider: fetched contributions', [
|
||||||
|
'user' => $this->username,
|
||||||
|
'days' => count($result),
|
||||||
|
'total' => array_sum($result),
|
||||||
|
]);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,6 +17,7 @@ class GitLabProvider implements ProviderInterface
|
|||||||
private readonly HttpClientInterface $client,
|
private readonly HttpClientInterface $client,
|
||||||
private readonly string $username,
|
private readonly string $username,
|
||||||
private readonly string $token,
|
private readonly string $token,
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
private readonly string $baseUrl = '',
|
private readonly string $baseUrl = '',
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -31,6 +33,8 @@ class GitLabProvider implements ProviderInterface
|
|||||||
{
|
{
|
||||||
$baseUrl = rtrim($this->baseUrl !== '' ? $this->baseUrl : 'https://gitlab.com', '/');
|
$baseUrl = rtrim($this->baseUrl !== '' ? $this->baseUrl : 'https://gitlab.com', '/');
|
||||||
|
|
||||||
|
$this->logger->debug('GitLabProvider: fetching contributions', ['user' => $this->username, 'url' => $baseUrl]);
|
||||||
|
|
||||||
// Resolve numeric user ID from username
|
// Resolve numeric user ID from username
|
||||||
$userResponse = $this->client->request('GET', "$baseUrl/api/v4/users", [
|
$userResponse = $this->client->request('GET', "$baseUrl/api/v4/users", [
|
||||||
'headers' => ['PRIVATE-TOKEN' => $this->token],
|
'headers' => ['PRIVATE-TOKEN' => $this->token],
|
||||||
@@ -67,6 +71,13 @@ class GitLabProvider implements ProviderInterface
|
|||||||
$page++;
|
$page++;
|
||||||
} while (count($events) === 100);
|
} while (count($events) === 100);
|
||||||
|
|
||||||
|
$this->logger->info('GitLabProvider: fetched contributions', [
|
||||||
|
'user' => $this->username,
|
||||||
|
'pages' => $page - 1,
|
||||||
|
'days' => count($result),
|
||||||
|
'total' => array_sum($result),
|
||||||
|
]);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,6 +20,7 @@ class GiteaProvider implements ProviderInterface
|
|||||||
private readonly string $username,
|
private readonly string $username,
|
||||||
private readonly string $token,
|
private readonly string $token,
|
||||||
private readonly string $baseUrl,
|
private readonly string $baseUrl,
|
||||||
|
private readonly LoggerInterface $logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function isConfigured(): bool
|
public function isConfigured(): bool
|
||||||
@@ -32,6 +34,9 @@ class GiteaProvider implements ProviderInterface
|
|||||||
public function fetch(): array
|
public function fetch(): array
|
||||||
{
|
{
|
||||||
$baseUrl = rtrim($this->baseUrl, '/');
|
$baseUrl = rtrim($this->baseUrl, '/');
|
||||||
|
|
||||||
|
$this->logger->debug('GiteaProvider: fetching contributions', ['user' => $this->username, 'url' => $baseUrl]);
|
||||||
|
|
||||||
$response = $this->client->request('GET', "$baseUrl/api/v1/users/{$this->username}/heatmap", [
|
$response = $this->client->request('GET', "$baseUrl/api/v1/users/{$this->username}/heatmap", [
|
||||||
'headers' => ['Authorization' => "token {$this->token}"],
|
'headers' => ['Authorization' => "token {$this->token}"],
|
||||||
]);
|
]);
|
||||||
@@ -48,6 +53,12 @@ class GiteaProvider implements ProviderInterface
|
|||||||
$result[$date] = ($result[$date] ?? 0) + (int) $entry['contributions'];
|
$result[$date] = ($result[$date] ?? 0) + (int) $entry['contributions'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->logger->info('GiteaProvider: fetched contributions', [
|
||||||
|
'user' => $this->username,
|
||||||
|
'days' => count($result),
|
||||||
|
'total' => array_sum($result),
|
||||||
|
]);
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user