Skip to content
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Fixed
- Fixed minor issues in Studio UI (#641)

### Fixed
- Fix "Max $ZF String" error when committing lots of files (#617)

## [2.7.1] - 2024-11-13

### Fixed
Expand Down
76 changes: 74 additions & 2 deletions cls/SourceControl/Git/Utils.cls
Original file line number Diff line number Diff line change
Expand Up @@ -3031,8 +3031,7 @@ ClassMethod SetConfiguredRemote(url) As %String
quit output
}

// Returns true if the current branch is the default merge branch and we are in basic mode

/// Returns true if the current branch is the default merge branch and we are in basic mode
ClassMethod InDefaultBranchBasicMode() As %Boolean
{
set basicMode = ..BasicMode()
Expand All @@ -3043,4 +3042,77 @@ ClassMethod InDefaultBranchBasicMode() As %Boolean
quit 0
}

/// Runs the commit on the specified files (unstaging and restaging currently staged files)
ClassMethod RunGitCommandReStage(Output outStream, Output errStream, command As %String, ByRef fileList As %Library.DynamicArray, args...) As %Integer
{
set sc = $$$OK
LOCK +^gitCommit
// Unstage and save all currently staged files
set sc = ..GitUnstage(.unstaged)

// Stage all files
set iterator = fileList.%GetIterator()
while iterator.%GetNext(.key, .value) {
do ..RunGitCommand("add",.err, .out, value)
}

// Run the git command
set returnCode = ..RunGitWithArgs(.errStream, .outStream, command, args...)

// Restage files
do ..GitStage(.unstaged)
LOCK -^gitCommit
return returnCode
}

ClassMethod GitStage(ByRef files As %Library.DynamicObject) As %Status
{
set staged = files.%Get("staged")
set tracked = files.%Get("tracked")

set iterator = staged.%GetIterator()
while iterator.%GetNext(.key, .value) {
do ..RunGitCommand("add",.errStream,.outStream, value)
}

set iterator = tracked.%GetIterator()
while iterator.%GetNext(.key, .value) {
do ..RunGitCommand("add",.errStream, .outStream, value, "--intent-to-add")
}
return $$$OK
}

/// Unstages all currently staged files and returns them in the array
ClassMethod GitUnstage(Output output As %Library.DynamicObject) As %Status
{
set stagedList = []
set trackedList = []

do ..RunGitCommandWithInput("status",, .errStream, .outStream, "--porcelain")
set line = outStream.ReadLine()
// Read through output
while (line'="") {
set staged = 0
set tracked = 0
set filename = $piece(line, " ", *-0)
if ($extract(line,1,1) '= " ") && ($extract(line,1,1) '= "?") {
set staged = 1
}
elseif ($extract(line,2,2) = "A") {
set tracked = 1
}
if staged {
do stagedList.%Push(filename)
do ..RunGitCommand("reset", .errStream, .out, filename)
} elseif tracked {
do trackedList.%Push(filename)
do ..RunGitCommand("reset",.errStream,.out, filename)
}
set line = outStream.ReadLine()
}

set output = {"staged": (stagedList), "tracked": (trackedList)}
return $$$OK
}

}
51 changes: 50 additions & 1 deletion cls/SourceControl/Git/WebUIDriver.cls
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
do %request.Set("EXPIRES",0)
do ##class(%CSP.StreamServer).OnPreHTTP() // Need to call this to set headers properly
set %stream = 1 // Leak this to webuidriver.csp
} elseif $match(pathStart,"git-command|git|dirname|hostname|viewonly|discarded-states|restore-discarded|contexts|create-branch") {
} elseif $match(pathStart,"git-command|git|dirname|hostname|viewonly|discarded-states|restore-discarded|contexts|create-branch|git-command-unstage") {
if (%request.Method = "GET") {
set %data = ##class(%Stream.TmpCharacter).%New()
// Things not handled from Python backend:
Expand Down Expand Up @@ -344,6 +344,55 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
}
set handled = 1
}
} elseif (pathStart = "git-command-unstage") {
set stringBody = ""
while '%request.Content.AtEnd {
set stringBody = stringBody _ %request.Content.Read()
}
set stringBody = $zconvert(stringBody,"I","UTF8")
set requestBody = ##class(%Library.DynamicObject).%FromJSON(stringBody)

set flags = requestBody.flags
if (flags '= "") {
set flaglist = $listfromstring(flags,",")
for i=1:1:$listlength(flaglist) {
set flag = $listget(flaglist,i)
set args($increment(args)) = flag
}
}
set message = requestBody.message
if (message '= "") {
set args($increment(args)) = "-m"
set args($increment(args)) = message
}
set details = requestBody.details
if (details '= "") {
set args($increment(args)) = "-m"
set args($increment(args)) = details
}
set command = requestBody.command
set files = ##class(%Library.DynamicObject).%FromJSON(requestBody.files)
set files = files.files

set returnCode = ##class(SourceControl.Git.Utils).RunGitCommandReStage(.outStream,.errStream,command,.files,args...)

set %data = ##class(%Stream.TmpCharacter).%New()
set changeTerminators = (%data.LineTerminator '= $char(13,10))
set %data.LineTerminator = $char(13,10) // For the CSPGateway.
while 'outStream.AtEnd {
do %data.WriteLine(outStream.ReadLine())
}

set nLines = 0
while 'errStream.AtEnd {
do %data.WriteLine(errStream.ReadLine())
set:changeTerminators nLines = nLines + 1
}

