feat: новая, вроде рабочая версия

This commit is contained in:
2025-05-16 22:35:55 +04:00
parent ccf328773f
commit af10faf664
13 changed files with 223 additions and 183 deletions

View File

@@ -1,130 +1,134 @@
import path from 'path';
import fsSync from 'fs';
import fs from 'fs/promises';
const { promises, ...isoGitFs } = fsSync;
import * as http from 'isomorphic-git/http/node';
import * as git from 'isomorphic-git';
import type { AppConfiguration } from '../config/app-configuration';
import { logger } from '../config/logger';
import { simpleGit, type SimpleGit } from 'simple-git';
import { progress } from '../utils/progress';
import { getRepoName } from '../utils/repo-name';
export class GitLoader {
private git?: SimpleGit;
constructor(private readonly config: AppConfiguration) {
logger.info('GitLoader instantiated');
logger.info('GitLoader initialized');
this.init();
}
private async init() {
private init(): void {
try {
const dir = path.resolve(this.config.pathToSave);
const dir = path.resolve(
path.join(process.cwd(), this.config.pathToSave),
);
if (fsSync.existsSync(dir)) {
fsSync.rmdirSync(dir, { recursive: true });
logger.info(`Directory ${dir} cleared`);
}
if (!fsSync.existsSync(dir)) {
await fs.mkdir(dir, { recursive: true });
fsSync.mkdirSync(dir, { recursive: true });
logger.info(`Directory ${dir} created`);
}
} catch (e: unknown) {
logger.error('Failed to create directory:', e);
logger.error(`Failed to create directory: ${e}`);
throw new Error(`Failed to create directory: ${e}`);
}
}
public async loadRepo() {
await this.init();
public async loadRepo(): Promise<void> {
logger.info(`Start cloning repo: ${this.config.gitPath}`);
const dir = path.resolve(this.config.pathToSave);
logger.info(
`Start cloning repository from ${this.config.gitPath} to ${dir}`,
);
try {
let cloneCompleted = false;
let lastProgressUpdate = Date.now();
let lastProgressMessage = '';
const repoName = getRepoName(this.config.gitPath);
const repoPath = path.join(this.config.pathToSave, repoName);
const progressTimer = setInterval(() => {
const now = Date.now();
if (now - lastProgressUpdate > 180000 && !cloneCompleted) {
logger.warn(
'No progress updates for 3 minutes, operation might be stuck',
);
}
}, 60000);
await simpleGit().clone(this.config.gitPath, repoPath, [
'--progress',
'--verbose',
]);
await git.clone({
fs: isoGitFs,
http,
dir,
url: this.config.gitPath,
singleBranch: true,
depth: 1,
onAuth: () => {
logger.info('Authentication required');
return {
username: this.config.sensitiveData.userEmail,
password: this.config.sensitiveData.password,
};
},
onAuthFailure: (error: unknown) => {
logger.error(
'Authentication failed:',
error,
'try to made repo public, auth don`t work now',
);
throw new Error('Authentication failed');
},
onAuthSuccess: () => {
logger.info('Authentication successful');
},
onProgress: (progress: any) => {
const progressMessage = JSON.stringify(progress);
if (progressMessage !== lastProgressMessage) {
lastProgressMessage = progressMessage;
logger.info('Progress:', progress);
}
},
corsProxy: 'https://cors.isomorphic-git.org',
this.git = simpleGit({
baseDir: path.resolve(path.join(process.cwd(), repoPath)),
progress,
});
cloneCompleted = true;
clearInterval(progressTimer);
logger.info('Clone successful');
logger.info(`Repository cloned to ${repoPath}`);
} catch (e: unknown) {
logger.error('Error cloning repository:', e);
throw new Error(`GitLoader: ${e}`);
logger.error(`Error cloning repo: ${e}`);
throw e;
}
}
public async checkoutBranch(branch: string) {
public async checkoutBranch(branch: string): Promise<void> {
if (!this.git) {
logger.error('Git not initialized. Run loadRepo first.');
throw new Error('Git not initialized');
}
try {
const dir = path.resolve(this.config.pathToSave);
logger.info(`Checking out branch ${branch} in ${dir}`);
const branches = await git.listBranches({
fs: isoGitFs,
dir,
gitdir: this.config.gitPath,
});
logger.info(`Available branches: ${branches.join(', ')}`);
await git.checkout({
fs: isoGitFs,
dir,
ref: branch,
});
logger.info(`Checked out branch ${branch} successfully`);
} catch (e: unknown) {
logger.error('Error checking out branch:', e);
try {
const dir = path.resolve(this.config.pathToSave);
logger.info(`Trying to use HEAD instead of branch`);
await git.checkout({
fs: isoGitFs,
dir,
ref: 'HEAD',
});
logger.info(`Used HEAD successfully`);
} catch (headError) {
logger.error('Error checking out HEAD:', headError);
throw new Error(`GitLoader CheckoutBranch error: ${e}`);
if (!(await this.git.checkIsRepo())) {
logger.error('Error: Directory is not a Git repository');
return;
}
await this.git.fetch(['--all']);
const rawBranches = await this.git.raw(['branch', '-r']);
const remoteBranch = `origin/${branch}`;
const branches = rawBranches.split('\n').map((b) => b.trim());
logger.info('Available remote branches:', branches);
if (!branches.includes(remoteBranch)) {
logger.error(`Error: Remote branch ${remoteBranch} does not exist`);
return;
}
await this.git.checkoutBranch(branch, remoteBranch);
await this.git.pull();
logger.info(`Switched to branch ${branch} and pulled ${remoteBranch}`);
const status = await this.git.status();
logger.info(`Current branch: ${status.current}`);
} catch (e: unknown) {
logger.error(`Error during checkout: ${e}`);
throw e;
}
}
public async getFile(removeComments: boolean = true): Promise<string[]> {
if (!this.git) {
logger.error('Git not initialized. Run loadRepo first.');
throw new Error('Git not initialized');
}
logger.info('Attempting to read .gitignore file');
try {
const gitignorePath = path.join(
this.config.pathToSave,
getRepoName(this.config.gitPath),
'.gitignore',
);
if (!fsSync.existsSync(gitignorePath)) {
logger.warn('.gitignore file not found');
return [];
}
const content = await fs.readFile(gitignorePath, 'utf-8');
let lines = content.split('\n');
if (removeComments) {
lines = lines
.filter((line) => line.trim() !== '' && !line.trim().startsWith('#'))
.map((line) => line.trim());
} else {
lines = lines
.filter((line) => line.trim() !== '')
.map((line) => line.trim());
}
logger.info(`Successfully read .gitignore with ${lines.length} patterns`);
return lines;
} catch (e: unknown) {
logger.error('Failed to read .gitignore file', e);
throw new Error(`Failed to read .gitignore: ${e}`);
}
}
}

View File

@@ -33,4 +33,8 @@ export class GitService {
throw new Error(`GitService: ${e}`);
}
}
public async getIgnore(removeComments: true) {
return this.gitLoader.getFile(removeComments);
}
}