forge-deploy-cli
Version:
Professional CLI for local deployments with automatic subdomain routing, SSL certificates, and infrastructure management
181 lines • 6.88 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GitService = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const child_process_1 = require("child_process");
const chalk_1 = __importDefault(require("chalk"));
const os_1 = require("os");
class GitService {
/**
* Clone a Git repository to a local directory
*/
static async cloneRepository(repoUrl, options = {}) {
try {
const { branch = 'main', depth = 1, recursive = false, targetDir } = options;
// Ensure clone directory exists
await fs_extra_1.default.ensureDir(this.DEFAULT_CLONE_DIR);
// Generate unique directory name
const repoName = this.extractRepoName(repoUrl);
const timestamp = Date.now();
const cloneDir = targetDir || path_1.default.join(this.DEFAULT_CLONE_DIR, `${repoName}-${timestamp}`);
console.log(chalk_1.default.cyan(`Cloning repository: ${repoUrl}`));
console.log(chalk_1.default.gray(`Target directory: ${cloneDir}`));
// Build git clone command
const gitArgs = [
'clone',
'--single-branch',
'--branch', branch,
'--depth', depth.toString()
];
if (recursive) {
gitArgs.push('--recursive');
}
gitArgs.push(repoUrl, cloneDir);
// Execute git clone
(0, child_process_1.execSync)(`git ${gitArgs.join(' ')}`, {
stdio: 'pipe',
encoding: 'utf8'
});
console.log(chalk_1.default.green('Repository cloned successfully'));
return {
success: true,
localPath: cloneDir
};
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(chalk_1.default.red(`Failed to clone repository: ${errorMessage}`));
return {
success: false,
error: errorMessage
};
}
}
/**
* Update an existing cloned repository
*/
static async updateRepository(localPath, branch = 'main') {
try {
if (!await fs_extra_1.default.pathExists(localPath)) {
throw new Error(`Repository path does not exist: ${localPath}`);
}
console.log(chalk_1.default.cyan(`Updating repository at: ${localPath}`));
// Fetch latest changes
(0, child_process_1.execSync)('git fetch origin', {
cwd: localPath,
stdio: 'pipe'
});
// Reset to latest commit on the specified branch
(0, child_process_1.execSync)(`git reset --hard origin/${branch}`, {
cwd: localPath,
stdio: 'pipe'
});
console.log(chalk_1.default.green('Repository updated successfully'));
return {
success: true,
localPath
};
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(chalk_1.default.red(`Failed to update repository: ${errorMessage}`));
return {
success: false,
error: errorMessage
};
}
}
/**
* Clean up old cloned repositories
*/
static async cleanupOldRepositories(maxAge = 24 * 60 * 60 * 1000) {
try {
if (!await fs_extra_1.default.pathExists(this.DEFAULT_CLONE_DIR)) {
return;
}
const entries = await fs_extra_1.default.readdir(this.DEFAULT_CLONE_DIR, { withFileTypes: true });
const now = Date.now();
for (const entry of entries) {
if (entry.isDirectory()) {
const dirPath = path_1.default.join(this.DEFAULT_CLONE_DIR, entry.name);
const stats = await fs_extra_1.default.stat(dirPath);
if (now - stats.mtime.getTime() > maxAge) {
console.log(chalk_1.default.gray(`Cleaning up old repository: ${entry.name}`));
await fs_extra_1.default.remove(dirPath);
}
}
}
}
catch (error) {
console.warn(chalk_1.default.yellow(`Failed to cleanup old repositories: ${error}`));
}
}
/**
* Check if a directory is a valid git repository
*/
static async isGitRepository(path) {
try {
(0, child_process_1.execSync)('git rev-parse --git-dir', {
cwd: path,
stdio: 'pipe'
});
return true;
}
catch {
return false;
}
}
/**
* Get repository information
*/
static async getRepositoryInfo(localPath) {
try {
const currentBranch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', {
cwd: localPath,
encoding: 'utf8'
}).trim();
const currentCommit = (0, child_process_1.execSync)('git rev-parse HEAD', {
cwd: localPath,
encoding: 'utf8'
}).trim();
const remoteUrl = (0, child_process_1.execSync)('git remote get-url origin', {
cwd: localPath,
encoding: 'utf8'
}).trim();
return {
branch: currentBranch,
commit: currentCommit,
remoteUrl,
shortCommit: currentCommit.substring(0, 7)
};
}
catch (error) {
throw new Error(`Failed to get repository info: ${error}`);
}
}
/**
* Extract repository name from URL
*/
static extractRepoName(repoUrl) {
const match = repoUrl.match(/\/([^\/]+)\/([^\/]+?)(?:\.git)?(?:\/)?$/);
return match ? `${match[1]}-${match[2]}` : 'unknown-repo';
}
/**
* Validate repository URL
*/
static isValidGitUrl(url) {
const gitUrlPatterns = [
/^https?:\/\/(www\.)?(github|gitlab|bitbucket)\.com\/[^\/]+\/[^\/]+/,
/^git@(github|gitlab|bitbucket)\.com:[^\/]+\/[^\/]+\.git$/,
/^https?:\/\/[^\/]+\/[^\/]+\/[^\/]+\.git$/
];
return gitUrlPatterns.some(pattern => pattern.test(url));
}
}
exports.GitService = GitService;
GitService.DEFAULT_CLONE_DIR = path_1.default.join((0, os_1.tmpdir)(), 'forge-repos');
//# sourceMappingURL=git.js.map