initial COmmit: Add KB Antora Importer plugin files
This commit is contained in:
13
kb-antora-importer/includes/GitLab/GitLabBranch.php
Normal file
13
kb-antora-importer/includes/GitLab/GitLabBranch.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KbAntoraImporter\GitLab;
|
||||
|
||||
final class GitLabBranch
|
||||
{
|
||||
public function __construct(
|
||||
public readonly string $name,
|
||||
public readonly string $commitSha = ''
|
||||
) {
|
||||
}
|
||||
}
|
||||
194
kb-antora-importer/includes/GitLab/GitLabClient.php
Normal file
194
kb-antora-importer/includes/GitLab/GitLabClient.php
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KbAntoraImporter\GitLab;
|
||||
|
||||
final class GitLabClient
|
||||
{
|
||||
private string $baseUrl;
|
||||
private string $token;
|
||||
private string $branchPattern;
|
||||
|
||||
public function __construct(array $settings)
|
||||
{
|
||||
$this->baseUrl = self::normalizeBaseUrl((string) ($settings['gitlab_base_url'] ?? ''));
|
||||
$this->token = (string) ($settings['gitlab_token'] ?? '');
|
||||
$this->branchPattern = (string) ($settings['branch_pattern'] ?? '^v.*');
|
||||
}
|
||||
|
||||
public static function normalizeBaseUrl(string $baseUrl): string
|
||||
{
|
||||
$baseUrl = rtrim(trim($baseUrl), '/');
|
||||
|
||||
if (preg_match('#/api/v4$#i', $baseUrl)) {
|
||||
$baseUrl = (string) preg_replace('#/api/v4$#i', '', $baseUrl);
|
||||
}
|
||||
|
||||
return $baseUrl;
|
||||
}
|
||||
|
||||
public function getGroup(string $group): array|\WP_Error
|
||||
{
|
||||
return $this->request('GET', '/groups/' . rawurlencode($group));
|
||||
}
|
||||
|
||||
public function getProjects(string $group): array|\WP_Error
|
||||
{
|
||||
return $this->requestAll('/groups/' . rawurlencode($group) . '/projects', [
|
||||
'include_subgroups' => 'true',
|
||||
'simple' => 'true',
|
||||
'order_by' => 'path',
|
||||
'sort' => 'asc',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getProject(string $projectId): array|\WP_Error
|
||||
{
|
||||
return $this->request('GET', '/projects/' . rawurlencode($projectId));
|
||||
}
|
||||
|
||||
public function getBranches(string $projectId): array|\WP_Error
|
||||
{
|
||||
return $this->requestAll('/projects/' . rawurlencode($projectId) . '/repository/branches', []);
|
||||
}
|
||||
|
||||
public function getDocumentationBranches(string $projectId): array|\WP_Error
|
||||
{
|
||||
$branches = $this->getBranches($projectId);
|
||||
|
||||
if (is_wp_error($branches)) {
|
||||
return $branches;
|
||||
}
|
||||
|
||||
$pattern = '/' . str_replace('/', '\/', $this->branchPattern) . '/';
|
||||
|
||||
return array_values(array_filter($branches, static function (array $branch) use ($pattern): bool {
|
||||
return isset($branch['name']) && @preg_match($pattern, (string) $branch['name']);
|
||||
}));
|
||||
}
|
||||
|
||||
public function getFileRaw(string $projectId, string $path, string $ref): string|\WP_Error
|
||||
{
|
||||
$response = $this->rawRequest('/projects/' . rawurlencode($projectId) . '/repository/files/' . rawurlencode($path) . '/raw', [
|
||||
'ref' => $ref,
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
return wp_remote_retrieve_body($response);
|
||||
}
|
||||
|
||||
public function getTree(string $projectId, string $ref, string $path = '', bool $recursive = true): array|\WP_Error
|
||||
{
|
||||
return $this->requestAll('/projects/' . rawurlencode($projectId) . '/repository/tree', [
|
||||
'ref' => $ref,
|
||||
'path' => $path,
|
||||
'recursive' => $recursive ? 'true' : 'false',
|
||||
]);
|
||||
}
|
||||
|
||||
private function requestAll(string $endpoint, array $query): array|\WP_Error
|
||||
{
|
||||
$page = 1;
|
||||
$items = [];
|
||||
|
||||
do {
|
||||
$response = $this->rawRequest($endpoint, array_merge($query, [
|
||||
'per_page' => '100',
|
||||
'page' => (string) $page,
|
||||
]));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$decoded = json_decode(wp_remote_retrieve_body($response), true);
|
||||
|
||||
if (! is_array($decoded)) {
|
||||
return new \WP_Error('kb_gitlab_invalid_json', __('GitLab returned invalid JSON.', 'kb-antora-importer'));
|
||||
}
|
||||
|
||||
$items = array_merge($items, $decoded);
|
||||
$next = wp_remote_retrieve_header($response, 'x-next-page');
|
||||
$page = $next ? (int) $next : 0;
|
||||
} while ($page > 0);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function request(string $method, string $endpoint, array $query = []): array|\WP_Error
|
||||
{
|
||||
$response = $this->rawRequest($endpoint, $query, $method);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$decoded = json_decode(wp_remote_retrieve_body($response), true);
|
||||
|
||||
if (! is_array($decoded)) {
|
||||
return new \WP_Error('kb_gitlab_invalid_json', __('GitLab returned invalid JSON.', 'kb-antora-importer'));
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
private function rawRequest(string $endpoint, array $query = [], string $method = 'GET'): array|\WP_Error
|
||||
{
|
||||
if (! $this->baseUrl || ! $this->token) {
|
||||
return new \WP_Error('kb_gitlab_missing_settings', __('GitLab base URL or token is missing.', 'kb-antora-importer'));
|
||||
}
|
||||
|
||||
$url = $this->baseUrl . '/api/v4' . $endpoint;
|
||||
|
||||
if ($query) {
|
||||
$url = add_query_arg($query, $url);
|
||||
}
|
||||
|
||||
$response = wp_remote_request($url, [
|
||||
'method' => $method,
|
||||
'timeout' => 30,
|
||||
'headers' => [
|
||||
'PRIVATE-TOKEN' => $this->token,
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$code = (int) wp_remote_retrieve_response_code($response);
|
||||
|
||||
if ($code >= 200 && $code < 300) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$body = wp_strip_all_tags(wp_remote_retrieve_body($response));
|
||||
$body = trim(preg_replace('/\s+/', ' ', $body) ?? $body);
|
||||
$body = substr($body, 0, 300);
|
||||
$retryAfter = wp_remote_retrieve_header($response, 'retry-after');
|
||||
$message = sprintf(
|
||||
/* translators: %d is an HTTP status code. */
|
||||
__('GitLab API request failed with HTTP %d.', 'kb-antora-importer'),
|
||||
$code
|
||||
);
|
||||
|
||||
if (503 === $code) {
|
||||
$message .= ' ' . __('The GitLab server or a proxy returned Service Unavailable. Check whether GitLab is reachable from the WordPress server and whether the Base URL points to the GitLab root, not to /api/v4.', 'kb-antora-importer');
|
||||
}
|
||||
|
||||
return new \WP_Error(
|
||||
'kb_gitlab_http_' . $code,
|
||||
$message,
|
||||
[
|
||||
'status' => $code,
|
||||
'url' => esc_url_raw($url),
|
||||
'retry_after' => $retryAfter ? (string) $retryAfter : '',
|
||||
'response_excerpt' => $body,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
14
kb-antora-importer/includes/GitLab/GitLabProject.php
Normal file
14
kb-antora-importer/includes/GitLab/GitLabProject.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KbAntoraImporter\GitLab;
|
||||
|
||||
final class GitLabProject
|
||||
{
|
||||
public function __construct(
|
||||
public readonly string $id,
|
||||
public readonly string $name,
|
||||
public readonly string $pathWithNamespace
|
||||
) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user