feat: первая версия
This commit is contained in:
130
git/git-loader.ts
Normal file
130
git/git-loader.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
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';
|
||||
|
||||
export class GitLoader {
|
||||
constructor(private readonly config: AppConfiguration) {
|
||||
logger.info('GitLoader instantiated');
|
||||
}
|
||||
|
||||
private async init() {
|
||||
try {
|
||||
const dir = path.resolve(this.config.pathToSave);
|
||||
if (!fsSync.existsSync(dir)) {
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
logger.info(`Directory ${dir} created`);
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
logger.error('Failed to create directory:', e);
|
||||
throw new Error(`Failed to create directory: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
public async loadRepo() {
|
||||
await this.init();
|
||||
|
||||
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 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 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',
|
||||
});
|
||||
|
||||
cloneCompleted = true;
|
||||
clearInterval(progressTimer);
|
||||
|
||||
logger.info('Clone successful');
|
||||
} catch (e: unknown) {
|
||||
logger.error('Error cloning repository:', e);
|
||||
throw new Error(`GitLoader: ${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
public async checkoutBranch(branch: string) {
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
git/index.ts
Normal file
36
git/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { GitLoader } from './git-loader';
|
||||
import { logger } from '../config/logger';
|
||||
import type { AppConfiguration } from '../config/app-configuration';
|
||||
|
||||
export class GitService {
|
||||
private readonly gitLoader: GitLoader;
|
||||
constructor(config: AppConfiguration) {
|
||||
logger.info('GitService initialized');
|
||||
this.gitLoader = new GitLoader(config);
|
||||
}
|
||||
|
||||
public async getRepo(branch: string = 'main'): Promise<void> {
|
||||
try {
|
||||
logger.info(`Cloning repo with target branch: ${branch}...`);
|
||||
|
||||
const cloneStartTime = Date.now();
|
||||
|
||||
await this.gitLoader.loadRepo();
|
||||
|
||||
const cloneEndTime = Date.now();
|
||||
const cloneTimeSeconds = ((cloneEndTime - cloneStartTime) / 1000).toFixed(
|
||||
2,
|
||||
);
|
||||
logger.info(`Repo cloned successfully in ${cloneTimeSeconds} seconds`);
|
||||
|
||||
logger.info(`Checking out branch ${branch}...`);
|
||||
|
||||
await this.gitLoader.checkoutBranch(branch);
|
||||
|
||||
logger.info('Branch checked out successfully');
|
||||
} catch (e: unknown) {
|
||||
logger.error('Error cloning repo:', e instanceof Error ? e.message : e);
|
||||
throw new Error(`GitService: ${e}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user