do %data.WriteLine("Git-Stderr-Length: " _ (errStream.Size + nLines))
do %data.Write("Git-Return-Code: " _ returnCode) // No ending newline expected
do %data.Rewind()
set handled = 1
}
}
}
Expand Down
163 changes: 109 additions & 54 deletions git-webui/release/share/git-webui/webui/js/git-webui.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,45 @@ webui.parseGitResponse = function(data) {
};
}

webui.processGitResponse = function(data, command, callback) {
var result = webui.parseGitResponse(data);
var rcode = result.rcode;
var output = result.output;
var message = result.message;

if (rcode == 0) {
if (callback) {
callback(output);
}
// Return code is 0 but there is stderr output: this is a warning message
if (message.length > 0) {
if(warningCallback) {
warningCallback(message);
} else {
webui.showWarning(message);
}
}
} else {
var displayMessage = ""
if(output.length > 0){
displayMessage += (output+"\n");
}
if(message.length > 0){
displayMessage += message;
}
if(displayMessage.length > 0){
if(displayMessage.indexOf("self.document.Login") != -1){
location.reload();
return false;
}
webui.showError(displayMessage);
//}
} else {
webui.showError("The command <pre>"+command.join(" ")+"</pre> failed because of an unknown reason. Returned response: \n\n"+data)
}
}
}

webui.git_command = function(command, callback) {
$.ajax({
url: "git-command",
Expand All @@ -155,45 +194,7 @@ webui.git_command = function(command, callback) {
command: command
}),
success: function(data) {
var result = webui.parseGitResponse(data);
var rcode = result.rcode;
var output = result.output;
var message = result.message;

if (rcode == 0) {
if (callback) {
callback(output);
}
// Return code is 0 but there is stderr output: this is a warning message
if (message.length > 0) {
if(warningCallback) {
warningCallback(message);
} else {
webui.showWarning(message);
}
}
} else {
var displayMessage = ""
if(output.length > 0){
displayMessage += (output+"\n");
}
if(message.length > 0){
displayMessage += message;
}
if(displayMessage.length > 0){
// if(errorCallback) {
// errorCallback(displayMessage);
// } else{
if(displayMessage.indexOf("self.document.Login") != -1){
location.reload();
return false;
}
webui.showError(displayMessage);
//}
} else {
webui.showError("The command <pre>"+command.join(" ")+"</pre> failed because of an unknown reason. Returned response: \n\n"+data)
}
}
webui.processGitResponse(data, command, callback);
},
error: function(data) {
var trimmedData = data.replace(/(\r\n)/gm, "\n");
Expand Down Expand Up @@ -3012,34 +3013,88 @@ webui.NewChangedFilesView = function(workspaceView) {
}

self.amend = function(message, details) {

if (self.commitMsgEmpty()) {
webui.git_command(["add"].concat(selectedItems));
webui.git_command(['commit', '--amend', '--no-edit', '--'].concat(selectedItems), function(output) {
webui.showSuccess(output);
workspaceView.update();
$.ajax({
url: "git-command-unstage",
type: "POST",
contentType: 'application/json',
data: JSON.stringify({
command: "commit",
message: message,
details: details,
flags: "--amend,--no-edit",
files: JSON.stringify({
files: selectedItems
})
}),
success: function(data) {
webui.processGitResponse(data, ["commit", "--amend","--no-edit","-m",message,"-m",details], function(output) {
webui.showSuccess(output);
workspaceView.update();
});
},
error: function(data) {
var trimmedData = data.replace(/(\r\n)/gm, "\n");
webui.showError(trimmedData);
},
});
} else if (selectedItems.length != 0) {
webui.git_command(["add"].concat(selectedItems));
webui.git_command(['commit', '--amend', '-m', message, '-m', details, '--'].concat(selectedItems), function(output) {
webui.showSuccess(output);
workspaceView.update();
$.ajax({
url: "git-command-unstage",
type: "POST",
contentType: 'application/json',
data: JSON.stringify({
command: "commit",
message: message,
details: details,
flags: "--amend",
files:JSON.stringify({
files: selectedItems
})
}),
success: function(data) {
webui.processGitResponse(data, ["commit","--amend","-m",message,"-m",details], function(output) {
webui.showSuccess(output);
workspaceView.update();
});
},
error: function(data) {
var trimmedData = data.replace(/(\r\n)/gm, "\n");
webui.showError(trimmedData);
},
});
} else {
webui.git_command(['commit', '--amend', '--allow-empty', '-m', message, '-m', details], function(output) {
webui.showSuccess(output);
workspaceView.update();
});
}


}

self.commit = function(message, details) {
webui.git_command(["add"].concat(selectedItems));
webui.git_command(['commit', '-m', message, '-m', details, '--'].concat(selectedItems), function(output) {
webui.showSuccess(output);
workspaceView.update();
$.ajax({
url: "git-command-unstage",
type: "POST",
contentType: 'application/json',
data: JSON.stringify({
command: "commit",
message: message,
details: details,
files:JSON.stringify({
files: selectedItems
})
}),
success: function(data) {
webui.processGitResponse(data, ["commit","-m",message,"-m",details], function(output) {
webui.showSuccess(output);
workspaceView.update();
});

},
error: function(data) {
var trimmedData = data.replace(/(\r\n)/gm, "\n");
webui.showError(trimmedData);
},
});
}

Expand Down
Loading