Skip to content

Various fixes for git pull #476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow changing namespaces and IPM package context from web UI (#280)
- Support for editing repo from filesystem perspective via web application (#464)
- Support for downloading a VSCode workspace file from web UI
- IncrementalLoad pull event handler will update the running production, if any (#473)

### Fixed
- Instance wide settings are placed in proper global (#444)
- Avoid delay/errors in loading interop JS when there is a URL prefix (e.g., instance name in multi-instance webserver configuration)
- Added proper JS escaping in sync output
- Added support to switch branch in basic mode from menu (#451)
- Pull event handler will not fail when change set includes unmapped files (#453)
- Pull event handler will attempt compile even if there are failures to load (#457)
- Improved logging in preview and when errors occur via WebSocket commands (#467)
- Fixed pull event handler handling of extremely long class names from diff (#467)

## [2.4.1] - 2024-08-02

Expand Down
18 changes: 11 additions & 7 deletions cls/SourceControl/Git/PullEventHandler/IncrementalLoad.cls
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,38 @@ Parameter DESCRIPTION = "Performs an incremental load and compile of all changes

Method OnPull() As %Status
{
set loadSC = $$$OK
set sc = $$$OK
set nFiles = 0

for i=1:1:$get(..ModifiedFiles){
set internalName = ..ModifiedFiles(i).internalName
if ((internalName = "") && (..ModifiedFiles(i).changeType '= "D")) {
write !, ..ModifiedFiles(i).externalName, " was not imported into the database and will not be compiled. "
} elseif (..ModifiedFiles(i).changeType = "D") {
set sc = ..DeleteFile(internalName)
if sc {
set delSC = ..DeleteFile(internalName)
if delSC {
write !, ..ModifiedFiles(i).externalName, " was deleted."
} else {
write !, "WARNING: Deletion of ", ..ModifiedFiles(i).externalName, " failed."
}
} else {
set compilelist(internalName) = ""
set nFiles = nFiles + 1
set loadSC = $$$ADDSC(loadSC,##class(SourceControl.Git.Utils).ImportItem(internalName, 1))
$$$ThrowOnError(loadSC)
set sc = $$$ADDSC(sc,##class(SourceControl.Git.Utils).ImportItem(internalName, 1))
}
}

if (nFiles = 0) {
write !, "Nothing to compile."
quit $$$OK
}
quit $system.OBJ.CompileList(.compilelist, "ck")
set sc = $$$ADDSC(sc,$system.OBJ.CompileList(.compilelist, "ck"))
if $$$comClassDefined("Ens.Director") && ##class(Ens.Director).IsProductionRunning() {
write !,"Updating production... "
set sc = $$$ADDSC(sc,##class(Ens.Director).UpdateProduction())
write "done."
}
quit sc
}

Method DeleteFile(item As %String) As %Status
Expand Down Expand Up @@ -71,4 +76,3 @@ Method DeleteFile(item As %String) As %Status
}

}

62 changes: 53 additions & 9 deletions cls/SourceControl/Git/Utils.cls
Original file line number Diff line number Diff line change
Expand Up @@ -546,14 +546,19 @@ ClassMethod GetCurrentBranch() As %String

ClassMethod Pull(remote As %String = "origin") As %Status
{
New %gitSCOutputFlag
Set %gitSCOutputFlag = 1
#define Force 1
do ##class(SourceControl.Git.Utils).RunGitCommandWithInput("branch",,.errStream,.outStream,"--show-current")
set branchName = outStream.ReadLine(outStream.Size)
write !, "Pulling from branch: ", branchName
kill errStream, outStream
set returnCode = ..RunGitWithArgs(.errStream, .outStream, "pull", remote, branchName)

w !, "Pull ran with return code: " _ returnCode
write !
do outStream.OutputToDevice()
write !
do errStream.OutputToDevice()
write !, "Pull ran with return code: " _ returnCode
quit $$$OK
}

Expand Down Expand Up @@ -626,10 +631,13 @@ ClassMethod ExternalName(InternalName As %String, ByRef MappingExists As %Boolea

ClassMethod AddToServerSideSourceControl(InternalName As %String) As %Status
{
#dim i as %Integer
#dim i as %Integer
#dim ec as %Status = $$$OK
for i = 1:1:$length(InternalName, ",") {
#dim item as %String = ..NormalizeExtension($piece(InternalName, ",", i))
if (item = "") {
continue
}
set @..#Storage@("items", item) = ""
#dim sc as %Status = ..ImportItem(item, 1)
if 'sc {
Expand Down Expand Up @@ -1791,12 +1799,16 @@ ClassMethod RunGitCommandWithInput(command As %String, inFile As %String = "", O
}
}
} elseif syncIrisWithCommand {
do ..PrintStreams(errStream, outStream)
if '$data(%gitSCOutputFlag)#2 {
do ..PrintStreams(errStream, outStream)
}
set buffer = ##class(SourceControl.Git.Util.Buffer).%New()
do buffer.BeginCaptureOutput()
set st = ..SyncIrisWithRepoThroughCommand(.outStream)
set out = ##class(%Stream.GlobalCharacter).%New()
do buffer.EndCaptureOutput(.out)
do outStream.MoveToEnd()
do errStream.MoveToEnd()
if $$$ISOK(st) {
while 'out.AtEnd {
do outStream.WriteLine(out.ReadLine())
Expand Down Expand Up @@ -1836,11 +1848,31 @@ ClassMethod SyncIrisWithRepoThroughCommand(ByRef outStream) As %Status
}
} elseif (line [ "|") {
set externalName = $zstrip($piece(line,"|",1),"<>W")
set modification = ##class(SourceControl.Git.Modification).%New()
set modification.changeType = "C"
set modification.internalName = ##class(SourceControl.Git.Utils).NameToInternalName(externalName,,0)
set modification.externalName = externalName
set files($i(files)) = modification
if $Extract(externalName,1,3) = "..." {
// For extremely long file names, git may truncate the path.
// Simplifying assumption: this is a class, because nothing else would have that long a name.
// In other cases, we'll just end up logging the invalid externalName.
if $Piece(externalName,".",*) = "cls" {
set possibleClasses = ..ExpandClasses(externalName)
set pointer = 0
while $ListNext(possibleClasses,pointer,class) {
set modification = ##class(SourceControl.Git.Modification).%New()
set modification.changeType = "C"
set modification.internalName = class_".CLS"
set modification.externalName = ..ExternalName(modification.internalName)
set files($i(files)) = modification
}
} else {
write !,"WARNING: unable to translate external name ",externalName
continue
}
} else {
set modification = ##class(SourceControl.Git.Modification).%New()
set modification.changeType = "C"
set modification.internalName = ##class(SourceControl.Git.Utils).NameToInternalName(externalName,,0)
set modification.externalName = externalName
set files($i(files)) = modification
}
}
}

Expand All @@ -1858,6 +1890,18 @@ ClassMethod SyncIrisWithRepoThroughCommand(ByRef outStream) As %Status
quit ##class(SourceControl.Git.PullEventHandler).ForModifications(.files)
}

ClassMethod ExpandClasses(externalName As %String) As %List
{
set internalName = $Piece(externalName,".",1,*-1)
set internalName = $Extract(internalName,4,*)
set internalName = $Translate(internalName,"/\%",".."_..PercentClassReplace())
&sql(select %DLIST(Name) into :classes from %Dictionary.ClassDefinition where Name like '%'||:internalName)
if (SQLCODE < 0) {
Throw ##class(%Exception.SQL).CreateFromSQLCODE(SQLCODE,%msg)
}
quit classes
}

ClassMethod ParseDiffStream(stream As %Stream.Object, verbose As %Boolean = 1, Output files)
{
kill files
Expand Down
74 changes: 40 additions & 34 deletions cls/_zpkg/isc/sc/git/Socket.cls
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,40 @@ Property OriginalDevice;

ClassMethod Run()
{
If %request.Get("method") = "preview" {
set branchName = ##class(SourceControl.Git.Utils).GetCurrentBranch()
do ##class(SourceControl.Git.Utils).RunGitWithArgs(.errStream, .outStream, "fetch")
kill errStream, outStream
do ##class(SourceControl.Git.Utils).RunGitWithArgs(.errStream, .outStream, "log", "HEAD..origin", "--name-status")
do ##class(SourceControl.Git.Utils).PrintStreams(errStream, outStream)
} ElseIf %request.Get("method") = "pull" {
Do ##class(SourceControl.Git.API).Pull()
} ElseIf %request.Get("method") = "init" {
Do ##class(SourceControl.Git.Utils).Init()
If %request.Get("method") = "preview" {
Set branchName = ##class(SourceControl.Git.Utils).GetCurrentBranch()
Write !,"Current branch: ",branchName
Do ##class(SourceControl.Git.Utils).RunGitWithArgs(.errStream, .outStream, "fetch")
Kill errStream, outStream
Do ##class(SourceControl.Git.Utils).RunGitWithArgs(.errStream, .outStream, "log", "HEAD..origin", "--name-status")
Do ##class(SourceControl.Git.Utils).PrintStreams(errStream, outStream)
If (outStream.Size = 0) && (errStream.Size = 0) {
Write !,"Already up to date."
}
} ElseIf %request.Get("method") = "pull" {
Do ##class(SourceControl.Git.API).Pull()
} ElseIf %request.Get("method") = "init" {
Do ##class(SourceControl.Git.Utils).Init()
Write !,"Done."
} ElseIf %request.Get("method") = "clone" {
Set remote = %request.Get("remote")
Do ##class(SourceControl.Git.Utils).Clone(remote)
} ElseIf %request.Get("method") = "clone" {
Set remote = %request.Get("remote")
Do ##class(SourceControl.Git.Utils).Clone(remote)
Write !,"Done."
} ElseIf %request.Get("method") = "sshkeygen" {
Do ##class(SourceControl.Git.Utils).GenerateSSHKeyPair()
} ElseIf %request.Get("method") = "sshkeygen" {
Do ##class(SourceControl.Git.Utils).GenerateSSHKeyPair()
Write !,"Done."
} Else {
Write !!,"Invalid method selected.",!!
}
} Else {
Write !!,"Invalid method selected.",!!
}
}

Method OnPreServer() As %Status
{
If '$System.Security.Check("%Development","USE") {
Quit $$$ERROR($$$AccessDenied)
}
If '$SYSTEM.Security.Check("%Development","USE") {
Quit $$$ERROR($$$AccessDenied)
}
If (%request.Get("$NAMESPACE") '= "") {
Set $Namespace = %request.Get("$NAMESPACE")
Set $NAMESPACE = %request.Get("$NAMESPACE")
}
Quit $$$OK
}
Expand All @@ -56,9 +60,11 @@ Method Server() As %Status

// In subclasses: Do Something that produces output to the current device.
// It will be sent back to the client, Base64-encoded, over the web socket connection.
Do ..Run()
Do ..Run()
} Catch e {
Do e.Log()
Write !,"An error occurred. More details can be found in the Application error log."
Write !,$SYSTEM.Status.GetErrorText(e.AsStatus())
Set tSC = e.AsStatus()
}

Expand All @@ -77,7 +83,7 @@ Method StartOutputCapture() [ ProcedureBlock = 0 ]
#dim tSC As %Status = $$$OK
#dim tRedirected As %Boolean = 0
Try {
Set %server = $this
Set %server = $THIS
Set ..OriginallyRedirected = 0
Set ..OriginalMnemonic = ""
Set ..OriginalDevice = $IO
Expand Down Expand Up @@ -107,27 +113,27 @@ Method StartOutputCapture() [ ProcedureBlock = 0 ]
#; Public entry points for I/O redirection
wstr(s) Do write(s)
Quit
wchr(a) Do write($char(a))
wchr(a) Do write($CHAR(a))
Quit
wnl Do write($$$EOL)
Set $X = 0
Quit
wff Do wnl Quit
wtab(n) New tTab
Set tTab = $J("",$S(n>$X:n-$X,1:0))
Set tTab = $JUSTIFY("",$SELECT(n>$X:n-$X,1:0))
Do write(tTab)
Quit
write(str)
// If there was an argumentless NEW, cache the output and leave it at that.
// This will be output next time there's a write with %server in scope.
If '$IsObject($Get(%server)) {
Set ^||OutputCapture.Cache($i(^||OutputCapture.Cache)) = str
If '$ISOBJECT($GET(%server)) {
Set ^||OutputCapture.Cache($INCREMENT(^||OutputCapture.Cache)) = str
Quit
}

// Restore previous I/O redirection settings.
New tOriginalDevice,i
Set tOriginalDevice = $io
Set tOriginalDevice = $IO
If ##class(%Library.Device).ReDirectIO(0) {
Use tOriginalDevice
}
Expand All @@ -138,8 +144,8 @@ write(str)
Do ##class(%Library.Device).ReDirectIO(1)
}

If $Data(^||OutputCapture.Cache) {
For i=1:1:$Get(^||OutputCapture.Cache) {
If $DATA(^||OutputCapture.Cache) {
For i=1:1:$GET(^||OutputCapture.Cache) {
Do reallywrite(^||OutputCapture.Cache(i))
}
Kill ^||OutputCapture.Cache
Expand All @@ -155,7 +161,7 @@ write(str)
reallywrite(pString)
New tMsg
Set tMsg = {"content":(pString)} // This is handy because it handles escaping of newlines, etc.
Do %server.Write($System.Encryption.Base64Encode(tMsg.%ToJSON()))
Do %server.Write($SYSTEM.Encryption.Base64Encode(tMsg.%ToJSON()))
Quit
rstr(len, time) Quit ""
rchr(time) Quit ""
Expand All @@ -179,7 +185,7 @@ Method EndOutputCapture()

Method SendJSON(pObject As %DynamicAbstractObject)
{
Set tOriginalDevice = $io
Set tOriginalDevice = $IO
If ##class(%Library.Device).ReDirectIO(0) {
Use tOriginalDevice
}
Expand All @@ -189,7 +195,7 @@ Method SendJSON(pObject As %DynamicAbstractObject)
If ..OriginallyRedirected {
Do ##class(%Library.Device).ReDirectIO(1)
}
Do ..Write($System.Encryption.Base64Encode(pObject.%ToJSON()))
Do ..Write($SYSTEM.Encryption.Base64Encode(pObject.%ToJSON()))
Do ##class(%Library.Device).ReDirectIO(1)
Use tOriginalDevice::("^"_$ZNAME)
}
Expand Down
Loading