@ts-common/azure-js-dev-tools
Version:
Developer dependencies for TypeScript related projects
1,035 lines • 60.9 kB
JavaScript
"use strict";
/**
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRemoteBranchFullName = exports.getGitRemoteBranch = exports.getFilesChangedFromFullDiff = exports.ExecutableGit = void 0;
var tslib_1 = require("tslib");
var arrays_1 = require("./arrays");
var common_1 = require("./common");
var path_1 = require("./path");
var run_1 = require("./run");
var fs_1 = require("fs");
var url_1 = require("./url");
/**
* An implementation of Git that uses a Git executable to run commands.
*/
var ExecutableGit = /** @class */ (function () {
/**
* Create a new ExecutableGit object.
* @param gitFilePath The file path to the git executable to use to run commands. This can be
* either a rooted path to the executable, or a relative path that will use the environment's PATH
* variable to resolve the executable's location.
* @param options The optional arguments that will be applied to each operation.
*/
function ExecutableGit(options) {
if (options === void 0) { options = {}; }
this.options = options;
this.authenticationStrings = new Set();
if (!options.gitFilePath) {
options.gitFilePath = "git";
}
}
ExecutableGit.prototype.maskAuthenticationInLog = function (options) {
var _this = this;
var authentication = this.options.authentication;
var log = options.log;
if (authentication && log) {
options.log = function (text) {
var e_1, _a;
try {
for (var _b = tslib_1.__values(_this.authenticationStrings.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var authenticationString = _c.value;
text = common_1.replaceAll(text, authenticationString, "<redacted>");
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return log(text);
};
}
return options;
};
ExecutableGit.prototype.addAuthenticationToURL = function (url, options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result, builder, authenticationToAdd, urlPath, matchingScope, _a, _b, _c, scope, authentication, scopes;
var e_2, _d;
return tslib_1.__generator(this, function (_e) {
switch (_e.label) {
case 0:
result = url;
if (!this.options.authentication) return [3 /*break*/, 8];
builder = url_1.URLBuilder.parse(url);
authenticationToAdd = void 0;
if (!(typeof this.options.authentication === "string")) return [3 /*break*/, 1];
authenticationToAdd = this.options.authentication;
return [3 /*break*/, 7];
case 1:
if (!(typeof this.options.authentication === "function")) return [3 /*break*/, 3];
return [4 /*yield*/, this.options.authentication(url)];
case 2:
authenticationToAdd = _e.sent();
return [3 /*break*/, 7];
case 3:
urlPath = builder.getPath();
if (!urlPath) return [3 /*break*/, 7];
urlPath = urlPath.toLowerCase();
matchingScope = "";
try {
for (_a = tslib_1.__values(Object.entries(this.options.authentication)), _b = _a.next(); !_b.done; _b = _a.next()) {
_c = tslib_1.__read(_b.value, 2), scope = _c[0], authentication = _c[1];
if (!scope.startsWith("/")) {
scope = "/" + scope;
}
scope = scope.toLowerCase();
if (urlPath.startsWith(scope) && scope.length > matchingScope.length) {
matchingScope = scope;
authenticationToAdd = authentication;
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
}
finally { if (e_2) throw e_2.error; }
}
if (!options.log) return [3 /*break*/, 7];
if (!matchingScope) return [3 /*break*/, 5];
return [4 /*yield*/, Promise.resolve(options.log("Git URL matches authentication scope \"" + matchingScope + "\". Inserting auth token \"" + authenticationToAdd + "\"."))];
case 4:
_e.sent();
return [3 /*break*/, 7];
case 5:
scopes = Object.keys(this.options.authentication);
return [4 /*yield*/, Promise.resolve(options.log("Git URL didn't match any of the authentication scopes (" + scopes.join(",") + "). Not inserting an auth token."))];
case 6:
_e.sent();
_e.label = 7;
case 7:
if (authenticationToAdd !== undefined) {
this.authenticationStrings.add(authenticationToAdd);
}
builder.setAuth(authenticationToAdd);
result = builder.toString();
_e.label = 8;
case 8: return [2 /*return*/, result];
}
});
});
};
/**
* Create a new ExecutableGit object that combines this ExecutableGit's options with the provieded
* options.
* @param options The options to combine with this ExecutableGit's options.
*/
ExecutableGit.prototype.scope = function (options) {
return new ExecutableGit(tslib_1.__assign(tslib_1.__assign({}, this.options), options));
};
/**
* Run an arbitrary Git command.
* @param args The arguments to provide to the Git executable.
*/
ExecutableGit.prototype.run = function (args, options) {
if (options === void 0) { options = {}; }
if (options.usePager === true) {
args.unshift("--paginate");
}
else if (options.usePager === false) {
args.unshift("--no-pager");
}
return run_1.run(options.gitFilePath || this.options.gitFilePath, args, this.maskAuthenticationInLog(tslib_1.__assign(tslib_1.__assign({}, this.options), options)));
};
/**
* Get the SHA of the currently checked out commit.
*/
ExecutableGit.prototype.currentCommitSha = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var runResult, result;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.run(["rev-parse", "HEAD"], options)];
case 1:
runResult = _a.sent();
result = tslib_1.__assign(tslib_1.__assign({}, runResult), { currentCommitSha: runResult.stdout });
return [2 /*return*/, result];
}
});
});
};
/**
* Download objects and refs from another repository.
* @param options The options that can be passed to `git fetch`.
*/
ExecutableGit.prototype.fetch = function (options) {
if (options === void 0) { options = {}; }
var args = ["fetch"];
if (options.prune) {
args.push("--prune");
}
if (options.all) {
args.push("--all");
}
if (options.depth) {
args.push("--depth", options.depth.toString());
}
if (options.remoteName) {
args.push(options.remoteName);
}
if (options.refSpec) {
args.push(options.refSpec);
}
return this.run(args, options);
};
ExecutableGit.prototype.merge = function (options) {
var e_3, _a, e_4, _b, e_5, _c;
if (options === void 0) { options = {}; }
var args = ["merge"];
if (options.squash != undefined) {
if (options.squash) {
args.push("--squash");
}
else {
args.push("--no-squash");
}
}
if (options.edit != undefined) {
if (options.edit) {
args.push("--edit");
}
else {
args.push("--no-edit");
}
}
if (options.strategyOptions) {
options.strategyOptions = arrays_1.toArray(options.strategyOptions);
try {
for (var _d = tslib_1.__values(options.strategyOptions), _e = _d.next(); !_e.done; _e = _d.next()) {
var strategyOption = _e.value;
args.push("--strategy-option=" + strategyOption);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
}
finally { if (e_3) throw e_3.error; }
}
}
if (options.quiet) {
args.push("--quiet");
}
if (options.messages != undefined) {
options.messages = arrays_1.toArray(options.messages);
try {
for (var _f = tslib_1.__values(options.messages), _g = _f.next(); !_g.done; _g = _f.next()) {
var message = _g.value;
args.push("-m", message);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
}
finally { if (e_4) throw e_4.error; }
}
}
if (options.refsToMerge) {
try {
for (var _h = tslib_1.__values(arrays_1.toArray(options.refsToMerge)), _j = _h.next(); !_j.done; _j = _h.next()) {
var refToMerge = _j.value;
if (refToMerge) {
args.push(refToMerge);
}
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_j && !_j.done && (_c = _h.return)) _c.call(_h);
}
finally { if (e_5) throw e_5.error; }
}
}
return this.run(args, options);
};
ExecutableGit.prototype.rebase = function (options) {
if (options === void 0) { options = {}; }
var args = ["rebase"];
if (options.strategy) {
args.push("--strategy=" + options.strategy);
}
if (options.strategyOption) {
args.push("--strategy-option=" + options.strategyOption);
}
if (options.quiet) {
args.push("--quiet");
}
if (options.verbose) {
args.push("--verbose");
}
if (options.newbase) {
args.push("--onto", options.newbase);
}
if (options.upstream) {
args.push(options.upstream);
}
if (options.branch) {
args.push(options.branch);
}
return this.run(args, options);
};
/**
* Clone the repository with the provided URI.
* @param gitUri The repository URI to clone.
* @param options The options that can be passed to "git clone".
*/
ExecutableGit.prototype.clone = function (gitUri, options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var args, _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
_a = getCloneArguments;
return [4 /*yield*/, this.addAuthenticationToURL(gitUri)];
case 1:
args = _a.apply(void 0, [_b.sent(), options]);
return [4 /*yield*/, this.run(args, options)];
case 2: return [2 /*return*/, _b.sent()];
}
});
});
};
/**
* Init git repo.
* @param options Options
*/
ExecutableGit.prototype.init = function (options) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
return [2 /*return*/, this.run(["init"], options)];
});
});
};
ExecutableGit.prototype.symbolicRef = function (name, ref, options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var args;
return tslib_1.__generator(this, function (_a) {
args = ["symbolic-ref"];
args.push(name);
if (ref) {
args.push(ref);
}
return [2 /*return*/, this.run(args, options)];
});
});
};
/**
* Checkout the provided git reference (branch, tag, or commit ID) in the repository.
* @param refId The git reference to checkout.
*/
ExecutableGit.prototype.checkout = function (refId, options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var args, runResult, filesThatWouldBeOverwritten, stderrLines, lineIndex, line;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
args = ["checkout"];
if (!options.remote) {
args.push(refId);
}
else {
args.push("--track", options.remote + "/" + refId);
}
if (options.localBranchName) {
args.push("-b", options.localBranchName);
}
if (options.detach) {
args.push("--detach");
}
return [4 /*yield*/, this.run(args, options)];
case 1:
runResult = _a.sent();
if (runResult.stderr) {
stderrLines = common_1.getLines(runResult.stderr);
if (stderrLines[0].trim() === "error: The following untracked working tree files would be overwritten by checkout:") {
filesThatWouldBeOverwritten = [];
lineIndex = 1;
while (lineIndex < stderrLines.length) {
line = stderrLines[lineIndex];
if (line.trim() === "Please move or remove them before you switch branches.") {
break;
}
else {
filesThatWouldBeOverwritten.push(path_1.joinPath(options.executionFolderPath || this.options.executionFolderPath || "", line.trim()));
++lineIndex;
}
}
}
}
return [2 /*return*/, tslib_1.__assign(tslib_1.__assign({}, runResult), { filesThatWouldBeOverwritten: filesThatWouldBeOverwritten })];
}
});
});
};
/**
* Pull the latest changes for the current branch from the registered remote branch.
*/
ExecutableGit.prototype.pull = function (options) {
if (options === void 0) { options = {}; }
return this.run(["pull"], options);
};
/**
* Push the current branch to the remote tracked repository.
* @param options The options for determining how this command will run.
*/
ExecutableGit.prototype.push = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var args, upstream, branchName, _a;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
args = ["push"];
if (!options.setUpstream) return [3 /*break*/, 3];
upstream = typeof options.setUpstream === "string" ? options.setUpstream : "origin";
_a = options.branchName;
if (_a) return [3 /*break*/, 2];
return [4 /*yield*/, this.currentBranch(options)];
case 1:
_a = (_b.sent());
_b.label = 2;
case 2:
branchName = _a;
args.push("--set-upstream", upstream, branchName);
_b.label = 3;
case 3:
if (options.force) {
args.push("--force");
}
return [4 /*yield*/, this.run(args, options)];
case 4: return [2 /*return*/, _b.sent()];
}
});
});
};
/**
* Add/stage the provided files.
* @param filePaths The paths to the files to stage.
* @param options The options for determining how this command will run.
*/
ExecutableGit.prototype.add = function (filePaths, options) {
if (options === void 0) { options = {}; }
var args = ["add"];
if (typeof filePaths === "string") {
args.push(filePaths);
}
else {
args.push.apply(args, tslib_1.__spread(filePaths));
}
return this.run(args, options);
};
/**
* Add/stage all of the current unstaged files.
* @param options The options that determine how this command will run.
*/
ExecutableGit.prototype.addAll = function (options) {
if (options === void 0) { options = {}; }
return this.add("*", options);
};
/**
* Commit the currently staged/added changes to the current branch.
* @param commitMessages The commit messages to apply to this commit.
* @param options The options that determine how this command will run.
*/
ExecutableGit.prototype.commit = function (commitMessages, options) {
var e_6, _a;
if (options === void 0) { options = {}; }
var args = ["commit"];
if (options.noVerify) {
args.push("--no-verify");
}
if (typeof commitMessages === "string") {
commitMessages = [commitMessages];
}
try {
for (var commitMessages_1 = tslib_1.__values(commitMessages), commitMessages_1_1 = commitMessages_1.next(); !commitMessages_1_1.done; commitMessages_1_1 = commitMessages_1.next()) {
var commitMessage = commitMessages_1_1.value;
args.push("-m", commitMessage);
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (commitMessages_1_1 && !commitMessages_1_1.done && (_a = commitMessages_1.return)) _a.call(commitMessages_1);
}
finally { if (e_6) throw e_6.error; }
}
return this.run(args, options);
};
/**
* Delete a local branch.
* @param branchName The name of the local branch to delete.
*/
ExecutableGit.prototype.deleteLocalBranch = function (branchName, options) {
if (options === void 0) { options = {}; }
return this.run(["branch", "-D", branchName], options);
};
/**
* Create a new local branch with the provided name.
* @param branchName The name of the new branch.
* @param options The options for determining how this command will run.
*/
ExecutableGit.prototype.createLocalBranch = function (branchName, options) {
if (options === void 0) { options = {}; }
var args = ["checkout", "-b", branchName];
if (options.startPoint) {
args.push(options.startPoint);
}
return this.run(args, options);
};
/**
* Remote the provided branch from the provided tracked remote repository.
* @param branchName The name of the remote branch to delete.
* @param remoteName The name of the tracked remote repository.
* @param options The options for determining how this command will run.
*/
ExecutableGit.prototype.deleteRemoteBranch = function (branchName, options) {
if (options === void 0) { options = {}; }
return this.run(["push", options.remoteName || "origin", ":" + branchName], options);
};
ExecutableGit.prototype.diff = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var args, commandResult, filesChanged, repositoryFolderPath, stdoutLines, _a, _b, fileChanged;
var e_7, _c;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
case 0:
args = ["diff"];
if (options.commit1) {
args.push(options.commit1);
}
if (options.commit2) {
args.push(options.commit2);
}
if (options.staged) {
args.push("--staged");
}
if (options.nameOnly) {
args.push("--name-only");
}
if (options.ignoreSpace === "all") {
args.push("--ignore-all-space");
}
else if (options.ignoreSpace) {
args.push("--ignore-space-" + options.ignoreSpace);
}
return [4 /*yield*/, this.run(args, options)];
case 1:
commandResult = _d.sent();
repositoryFolderPath = options.executionFolderPath || this.options.executionFolderPath || process.cwd();
stdoutLines = common_1.getLines(commandResult.stdout);
if (options.nameOnly) {
filesChanged = [];
try {
for (_a = tslib_1.__values(common_1.getLines(commandResult.stdout)), _b = _a.next(); !_b.done; _b = _a.next()) {
fileChanged = _b.value;
if (fileChanged) {
filesChanged.push(path_1.joinPath(repositoryFolderPath, fileChanged));
}
}
}
catch (e_7_1) { e_7 = { error: e_7_1 }; }
finally {
try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
}
finally { if (e_7) throw e_7.error; }
}
}
else {
filesChanged = getFilesChangedFromFullDiff(stdoutLines, repositoryFolderPath);
}
return [2 /*return*/, tslib_1.__assign(tslib_1.__assign({}, commandResult), { filesChanged: filesChanged })];
}
});
});
};
/**
* Get the branches that are local to this repository.
*/
ExecutableGit.prototype.localBranches = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var commandResult, currentBranch, localBranches, _a, _b, branch, detachedHeadMatch;
var e_8, _c;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
case 0: return [4 /*yield*/, this.run(["branch"], options)];
case 1:
commandResult = _d.sent();
currentBranch = "";
localBranches = [];
try {
for (_a = tslib_1.__values(common_1.getLines(commandResult.stdout)), _b = _a.next(); !_b.done; _b = _a.next()) {
branch = _b.value;
if (branch) {
branch = branch.trim();
if (branch) {
if (branch.startsWith("*")) {
branch = branch.substring(1).trimLeft();
detachedHeadMatch = branch.match(branchDetachedHeadRegExp);
if (detachedHeadMatch) {
branch = detachedHeadMatch[1];
}
currentBranch = branch;
}
localBranches.push(branch);
}
}
}
}
catch (e_8_1) { e_8 = { error: e_8_1 }; }
finally {
try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
}
finally { if (e_8) throw e_8.error; }
}
return [2 /*return*/, tslib_1.__assign(tslib_1.__assign({}, commandResult), { localBranches: localBranches,
currentBranch: currentBranch })];
}
});
});
};
/**
* Get the branch that the repository is currently on.
* @param options The options to run this command with.
*/
ExecutableGit.prototype.currentBranch = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.localBranches(options)];
case 1: return [2 /*return*/, (_a.sent()).currentBranch];
}
});
});
};
/**
* Get the remote branches that this repository clone is aware of.
* @param options The options to run this command with.
*/
ExecutableGit.prototype.remoteBranches = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var gitResult, remoteBranches, _a, _b, remoteBranchLine, firstSlashIndex, repositoryTrackingName, branchName;
var e_9, _c;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
case 0: return [4 /*yield*/, this.run(["branch", "--remotes"], options)];
case 1:
gitResult = _d.sent();
remoteBranches = [];
try {
for (_a = tslib_1.__values(common_1.getLines(gitResult.stdout)), _b = _a.next(); !_b.done; _b = _a.next()) {
remoteBranchLine = _b.value;
if (remoteBranchLine && remoteBranchLine.indexOf("->") === -1) {
remoteBranchLine = remoteBranchLine.trim();
if (remoteBranchLine) {
firstSlashIndex = remoteBranchLine.indexOf("/");
repositoryTrackingName = remoteBranchLine.substring(0, firstSlashIndex);
branchName = remoteBranchLine.substring(firstSlashIndex + 1);
remoteBranches.push({
repositoryTrackingName: repositoryTrackingName,
branchName: branchName
});
}
}
}
}
catch (e_9_1) { e_9 = { error: e_9_1 }; }
finally {
try {
if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
}
finally { if (e_9) throw e_9.error; }
}
return [2 /*return*/, tslib_1.__assign(tslib_1.__assign({}, gitResult), { remoteBranches: remoteBranches })];
}
});
});
};
ExecutableGit.prototype.stash = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var args;
return tslib_1.__generator(this, function (_a) {
args = ["stash"];
if (options.pop) {
args.push("pop");
}
if (options.keepIndex) {
args.push("--keep-index");
}
if (options.all) {
args.push("--all");
}
return [2 /*return*/, this.run(args, options)];
});
});
};
/**
* Reset a local git repo, possible with existing git data.
* Delete all the branches and all the remotes.
* Use this function to reuse existing git repo data to accelerate fetching.
*/
ExecutableGit.prototype.resetRepoFolder = function () {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var log, initResult, e_10, localBranchesResult, e_11, _a, _b, branchName, e_12, e_13_1, listRemotesResult, _c, _d, remoteName, e_14_1;
var e_13, _e, e_14, _f;
return tslib_1.__generator(this, function (_g) {
switch (_g.label) {
case 0:
log = this.options.log || console.error;
if (this.options.executionFolderPath) {
fs_1.mkdirSync(this.options.executionFolderPath, { recursive: true });
}
return [4 /*yield*/, this.init()];
case 1:
initResult = _g.sent();
if (initResult.exitCode !== 0) {
log("Failed to init repo at " + this.options.executionFolderPath);
if (initResult.error) {
log(JSON.stringify(initResult.error));
throw initResult;
}
}
_g.label = 2;
case 2:
_g.trys.push([2, 4, , 5]);
return [4 /*yield*/, this.addAll()];
case 3:
_g.sent();
return [3 /*break*/, 5];
case 4:
e_10 = _g.sent();
return [3 /*break*/, 5];
case 5: return [4 /*yield*/, this.resetAll({ hard: true })];
case 6:
_g.sent();
return [4 /*yield*/, this.run(["clean", "-xdf"])];
case 7:
_g.sent();
return [4 /*yield*/, this.localBranches()];
case 8:
localBranchesResult = _g.sent();
if (!localBranchesResult.currentBranch) return [3 /*break*/, 13];
_g.label = 9;
case 9:
_g.trys.push([9, 12, , 13]);
return [4 /*yield*/, this.checkout(localBranchesResult.currentBranch, { detach: true })];
case 10:
_g.sent();
return [4 /*yield*/, this.deleteLocalBranch(localBranchesResult.currentBranch)];
case 11:
_g.sent();
return [3 /*break*/, 13];
case 12:
e_11 = _g.sent();
return [3 /*break*/, 13];
case 13:
_g.trys.push([13, 20, 21, 22]);
_a = tslib_1.__values(localBranchesResult.localBranches), _b = _a.next();
_g.label = 14;
case 14:
if (!!_b.done) return [3 /*break*/, 19];
branchName = _b.value;
if (!(branchName && branchName !== localBranchesResult.currentBranch)) return [3 /*break*/, 18];
_g.label = 15;
case 15:
_g.trys.push([15, 17, , 18]);
return [4 /*yield*/, this.deleteLocalBranch(branchName)];
case 16:
_g.sent();
return [3 /*break*/, 18];
case 17:
e_12 = _g.sent();
return [3 /*break*/, 18];
case 18:
_b = _a.next();
return [3 /*break*/, 14];
case 19: return [3 /*break*/, 22];
case 20:
e_13_1 = _g.sent();
e_13 = { error: e_13_1 };
return [3 /*break*/, 22];
case 21:
try {
if (_b && !_b.done && (_e = _a.return)) _e.call(_a);
}
finally { if (e_13) throw e_13.error; }
return [7 /*endfinally*/];
case 22: return [4 /*yield*/, this.listRemotes()];
case 23:
listRemotesResult = _g.sent();
_g.label = 24;
case 24:
_g.trys.push([24, 29, 30, 31]);
_c = tslib_1.__values(Object.keys(listRemotesResult.remotes)), _d = _c.next();
_g.label = 25;
case 25:
if (!!_d.done) return [3 /*break*/, 28];
remoteName = _d.value;
if (!remoteName) return [3 /*break*/, 27];
return [4 /*yield*/, this.removeRemote(remoteName)];
case 26:
_g.sent();
_g.label = 27;
case 27:
_d = _c.next();
return [3 /*break*/, 25];
case 28: return [3 /*break*/, 31];
case 29:
e_14_1 = _g.sent();
e_14 = { error: e_14_1 };
return [3 /*break*/, 31];
case 30:
try {
if (_d && !_d.done && (_f = _c.return)) _f.call(_c);
}
finally { if (e_14) throw e_14.error; }
return [7 /*endfinally*/];
case 31: return [2 /*return*/];
}
});
});
};
/**
* Run "git status".
*/
ExecutableGit.prototype.status = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var folderPath, parseState, localBranch, remoteBranch, hasUncommittedChanges, stagedModifiedFiles, stagedDeletedFiles, notStagedModifiedFiles, notStagedDeletedFiles, untrackedFiles, runResult, lines, lineIndex, line, onBranchMatch, detachedHeadMatch, remoteBranchMatch, modifiedMatch, modifiedFilePath, deletedMatch, deletedFilePath, modifiedMatch, modifiedFilePath, deletedMatch, deletedFilePath, resolveUntrackedFilePath, modifiedFiles;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
folderPath = options.executionFolderPath || this.options.executionFolderPath || process.cwd();
parseState = "CurrentBranch";
hasUncommittedChanges = false;
stagedModifiedFiles = [];
stagedDeletedFiles = [];
notStagedModifiedFiles = [];
notStagedDeletedFiles = [];
untrackedFiles = [];
return [4 /*yield*/, this.run(["status"], options)];
case 1:
runResult = _a.sent();
lines = common_1.getLines(runResult.stdout);
lineIndex = 0;
while (lineIndex < lines.length) {
line = lines[lineIndex].trim();
if (!line) {
++lineIndex;
}
else {
switch (parseState) {
case "CurrentBranch":
onBranchMatch = line.match(onBranchRegExp);
if (onBranchMatch) {
localBranch = onBranchMatch[1];
}
else {
detachedHeadMatch = line.match(statusDetachedHeadRegExp);
if (detachedHeadMatch) {
localBranch = detachedHeadMatch[1];
}
}
parseState = "RemoteBranch";
++lineIndex;
break;
case "RemoteBranch":
remoteBranchMatch = line.match(/.*\'(.*)\'.*/);
if (remoteBranchMatch) {
remoteBranch = remoteBranchMatch[1];
++lineIndex;
}
parseState = "Changes";
break;
case "Changes":
hasUncommittedChanges = !line.match(/nothing to commit, working tree clean/i);
if (hasUncommittedChanges) {
if (line.match(/Changes to be committed:/i)) {
parseState = "ChangesToBeCommitted";
}
if (isChangesNotStagedForCommitHeader(line)) {
parseState = "ChangesNotStagedForCommit";
}
else if (isUntrackedFilesHeader(line)) {
parseState = "UntrackedFiles";
}
}
++lineIndex;
break;
case "ChangesToBeCommitted":
if (!line.match(/\(use "git reset HEAD <file>..." to unstage\)/i)) {
modifiedMatch = line.match(/modified:(.*)/i);
if (modifiedMatch) {
modifiedFilePath = path_1.joinPath(folderPath, modifiedMatch[1].trim());
stagedModifiedFiles.push(modifiedFilePath);
}
else {
deletedMatch = line.match(/deleted:(.*)/i);
if (deletedMatch) {
deletedFilePath = path_1.joinPath(folderPath, deletedMatch[1].trim());
stagedDeletedFiles.push(deletedFilePath);
}
else if (isChangesNotStagedForCommitHeader(line)) {
parseState = "ChangesNotStagedForCommit";
}
else if (isUntrackedFilesHeader(line)) {
parseState = "UntrackedFiles";
}
}
}
++lineIndex;
break;
case "ChangesNotStagedForCommit":
if (!line.match(/\(use "git add <file>..." to update what will be committed\)/i) && !line.match(/\(use "git checkout -- <file>..." to discard changes in working directory\)/i)) {
modifiedMatch = line.match(/modified:(.*)/i);
if (modifiedMatch) {
modifiedFilePath = path_1.joinPath(folderPath, modifiedMatch[1].trim());
notStagedModifiedFiles.push(modifiedFilePath);
}
else {
deletedMatch = line.match(/deleted:(.*)/i);
if (deletedMatch) {
deletedFilePath = path_1.joinPath(folderPath, deletedMatch[1].trim());
notStagedDeletedFiles.push(deletedFilePath);
}
else if (isUntrackedFilesHeader(line)) {
parseState = "UntrackedFiles";
}
}
}
++lineIndex;
break;
case "UntrackedFiles":
if (!line.match(/\(use "git add <file>..." to include in what will be committed\)/i) &&
!line.match(/nothing added to commit but untracked files present \(use "git add" to track\)/i) &&
!line.match(/no changes added to commit \(use \"git add\" and\/or \"git commit -a\"\)/i)) {
resolveUntrackedFilePath = path_1.joinPath(folderPath, line);
untrackedFiles.push(resolveUntrackedFilePath);
}
++lineIndex;
break;
}
}
}
modifiedFiles = [];
if (hasUncommittedChanges) {
modifiedFiles.push.apply(modifiedFiles, tslib_1.__spread(stagedModifiedFiles, stagedDeletedFiles, notStagedModifiedFiles, notStagedDeletedFiles, untrackedFiles));
}
return [2 /*return*/, tslib_1.__assign(tslib_1.__assign({}, runResult), { localBranch: localBranch,
remoteBranch: remoteBranch,
hasUncommittedChanges: hasUncommittedChanges,
modifiedFiles: modifiedFiles,
stagedModifiedFiles: stagedModifiedFiles,
stagedDeletedFiles: stagedDeletedFiles,
notStagedModifiedFiles: notStagedModifiedFiles,
notStagedDeletedFiles: notStagedDeletedFiles,
untrackedFiles: untrackedFiles })];
}
});
});
};
/**
* Get the configuration value for the provided configuration value name.
* @param configurationValueName The name of the configuration value to get.
* @param options The options that can configure how the command will run.
*/
ExecutableGit.prototype.getConfigurationValue = function (configurationValueName, options) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.run(["config", "--get", configurationValueName], options)];
case 1:
result = _a.sent();
if (result.exitCode === 0 && result.stdout) {
result.configurationValue = result.stdout;
}
return [2 /*return*/, result];
}
});
});
};
/**
* Get the URL of the current repository.
* @param options The options that can configure how the command will run.
*/
ExecutableGit.prototype.getRepositoryUrl = function (options) {
if (options === void 0) { options = {}; }
return tslib_1.__awaiter(this, void 0, void 0, function () {
var result;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.getConfigurationValue("remote.origin.url", options)];
case 1:
result = (_a.sent()).configurationValue;
if (result) {
result = result.trim();
}
return [2 /*return*/, result];
}
});
});
};
/**
* Reset all the file.
* @param options The options that can configure how the command will run.
*/
ExecutableGit.prototype.resetAll = function (options) {
if (options === void 0) { options = {}; }
var args = ["reset"];
if (options.hard) {
args.push("--hard");
}
if (options.soft) {
args.push("--soft");
}
if (options.target) {
args.push(options.target);
}
else if (!options.hard && !options.soft) {
args.push("*");
}
return this.run(args, options);
};
/**
* Add the provided remote URL to this local repository's list of remote repositories using the
* provided remoteName.
* @param remoteName The name/reference that will be used to refer to the remote repository.
* @param remoteUrl The URL of the remote repository.
* @param options Options that can be used to modify the way that this operation is run.
*/
ExecutableGit.prototype.addRemote = function (remoteName, remoteUrl, options) {
if (options === void