sync-worktrees
Version:
Automatically synchronize Git worktrees with remote branches - perfect for multi-branch development workflows
193 lines • 8.89 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigLoaderService = void 0;
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
class ConfigLoaderService {
async loadConfigFile(configPath) {
const absolutePath = path.resolve(configPath);
try {
await fs.access(absolutePath);
}
catch {
throw new Error(`Config file not found: ${absolutePath}`);
}
try {
delete require.cache[absolutePath];
const configModule = require(absolutePath);
const config = configModule.default || configModule;
this.validateConfigFile(config);
return config;
}
catch (error) {
if (error instanceof Error && error.message.includes("Config file not found")) {
throw error;
}
throw new Error(`Failed to load config file: ${error.message}`);
}
}
validateConfigFile(config) {
if (!config || typeof config !== "object") {
throw new Error("Config file must export an object");
}
const configObj = config;
if (!Array.isArray(configObj.repositories)) {
throw new Error("Config file must have a 'repositories' array");
}
if (configObj.repositories.length === 0) {
throw new Error("Config file must have at least one repository");
}
const seenNames = new Set();
configObj.repositories.forEach((repo, index) => {
if (!repo || typeof repo !== "object") {
throw new Error(`Repository at index ${index} must be an object`);
}
const repoObj = repo;
if (!repoObj.name || typeof repoObj.name !== "string") {
throw new Error(`Repository at index ${index} must have a 'name' property`);
}
if (seenNames.has(repoObj.name)) {
throw new Error(`Duplicate repository name: ${repoObj.name}`);
}
seenNames.add(repoObj.name);
if (!repoObj.repoUrl || typeof repoObj.repoUrl !== "string") {
throw new Error(`Repository '${repoObj.name}' must have a 'repoUrl' property`);
}
if (!repoObj.worktreeDir || typeof repoObj.worktreeDir !== "string") {
throw new Error(`Repository '${repoObj.name}' must have a 'worktreeDir' property`);
}
if (repoObj.bareRepoDir !== undefined && typeof repoObj.bareRepoDir !== "string") {
throw new Error(`Repository '${repoObj.name}' has invalid 'bareRepoDir' property`);
}
if (repoObj.cronSchedule !== undefined && typeof repoObj.cronSchedule !== "string") {
throw new Error(`Repository '${repoObj.name}' has invalid 'cronSchedule' property`);
}
if (repoObj.runOnce !== undefined && typeof repoObj.runOnce !== "boolean") {
throw new Error(`Repository '${repoObj.name}' has invalid 'runOnce' property`);
}
});
if (configObj.defaults) {
if (typeof configObj.defaults !== "object") {
throw new Error("'defaults' must be an object");
}
const defaults = configObj.defaults;
if (defaults.cronSchedule !== undefined && typeof defaults.cronSchedule !== "string") {
throw new Error("Invalid 'cronSchedule' in defaults");
}
if (defaults.runOnce !== undefined && typeof defaults.runOnce !== "boolean") {
throw new Error("Invalid 'runOnce' in defaults");
}
if (defaults.retry !== undefined && typeof defaults.retry !== "object") {
throw new Error("Invalid 'retry' in defaults");
}
}
if (configObj.retry !== undefined) {
if (typeof configObj.retry !== "object") {
throw new Error("'retry' must be an object");
}
const retry = configObj.retry;
if (retry.maxAttempts !== undefined) {
if (retry.maxAttempts !== "unlimited" && (typeof retry.maxAttempts !== "number" || retry.maxAttempts < 1)) {
throw new Error("Invalid 'maxAttempts' in retry config. Must be 'unlimited' or a positive number");
}
}
if (retry.maxLfsRetries !== undefined) {
if (typeof retry.maxLfsRetries !== "number" || retry.maxLfsRetries < 0) {
throw new Error("Invalid 'maxLfsRetries' in retry config. Must be a non-negative number");
}
}
if (retry.initialDelayMs !== undefined &&
(typeof retry.initialDelayMs !== "number" || retry.initialDelayMs < 0)) {
throw new Error("Invalid 'initialDelayMs' in retry config");
}
if (retry.maxDelayMs !== undefined && (typeof retry.maxDelayMs !== "number" || retry.maxDelayMs < 0)) {
throw new Error("Invalid 'maxDelayMs' in retry config");
}
if (retry.backoffMultiplier !== undefined &&
(typeof retry.backoffMultiplier !== "number" || retry.backoffMultiplier < 1)) {
throw new Error("Invalid 'backoffMultiplier' in retry config");
}
}
}
resolveRepositoryConfig(repo, defaults, configDir, globalRetry) {
const resolved = {
name: repo.name,
repoUrl: repo.repoUrl,
worktreeDir: this.resolvePath(repo.worktreeDir, configDir),
cronSchedule: repo.cronSchedule ?? defaults?.cronSchedule ?? "0 * * * *",
runOnce: repo.runOnce ?? defaults?.runOnce ?? false,
};
if (repo.bareRepoDir) {
resolved.bareRepoDir = this.resolvePath(repo.bareRepoDir, configDir);
}
if (repo.branchMaxAge || defaults?.branchMaxAge) {
resolved.branchMaxAge = repo.branchMaxAge ?? defaults?.branchMaxAge;
}
if (repo.skipLfs !== undefined || defaults?.skipLfs !== undefined) {
resolved.skipLfs = repo.skipLfs ?? defaults?.skipLfs ?? false;
}
if (repo.retry || defaults?.retry || globalRetry) {
resolved.retry = { ...globalRetry, ...defaults?.retry, ...repo.retry };
}
if (repo.updateExistingWorktrees !== undefined || defaults?.updateExistingWorktrees !== undefined) {
resolved.updateExistingWorktrees = repo.updateExistingWorktrees ?? defaults?.updateExistingWorktrees ?? true;
}
return resolved;
}
resolvePath(inputPath, baseDir) {
if (path.isAbsolute(inputPath)) {
return inputPath;
}
return path.resolve(baseDir || process.cwd(), inputPath);
}
filterRepositories(repositories, filter) {
if (!filter) {
return repositories;
}
const patterns = filter.split(",").map((p) => p.trim());
return repositories.filter((repo) => {
return patterns.some((pattern) => {
if (pattern.includes("*")) {
const regex = new RegExp("^" + pattern.replace(/\*/g, ".*") + "$");
return regex.test(repo.name);
}
return repo.name === pattern;
});
});
}
}
exports.ConfigLoaderService = ConfigLoaderService;
//# sourceMappingURL=config-loader.service.js.map