forked from morrning/hesabixCore
support for change repositories
This commit is contained in:
parent
0d18762f1e
commit
b1f8af83f4
|
@ -23,8 +23,9 @@ final class UpdateCoreController extends AbstractController
|
|||
public function api_admin_updatecore_run(): JsonResponse
|
||||
{
|
||||
$projectDir = $this->getParameter('kernel.project_dir');
|
||||
$gitRoot = dirname($projectDir); // رفتن به ریشه پروژه
|
||||
$uuid = uniqid();
|
||||
$stateFile = $projectDir . '/../hesabixBackup/update_state_' . $uuid . '.json';
|
||||
$stateFile = $gitRoot . '/hesabixBackup/update_state_' . $uuid . '.json';
|
||||
|
||||
if (!file_exists(dirname($stateFile))) {
|
||||
mkdir(dirname($stateFile), 0755, true);
|
||||
|
@ -41,7 +42,7 @@ final class UpdateCoreController extends AbstractController
|
|||
'COMPOSER_HOME' => '/var/www/.composer',
|
||||
]);
|
||||
|
||||
$process = new Process(['php', 'bin/console', 'hesabix:update', $stateFile], $projectDir, $env);
|
||||
$process = new Process(['php', 'hesabixCore/bin/console', 'hesabix:update', $stateFile], $gitRoot, $env);
|
||||
$process->setTimeout(7200); // افزایش تایماوت به 2 ساعت
|
||||
$process->start(function ($type, $buffer) use ($stateFile) {
|
||||
$state = json_decode(file_get_contents($stateFile), true) ?? ['uuid' => uniqid(), 'log' => ''];
|
||||
|
@ -70,7 +71,9 @@ final class UpdateCoreController extends AbstractController
|
|||
], 400);
|
||||
}
|
||||
|
||||
$stateFile = $this->getParameter('kernel.project_dir') . '/../hesabixBackup/update_state_' . $uuid . '.json';
|
||||
$projectDir = $this->getParameter('kernel.project_dir');
|
||||
$gitRoot = dirname($projectDir);
|
||||
$stateFile = $gitRoot . '/hesabixBackup/update_state_' . $uuid . '.json';
|
||||
|
||||
if (!file_exists($stateFile)) {
|
||||
return new JsonResponse([
|
||||
|
@ -97,7 +100,7 @@ final class UpdateCoreController extends AbstractController
|
|||
}
|
||||
|
||||
if (!$isRunning) {
|
||||
$backupDir = $this->getParameter('kernel.project_dir') . '/../hesabixBackup';
|
||||
$backupDir = $gitRoot . '/hesabixBackup';
|
||||
$stateFiles = glob($backupDir . '/update_state_*.json');
|
||||
foreach ($stateFiles as $file) {
|
||||
if (is_file($file)) {
|
||||
|
@ -128,7 +131,9 @@ final class UpdateCoreController extends AbstractController
|
|||
return new JsonResponse(['status' => 'error', 'message' => 'UUID is required'], 400);
|
||||
}
|
||||
|
||||
$stateFile = $this->getParameter('kernel.project_dir') . '/../hesabixBackup/update_state_' . $uuid . '.json';
|
||||
$projectDir = $this->getParameter('kernel.project_dir');
|
||||
$gitRoot = dirname($projectDir);
|
||||
$stateFile = $gitRoot . '/hesabixBackup/update_state_' . $uuid . '.json';
|
||||
|
||||
return new StreamedResponse(function () use ($stateFile) {
|
||||
header('Content-Type: text/event-stream');
|
||||
|
@ -167,13 +172,14 @@ final class UpdateCoreController extends AbstractController
|
|||
public function api_admin_updatecore_commits(): JsonResponse
|
||||
{
|
||||
$projectDir = $this->getParameter('kernel.project_dir');
|
||||
$gitRoot = dirname($projectDir); // رفتن به ریشه پروژه
|
||||
|
||||
$currentProcess = new Process(['git', 'rev-parse', 'HEAD'], $projectDir);
|
||||
$currentProcess = new Process(['git', 'rev-parse', 'HEAD'], $gitRoot);
|
||||
$currentProcess->setTimeout(7200); // افزایش تایماوت
|
||||
$currentProcess->run();
|
||||
$currentCommit = $currentProcess->isSuccessful() ? trim($currentProcess->getOutput()) : 'unknown';
|
||||
|
||||
$targetProcess = new Process(['git', 'ls-remote', 'origin', 'HEAD'], $projectDir);
|
||||
$targetProcess = new Process(['git', 'ls-remote', 'origin', 'HEAD'], $gitRoot);
|
||||
$targetProcess->setTimeout(7200); // افزایش تایماوت
|
||||
$targetProcess->run();
|
||||
$targetOutput = $targetProcess->isSuccessful() ? explode("\t", trim($targetProcess->getOutput()))[0] : 'unknown';
|
||||
|
@ -428,4 +434,170 @@ final class UpdateCoreController extends AbstractController
|
|||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/api/admin/updatecore/current-source', name: 'api_admin_updatecore_current_source', methods: ['GET'])]
|
||||
public function api_admin_updatecore_current_source(): JsonResponse
|
||||
{
|
||||
$projectDir = $this->getParameter('kernel.project_dir');
|
||||
$gitRoot = dirname($projectDir); // رفتن به ریشه پروژه
|
||||
$output = '';
|
||||
|
||||
try {
|
||||
// بررسی اینکه آیا پروژه یک مخزن Git است
|
||||
if (!is_dir($gitRoot . '/.git')) {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'این پروژه یک مخزن Git نیست',
|
||||
'sourceUrl' => '',
|
||||
], 400);
|
||||
}
|
||||
|
||||
// دریافت آدرس مخزن origin فعلی
|
||||
$process = new Process(['git', 'remote', 'get-url', 'origin'], $gitRoot);
|
||||
$process->setTimeout(7200); // افزایش تایماوت
|
||||
$process->run();
|
||||
|
||||
if (!$process->isSuccessful()) {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'خطا در دریافت آدرس مخزن: ' . $process->getErrorOutput(),
|
||||
'sourceUrl' => '',
|
||||
], 500);
|
||||
}
|
||||
|
||||
$sourceUrl = trim($process->getOutput());
|
||||
$output .= "آدرس مخزن فعلی: $sourceUrl\n";
|
||||
|
||||
return new JsonResponse([
|
||||
'status' => 'success',
|
||||
'sourceUrl' => $sourceUrl,
|
||||
'output' => $output,
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'خطا در بررسی مخزن: ' . $e->getMessage(),
|
||||
'sourceUrl' => '',
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/api/admin/updatecore/change-source', name: 'api_admin_updatecore_change_source', methods: ['POST'])]
|
||||
public function api_admin_updatecore_change_source(Request $request): JsonResponse
|
||||
{
|
||||
$sourceUrl = $request->getPayload()->get('sourceUrl');
|
||||
$output = '';
|
||||
|
||||
if (!$sourceUrl || !filter_var($sourceUrl, FILTER_VALIDATE_URL) && !preg_match('/^git@[^:]+:[^\/]+\/[^\/]+\.git$/', $sourceUrl)) {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'آدرس مخزن نامعتبر است. لطفاً یک آدرس HTTP یا SSH معتبر وارد کنید.',
|
||||
'output' => $output,
|
||||
], 400);
|
||||
}
|
||||
|
||||
$projectDir = $this->getParameter('kernel.project_dir');
|
||||
$gitRoot = dirname($projectDir); // رفتن به ریشه پروژه
|
||||
|
||||
try {
|
||||
// بررسی اینکه آیا پروژه یک مخزن Git است
|
||||
if (!is_dir($gitRoot . '/.git')) {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'این پروژه یک مخزن Git نیست',
|
||||
'output' => $output,
|
||||
], 400);
|
||||
}
|
||||
|
||||
$output .= "شروع تغییر آدرس مخزن...\n";
|
||||
|
||||
// دریافت آدرس مخزن فعلی
|
||||
$currentProcess = new Process(['git', 'remote', 'get-url', 'origin'], $gitRoot);
|
||||
$currentProcess->setTimeout(7200);
|
||||
$currentProcess->run();
|
||||
$currentUrl = $currentProcess->isSuccessful() ? trim($currentProcess->getOutput()) : '';
|
||||
|
||||
if ($currentUrl) {
|
||||
$output .= "آدرس مخزن فعلی: $currentUrl\n";
|
||||
}
|
||||
|
||||
// تغییر آدرس مخزن origin
|
||||
$changeProcess = new Process(['git', 'remote', 'set-url', 'origin', $sourceUrl], $gitRoot);
|
||||
$changeProcess->setTimeout(7200);
|
||||
$changeProcess->run();
|
||||
|
||||
if (!$changeProcess->isSuccessful()) {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'خطا در تغییر آدرس مخزن: ' . $changeProcess->getErrorOutput(),
|
||||
'output' => $output,
|
||||
], 500);
|
||||
}
|
||||
|
||||
$output .= "آدرس مخزن به $sourceUrl تغییر یافت\n";
|
||||
|
||||
// بررسی اتصال به مخزن جدید
|
||||
$testProcess = new Process(['git', 'remote', 'show', 'origin'], $gitRoot);
|
||||
$testProcess->setTimeout(7200);
|
||||
$testProcess->run();
|
||||
|
||||
if (!$testProcess->isSuccessful()) {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'خطا در اتصال به مخزن جدید: ' . $testProcess->getErrorOutput(),
|
||||
'output' => $output,
|
||||
], 500);
|
||||
}
|
||||
|
||||
$output .= "اتصال به مخزن جدید با موفقیت برقرار شد\n";
|
||||
|
||||
// دریافت اطلاعات مخزن جدید
|
||||
$fetchProcess = new Process(['git', 'fetch', 'origin'], $gitRoot);
|
||||
$fetchProcess->setTimeout(7200);
|
||||
$fetchProcess->run();
|
||||
|
||||
if (!$fetchProcess->isSuccessful()) {
|
||||
$output .= "هشدار: خطا در دریافت اطلاعات از مخزن جدید: " . $fetchProcess->getErrorOutput() . "\n";
|
||||
} else {
|
||||
$output .= "اطلاعات مخزن جدید با موفقیت دریافت شد\n";
|
||||
}
|
||||
|
||||
// بررسی branch های موجود
|
||||
$branchProcess = new Process(['git', 'branch', '-r'], $gitRoot);
|
||||
$branchProcess->setTimeout(7200);
|
||||
$branchProcess->run();
|
||||
|
||||
if ($branchProcess->isSuccessful()) {
|
||||
$branches = trim($branchProcess->getOutput());
|
||||
if ($branches) {
|
||||
$output .= "شاخههای موجود در مخزن جدید:\n$branches\n";
|
||||
} else {
|
||||
$output .= "هیچ شاخهای در مخزن جدید یافت نشد\n";
|
||||
}
|
||||
}
|
||||
|
||||
// پاک کردن کش Git
|
||||
$cleanProcess = new Process(['git', 'gc', '--prune=now'], $gitRoot);
|
||||
$cleanProcess->setTimeout(7200);
|
||||
$cleanProcess->run();
|
||||
|
||||
if ($cleanProcess->isSuccessful()) {
|
||||
$output .= "کش Git پاک شد\n";
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'status' => 'success',
|
||||
'message' => 'آدرس مخزن با موفقیت تغییر یافت و اتصال برقرار شد',
|
||||
'output' => $output,
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'خطا در تغییر آدرس مخزن: ' . $e->getMessage(),
|
||||
'output' => $output,
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -268,6 +268,19 @@ const fa_lang = {
|
|||
"fetchError": "خطا در دریافت",
|
||||
"cancel": "لغو",
|
||||
"confirm": "تأیید",
|
||||
"updateSourceTitle": "منبع بهروزرسانی",
|
||||
"updateSourceLabel": "آدرس منبع بهروزرسانی",
|
||||
"changeSourceButton": "تغییر منبع",
|
||||
"sourceUrlRequired": "لطفاً آدرس منبع بهروزرسانی را وارد کنید",
|
||||
"changingSourceMessage": "در حال تغییر منبع بهروزرسانی...",
|
||||
"sourceChangeSuccess": "منبع بهروزرسانی با موفقیت تغییر یافت",
|
||||
"sourceChangeError": "خطایی در تغییر منبع بهروزرسانی رخ داد",
|
||||
"notGitRepository": "این پروژه یک مخزن Git نیست",
|
||||
"invalidRepositoryUrl": "آدرس مخزن نامعتبر است. لطفاً یک آدرس HTTP یا SSH معتبر وارد کنید.",
|
||||
"repositoryUrlError": "خطا در دریافت آدرس مخزن",
|
||||
"repositoryChangeError": "خطا در تغییر آدرس مخزن",
|
||||
"repositoryConnectionError": "خطا در اتصال به مخزن جدید",
|
||||
"repositoryChangeSuccess": "آدرس مخزن با موفقیت تغییر یافت و اتصال برقرار شد",
|
||||
},
|
||||
static: {
|
||||
not_found: "صفحه مورد نظر یافت نشد",
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<p><span class="font-weight-bold primary--text">{{ $t('updateSoftware.distroVersion') }}:</span> {{ systemInfo.distroVersion }}</p>
|
||||
<p><span class="font-weight-bold primary--text">{{ $t('updateSoftware.webServer') }}:</span> {{ systemInfo.webServer }}</p>
|
||||
<p><span class="font-weight-bold primary--text">{{ $t('updateSoftware.dbName') }}:</span> {{ systemInfo.dbName }}</p>
|
||||
<p><span class="font-weight-bold primary--useStateFiletext">{{ $t('updateSoftware.dbVersion') }}:</span> {{ systemInfo.dbVersion }}</p>
|
||||
<p><span class="font-weight-bold primary--text">{{ $t('updateSoftware.dbVersion') }}:</span> {{ systemInfo.dbVersion }}</p>
|
||||
<p><span class="font-weight-bold primary--text">{{ $t('updateSoftware.currentEnv') }}:</span> {{ selectedEnv }}</p>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
@ -76,6 +76,39 @@
|
|||
<v-window-item>
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
<!-- بخش تنظیمات منبع بهروزرسانی -->
|
||||
<v-card class="mb-4" variant="outlined">
|
||||
<v-card-title class="text-subtitle-1">
|
||||
{{ $t('updateSoftware.updateSourceTitle') }}
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="8">
|
||||
<v-text-field
|
||||
v-model="updateSourceUrl"
|
||||
:label="$t('updateSoftware.updateSourceLabel')"
|
||||
placeholder="https://github.com/username/repository.git"
|
||||
outlined
|
||||
dense
|
||||
:disabled="isUpdating || isChangingSource"
|
||||
:loading="isChangingSource"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-btn
|
||||
color="secondary"
|
||||
:loading="isChangingSource"
|
||||
:disabled="isUpdating || isChangingSource || !updateSourceUrl.trim()"
|
||||
@click="changeUpdateSource"
|
||||
block
|
||||
>
|
||||
{{ $t('updateSoftware.changeSourceButton') }}
|
||||
</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-row justify="end" class="mb-4">
|
||||
<v-col cols="auto">
|
||||
<v-btn-group size="small">
|
||||
|
@ -201,6 +234,8 @@ export default {
|
|||
const isLoadingLogs = ref(false);
|
||||
const isClearingLogs = ref(false);
|
||||
const isPolling = ref(false);
|
||||
const updateSourceUrl = ref('');
|
||||
const isChangingSource = ref(false);
|
||||
|
||||
return {
|
||||
isUpdating,
|
||||
|
@ -229,6 +264,8 @@ export default {
|
|||
isLoadingLogs,
|
||||
isClearingLogs,
|
||||
isPolling,
|
||||
updateSourceUrl,
|
||||
isChangingSource,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -508,6 +545,32 @@ export default {
|
|||
};
|
||||
}
|
||||
},
|
||||
async fetchCurrentSource() {
|
||||
try {
|
||||
const response = await axios.get('/api/admin/updatecore/current-source', {
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
||||
timeout: 7200000 // تایماوت 2 ساعته
|
||||
});
|
||||
|
||||
if (response.data.status === 'success') {
|
||||
this.updateSourceUrl = response.data.sourceUrl || '';
|
||||
} else {
|
||||
console.error('Failed to fetch current source:', response.data.message);
|
||||
this.updateSourceUrl = '';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch current source:', error);
|
||||
this.updateSourceUrl = '';
|
||||
|
||||
// نمایش پیام خطا به کاربر
|
||||
if (error.response?.data?.message) {
|
||||
this.showResultDialog = true;
|
||||
this.dialogTitle = this.$t('updateSoftware.dialogErrorTitle');
|
||||
this.dialogMessage = error.response.data.message;
|
||||
this.dialogColor = 'error';
|
||||
}
|
||||
}
|
||||
},
|
||||
async fetchCurrentEnv() {
|
||||
try {
|
||||
const response = await axios.get('/api/admin/updatecore/current-env', {
|
||||
|
@ -570,6 +633,42 @@ export default {
|
|||
this.isClearingLogs = false;
|
||||
}
|
||||
},
|
||||
async changeUpdateSource() {
|
||||
if (!this.updateSourceUrl.trim()) {
|
||||
this.showResultDialog = true;
|
||||
this.dialogTitle = this.$t('updateSoftware.dialogErrorTitle');
|
||||
this.dialogMessage = this.$t('updateSoftware.sourceUrlRequired');
|
||||
this.dialogColor = 'error';
|
||||
return;
|
||||
}
|
||||
|
||||
this.isChangingSource = true;
|
||||
this.showOutput = true;
|
||||
this.output = this.$t('updateSoftware.changingSourceMessage') + '\n';
|
||||
|
||||
try {
|
||||
const response = await axios.post('/api/admin/updatecore/change-source', {
|
||||
sourceUrl: this.updateSourceUrl.trim()
|
||||
}, {
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
||||
timeout: 7200000 // تایماوت 2 ساعته
|
||||
});
|
||||
|
||||
this.output += response.data.output || response.data.message + '\n';
|
||||
this.showResultDialog = true;
|
||||
this.dialogTitle = this.$t('updateSoftware.dialogSuccessTitle');
|
||||
this.dialogMessage = response.data.message || this.$t('updateSoftware.repositoryChangeSuccess');
|
||||
this.dialogColor = 'success';
|
||||
} catch (error) {
|
||||
this.output += 'خطا: ' + (error.response?.data?.message || error.message) + '\n';
|
||||
this.showResultDialog = true;
|
||||
this.dialogTitle = this.$t('updateSoftware.dialogErrorTitle');
|
||||
this.dialogMessage = error.response?.data?.message || this.$t('updateSoftware.sourceChangeError');
|
||||
this.dialogColor = 'error';
|
||||
} finally {
|
||||
this.isChangingSource = false;
|
||||
}
|
||||
},
|
||||
copyLogsToClipboard() {
|
||||
const plainLogs = this.systemLogs.replace(/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+\+\d{2}:\d{2}\]/g, '\n[$&]')
|
||||
.replace(/\s+\[\]/g, ' []')
|
||||
|
@ -593,6 +692,7 @@ export default {
|
|||
this.fetchCommits();
|
||||
this.fetchSystemInfo();
|
||||
this.fetchCurrentEnv();
|
||||
this.fetchCurrentSource();
|
||||
this.buttonText = this.$t('updateSoftware.startButton');
|
||||
this.refreshLogs();
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue