host = rtrim($config['host'] ?? '', '/'); $this->username = $config['username'] ?? null; $this->apiToken = $config['api_token'] ?? null; $this->timeout = $config['timeout'] ?? 30; } public function isConfigured(): bool { return ! empty($this->host) && ! empty($this->username) && ! empty($this->apiToken); } public function getJobInfo(string $jobName): ?array { return $this->request($this->getJobPath($jobName).'/api/json'); } public function getBuildInfo(string $jobName, int $buildNumber): ?array { return $this->request($this->getJobPath($jobName)."/{$buildNumber}/api/json"); } public function getLastBuild(string $jobName): ?array { return $this->request($this->getJobPath($jobName).'/lastBuild/api/json'); } public function getParameterDefinitions(string $jobName): array { $jobInfo = $this->getJobInfo($jobName); if (! $jobInfo || empty($jobInfo['property'])) { return []; } $buildFormParameters = $this->getBuildFormParameters($jobName); foreach ($jobInfo['property'] as $property) { if (empty($property['parameterDefinitions']) || ! is_array($property['parameterDefinitions'])) { continue; } return array_map(function (array $definition) use ($buildFormParameters) { $name = $definition['name'] ?? ''; $formParameter = $buildFormParameters[$name] ?? []; $default = $definition['defaultParameterValue']['value'] ?? null; if (($formParameter['multiple'] ?? false) && isset($formParameter['default'])) { $default = $formParameter['default']; } return [ 'name' => $name, 'type' => $definition['type'] ?? $definition['_class'] ?? 'StringParameterDefinition', 'description' => $definition['description'] ?? '', 'default' => $default, 'choices' => $definition['choices'] ?? $formParameter['choices'] ?? [], 'multiple' => (bool) ($formParameter['multiple'] ?? false), ]; }, array_values(array_filter($property['parameterDefinitions'], fn ($definition) => ! empty($definition['name'])))); } return []; } public function triggerBuild(string $jobName, array $parameters = []): array { if (! $this->isConfigured()) { Log::warning('Jenkins client is not configured'); return [ 'success' => false, 'message' => 'Jenkins not configured', ]; } $path = $this->getJobPath($jobName).(empty($parameters) ? '/build' : '/buildWithParameters'); $url = $this->host.$path; try { $request = $this->http(); $crumb = $this->getCrumb(); if ($crumb) { $request = $request->withHeaders([$crumb['field'] => $crumb['crumb']]); } $response = empty($parameters) ? $request->post($url) : $request->asForm()->post($url, $parameters); if ($response->successful() || $response->status() === 201) { return [ 'success' => true, 'queue_url' => $response->header('Location'), 'status' => $response->status(), ]; } Log::warning('Jenkins build trigger failed', [ 'url' => $url, 'status' => $response->status(), 'body' => $response->body(), ]); return [ 'success' => false, 'message' => 'Jenkins 返回状态码 '.$response->status(), 'status' => $response->status(), ]; } catch (\Throwable $e) { Log::error('Jenkins build trigger error', [ 'url' => $url, 'error' => $e->getMessage(), ]); return [ 'success' => false, 'message' => $e->getMessage(), ]; } } public function getBuilds(string $jobName, int $limit = 10): array { $jobInfo = $this->getJobInfo($jobName); if (! $jobInfo || empty($jobInfo['builds'])) { return []; } $builds = array_slice($jobInfo['builds'], 0, $limit); $result = []; foreach ($builds as $build) { $buildInfo = $this->getBuildInfo($jobName, $build['number']); if ($buildInfo) { $result[] = $buildInfo; } } return $result; } private function request(string $path): ?array { if (! $this->isConfigured()) { Log::warning('Jenkins client is not configured'); return null; } $url = $this->host.$path; try { $response = $this->http()->get($url); if ($response->successful()) { return $response->json(); } Log::warning('Jenkins API request failed', [ 'url' => $url, 'status' => $response->status(), ]); return null; } catch (\Throwable $e) { Log::error('Jenkins API request error', [ 'url' => $url, 'error' => $e->getMessage(), ]); return null; } } private function requestBody(string $path, bool $allowMethodNotAllowed = false): ?string { if (! $this->isConfigured()) { Log::warning('Jenkins client is not configured'); return null; } $url = $this->host.$path; try { $response = $this->http()->get($url); if ($response->successful() || ($allowMethodNotAllowed && $response->status() === 405)) { return $response->body(); } Log::warning('Jenkins page request failed', [ 'url' => $url, 'status' => $response->status(), ]); return null; } catch (\Throwable $e) { Log::error('Jenkins page request error', [ 'url' => $url, 'error' => $e->getMessage(), ]); return null; } } private function getBuildFormParameters(string $jobName): array { $html = $this->requestBody($this->getJobPath($jobName).'/build?delay=0sec', allowMethodNotAllowed: true); if (! $html) { return []; } $parameters = []; foreach (array_slice(preg_split('/