#feature: add config page
This commit is contained in:
106
app/Http/Controllers/Admin/ConfigController.php
Normal file
106
app/Http/Controllers/Admin/ConfigController.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Config;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class ConfigController extends Controller
|
||||
{
|
||||
public function index(): JsonResponse
|
||||
{
|
||||
$configs = Config::query()
|
||||
->orderBy('key')
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'configs' => $configs,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'key' => ['required', 'string', 'max:255', 'unique:configs,key'],
|
||||
'value' => ['nullable', 'string'],
|
||||
'description' => ['nullable', 'string', 'max:255'],
|
||||
]);
|
||||
|
||||
$config = Config::query()->create([
|
||||
'key' => $data['key'],
|
||||
'value' => $this->decodeValue($data['value'] ?? null),
|
||||
'description' => $data['description'] ?? null,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'config' => $config,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request, Config $config): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'key' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:255',
|
||||
Rule::unique('configs', 'key')->ignore($config->id),
|
||||
],
|
||||
'value' => ['nullable', 'string'],
|
||||
'description' => ['nullable', 'string', 'max:255'],
|
||||
]);
|
||||
|
||||
$config->update([
|
||||
'key' => $data['key'],
|
||||
'value' => $this->decodeValue($data['value'] ?? null),
|
||||
'description' => $data['description'] ?? null,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'config' => $config->refresh(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Config $config): JsonResponse
|
||||
{
|
||||
$config->delete();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
private function decodeValue(?string $raw): mixed
|
||||
{
|
||||
if ($raw === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$trimmed = trim($raw);
|
||||
if ($trimmed === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$decoded = json_decode($trimmed, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw ValidationException::withMessages([
|
||||
'value' => 'value 必须是合法 JSON',
|
||||
]);
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
@@ -163,79 +163,57 @@ class GitMonitorService
|
||||
private function inspectRepository(string $repoKey, array $repoConfig, string $branch): array
|
||||
{
|
||||
$path = $this->resolveProjectPath($repoKey, $repoConfig);
|
||||
$restoreBranch = null;
|
||||
|
||||
if (!is_dir($path) || !is_dir($path . DIRECTORY_SEPARATOR . '.git')) {
|
||||
throw new \RuntimeException("Project path {$path} is not a valid git repository");
|
||||
}
|
||||
|
||||
try {
|
||||
$restoreBranch = $this->synchronizeRepository($path, $branch);
|
||||
$head = $this->runGit($path, ['git', 'rev-parse', 'HEAD']);
|
||||
$this->synchronizeRepository($path, $branch);
|
||||
$remoteBranch = 'origin/' . $branch;
|
||||
$head = $this->runGit($path, ['git', 'rev-parse', $remoteBranch]);
|
||||
|
||||
$lastChecked = $this->configService->getNested(self::LAST_CHECKED_KEY, $repoKey);
|
||||
$commits = $this->collectCommits($path, $branch, $lastChecked);
|
||||
$lastChecked = $this->configService->getNested(self::LAST_CHECKED_KEY, $repoKey);
|
||||
$commits = $this->collectCommits($path, $remoteBranch, $lastChecked);
|
||||
|
||||
$issues = [
|
||||
'develop_merges' => [],
|
||||
'missing_functions' => [],
|
||||
];
|
||||
$issues = [
|
||||
'develop_merges' => [],
|
||||
'missing_functions' => [],
|
||||
];
|
||||
|
||||
foreach ($commits as $commit) {
|
||||
if ($this->isDevelopMerge($path, $commit)) {
|
||||
$issues['develop_merges'][] = $this->getCommitMetadata($path, $commit);
|
||||
}
|
||||
|
||||
$missingFunctions = $this->detectMissingFunctions($path, $commit);
|
||||
if (!empty($missingFunctions)) {
|
||||
$issues['missing_functions'][] = [
|
||||
'commit' => $this->getCommitMetadata($path, $commit),
|
||||
'details' => $missingFunctions,
|
||||
];
|
||||
}
|
||||
foreach ($commits as $commit) {
|
||||
if ($this->isDevelopMerge($path, $commit)) {
|
||||
$issues['develop_merges'][] = $this->getCommitMetadata($path, $commit);
|
||||
}
|
||||
|
||||
$this->updateLastChecked($repoKey, $head);
|
||||
|
||||
return [
|
||||
'repository' => $repoKey,
|
||||
'display' => $repoConfig['display'] ?? ucfirst($repoKey),
|
||||
'branch' => $branch,
|
||||
'path' => $path,
|
||||
'head' => $head,
|
||||
'commits_scanned' => count($commits),
|
||||
'issues' => $issues,
|
||||
];
|
||||
} finally {
|
||||
if ($restoreBranch) {
|
||||
try {
|
||||
$this->runGit($path, ['git', 'checkout', $restoreBranch]);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Failed to restore branch', [
|
||||
'repository' => $repoKey,
|
||||
'branch' => $restoreBranch,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
$missingFunctions = $this->detectMissingFunctions($path, $commit);
|
||||
if (!empty($missingFunctions)) {
|
||||
$issues['missing_functions'][] = [
|
||||
'commit' => $this->getCommitMetadata($path, $commit),
|
||||
'details' => $missingFunctions,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$this->updateLastChecked($repoKey, $head);
|
||||
|
||||
return [
|
||||
'repository' => $repoKey,
|
||||
'display' => $repoConfig['display'] ?? ucfirst($repoKey),
|
||||
'branch' => $branch,
|
||||
'path' => $path,
|
||||
'head' => $head,
|
||||
'commits_scanned' => count($commits),
|
||||
'issues' => $issues,
|
||||
];
|
||||
}
|
||||
|
||||
private function synchronizeRepository(string $path, string $branch): ?string
|
||||
private function synchronizeRepository(string $path, string $branch): void
|
||||
{
|
||||
$currentBranch = trim($this->runGit($path, ['git', 'rev-parse', '--abbrev-ref', 'HEAD']));
|
||||
$restoreBranch = $currentBranch !== $branch && $currentBranch !== 'HEAD'
|
||||
? $currentBranch
|
||||
: null;
|
||||
|
||||
$this->runGit($path, ['git', 'fetch', 'origin']);
|
||||
$this->runGit($path, ['git', 'fetch', 'origin', $branch]);
|
||||
$this->runGit($path, ['git', 'fetch', 'origin', self::DEVELOP_BRANCH]);
|
||||
|
||||
$this->checkoutBranch($path, $branch);
|
||||
$this->runGit($path, ['git', 'pull', '--ff-only', 'origin', $branch]);
|
||||
|
||||
return $restoreBranch;
|
||||
$this->runGit($path, ['git', 'show-ref', '--verify', "refs/remotes/origin/{$branch}"]);
|
||||
}
|
||||
|
||||
private function checkoutBranch(string $path, string $branch): void
|
||||
@@ -468,8 +446,41 @@ class GitMonitorService
|
||||
{
|
||||
$projects = $this->configService->get('workspace.repositories');
|
||||
|
||||
if (!is_array($projects) || empty($projects)) {
|
||||
throw new \RuntimeException('configs 表未设置 workspace.repositories。');
|
||||
if ($projects === null) {
|
||||
$fallback = $this->buildFallbackProjects(config('git-monitor.enabled_projects', []));
|
||||
if (!empty($fallback)) {
|
||||
Log::warning('configs 表未设置 workspace.repositories,已使用 git-monitor.enabled_projects。');
|
||||
}
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
if (!is_array($projects)) {
|
||||
Log::warning('configs 表 workspace.repositories 配置格式不正确,已降级使用 git-monitor.enabled_projects。');
|
||||
return $this->buildFallbackProjects(config('git-monitor.enabled_projects', []));
|
||||
}
|
||||
|
||||
return $projects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
private function buildFallbackProjects(array $enabled): array
|
||||
{
|
||||
$projects = [];
|
||||
$jiraKeyMap = [
|
||||
'portal-be' => 'WP',
|
||||
'agent-be' => 'AM',
|
||||
];
|
||||
|
||||
foreach ($enabled as $repoKey) {
|
||||
if (!is_string($repoKey) || $repoKey === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$projects[$repoKey] = [
|
||||
'jira_project' => $jiraKeyMap[$repoKey] ?? $repoKey,
|
||||
];
|
||||
}
|
||||
|
||||
return $projects;
|
||||
|
||||
Reference in New Issue
Block a user