Skip to content
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

Safeguard discard #459

Merged
merged 22 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.5.1] - Unreleased
## [2.6.0] - Unreleased

### Added
- Discards safeguarded by discard stash and warning modal (#455)

### Fixed
- Changed prompts in configure from 0/1 to no/yes (#461)
Expand Down
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/Build.cls
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,4 @@ ClassMethod BuildUIForDevMode(devMode As %Boolean, rootDirectory As %String)
write !, $zf(-100, "/SHELL", "npm", "run", "build", "--prefix", webUIDirectory)
}

}

}
1 change: 1 addition & 0 deletions cls/SourceControl/Git/Change.cls
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ ClassMethod AddDeletedToUncommitted(Filename, InternalName) As %Status
Quit ..SetUncommitted(Filename, "delete", InternalName, $USERNAME, "", 1, "", "", 0)
}

/// The Filename here is an ExternalName formatted name with the full file path
ClassMethod IsUncommitted(Filename, ByRef ID) As %Boolean
{
&SQL(SELECT ID INTO :ID FROM SourceControl_Git.Change WHERE ItemFile = :Filename AND Committed = '0')
Expand Down
138 changes: 138 additions & 0 deletions cls/SourceControl/Git/DiscardState.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
Class SourceControl.Git.DiscardState Extends (%Persistent, %JSON.Adaptor)
isc-etamarch marked this conversation as resolved.
Show resolved Hide resolved
{

Property FullExternalName As %String(MAXLEN = "") [ Required ];

Property Name As %String [ Required ];

Property Contents As %Stream.GlobalCharacter(LOCATION = "^DiscardStateContents");
isc-etamarch marked this conversation as resolved.
Show resolved Hide resolved

Property Username As %String [ Required ];

Property Branch As %String [ Required ];
isc-etamarch marked this conversation as resolved.
Show resolved Hide resolved

Property Timestamp As %TimeStamp [ Required ];

Property ExternalFile As %Boolean [ Required ];

Method RestoreToFileTree()
{
// Make sure directory for file exists
set dir = ##class(%File).GetDirectory(..FullExternalName)
if ('##class(%File).DirectoryExists(dir)) {
do ##class(%File).CreateDirectoryChain(dir)
}

// Recreate File
set fileStream = ##class(%Stream.FileCharacter).%New()
set fileStream.Filename = ..FullExternalName
$$$ThrowOnError(fileStream.CopyFrom(..Contents))
$$$ThrowOnError(fileStream.%Save())

// Add file to source-control / IRIS
if '..ExternalFile {
do ##class(SourceControl.Git.Utils).ImportItem(..Name, 1, 1)
isc-etamarch marked this conversation as resolved.
Show resolved Hide resolved
do ##class(SourceControl.Git.Utils).AddToServerSideSourceControl(..Name)
}

// Delete discard record
$$$ThrowOnError(..%DeleteId(..%Id()))
}

ClassMethod SaveDiscardState(InternalName As %String, name As %String) As %Status
{
set discardState = ..%New()

if (InternalName = "") {
// If not in IRIS
set externalName = ##class(%File).Construct($Get(^SYS("SourceControl","Git","settings","namespaceTemp")),name)
isc-etamarch marked this conversation as resolved.
Show resolved Hide resolved
set discardState.FullExternalName = externalName
set discardState.Name = name
set discardState.ExternalFile = 1
} else {
set discardState.FullExternalName = ##class(SourceControl.Git.Utils).FullExternalName(InternalName)
set discardState.Name = InternalName
set discardState.ExternalFile = 0
}
// Copy over file contents
set fileStream = ##class(%Stream.FileCharacter).%New()
set fileStream.Filename = discardState.FullExternalName
do fileStream.%Open()
do discardState.Contents.CopyFrom(fileStream)
do fileStream.%Close()

// Save extra information
set discardState.Username = $USERNAME
set discardState.Branch = ##class(SourceControl.Git.Utils).GetCurrentBranch()
set discardState.Timestamp = $zdatetime($horolog, 3)

set st = discardState.%Save()

quit st
}

ClassMethod DiscardStatesInBranch() As %DynamicArray
{
set currentBranch = ##class(SourceControl.Git.Utils).GetCurrentBranch()

set query = "SELECT ID FROM SourceControl_Git.DiscardState WHERE branch = ?"
isc-etamarch marked this conversation as resolved.
Show resolved Hide resolved
set statement = ##class(%SQL.Statement).%New()
set status = statement.%Prepare(query, 0)
$$$ThrowOnError(status)
set resultSet = statement.%Execute(currentBranch)
if (resultSet.%SQLCODE < 0) {
throw ##class(%Exception.SQL).CreateFromSQLCODE(resultSet.%SQLCODE,resultSet.%Message)
}

set discardStates = []
while resultSet.%Next() {
set discardState = ..%OpenId(resultSet.ID)
do discardState.%JSONExportToString(.JSONStr)
set discardStateObject = ##class(%DynamicAbstractObject).%FromJSON(JSONStr)
set discardStateObject.Id = resultSet.ID
do discardStates.%Push(discardStateObject)
}

quit discardStates
}

Storage Default
{
<Data name="DiscardStateDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>FullExternalName</Value>
</Value>
<Value name="3">
<Value>InternalName</Value>
</Value>
<Value name="4">
<Value>Contents</Value>
</Value>
<Value name="5">
<Value>Username</Value>
</Value>
<Value name="6">
<Value>Branch</Value>
</Value>
<Value name="7">
<Value>Timestamp</Value>
</Value>
<Value name="8">
<Value>Name</Value>
</Value>
<Value name="9">
<Value>ExternalFile</Value>
</Value>
</Data>
<DataLocation>^SourceControl22B9.DiscardStateD</DataLocation>
<DefaultData>DiscardStateDefaultData</DefaultData>
<IdLocation>^SourceControl22B9.DiscardStateD</IdLocation>
<IndexLocation>^SourceControl22B9.DiscardStateI</IndexLocation>
<StreamLocation>^SourceControl22B9.DiscardStateS</StreamLocation>
<Type>%Storage.Persistent</Type>
}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/File.cls
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,4 @@ Storage Default
<Type>%Storage.Persistent</Type>
}

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/Modification.cls
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ Property internalName As %String;
/// Type of change (A|C|D|M|R|T|U|X|B). See git diff documentation.
Property changeType As %String;

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/PackageManagerContext.cls
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,4 @@ Method Dump()
write !?4,"Git-enabled? ",$select(..IsInGitEnabledPackage:"Yes",1:"No"),!
}

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/PullEventHandler.cls
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,4 @@ ClassMethod ForInternalNames(InternalName As %String) As %Status
quit ..ForModifications(.files)
}

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/PullEventHandler/Default.cls
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ Method OnPull() As %Status
quit ##class(SourceControl.Git.PullEventHandler.IncrementalLoad)$this.OnPull()
}

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/PullEventHandler/PackageManager.cls
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ Method OnPull() As %Status
quit ##class(%ZPM.PackageManager).Shell("load "_..LocalRoot)
}

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/Settings.cls
Original file line number Diff line number Diff line change
Expand Up @@ -319,5 +319,4 @@ Method OnAfterConfigure() As %Boolean
}
}

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/Util/Buffer.cls
Original file line number Diff line number Diff line change
Expand Up @@ -280,5 +280,4 @@ Method UsePreviousDeviceAndSettings() [ Internal, Private ]
}
}

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/Util/ProductionConflictResolver.cls
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,4 @@ ClassMethod ResolveStream(stream As %Stream.Object)
Quit 1
}

}

}
3 changes: 1 addition & 2 deletions cls/SourceControl/Git/Util/Singleton.cls
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,4 @@ Method %RemoveOref() As %Status [ CodeMode = objectgenerator, Final, Internal, P
Quit $$$OK
}

}

}
1 change: 1 addition & 0 deletions cls/SourceControl/Git/Utils.cls
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ ClassMethod Init() As %Status
ClassMethod Revert(InternalName As %String) As %Status
{
set filename = ..FullExternalName(.InternalName)
do ##class(SourceControl.Git.DiscardState).SaveDiscardState(InternalName)
do ..RunGitCommand("checkout", .errStream, .outStream, "--", filename)
$$$QuitOnError(##class(SourceControl.Git.Change).RemoveUncommitted(filename,0,1))
$$$QuitOnError(##class(SourceControl.Git.Change).RefreshUncommitted(0,1,,1))
Expand Down
56 changes: 55 additions & 1 deletion cls/SourceControl/Git/WebUIDriver.cls
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,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|contexts") {
} elseif $match(pathStart,"git-command|git|dirname|hostname|viewonly|discarded-states|restore-discarded|contexts") {
if (%request.Method = "GET") {
set %data = ##class(%Stream.TmpCharacter).%New()
// Things not handled from Python backend:
Expand Down Expand Up @@ -137,6 +137,10 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
} elseif (pathStart = "dirname") {
do %data.Write(##class(SourceControl.Git.Utils).TempFolder())
set handled = 1
} elseif (pathStart = "discarded-states") {
set discardsInBranch = ##class(SourceControl.Git.DiscardState).DiscardStatesInBranch()
do %data.Write(discardsInBranch.%ToJSON())
isc-etamarch marked this conversation as resolved.
Show resolved Hide resolved
set handled = 1
} elseif (pathStart = "contexts") {
set contexts = ##class(SourceControl.Git.Utils).GetContexts()
do contexts.%ToJSON(%data)
Expand Down Expand Up @@ -228,6 +232,30 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
set requestBody = ##class(%Library.DynamicObject).%FromJSON(%request.Content)
set command = requestBody.command

set gitCmd = command.%Get(0)

set discardedFiles = []
if gitCmd = "restore" {
set iter = command.%GetIterator()
set isFile = 0
while iter.%GetNext(,.value) {
if isFile {
set internalName = ##class(SourceControl.Git.Utils).NameToInternalName(value)
do ##class(SourceControl.Git.DiscardState).SaveDiscardState(internalName, value)
if (internalName'="") {
set externalName = ##class(SourceControl.Git.Utils).FullExternalName(internalName)
$$$ThrowOnError(##class(SourceControl.Git.Change).RemoveUncommitted(externalName,0,1))
do discardedFiles.%Push(externalName)
}

}
if value = "--"{
set isFile = 1
}
}
}
$$$ThrowOnError(##class(SourceControl.Git.Change).RefreshUncommitted(0,1,,1))

set argsArr = ""
set argsArr($increment(argsArr)) = "color.ui=true"
set iterator = command.%GetIterator()
Expand Down Expand Up @@ -258,6 +286,32 @@ ClassMethod HandleRequest(pagePath As %String, InternalName As %String = "", Out
do %data.Write("Git-Return-Code: " _ returnCode) // No ending newline expected
do %data.Rewind()
set handled = 1

// Make sure discarded items are not in the uncommitted queue
set item = discardedFiles.%Pop()
while (item '= "") {
do ##class(SourceControl.Git.Change).RemoveUncommitted(item,0,1)
set item = discardedFiles.%Pop()
}

} elseif (pathStart = "restore-discarded") {
merge data = %request.Data
set fileId = data("file",1)

set %data = ##class(%Stream.TmpCharacter).%New()

set discardState = ##class(SourceControl.Git.DiscardState).%OpenId(fileId)
do ##class(SourceControl.Git.Change).RefreshUncommitted(,,,1)
if ##class(SourceControl.Git.Change).IsUncommitted(discardState.FullExternalName) {
do %data.WriteLine("Please commit changes to file before restoring discarded state")
} else {
do discardState.RestoreToFileTree()
do %data.WriteLine("Successfully restored discarded file state")
}

do %data.Rewind()
do ##class(SourceControl.Git.Change).RefreshUncommitted(,,,1)
set handled = 1
}
}
}
Expand Down
Loading
Loading