Add GitHub Sync - Automated repository synchronization tool
Complete implementation of automated GitHub repository synchronization: - Webhook-based auto-sync from GitHub - Multi-repository support with branch selection - Web dashboard for management - Manual sync and rollback functionality - Comprehensive logging and monitoring Located in /gitpusher/ subdirectory as standalone application.
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* Log API
|
||||
* Retrieves log entries
|
||||
*/
|
||||
|
||||
require_once '../../src/ConfigManager.php';
|
||||
require_once '../../src/Logger.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method not allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$configManager = new ConfigManager();
|
||||
$logger = new Logger($configManager);
|
||||
|
||||
// Get query parameters
|
||||
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 100;
|
||||
$offset = isset($_GET['offset']) ? (int)$_GET['offset'] : 0;
|
||||
$repoId = $_GET['repo_id'] ?? null;
|
||||
$type = $_GET['type'] ?? null;
|
||||
|
||||
// Get logs based on filters
|
||||
if ($repoId) {
|
||||
$logs = $logger->getByRepository($repoId, $limit);
|
||||
} elseif ($type) {
|
||||
$logs = $logger->getByType($type, $limit);
|
||||
} else {
|
||||
$logs = $logger->getAll($limit, $offset);
|
||||
}
|
||||
|
||||
// Get statistics
|
||||
$stats = $logger->getStats();
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'logs' => $logs,
|
||||
'stats' => $stats,
|
||||
'count' => count($logs)
|
||||
]);
|
||||
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
/**
|
||||
* Repository Management API
|
||||
* Handles CRUD operations for repositories
|
||||
*/
|
||||
|
||||
require_once '../../src/ConfigManager.php';
|
||||
require_once '../../src/Logger.php';
|
||||
require_once '../../src/GitHandler.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$configManager = new ConfigManager();
|
||||
$logger = new Logger($configManager);
|
||||
$gitHandler = new GitHandler($logger, $configManager);
|
||||
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
// GET - List all repositories or get single repository
|
||||
if ($method === 'GET') {
|
||||
if (isset($_GET['id'])) {
|
||||
$repo = $configManager->getRepository($_GET['id']);
|
||||
|
||||
if (!$repo) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Repository not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Add current git status if path exists
|
||||
if (file_exists($repo['target_path'])) {
|
||||
$status = $gitHandler->getStatus($repo['target_path']);
|
||||
$repo['git_status'] = $status;
|
||||
$repo['current_branch'] = $gitHandler->getCurrentBranch($repo['target_path']);
|
||||
$repo['current_commit'] = $gitHandler->getCurrentCommit($repo['target_path']);
|
||||
}
|
||||
|
||||
echo json_encode($repo);
|
||||
} else {
|
||||
$repos = $configManager->getRepositories();
|
||||
|
||||
// Add status for each repo
|
||||
foreach ($repos as &$repo) {
|
||||
if (file_exists($repo['target_path'])) {
|
||||
$repo['exists'] = true;
|
||||
$repo['current_branch'] = $gitHandler->getCurrentBranch($repo['target_path']);
|
||||
} else {
|
||||
$repo['exists'] = false;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(['repositories' => $repos]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// POST - Add new repository
|
||||
if ($method === 'POST') {
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
// Validate required fields
|
||||
$required = ['name', 'repo_url', 'target_path', 'branch'];
|
||||
foreach ($required as $field) {
|
||||
if (empty($input[$field])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => "Field '$field' is required"]);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate target path
|
||||
$targetPath = rtrim($input['target_path'], '/');
|
||||
|
||||
// Check if target path already exists
|
||||
if (file_exists($targetPath)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Target path already exists']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Validate repository URL format
|
||||
if (!filter_var($input['repo_url'], FILTER_VALIDATE_URL)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Invalid repository URL']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Generate webhook secret
|
||||
$webhookSecret = $configManager->generateWebhookSecret();
|
||||
|
||||
// Prepare repository data
|
||||
$repoData = [
|
||||
'name' => $input['name'],
|
||||
'repo_url' => $input['repo_url'],
|
||||
'target_path' => $targetPath,
|
||||
'branch' => $input['branch'],
|
||||
'auto_sync' => $input['auto_sync'] ?? true,
|
||||
'status' => 'cloning'
|
||||
];
|
||||
|
||||
// Add repository to config
|
||||
$repoId = $configManager->addRepository($repoData);
|
||||
|
||||
if (!$repoId) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to add repository']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Save webhook secret
|
||||
$configManager->setWebhookSecret($repoId, $webhookSecret);
|
||||
|
||||
// Clone repository
|
||||
$result = $gitHandler->cloneRepository(
|
||||
$repoId,
|
||||
$input['repo_url'],
|
||||
$targetPath,
|
||||
$input['branch']
|
||||
);
|
||||
|
||||
if ($result['success']) {
|
||||
$configManager->updateRepository($repoId, [
|
||||
'status' => 'synced',
|
||||
'last_sync' => date('Y-m-d H:i:s')
|
||||
]);
|
||||
|
||||
$repo = $configManager->getRepository($repoId);
|
||||
$repo['webhook_secret'] = $webhookSecret;
|
||||
$repo['webhook_url'] = (isset($_SERVER['HTTPS']) ? 'https' : 'http') .
|
||||
'://' . $_SERVER['HTTP_HOST'] .
|
||||
dirname(dirname($_SERVER['REQUEST_URI'])) . '/webhook.php';
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'repository' => $repo
|
||||
]);
|
||||
} else {
|
||||
$configManager->updateRepository($repoId, ['status' => 'error']);
|
||||
|
||||
http_response_code(500);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => $result['message'],
|
||||
'details' => $result['error'] ?? null
|
||||
]);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
// PUT - Update repository
|
||||
if ($method === 'PUT') {
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (empty($input['id'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Repository ID is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$repo = $configManager->getRepository($input['id']);
|
||||
|
||||
if (!$repo) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Repository not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Prepare updates (only allow certain fields to be updated)
|
||||
$allowedFields = ['name', 'branch', 'auto_sync'];
|
||||
$updates = [];
|
||||
|
||||
foreach ($allowedFields as $field) {
|
||||
if (isset($input[$field])) {
|
||||
$updates[$field] = $input[$field];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($updates)) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'No valid fields to update']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$success = $configManager->updateRepository($input['id'], $updates);
|
||||
|
||||
if ($success) {
|
||||
$repo = $configManager->getRepository($input['id']);
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'repository' => $repo
|
||||
]);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to update repository']);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
// DELETE - Delete repository
|
||||
if ($method === 'DELETE') {
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (empty($input['id'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Repository ID is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$repo = $configManager->getRepository($input['id']);
|
||||
|
||||
if (!$repo) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Repository not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Delete repository from config
|
||||
$success = $configManager->deleteRepository($input['id']);
|
||||
|
||||
if ($success) {
|
||||
$logger->info($input['id'], "Repository removed from configuration");
|
||||
|
||||
// Optionally delete files if requested
|
||||
if (!empty($input['delete_files']) && file_exists($repo['target_path'])) {
|
||||
exec('rm -rf ' . escapeshellarg($repo['target_path']));
|
||||
$logger->info($input['id'], "Repository files deleted from disk");
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Repository deleted'
|
||||
]);
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Failed to delete repository']);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
// Method not allowed
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method not allowed']);
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* Rollback API
|
||||
* Reverts repository to a specific commit
|
||||
*/
|
||||
|
||||
require_once '../../src/ConfigManager.php';
|
||||
require_once '../../src/Logger.php';
|
||||
require_once '../../src/GitHandler.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$configManager = new ConfigManager();
|
||||
$logger = new Logger($configManager);
|
||||
$gitHandler = new GitHandler($logger, $configManager);
|
||||
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
|
||||
// GET - Get commit history
|
||||
if ($method === 'GET') {
|
||||
if (empty($_GET['repo_id'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Repository ID is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$repo = $configManager->getRepository($_GET['repo_id']);
|
||||
|
||||
if (!$repo) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Repository not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!file_exists($repo['target_path'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Repository path does not exist']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 20;
|
||||
$commits = $gitHandler->getCommitHistory($repo['target_path'], $limit);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'commits' => $commits
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// POST - Perform rollback
|
||||
if ($method === 'POST') {
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (empty($input['repo_id'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Repository ID is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (empty($input['commit_hash'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Commit hash is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$repo = $configManager->getRepository($input['repo_id']);
|
||||
|
||||
if (!$repo) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Repository not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!file_exists($repo['target_path'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Repository path does not exist']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Perform revert
|
||||
$result = $gitHandler->revert(
|
||||
$repo['id'],
|
||||
$repo['target_path'],
|
||||
$input['commit_hash']
|
||||
);
|
||||
|
||||
if ($result['success']) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => $result['message'],
|
||||
'output' => $result['output']
|
||||
]);
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => $result['message'],
|
||||
'error' => $result['error'] ?? null
|
||||
]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Method not allowed
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method not allowed']);
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* Manual Sync API
|
||||
* Triggers manual sync for a repository
|
||||
*/
|
||||
|
||||
require_once '../../src/ConfigManager.php';
|
||||
require_once '../../src/Logger.php';
|
||||
require_once '../../src/GitHandler.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['error' => 'Method not allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (empty($input['repo_id'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Repository ID is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$configManager = new ConfigManager();
|
||||
$logger = new Logger($configManager);
|
||||
$gitHandler = new GitHandler($logger, $configManager);
|
||||
|
||||
$repo = $configManager->getRepository($input['repo_id']);
|
||||
|
||||
if (!$repo) {
|
||||
http_response_code(404);
|
||||
echo json_encode(['error' => 'Repository not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check if repository path exists
|
||||
if (!file_exists($repo['target_path'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Repository path does not exist. Please clone first.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Perform sync
|
||||
$logger->info($repo['id'], "Manual sync triggered");
|
||||
|
||||
$result = $gitHandler->pull(
|
||||
$repo['id'],
|
||||
$repo['target_path'],
|
||||
$repo['branch']
|
||||
);
|
||||
|
||||
if ($result['success']) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => $result['message'],
|
||||
'files_changed' => $result['files_changed'] ?? 0,
|
||||
'output' => $result['output']
|
||||
]);
|
||||
} else {
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => $result['message'],
|
||||
'conflict' => $result['conflict'] ?? false,
|
||||
'error' => $result['error'] ?? null,
|
||||
'output' => $result['output'] ?? null
|
||||
]);
|
||||
}
|
||||
Reference in New Issue
Block a user