Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 10x 10x 193x 193x 25x 25x 25x 25x 193x 193x 193x 193x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 193x 193x 193x 193x 6x 6x 6x 6x 6x 6x 6x 6x 6x 193x 193x 6x 6x 6x 6x 6x 6x 6x 193x 193x 6x 6x 6x 6x 6x 6x 6x 6x 193x 193x 1x 1x 1x 1x 1x 1x 1x 193x 193x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x 193x | import * as git from 'isomorphic-git';
import _ from 'lodash';
import fs from 'node:fs';
import { config } from '../config/config.js';
import { slugify } from '../lib/slugify.js';
import { Git } from './git.js';
import * as http from './isomorphic-http-with-agent.js';
export class GitIsomorphic extends Git {
constructor() {
super('isomorphic');
}
async #getRepo() {
const dir = await this._getRepoDir();
if (await this._isLinkedWorktree(dir)) {
throw new LinkedWorktreeNotSupportedError();
}
return { fs, dir, http };
}
#onAuth() {
return {
username: config.token,
password: config.secret,
};
}
async addRemote(remoteName, url) {
this._debug('addRemote', remoteName, url);
const repo = await this.#getRepo();
const safeRemoteName = slugify(remoteName);
const allRemotes = await git.listRemotes({ ...repo });
const existingRemote = _.find(allRemotes, { remote: safeRemoteName });
if (existingRemote == null) {
// In some situations, we may end up with race conditions so we force it
return git.addRemote({ ...repo, remote: safeRemoteName, url, force: true });
}
}
async resolveFullCommitId(commitId) {
this._debug('resolveFullCommitId', commitId);
if (commitId == null) {
return null;
}
try {
const repo = await this.#getRepo();
return await git.expandOid({ ...repo, oid: commitId });
} catch (e) {
if (e.code === 'ShortOidNotFound') {
throw new Error(`Commit id ${commitId} is ambiguous`);
}
throw e;
}
}
async getRemoteCommit(remoteUrl) {
this._debug('getRemoteCommit', remoteUrl);
const repo = await this.#getRepo();
const remoteInfos = await git.getRemoteInfo({
...repo,
onAuth: this.#onAuth,
url: remoteUrl,
});
return _.get(remoteInfos, 'refs.heads.master');
}
async getFullBranch(branchName) {
this._debug('getFullBranch', branchName);
const repo = await this.#getRepo();
if (branchName === '') {
const currentBranch = await git.currentBranch({ ...repo, fullname: true });
return currentBranch || 'HEAD';
}
return git.expandRef({ ...repo, ref: branchName });
}
async getBranchCommit(refspec) {
this._debug('getBranchCommit', refspec);
const repo = await this.#getRepo();
const oid = await git.resolveRef({ ...repo, ref: refspec });
// When a refspec refers to an annotated tag, the OID ref represents the annotation and not the commit directly,
// that's why we need a call to `readCommit`.
const res = await git.readCommit({ ...repo, ref: refspec, oid });
return res.oid;
}
async isExistingTag(tag) {
this._debug('isExistingTag', tag);
const repo = await this.#getRepo();
const tags = await git.listTags({
...repo,
});
return tags.includes(tag);
}
async push(remoteUrl, branchRefspec, force, remoteName) {
const refspec = `${branchRefspec}:refs/heads/master`;
this._debug('push', remoteUrl, refspec, force ? '--force' : '');
const repo = await this.#getRepo();
try {
const push = await git.push({
...repo,
onAuth: this.#onAuth,
url: remoteUrl,
ref: branchRefspec,
remoteRef: 'master',
remote: remoteName,
force,
});
if (push.errors != null) {
throw new Error(push.errors.join(', '));
}
return push;
} catch (e) {
if (e.code === 'PushRejectedNonFastForward') {
throw new Error('Push rejected because it was not a simple fast-forward, use --force to override');
}
throw e;
}
}
async completeBranches() {
this._debug('completeBranches');
return this.#getRepo().then((repo) => git.listBranches(repo));
}
/**
* Check if the current directory is a git repository
* @returns {Promise<boolean>}
*/
async isInsideGitRepo() {
this._debug('isInsideGitRepo');
// Don't go through #getRepo: it rejects linked worktrees, which are still git repos
return this._getRepoDir()
.then(() => true)
.catch(() => false);
}
/**
* Check if the current git working directory is clean
* @returns {Promise<boolean>}
*/
async isGitWorkingDirectoryClean() {
this._debug('isGitWorkingDirectoryClean');
const repo = await this.#getRepo();
const status = await git.statusMatrix({ ...repo });
const isStatusEmpty =
status.filter(([filepath, head, workdir]) => {
// WARNING: isomorphic-git does not support global gitignore so we filter hidden files and dirs to reduce the amount of false positives
const isHidden = filepath.startsWith('.');
const isCleverJson = filepath === '.clever.json';
return (!isHidden || isCleverJson) && head !== workdir;
}).length === 0;
return isStatusEmpty;
}
}
export class LinkedWorktreeNotSupportedError extends Error {
constructor() {
super(
"Linked git worktrees aren't supported by the default JS git backend.\n" +
'Enable the system git backend (it uses your installed git):\n' +
' clever features enable system-git',
);
this.name = 'LinkedWorktreeNotSupportedError';
}
}
|