Skip to content
Open
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- #961: Adding creation of a lock file for a module by using the `-create-lockfile` flag on install.
- #959: In ORAS repos, external name can now be used interchangeably with (default) name for `install` and `update`, i.e. a module published with its (default) name can be installed using its external name.
- #951: The `unpublish` command will skip user confirmation prompt if the `-force` flag is provided.
- #992: Implement automatic history purge logic

### Changed
- #316: All parameters, except developer mode, included with a `load`, `install` or `update` command will be propagated to dependencies
Expand Down
38 changes: 38 additions & 0 deletions src/cls/IPM/General/History.cls
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,44 @@ ClassMethod DeleteHistory(ByRef filter) As %Integer
quit rs.%ROWCOUNT
}

/// Automatically purge old history based on retention settings
ClassMethod AutoPurgeOldHistory() As %Status
{
set sc = $$$OK
if ..GetHistoryLastPurge() = +$horolog {
quit sc
}
set retainDays = ##class(%IPM.Repo.UniversalSettings).GetHistoryRetain()
if +retainDays <=0 {
quit sc
}
set cutoffDate = $system.SQL.Functions.DATEADD("d", -retainDays, +$horolog)
set filter("TimeStart") = "<='" _cutoffDate_"'"
try {
set count = ..DeleteHistoryGlobally(.filter, 0)
do ..SetHistoryLastPurge()
} catch ex {
set sc = ex.AsStatus()
}
return sc
}

ClassMethod SetHistoryLastPurge()
{
new $namespace
set index = ##class(%IPM.Repo.UniversalSettings).#HistoryRetain
set $namespace = "%SYS"
set ^IPM.settings(index, "lastPurge") = +$horolog
}

ClassMethod GetHistoryLastPurge() As %String
{
new $namespace
set index = ##class(%IPM.Repo.UniversalSettings).#HistoryRetain
set $namespace = "%SYS"
return $get(^IPM.settings(index, "lastPurge"))
}

ClassMethod DeleteHistoryGlobally(
ByRef filter,
verbose As %Boolean = 0) As %Integer
Expand Down
8 changes: 7 additions & 1 deletion src/cls/IPM/Main.cls
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,9 @@ generate /my/path -export 00000,PacketName2,IgnorePacket2^00000,PacketName3,Igno
<example description="Show only installation history of package &quot;zpip&quot; in all namespaces ">history find -globally -Daction=install -Dpackage=zpip</example>
<example description="Delete all histories in the namespace">history delete -confirm</example>
<example description="Show details of history item with ID 3 and information for each undergone lifecyle phase">history details 3 -phases</example>
<example description="Enable history auto-purge. Example: config set HistoryRetain 30.">config set HistoryRetain "days" </example>
<example description="Disable history auto-purge">config set HistoryRetain 0</example>
<example description="Display the current history retention setting.">config get HistoryRetain</example>
</command>

</commands>
Expand All @@ -807,7 +810,10 @@ ClassMethod Shell(
pTerminateOnError As %Boolean = 0,
pHaltOnComplete As %Boolean = 0) As %Status
{
set tSC = $$$OK
set tSC = ##class(%IPM.General.History).AutoPurgeOldHistory()
if $$$ISERR(tSC) {
return tSC
}
do ..ShellInternal(pCommand,.tException)
if $isobject(tException) {
if pTerminateOnError {
Expand Down
11 changes: 10 additions & 1 deletion src/cls/IPM/Repo/UniversalSettings.cls
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ Parameter UseStandalonePip = "UseStandalonePip";
/// Default value is 0, where 1.0.0-anystring is considered a pre-release of 1.0.0, hence 1.0.0-anystring < 1.0.0
Parameter SemVerPostRelease = "SemVerPostRelease";

Parameter CONFIGURABLE = "trackingId,analytics,ColorScheme,TerminalPrompt,PublishTimeout,PipCaller,UseStandalonePip,SemVerPostRelease,DefaultLogEntryLimit";
/// Configuration setting name used to determine the number of days
/// to retain IPM history records before they are eligible for cleanup.
Parameter HistoryRetain = "history_retain";

Parameter CONFIGURABLE = "trackingId,analytics,ColorScheme,TerminalPrompt,PublishTimeout,PipCaller,UseStandalonePip,SemVerPostRelease,DefaultLogEntryLimit,HistoryRetain";

/// Returns configArray, that includes all configurable settings
ClassMethod GetAll(Output configArray) As %Status
Expand Down Expand Up @@ -181,4 +185,9 @@ ClassMethod SetAnalyticsAvailable(
return ..SetValue(..#analytics, +val, overwrite)
}

ClassMethod GetHistoryRetain() As %Integer
{
return ..GetValue(..#HistoryRetain)
}

}
28 changes: 26 additions & 2 deletions tests/unit_tests/Test/PM/Unit/CLI.cls
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,11 @@ Method CompareModifiers(
}
}

Method RunCommand(pCommand As %String)
Method RunCommand(pCommand As %String) As %Status
{
do ##class(%IPM.Main).Shell(pCommand)
set status = ##class(%IPM.Main).Shell(pCommand)
do $$$LogMessage("Run command: "_pCommand)
return status
}

Method AssertNoException(pCommand As %String)
Expand Down Expand Up @@ -313,4 +314,27 @@ Method TestListPython() As %Status
quit sc
}

Method TestAutoPurgeOldHistory() As %Status
{
set status = ..RunCommand("config set HistoryRetain 30")
do $$$AssertStatusOK(status, "Config set executed successfully")

set status = ..RunCommand("config get HistoryRetain")
do $$$AssertStatusOK(status, "Config get executed successfully")

do $$$LogMessage("Update HistoryRetain from 30 days to 1 day")
set status = ..RunCommand("config set HistoryRetain 1")
do $$$AssertStatusOK(status, "HistoryRetain is changed from 30 days to 1 day successfully")

do $$$LogMessage("Purging old history entries older than 1 day")
set status = ##class(%IPM.General.History).AutoPurgeOldHistory()
do $$$AssertStatusOK(status, "AutoPurgeOldHistory executed successfully")

set afterPurge = ##class(%IPM.General.History).GetHistoryLastPurge()
do $$$LogMessage("After purge timestamp: "_afterPurge)
do $$$LogMessage("reset set the HistoryRetain to default value by deleting the config")
set status = ..RunCommand("config delete HistoryRetain")
do $$$AssertStatusOK(status, "Config delete executed successfully")
}

}