272 lines
7.6 KiB
JavaScript
272 lines
7.6 KiB
JavaScript
const fs = require("fs");
|
||
const path = require("path");
|
||
const { execSync } = require("child_process");
|
||
|
||
class AdminSync {
|
||
constructor() {
|
||
this.mainRepoPath = "temp-main";
|
||
this.adminRepoPath = process.cwd();
|
||
this.mainRepoUrl = "https://git.kh3group.com/george/website.git";
|
||
this.syncLog = [];
|
||
}
|
||
|
||
async syncToMain() {
|
||
console.log("🚀 Starting sync to main site...");
|
||
this.log("Starting sync process");
|
||
|
||
try {
|
||
// Step 1: Clone main repository
|
||
await this.cloneMainRepo();
|
||
|
||
// Step 2: Sync products.json
|
||
await this.syncProducts();
|
||
|
||
// Step 3: Sync images
|
||
await this.syncImages();
|
||
|
||
// Step 4: Validate changes
|
||
await this.validateChanges();
|
||
|
||
// Step 5: Commit and push
|
||
await this.commitAndPush();
|
||
|
||
// Step 6: Cleanup
|
||
this.cleanup();
|
||
|
||
console.log("✅ Successfully synced to main site!");
|
||
console.log("🌐 Your changes should be live shortly.");
|
||
this.log("Sync completed successfully");
|
||
} catch (error) {
|
||
console.error("❌ Sync failed:", error.message);
|
||
this.log(`Sync failed: ${error.message}`, "error");
|
||
this.cleanup();
|
||
process.exit(1);
|
||
}
|
||
}
|
||
|
||
async cloneMainRepo() {
|
||
console.log("📥 Cloning main repository...");
|
||
this.log("Cloning main repository");
|
||
|
||
if (fs.existsSync(this.mainRepoPath)) {
|
||
execSync(`rm -rf ${this.mainRepoPath}`);
|
||
}
|
||
|
||
try {
|
||
execSync(`git clone ${this.mainRepoUrl} ${this.mainRepoPath}`, {
|
||
stdio: "pipe",
|
||
});
|
||
execSync(`cd ${this.mainRepoPath} && git checkout main`, {
|
||
stdio: "pipe",
|
||
});
|
||
this.log("Main repository cloned successfully");
|
||
} catch (error) {
|
||
throw new Error(`Failed to clone repository: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
async syncProducts() {
|
||
console.log("📦 Syncing products.json...");
|
||
this.log("Syncing products data");
|
||
|
||
const adminProductsPath = path.join(
|
||
this.adminRepoPath,
|
||
"data/products.json"
|
||
);
|
||
const mainProductsPath = path.join(this.mainRepoPath, "data/products.json");
|
||
|
||
if (!fs.existsSync(adminProductsPath)) {
|
||
throw new Error("products.json not found in admin repo");
|
||
}
|
||
|
||
// Ensure main data directory exists
|
||
const mainDataDir = path.dirname(mainProductsPath);
|
||
if (!fs.existsSync(mainDataDir)) {
|
||
fs.mkdirSync(mainDataDir, { recursive: true });
|
||
}
|
||
|
||
// Copy products.json
|
||
fs.copyFileSync(adminProductsPath, mainProductsPath);
|
||
console.log(" ✅ Products synced");
|
||
this.log("Products data synced successfully");
|
||
}
|
||
|
||
async syncImages() {
|
||
console.log("🖼️ Syncing images...");
|
||
this.log("Syncing product images");
|
||
|
||
const adminImagesPath = path.join(
|
||
this.adminRepoPath,
|
||
"assets/images/products"
|
||
);
|
||
const mainImagesPath = path.join(
|
||
this.mainRepoPath,
|
||
"assets/images/products"
|
||
);
|
||
|
||
// Create main images directory if it doesn't exist
|
||
if (!fs.existsSync(mainImagesPath)) {
|
||
fs.mkdirSync(mainImagesPath, { recursive: true });
|
||
}
|
||
|
||
let imagesProcessed = 0;
|
||
let imagesRemoved = 0;
|
||
|
||
if (fs.existsSync(adminImagesPath)) {
|
||
// Get all files in admin images directory
|
||
const adminImages = fs.readdirSync(adminImagesPath);
|
||
const mainImages = fs.existsSync(mainImagesPath)
|
||
? fs.readdirSync(mainImagesPath)
|
||
: [];
|
||
|
||
// Copy new/updated images
|
||
for (const image of adminImages) {
|
||
const srcPath = path.join(adminImagesPath, image);
|
||
const destPath = path.join(mainImagesPath, image);
|
||
|
||
if (fs.statSync(srcPath).isFile()) {
|
||
fs.copyFileSync(srcPath, destPath);
|
||
console.log(` 📸 Copied: ${image}`);
|
||
imagesProcessed++;
|
||
}
|
||
}
|
||
|
||
// Remove orphaned images (in main but not in admin)
|
||
for (const image of mainImages) {
|
||
const adminImagePath = path.join(adminImagesPath, image);
|
||
if (!fs.existsSync(adminImagePath)) {
|
||
fs.unlinkSync(path.join(mainImagesPath, image));
|
||
console.log(` 🗑️ Removed: ${image}`);
|
||
imagesRemoved++;
|
||
}
|
||
}
|
||
}
|
||
|
||
console.log(
|
||
` ✅ Images synced (${imagesProcessed} copied, ${imagesRemoved} removed)`
|
||
);
|
||
this.log(
|
||
`Images synced: ${imagesProcessed} copied, ${imagesRemoved} removed`
|
||
);
|
||
}
|
||
|
||
async validateChanges() {
|
||
console.log("🔍 Validating changes...");
|
||
this.log("Validating synced data");
|
||
|
||
// Validate JSON
|
||
const productsPath = path.join(this.mainRepoPath, "data/products.json");
|
||
if (!fs.existsSync(productsPath)) {
|
||
throw new Error("products.json not found after sync");
|
||
}
|
||
|
||
let productsData;
|
||
try {
|
||
productsData = JSON.parse(fs.readFileSync(productsPath, "utf8"));
|
||
} catch (error) {
|
||
throw new Error("Invalid JSON in products.json");
|
||
}
|
||
|
||
if (!productsData.products || !Array.isArray(productsData.products)) {
|
||
throw new Error("Invalid products.json structure");
|
||
}
|
||
|
||
// Check if all referenced images exist
|
||
let missingImages = 0;
|
||
for (const product of productsData.products) {
|
||
if (product.images) {
|
||
for (const imagePath of product.images) {
|
||
const fullPath = path.join(this.mainRepoPath, imagePath);
|
||
if (!fs.existsSync(fullPath)) {
|
||
console.warn(`⚠️ Warning: Image not found: ${imagePath}`);
|
||
missingImages++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (missingImages > 0) {
|
||
console.warn(`⚠️ Found ${missingImages} missing images`);
|
||
}
|
||
|
||
console.log(" ✅ Validation passed");
|
||
this.log(`Validation passed (${missingImages} missing images)`);
|
||
}
|
||
|
||
async commitAndPush() {
|
||
console.log("💾 Committing and pushing changes...");
|
||
this.log("Committing and pushing changes");
|
||
|
||
try {
|
||
// Add all changes
|
||
execSync(`cd ${this.mainRepoPath} && git add .`, { stdio: "pipe" });
|
||
|
||
// Check if there are changes to commit
|
||
try {
|
||
execSync(`cd ${this.mainRepoPath} && git diff --cached --quiet`, {
|
||
stdio: "pipe",
|
||
});
|
||
console.log(" ℹ️ No changes to commit");
|
||
this.log("No changes to commit");
|
||
return;
|
||
} catch (error) {
|
||
// There are changes, proceed with commit
|
||
}
|
||
|
||
// Commit changes
|
||
const commitMessage = `Update products and images from admin dashboard - ${new Date().toISOString()}`;
|
||
execSync(`cd ${this.mainRepoPath} && git commit -m "${commitMessage}"`, {
|
||
stdio: "pipe",
|
||
});
|
||
|
||
// Push to main branch
|
||
execSync(`cd ${this.mainRepoPath} && git push origin main`, {
|
||
stdio: "pipe",
|
||
});
|
||
|
||
console.log(" ✅ Changes pushed to main repository");
|
||
this.log("Changes pushed successfully");
|
||
} catch (error) {
|
||
throw new Error(`Failed to commit/push: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
cleanup() {
|
||
console.log("🧹 Cleaning up...");
|
||
this.log("Cleaning up temporary files");
|
||
if (fs.existsSync(this.mainRepoPath)) {
|
||
execSync(`rm -rf ${this.mainRepoPath}`);
|
||
}
|
||
}
|
||
|
||
log(message, type = "info") {
|
||
const timestamp = new Date().toISOString();
|
||
const logEntry = {
|
||
timestamp,
|
||
type,
|
||
message,
|
||
};
|
||
this.syncLog.push(logEntry);
|
||
|
||
// Save log to file
|
||
const logPath = path.join(this.adminRepoPath, "sync-log.json");
|
||
fs.writeFileSync(logPath, JSON.stringify(this.syncLog, null, 2));
|
||
}
|
||
|
||
// Method to get sync history
|
||
getSyncHistory() {
|
||
const logPath = path.join(this.adminRepoPath, "sync-log.json");
|
||
if (fs.existsSync(logPath)) {
|
||
return JSON.parse(fs.readFileSync(logPath, "utf8"));
|
||
}
|
||
return [];
|
||
}
|
||
}
|
||
|
||
// Run sync if called directly
|
||
if (require.main === module) {
|
||
const sync = new AdminSync();
|
||
sync.syncToMain();
|
||
}
|
||
|
||
module.exports = AdminSync;
|