UNPKG

@ts-common/azure-js-dev-tools

Version:

Developer dependencies for TypeScript related projects

1,035 lines 60.9 kB
"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