smartgit/ts/smartgit.classes.gitrepo.ts

229 lines
6.3 KiB
TypeScript

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<GitRepo> {
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<GitRepo> {
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<void> {
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<string> {
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<string[]> {
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;
}
/**
* Get all commit messages with their dates and package.json version at each commit
*/
public async getAllCommitMessages(): Promise<
{ date: string; version: string; message: string }[]
> {
const commits = await plugins.isomorphicGit.log({
fs: this.smartgitRef.envDeps.fs,
dir: this.repoDir,
});
const results = [];
for (const commit of commits) {
let version = 'unknown';
try {
const packageJsonBlob = await plugins.isomorphicGit.readBlob({
fs: this.smartgitRef.envDeps.fs,
dir: this.repoDir,
oid: commit.oid,
filepath: 'package.json',
});
const packageJson = JSON.parse(new TextDecoder().decode(packageJsonBlob.blob));
version = packageJson.version;
} catch (error) {
// If package.json does not exist or any error occurs, leave version as 'unknown'
}
results.push({
date: new plugins.smarttime.ExtendedDate(commit.commit.committer.timestamp * 1000).exportToHyphedSortableDate(),
version: version,
message: commit.commit.message,
});
}
return results;
}
}