import * as plugins from './smartgit.plugins.js'; import { Smartgit } from './smartgit.classes.smartgit.js'; /** * class GitRepo allows access to git directories from node */ export class GitRepo { // STATIC /** * creates a new GitRepo Instance after cloning a project */ public static async fromCloningIntoDir( smartgitRefArg: Smartgit, fromArg: string, toArg: string ): Promise { const dirArg = plugins.path.resolve(toArg); await plugins.isomorphicGit.clone({ dir: toArg, fs: smartgitRefArg.envDeps.fs, http: smartgitRefArg.envDeps.http, url: fromArg, }); return new GitRepo(smartgitRefArg, toArg); } public static async fromCreatingRepoInDir( smartgitRefArg: Smartgit, dirArg: string ): Promise { dirArg = plugins.path.resolve(dirArg); await plugins.isomorphicGit.init({ dir: dirArg, fs: smartgitRefArg.envDeps.fs, }); return new GitRepo(smartgitRefArg, dirArg); } public static async fromOpeningRepoDir(smartgitRefArg: Smartgit, dirArg: string) { dirArg = plugins.path.resolve(dirArg); return new GitRepo(smartgitRefArg, dirArg); } // INSTANCE public smartgitRef: Smartgit; public repoDir: string; constructor(smartgitRefArg: Smartgit, repoDirArg: string) { this.smartgitRef = smartgitRefArg; this.repoDir = repoDirArg; } /** * lists remotes */ public async listRemotes(): Promise< { remote: string; url: string; }[] > { const remotes = await plugins.isomorphicGit.listRemotes({ fs: this.smartgitRef.envDeps.fs, dir: this.repoDir, }); return remotes; } /** * ensures the existence of a remote within a repository * @param remoteNameArg * @param remoteUrlArg */ public async ensureRemote(remoteNameArg: string, remoteUrlArg: string): Promise { const remotes = await this.listRemotes(); const existingRemote = remotes.find((itemArg) => itemArg.remote === remoteNameArg); if (existingRemote) { if (existingRemote.url !== remoteUrlArg) { await plugins.isomorphicGit.deleteRemote({ remote: remoteNameArg, fs: this.smartgitRef.envDeps.fs, dir: this.repoDir, }); } else { return; } } await plugins.isomorphicGit.addRemote({ remote: remoteNameArg, fs: this.smartgitRef.envDeps.fs, url: remoteUrlArg, }); } /** * gets the url for a specific remote */ public async getUrlForRemote(remoteName: string): Promise { const remotes = await this.listRemotes(); const existingRemote = remotes.find((remoteArg) => remoteArg.remote === remoteName); return existingRemote?.url; } public async pushBranchToRemote(branchName: string, remoteName: string) { await plugins.isomorphicGit.push({ fs: this.smartgitRef.envDeps.fs, http: this.smartgitRef.envDeps.http, ref: branchName, remote: remoteName, }); } /** * Get the diff of the current uncommitted changes while excluding specified files */ public async getUncommittedDiff(excludeFiles: string[] = []): Promise { const statusMatrix = await plugins.isomorphicGit.statusMatrix({ fs: this.smartgitRef.envDeps.fs, dir: this.repoDir, }); const diffs: string[] = []; for (const row of statusMatrix) { const [filepath, head, workdir] = row; if (excludeFiles.includes(filepath)) { continue; // Skip excluded files } let headContent = ''; let workdirContent = ''; // Handle modified files if (head !== 0 && workdir !== 0 && head !== workdir) { headContent = await plugins.isomorphicGit.readBlob({ fs: this.smartgitRef.envDeps.fs, dir: this.repoDir, oid: await plugins.isomorphicGit.resolveRef({ fs: this.smartgitRef.envDeps.fs, dir: this.repoDir, ref: 'HEAD', }), filepath, }).then(result => new TextDecoder().decode(result.blob)); workdirContent = await this.smartgitRef.envDeps.fs.promises.readFile(plugins.path.join(this.repoDir, filepath), 'utf8'); } // Handle added files if (head === 0 && workdir !== 0) { workdirContent = await this.smartgitRef.envDeps.fs.promises.readFile(plugins.path.join(this.repoDir, filepath), 'utf8'); } // Handle deleted files if (head !== 0 && workdir === 0) { headContent = await plugins.isomorphicGit.readBlob({ fs: this.smartgitRef.envDeps.fs, dir: this.repoDir, oid: await plugins.isomorphicGit.resolveRef({ fs: this.smartgitRef.envDeps.fs, dir: this.repoDir, ref: 'HEAD', }), filepath, }).then(result => new TextDecoder().decode(result.blob)); } if (headContent || workdirContent) { const diff = plugins.diff.createTwoFilesPatch(filepath, filepath, headContent, workdirContent); diffs.push(diff); } } return diffs; } }