khy_admin/admin-dashboard/scripts/sync-to-main.js

272 lines
7.6 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;