diff --git a/Test/private/MockCall_Project700.ps1 b/Test/private/MockCall_Project700.ps1 index 62079dd..8be1a0e 100644 --- a/Test/private/MockCall_Project700.ps1 +++ b/Test/private/MockCall_Project700.ps1 @@ -48,7 +48,7 @@ function Get-Mock_Project_700 { $project.title = $pActual.title $project.number = $pActual.number $project.url = $pActual.url - $project.cacheFileName = "$($pActual.owner.login)_$($pActual.number).json" + $project.cacheFileName = "db-$($pActual.owner.login)-$($pActual.number)-project.json" # Fields info $project.fields = @{} diff --git a/Test/private/mockdatabase.ps1 b/Test/private/mockdatabase.ps1 index bd46e96..3019de1 100644 --- a/Test/private/mockdatabase.ps1 +++ b/Test/private/mockdatabase.ps1 @@ -24,8 +24,13 @@ function Get-Mock_DatabaseRootPath{ } function Update-Mock_DatabaseFileWithReplace([string]$FileName, [string]$SearchString, [string]$ReplaceString){ + $dbpath = Get-Mock_DatabaseRootPath | Join-Path -ChildPath $FileName $content = Get-Content $dbpath $content = $content -replace $SearchString, $ReplaceString $content | Set-Content $dbpath + + # Reset the memory cache deleting the cachelock file + $cachelock = $dbpath -replace '\.json$', '-lock.json' + Remove-Item -Path $cachelock -Force -ErrorAction SilentlyContinue } \ No newline at end of file diff --git a/Test/private/mocks/invoke-getitem-PVTI_lADOAlIw4c4BCe3Vzgeio4o-Normalized.json b/Test/private/mocks/invoke-getitem-PVTI_lADOAlIw4c4BCe3Vzgeio4o-Normalized.json new file mode 100644 index 0000000..f25a1af --- /dev/null +++ b/Test/private/mocks/invoke-getitem-PVTI_lADOAlIw4c4BCe3Vzgeio4o-Normalized.json @@ -0,0 +1,185 @@ +{ + "data": { + "node": { + "id": "PVTI_lADOAlIw4c4BCe3Vzgeio4o", + "type": "ISSUE", + "fullDatabaseId": "128099210", + "project": { + "id": "PVT_kwDOAlIw4c4BCe3V", + "url": "https://github.com/orgs/octodemo/projects/700" + }, + "content": { + "__typename": "Issue", + "id": "I_kwDOPrRnkc7KkwSq", + "body": "Body of issue for development", + "title": "[RULaSG-DeV-1] Issue [RULASG-DEV-1] for [value between] development", + "updatedAt": "2025-10-15T21:30:02Z", + "createdAt": "2025-09-09T14:01:17Z", + "number": 26, + "url": "https://github.com/octodemo/rulasg-dev-1/issues/26", + "state": "OPEN", + "repository": { + "name": "rulasg-dev-1", + "owner": { + "login": "octodemo" + } + }, + "comments": { + "totalCount": 3, + "nodes": [ + { + "createdAt": "2025-09-23T17:51:06Z", + "updatedAt": "2025-10-15T21:29:45Z", + "url": "https://github.com/octodemo/rulasg-dev-1/issues/26#issuecomment-3324995787", + "body": "Sample comment 1", + "fullDatabaseId": "3324995787", + "author": { + "login": "rulasg" + } + }, + { + "createdAt": "2025-09-24T08:29:13Z", + "updatedAt": "2025-10-15T21:29:55Z", + "url": "https://github.com/octodemo/rulasg-dev-1/issues/26#issuecomment-3327194303", + "body": "Sample comment 2", + "fullDatabaseId": "3327194303", + "author": { + "login": "rulasg" + } + }, + { + "createdAt": "2025-09-30T05:42:49Z", + "updatedAt": "2025-10-15T21:30:02Z", + "url": "https://github.com/octodemo/rulasg-dev-1/issues/26#issuecomment-3350059109", + "body": "Sample comment 3", + "fullDatabaseId": "3350059109", + "author": { + "login": "rulasg" + } + } + ] + } + }, + "fieldValues": { + "nodes": [ + { + "__typename": "ProjectV2ItemFieldRepositoryValue", + "repository": { + "url": "https://github.com/octodemo/rulasg-dev-1" + }, + "field": { + "__typename": "ProjectV2Field", + "id": "PVTF_lADOAlIw4c4BCe3Vzg0rg-k", + "name": "Repository", + "dataType": "REPOSITORY" + } + }, + { + "__typename": "ProjectV2ItemFieldMilestoneValue", + "milestone": { + "title": "Milestone 3: Quality and Deployment", + "description": "Testing, documentation, and deployment pipeline setup", + "dueOn": "2025-10-18T00:00:00Z" + }, + "field": { + "__typename": "ProjectV2Field", + "id": "PVTF_lADOAlIw4c4BCe3Vzg0rg-g", + "name": "Milestone", + "dataType": "MILESTONE" + } + }, + { + "__typename": "ProjectV2ItemFieldTextValue", + "text": "[RULaSG-DeV-1] Issue [RULASG-DEV-1] for [value between] development", + "field": { + "__typename": "ProjectV2Field", + "id": "PVTF_lADOAlIw4c4BCe3Vzg0rg-M", + "name": "Title", + "dataType": "TITLE" + } + }, + { + "__typename": "ProjectV2ItemFieldSingleSelectValue", + "name": "In Progress", + "field": { + "__typename": "ProjectV2SingleSelectField", + "id": "PVTSSF_lADOAlIw4c4BCe3Vzg0rg-U", + "name": "Status", + "dataType": "SINGLE_SELECT", + "options": [ + { + "id": "f75ad846", + "name": "Todo" + }, + { + "id": "47fc9ee4", + "name": "In Progress" + }, + { + "id": "98236657", + "name": "Done" + } + ] + } + }, + { + "__typename": "ProjectV2ItemFieldNumberValue", + "number": 333.0, + "field": { + "__typename": "ProjectV2Field", + "id": "PVTF_lADOAlIw4c4BCe3Vzg0rhjU", + "name": "field-number", + "dataType": "NUMBER" + } + }, + { + "__typename": "ProjectV2ItemFieldIterationValue", + "title": "field-iteration 3", + "startDate": "2025-10-05", + "duration": 14, + "field": { + "__typename": "ProjectV2IterationField", + "id": "PVTIF_lADOAlIw4c4BCe3Vzg0rhqQ", + "name": "field-iteration", + "dataType": "ITERATION" + } + }, + { + "__typename": "ProjectV2ItemFieldTextValue", + "text": "text3", + "field": { + "__typename": "ProjectV2Field", + "id": "PVTF_lADOAlIw4c4BCe3Vzg0rhko", + "name": "field-text", + "dataType": "TEXT" + } + }, + { + "__typename": "ProjectV2ItemFieldSingleSelectValue", + "name": "option-3", + "field": { + "__typename": "ProjectV2SingleSelectField", + "id": "PVTSSF_lADOAlIw4c4BCe3Vzg0rhno", + "name": "field-singleselect", + "dataType": "SINGLE_SELECT", + "options": [ + { + "id": "7d96a925", + "name": "option-1" + }, + { + "id": "cd02c585", + "name": "option-2" + }, + { + "id": "6b66c93a", + "name": "option-3" + } + ] + } + } + ] + } + } + } +} diff --git a/Test/public/environment/projectParameters.test.ps1 b/Test/public/environment/projectParameters.test.ps1 index c2efa16..30cee65 100644 --- a/Test/public/environment/projectParameters.test.ps1 +++ b/Test/public/environment/projectParameters.test.ps1 @@ -8,9 +8,9 @@ function Test_SetProjectParameters_SUCCESS{ Set-ProjectParameters -Owner $owner -ProjectNumber $projectNumber $v = @{ - Owner = @{value =$owner ; file = $($dbPath | Join-Path -Child "EnvironmentCache_Owner.json")} - ProjectNumber = @{value =$projectNumber ; file = $($dbPath | Join-Path -Child "EnvironmentCache_ProjectNumber.json")} - ProjectTitle = @{value =$projectTitle ; file = $($dbPath | Join-Path -Child "EnvironmentCache_ProjectTitle.json")} + Owner = @{value =$owner ; file = $($dbPath | Join-Path -Child "env-owner.json")} + ProjectNumber = @{value =$projectNumber ; file = $($dbPath | Join-Path -Child "env-ProjectNumber.json")} + ProjectTitle = @{value =$projectTitle ; file = $($dbPath | Join-Path -Child "env-ProjectTitle.json")} } $v.keys | ForEach-Object { diff --git a/Test/public/items/edit_project_item.test.ps1 b/Test/public/items/edit_project_item.test.ps1 index 99815d0..73fc2f5 100644 --- a/Test/public/items/edit_project_item.test.ps1 +++ b/Test/public/items/edit_project_item.test.ps1 @@ -263,6 +263,57 @@ function Test_EditProjectItems_NormalizeTitle{ Assert-AreEqual -Expected $newTitle -Presented $result.$itemId.title.Value } +function Test_EditProjectItems_NormalizeTitle_AlreadyNormalized{ + + # Arrange + $p = Get-Mock_Project_700 ; $Owner = $p.owner ; $ProjectNumber = $p.number + MockCall_GetProject $p -skipItems + $i= $p.issue ; $itemId = $i.id + + MockCall_GetProject $p -SkipItems + + $newTitle = "[rulasg-dev-1] Issue [rulasg-dev-1] for [value between] development" + + # Mock the direct call for item + MockCallJson -Command "Invoke-GetItem -itemid $itemId" -FileName "invoke-getitem-$itemId-Normalized.json" + # Act + Edit-ProjectItem -Owner $owner -ProjectNumber $projectNumber -ItemId $itemId -NormalizeTitle + + # Assert + $result = Get-ProjectItemStaged -Owner $owner -ProjectNumber $projectNumber + + Assert-Count -Expected 1 -Presented $result.$itemId.Keys + Assert-AreEqual -Expected $newTitle -Presented $result.$itemId.title.Value +} + +function Test_NormalizedTitle{ + + Invoke-PrivateContext{ + $cases = @( + @{item = @{Title= "Test"; repositoryName = "rulasg-dev-1"}; expected = "[rulasg-dev-1] Test"} + @{item = @{Title= "[rulasg-dev-1] Test"; repositoryName = "rulasg-dev-1"}; expected = "[rulasg-dev-1] Test"} + + @{item = @{Title= "[BBVA] Test"; repositoryName = "bBva"}; expected = "[bBva] Test"} + + @{item = @{Title= "Test [rulasg-dev-1]"; repositoryName = "rulasg-dev-1"}; expected = "Test [rulasg-dev-1]"} + + @{item = @{Title= "Test [rulasg-dEv-1]"; repositoryName = "rulasg-dev-1"}; expected = "Test [rulasg-dev-1]"} + + @{item = @{Title= "[RULaSG-DeV-1] Test"; repositoryName = "rulasg-dev-1"}; expected = "[rulasg-dev-1] Test"} + @{item = @{Title= "[RULaSG-DeV-1] Test [value between] development"; repositoryName = "rulasg-dev-1"}; ` + expected = "[rulasg-dev-1] Test [value between] development"} + @{item = @{Title= "[RULaSG-DeV-1] Issue [RULASG-DEV-1] for [value between] development"; repositoryName = "rulasg-dev-1"}; ` + expected = "[rulasg-dev-1] Issue [rulasg-dev-1] for [value between] development"} + ) + + foreach($case in $cases){ + $result = Get-NormalizedTitle -Item $case.item + Assert-AreEqual -Expected $case.expected -Presented $result + } + + } +} + function Test_EditProjectItems_OpenInBrowser{ # Arrange diff --git a/Test/public/project/updateprojectrecent.test.ps1 b/Test/public/project/updateprojectrecent.test.ps1 index e11b332..c241b7f 100644 --- a/Test/public/project/updateprojectrecent.test.ps1 +++ b/Test/public/project/updateprojectrecent.test.ps1 @@ -12,10 +12,10 @@ function Test_UpdateProject_SetsRecentUpdateToday_WhenQueryIsNull{ # Assert Assert-IsTrue $result - # Verify Set-EnvItem_Last_RecentUpdate_Today was called - check the env item is set to today - $envValue = Invoke-PrivateContext { Get-EnvItem_Last_RecentUpdate -Owner "octodemo" -ProjectNumber 700 } + # Verify Set-EnvProjectLastUpdate_Today was called - check the env item is set to today + $envValue = Invoke-PrivateContext { Get-EnvProjectLastUpdate -Owner "octodemo" -ProjectNumber 700 } - Assert-AreEqual -Expected $today -Presented $envValue -Comment "Set-EnvItem_Last_RecentUpdate_Today should set env item to today when Query is null" + Assert-AreEqual -Expected $today -Presented $envValue -Comment "Set-EnvProjectLastUpdate_Today should set env item to today when Query is null" } function Test_UpdateProjectRecent_FirstCAll_SetRecentUpdate_toToday{ @@ -34,8 +34,8 @@ function Test_UpdateProjectRecent_FirstCAll_SetRecentUpdate_toToday{ # Assert Assert-IsTrue $result - # Verify Set-EnvItem_Last_RecentUpdate_Today was NOT called - env item should be null/empty - $envValue = Invoke-PrivateContext { Get-EnvItem_Last_RecentUpdate -Owner "octodemo" -ProjectNumber 700 } + # Verify Set-EnvProjectLastUpdate_Today was NOT called - env item should be null/empty + $envValue = Invoke-PrivateContext { Get-EnvProjectLastUpdate -Owner "octodemo" -ProjectNumber 700 } Assert-AreEqual -Expected $today -Presented $envValue } @@ -50,8 +50,8 @@ function Test_UpdateProjectRecent_UpdateBasedOn_FirstTime{ $result = Update-ProjectRecent -Owner $owner -ProjectNumber $projectNumber - ## Assert check that the EnvironmentCache_Last_RecentUpdate_octodemo_700.json is set to today - $envValue = Invoke-PrivateContext { Get-EnvItem_Last_RecentUpdate -Owner "octodemo" -ProjectNumber 700 } + ## Assert check that the env-Last_RecentUpdate_octodemo_700.json is set to today + $envValue = Invoke-PrivateContext { Get-EnvProjectLastUpdate -Owner "octodemo" -ProjectNumber 700 } Assert-AreEqual -Expected $today -Presented $envValue } @@ -64,8 +64,8 @@ function Test_UpdateProjectRecent_UpdateBasedOn_SetToToday{ # Act - use the mock to run the project full sync to set the last recent update to today MockCall_GetProject_700 -Cache - ## Assert check that the EnvironmentCache_Last_RecentUpdate_octodemo_700.json is set to today - $envValue = Invoke-PrivateContext { Get-EnvItem_Last_RecentUpdate -Owner "octodemo" -ProjectNumber 700 } + ## Assert check that the env-Last_RecentUpdate_octodemo_700.json is set to today + $envValue = Invoke-PrivateContext { Get-EnvProjectLastUpdate -Owner "octodemo" -ProjectNumber 700 } Assert-AreEqual -Expected $today -Presented $envValue # Reset Mocks to ensure no mocks functions left from caching project @@ -91,8 +91,8 @@ function Test_UpdateProjectRecent_UpdateBasedOn_SetToTehPast{ # Act - use the mock to run the project full sync to set the last recent update to today MockCall_GetProject_700 -Cache - ## Assert check that the EnvironmentCache_Last_RecentUpdate_octodemo_700.json is set to today - Invoke-PrivateContext { Set-EnvItem_Last_RecentUpdate -Owner "octodemo" -ProjectNumber 700 -Value "2024-02-18" } + ## Assert check that the env-Last_RecentUpdate_octodemo_700.json is set to today + Invoke-PrivateContext { Set-EnvProjectLastUpdate -Owner "octodemo" -ProjectNumber 700 -Value "2024-02-18" } # Reset Mocks to ensure no mocks functions left from caching project @@ -110,6 +110,6 @@ function Test_UpdateProjectRecent_UpdateBasedOn_SetToTehPast{ Assert-IsTrue $result # ASsert that value has changed to today - $envValue = Invoke-PrivateContext { Get-EnvItem_Last_RecentUpdate -Owner "octodemo" -ProjectNumber 700 } + $envValue = Invoke-PrivateContext { Get-EnvProjectLastUpdate -Owner "octodemo" -ProjectNumber 700 } Assert-AreEqual -Expected $today -Presented $envValue } diff --git a/Test/public/projectDatabase/project_database.test.ps1 b/Test/public/projectDatabase/project_database.test.ps1 index d8a36eb..dc3bc4b 100644 --- a/Test/public/projectDatabase/project_database.test.ps1 +++ b/Test/public/projectDatabase/project_database.test.ps1 @@ -27,25 +27,29 @@ function Test_SaveProjectDatabase_SafeId_Flag_PrivateCall{ function Test_SaveProjectDatabase_Safe_PrivateCall{ $p = Get-Mock_Project_700 ; $owner = $p.owner ; $projectNumber = $p.number - MockCall_GetProject_700 + MockCall_GetProject_700 -Cache Invoke-PrivateContext { $Owner = "octodemo" ; $ProjectNumber = 700 # Cache the project - $prj1 = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber + # $prj1 = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber # modify the project - $db = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber ; Save-ProjectDatabaseSafe -Database $db - + # $db = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber + $db1 = Get-ProjectFromDatabase -Owner $Owner -ProjectNumber $ProjectNumber + $dbClone = $db1 | ConvertTo-Json | ConvertFrom-Json + Save-ProjectDatabaseSafe -Database $db1 + # Check that safeId has changed - $prj2 = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber - Assert-AreNotEqual -Presented $prj2.safeId -Expected $prj1.safeId + $db2 = Get-ProjectFromDatabase -Owner $Owner -ProjectNumber $ProjectNumber + # $prj2 = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber + Assert-AreNotEqual -Presented $dbClone.safeId -Expected $db2.safeId ## When saving again as prj1 that has been saved before it will throw $hasThrow = $false try{ - Save-ProjectDatabaseSafe -Database $prj1 + Save-ProjectDatabaseSafe -Database $dbClone } catch { $hasThrow = $true } diff --git a/Test/public/repository/get-repository.test.ps1 b/Test/public/repository/get-repository.test.ps1 index a06711f..2cbe4e6 100644 --- a/Test/public/repository/get-repository.test.ps1 +++ b/Test/public/repository/get-repository.test.ps1 @@ -16,7 +16,7 @@ function Test_GetRepository{ # Assert repo cache created $dbpath = get-Mock_DatabaseRootPath - $dbname = "$($r.owner)-$($r.name).json" + $dbname = "repo-$($r.owner)-$($r.name).json" Assert-ItemExist -Path (Join-Path -Path $dbpath -ChildPath $dbname) diff --git a/include/MyWrite.ps1 b/include/MyWrite.ps1 index 5226eab..ca3269f 100644 --- a/include/MyWrite.ps1 +++ b/include/MyWrite.ps1 @@ -61,7 +61,7 @@ function Write-MyDebug { [CmdletBinding()] [Alias("Write-Debug")] param( - [Parameter(Position = 0)][string]$section, + [Parameter(Position = 0)][string]$section = "none", [Parameter(Position = 1, ValueFromPipeline)][string]$Message, [Parameter(Position = 2)][object]$Object ) @@ -103,14 +103,13 @@ function Write-MyDebugLogging { # Check if file exists # This should always exist as logging checks for parent path to be enabled # It may happen if since enable to execution the parent folder aka loggingFilePath is deleted. - if(-not (Test-Path -Path $loggingFilePath) ){ + if(-not (Test-Path -Path $loggingFilePath -PathType Leaf) ){ Write-Warning "Debug logging file path not accesible : '$loggingFilePath'" return $false } # Write to log file - $logFilePath = Join-Path -Path $loggingFilePath -ChildPath "$($MODULE_NAME)_debug.log" - Add-Content -Path $logFilePath -Value $LogMessage + Add-Content -Path $loggingFilePath -Value $LogMessage } } @@ -178,53 +177,100 @@ function Test-MyDebug { [Parameter()][switch]$Logging ) - # Get the module debug environment variable + function testSection($section,$flags){ + if($flags.Count -eq 0){ + return $false + } + $flags = $flags.ToLower() + $section = $section.ToLower() + + return ($flags.Contains("all")) -or ( $flags.Contains($section)) + } + $moduleDebugVarName = $MODULE_NAME + "_DEBUG" - $flag = [System.Environment]::GetEnvironmentVariable($moduleDebugVarName) + $flagsString = [System.Environment]::GetEnvironmentVariable($moduleDebugVarName) - # check if debugging is enabled - if ([string]::IsNullOrWhiteSpace( $flag )) { + # No configuration means no debug + if([string]::IsNullOrWhiteSpace( $flagsString )) { return $false } - $flag = $flag.ToLower() - $section = $section.ToLower() + # Get flags from flagdsString + $flags = getFlagsFromSectionsString $flagsString + + # Add all if allow is empty. + # This mean stat flagsString only contains filters. + $flags.allow = $flags.allow.Count -eq 0 ? @("all") : $flags.allow + + # Get the module debug environment variable + $isAllow = testSection -Section:$section -Flags:$flags.allow + $isFiltered = testSection -Section:$section -Flags:$flags.filter + + $trace = $isAllow -and -not $isFiltered - $trace = ($flag -like '*all*') -or ( $section -like "*$flag*") return $trace } function Enable-ModuleNameDebug{ param( - [Parameter(Position = 0)][string]$section, + [Parameter(Position = 0)][string[]]$Sections, + [Parameter()][string[]]$AddSections, [Parameter()][string]$LoggingFilePath ) # Check if logging file path is provided if( -Not ( [string]::IsNullOrWhiteSpace( $LoggingFilePath )) ) { - if(Test-Path -Path $LoggingFilePath){ - $moduleDEbugLoggingVarName = $MODULE_NAME + "_DEBUG_LOGGING_FILEPATH" - [System.Environment]::SetEnvironmentVariable($moduleDEbugLoggingVarName, $LoggingFilePath) + if(Test-Path -Path $LoggingFilePath -PathType Leaf){ + set-LogFile $LoggingFilePath } else { Write-Error "Logging file path '$LoggingFilePath' does not exist. Debug logging will not be enabled." return } } - # Check section value - if( [string]::IsNullOrWhiteSpace( $section )) { - $flag = "all" - } else { - $flag = $section + $flagsString = $sections -join " " + $addedFlagsString = $AddSections -join " " + + # if no section get value from env and is still mepty set to all + if([string]::IsNullOrWhiteSpace( $flagsString )) { + $flagsString = get-Sections + if( [string]::IsNullOrWhiteSpace( $flagsString )) { + $flagsString = "all" + } + } + + # Add added to flagsString if provided + if(-Not [string]::IsNullOrWhiteSpace( $addedFlagsString )) { + $flagsString += " " + $addedFlagsString } - $moduleDebugVarName = $MODULE_NAME + "_DEBUG" - [System.Environment]::SetEnvironmentVariable($moduleDebugVarName, $flag) + set-Sections $flagsString } Copy-Item -path Function:Enable-ModuleNameDebug -Destination Function:"Enable-$($MODULE_NAME)Debug" Export-ModuleMember -Function "Enable-$($MODULE_NAME)Debug" +function getFlagsFromSectionsString($sectionsString){ + $flags = @{ + allow = $null + filter = $null + } + + if([string]::IsNullOrWhiteSpace($sectionsString) ){ + $flags.allow = @("all") + return $flags + } + + $list = $sectionsString.Split(" ", [StringSplitOptions]::RemoveEmptyEntries) + + $split = @($list).Where({ $_ -like '-*' }, 'Split') + + $flags.filter = $split[0] | ForEach-Object { $_ -replace '^-', '' } # -> API, Auth + $flags.allow = $split[1] # -> Sync, Cache + + return $flags +} + function Disable-ModuleNameDebug { param() @@ -237,6 +283,18 @@ function Disable-ModuleNameDebug { Copy-Item -path Function:Disable-ModuleNameDebug -Destination Function:"Disable-$($MODULE_NAME)Debug" Export-ModuleMember -Function "Disable-$($MODULE_NAME)Debug" +function Get-ModuleNameDebug { + [cmdletbinding()] + param() + + return @{ + Sections = get-Sections + LoggingFilePath = get-LogFile + } +} +Copy-Item -path Function:Get-ModuleNameDebug -Destination Function:"Get-$($MODULE_NAME)Debug" +Export-ModuleMember -Function "Get-$($MODULE_NAME)Debug" + function Get-ObjetString { param( [Parameter(ValueFromPipeline, Position = 0)][object]$Object @@ -255,3 +313,27 @@ function Get-ObjetString { return $Object | ConvertTo-Json -Depth 10 -ErrorAction SilentlyContinue } } + +function get-Sections(){ + $moduleDebugVarName = $MODULE_NAME + "_DEBUG" + $sections = [System.Environment]::GetEnvironmentVariable($moduleDebugVarName) + + return $sections +} + +function set-Sections($sections){ + $moduleDebugVarName = $MODULE_NAME + "_DEBUG" + [System.Environment]::SetEnvironmentVariable($moduleDebugVarName, $sections) +} + +function get-LogFile(){ + $moduleDEbugLoggingVarName = $MODULE_NAME + "_DEBUG_LOGGING_FILEPATH" + $logfile = [System.Environment]::GetEnvironmentVariable($moduleDEbugLoggingVarName) + + return $logfile +} + +function set-LogFile($logFilePath){ + $moduleDEbugLoggingVarName = $MODULE_NAME + "_DEBUG_LOGGING_FILEPATH" + [System.Environment]::SetEnvironmentVariable($moduleDEbugLoggingVarName, $logFilePath) +} diff --git a/private/database/databaseV2.ps1 b/private/database/databaseV2.ps1 index f01301e..c7a3ec2 100644 --- a/private/database/databaseV2.ps1 +++ b/private/database/databaseV2.ps1 @@ -47,6 +47,8 @@ function Get-Database { [Parameter(Position = 0)][string]$Key ) + "Getting database for key [$Key]" | Write-MyDebug -Section Database + $path = Get-DatabaseFile $Key if (-Not (Test-Path $path)) { @@ -67,6 +69,8 @@ function Test-Database { $path = Get-DatabaseFile -Key $Key $ret = Test-Path $path + + "Test [$ret] database for key [$Key] at path [$path]" | Write-MyDebug -Section Database return $ret } @@ -76,9 +80,12 @@ function Reset-Database { param( [Parameter(Position = 0)][string]$Key ) + $path = Get-DatabaseFile -Key $Key + + "Resetting database for key [$Key] at path [$path]" | Write-MyDebug -Section Database + Microsoft.PowerShell.Management\Remove-Item -Path $path -Force -ErrorAction SilentlyContinue - return } function Save-Database { @@ -95,6 +102,29 @@ function Save-Database { $Database | ConvertTo-Json -Depth 10 | Set-Content $path } +function Get-DatabaseKey{ + [CmdletBinding()] + param( + [Parameter(Position = 0)][string]$Owner, + [Parameter(Position = 1)][int]$ProjectNumber, + [Parameter(Position = 2)][string] $Category + ) + + if([string]::IsNullOrWhiteSpace($Owner)){ + throw "Owner is null or empty" + } + if($ProjectNumber -le 0){ + throw "ProjectNumber is null or not a positive integer" + } + if([string]::IsNullOrWhiteSpace($Category)){ + throw "Category is null or empty" + } + + $ret = "db-{0}-{1}-{2}" -f $Owner, $ProjectNumber, $Category + + return $ret +} + function Get-DatabaseFile { [CmdletBinding()] param( diff --git a/private/projectDatabase/project_database.ps1 b/private/projectDatabase/project_database.ps1 index 9a60638..0793c9f 100644 --- a/private/projectDatabase/project_database.ps1 +++ b/private/projectDatabase/project_database.ps1 @@ -7,7 +7,7 @@ function Test-ProjectDatabase{ [Parameter(Position = 1)][int]$ProjectNumber ) - $key = Get-DatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber + $key,$keyLock = Get-ProjectDatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber $ret = Test-Database -Key $key @@ -21,8 +21,7 @@ function Test-ProjectDatabaseStaged{ [Parameter(Position = 1)][int]$ProjectNumber ) - $key = Get-DatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber - $prj = Get-Database -Key $key + $prj = Get-ProjectFromDatabase -Owner $Owner -ProjectNumber $ProjectNumber if($null -eq $prj){ return $false @@ -46,7 +45,16 @@ function Get-ProjectFromDatabase{ [Parameter(Position = 1)][int]$ProjectNumber ) - $key = Get-DatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber + $key,$keyLock = Get-ProjectDatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber + + $prj = getProjectDatabaseCache -KeyLock $keyLock + + if($null -ne $prj){ + "Project cache hit for $Owner/$ProjectNumber" | Write-MyDebug -Section "ProjectDatabase" + return $prj + } + + # No cache or cache mismatch, read from database $prj = Get-Database -Key $key if($null -eq $prj){ @@ -67,8 +75,9 @@ function Reset-ProjectDatabase{ [Parameter(Position = 1)][int]$ProjectNumber ) - $dbKey = Get-DatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber + $dbKey, $dbKeyLock = Get-ProjectDatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber Reset-Database -Key $dbKey + resetProjectDatabaseCache -Owner $Owner -ProjectNumber $ProjectNumber } function Save-ProjectV2toDatabase{ @@ -77,7 +86,7 @@ function Save-ProjectV2toDatabase{ [Parameter(Position = 0)][object]$ProjectV2, [Parameter(Position = 1)][hashtable]$Items, [Parameter(Position = 1)][hashtable]$QueryItems, - [Parameter(Position = 2)][Object[]]$Fields + [Parameter(Position = 2)][hashtable]$Fields ) $owner = $ProjectV2.owner.login @@ -139,7 +148,7 @@ function Save-ProjectDatabase{ throw "Database.number is null or not a positive integer" } - $dbkey = Get-DatabaseKey -Owner $owner -ProjectNumber $projectnumber + $dbkey, $dbkeyLock = Get-ProjectDatabaseKey -Owner $owner -ProjectNumber $projectnumber if($Safe){ $oldDatabase = Get-Database -Key $dbkey @@ -147,30 +156,82 @@ function Save-ProjectDatabase{ if ($oldDatabase.safeId -ne $Database.safeId){ throw "The database has changed since it was read. Aborting save to prevent overwriting changes." } - } # Add safe mark $Database.safeId = [guid]::NewGuid().ToString() + # Save database Save-Database -Key $dbkey -Database $Database + setProjectDatabaseCache -KeyLock $dbkeyLock -SafeId $Database.safeId -Database $Database } -function Get-DatabaseKey{ +function Get-ProjectDatabaseKey{ [CmdletBinding()] param( [Parameter(Position = 0)][string]$Owner, [Parameter(Position = 1)][int]$ProjectNumber ) - if([string]::IsNullOrWhiteSpace($Owner)){ - throw "Owner is null or empty" + $key = Get-DatabaseKey $Owner $ProjectNumber "project" + $keylock = "$key-lock" + + return $key, $keylock +} + +$script:ProjectDatabaseCache = @{} + +function getProjectDatabaseCache{ + param( + [Parameter(Mandatory,Position = 0)][string]$KeyLock + ) + + $lock = Get-Database -Key $KeyLock + + if([string]::IsNullOrWhiteSpace($lock)){ + "No cache lock found for $KeyLock. Cache will be ignored." | Write-MyDebug -Section "ProjectDatabase" + return $null + } + + $cache = $script:ProjectDatabaseCache[$KeyLock] + + if($lock -cne $cache.safeId) { + "Cache lock mismatch for $KeyLock. Cache safeId [$($cache.SafeId)], lock [$lock]. Cache will be ignored." | Write-MyDebug -Section "ProjectDatabase" + resetProjectDatabaseCache -KeyLock $KeyLock + return $null } - if($ProjectNumber -le 0){ - throw "ProjectNumber is null or not a positive integer" + + "Getting fields cache for $KeyLock with lock [$lock] and cache safeId [$($cache.SafeId)]" | Write-MyDebug -Section "ProjectDatabase" + return $cache.Database +} + +function setProjectDatabaseCache{ + param( + [Parameter(Mandatory,Position = 0)][string]$KeyLock, + [Parameter(Mandatory,Position = 1)][string]$SafeId, + [Parameter(Mandatory,Position = 2)][object]$Database + ) + + "Setting project cache for $KeyLock with safeId [$SafeId]" | Write-MyDebug -Section "ProjectDatabase" + + # Save safeId to project-lock + Save-Database -Database $SafeId -Key $KeyLock + + # Set lock in database to prevent concurrent updates + $script:ProjectDatabaseCache[$KeyLock] = @{ + Database = $Database + SafeId = $SafeId } +} - $ret = "$($owner)_$($projectnumber)" +function resetProjectDatabaseCache{ + param( + [Parameter(Mandatory,Position = 0)][string]$KeyLock + ) - return $ret + "Resetting project cache for $KeyLock" | Write-MyDebug -Section "ProjectDatabase" + + Reset.Database -Key $KeyLock + + $script:ProjectDatabaseCache.Remove($KeyLock) } \ No newline at end of file diff --git a/private/projectDatabase/project_database_Item_Resolve.ps1 b/private/projectDatabase/project_database_Item_Resolve.ps1 index e2b0a65..49e05ad 100644 --- a/private/projectDatabase/project_database_Item_Resolve.ps1 +++ b/private/projectDatabase/project_database_Item_Resolve.ps1 @@ -22,6 +22,16 @@ function Resolve-ProjectItem { return $null, $false } + # Add Sanity check for item + # Ensure that we hare retrieved an item for the correct database + # As Get-ProjectItemDirect retrives a node based on item we do not know + # if this itemid belongs to this project or not until here. + # + # Find bugs early when calling to resolve ItemId of wrong projects. + if($Database.ProjectId -ne $Item.projectId){ + Wait-Debugger + } + # Add to database Set-Item $Database $item diff --git a/private/projectDatabase/project_database_update.ps1 b/private/projectDatabase/project_database_update.ps1 index b7c3ca2..0a84604 100644 --- a/private/projectDatabase/project_database_update.ps1 +++ b/private/projectDatabase/project_database_update.ps1 @@ -93,20 +93,14 @@ function Update-ProjectDatabase { $queryItems = $items $actualprj = Get-ProjectFromDatabase -Owner $Owner -ProjectNumber $ProjectNumber - - # Check if project has no items or the project is not cached yet $items = $actualprj.items ?? $(New-HashTable) } - # If we are Skiping items on the update we need to keep the existing items in the database and just update the fields + # We need to keep actualitems if SkipedItems to avoid losing them in the DB if($SkipItems){ $actualprj = Get-ProjectFromDatabase -Owner $Owner -ProjectNumber $ProjectNumber - - # Check if project has no items or the project is not cached yet - $actualItems = $actualprj.items ?? $(New-HashTable) - - $items = $actualItems + $items = $actualprj.items ?? $(New-HashTable) } # Save ProjectV2 object to ProjectDatabase diff --git a/public/driver/issue/Invoke-GetItem.ps1 b/public/driver/issue/Invoke-GetItem.ps1 index fef6600..646d185 100644 --- a/public/driver/issue/Invoke-GetItem.ps1 +++ b/public/driver/issue/Invoke-GetItem.ps1 @@ -4,45 +4,14 @@ function Invoke-GetItem { [Parameter(Mandatory = $true)][string]$ItemId ) - # Use the environmentraviable - $token = Get-GithubToken - if(-not $token){ - throw "GH Cli Auth Token not available. Run 'gh auth login' in your terminal." - } - - # Define the GraphQL query with variables - $query = Get-GraphQLString "getProjectV2Item.query" - - # Define the headers for the request - $headers = @{ - "Authorization" = "Bearer $token" - "Content-Type" = "application/json" - } - # Define the variables for the request $variables = @{ itemId = $ItemId } - # Define the body for the request - $body = @{ - query= $query - variables = $variables - } | ConvertTo-Json -Depth 10 - - # Send the request - $response = Invoke-RestMethod -Uri 'https://api.github.com/graphql' -Method Post -Body $body -Headers $headers - - # Check if here are errors - if($response.errors){ - $response.errors | ForEach-Object { - "RESPONSE Type[$($_.type)] $($_.message)" | Write-MyError - } - return $null - } + $response = Invoke-GraphQL -Query $query -Variables $variables - # Return the field names return $response } Export-ModuleMember -Function Invoke-GetItem \ No newline at end of file diff --git a/public/environment/environmentCache.ps1 b/public/environment/environmentCache.ps1 index e05d352..a513388 100644 --- a/public/environment/environmentCache.ps1 +++ b/public/environment/environmentCache.ps1 @@ -8,17 +8,17 @@ function Get-ProjectHelperEnvironment{ $ret = @{ # Last Known Good Owner - Owner = Get-EnvItem -Name "EnvironmentCache_Owner" + Owner = Get-EnvItem -Name "env-owner" # Last Known Good Project Number - ProjectNumber = Get-EnvItem -Name "EnvironmentCache_ProjectNumber" + ProjectNumber = Get-EnvItem -Name "env-ProjectNumber" # Last known good Project Name - ProjectTitle = Get-EnvItem -Name "EnvironmentCache_ProjectTitle" + ProjectTitle = Get-EnvItem -Name "env-ProjectTitle" # List of fields to display on Items display commands. Useful with ConvertToItemDisplay # TODO : Consider if its worth keeping this setting - DisplayFields = Get-EnvItem -Name "EnvironmentCache_Display_Fields" + DisplayFields = Get-EnvItem -Name "env-Display_Fields" } return $ret @@ -29,10 +29,10 @@ function Reset-ProjectHelperEnvironment{ [CmdletBinding()] param() - Set-EnvItem -Name "EnvironmentCache_Owner" -Value $null - Set-EnvItem -Name "EnvironmentCache_ProjectNumber" -Value $null - Set-EnvItem -Name "EnvironmentCache_ProjectTitle" -Value $null - Set-EnvItem -Name "EnvironmentCache_Display_Fields" -Value $null + Set-EnvItem -Name "env-owner" -Value $null + Set-EnvItem -Name "env-ProjectNumber" -Value $null + Set-EnvItem -Name "env-ProjectTitle" -Value $null + Set-EnvItem -Name "env-Display_Fields" -Value $null } Export-ModuleMember -Function Reset-ProjectHelperEnvironment @@ -46,19 +46,19 @@ function Set-ProjectHelperEnvironment{ ) if(! [string]::IsNullOrWhiteSpace($Owner)) { - Set-EnvItem -Name "EnvironmentCache_Owner" -Value $Owner + Set-EnvItem -Name "env-owner" -Value $Owner } if(! [string]::IsNullOrWhiteSpace($ProjectNumber)) { - Set-EnvItem -Name "EnvironmentCache_ProjectNumber" -Value $ProjectNumber + Set-EnvItem -Name "env-ProjectNumber" -Value $ProjectNumber } if(! [string]::IsNullOrWhiteSpace($ProjectTitle)) { - Set-EnvItem -Name "EnvironmentCache_ProjectTitle" -Value $ProjectTitle + Set-EnvItem -Name "env-ProjectTitle" -Value $ProjectTitle } if($DisplayFields) { - Set-EnvItem -Name "EnvironmentCache_Display_Fields" -Value $DisplayFields + Set-EnvItem -Name "env-Display_Fields" -Value $DisplayFields } } Export-ModuleMember -Function Set-ProjectHelperEnvironment @@ -69,7 +69,7 @@ function Get-EnvironmentDisplayFields{ [Parameter()][string[]]$Fields ) - $displayFields = Get-EnvItem -Name "EnvironmentCache_Display_Fields" + $displayFields = Get-EnvItem -Name "env-Display_Fields" # Use this order $fields_Options = @() if ($DEFAULT_DISPLAY_FIELDS) { $fields_Options += $DEFAULT_DISPLAY_FIELDS } @@ -114,6 +114,6 @@ function Get-DefaultDisplayFields{ [CmdletBinding()] param() - # return Get-EnvItem -Name "EnvironmentCache_Display_Fields" + # return Get-EnvItem -Name "env-Display_Fields" return $DEFAULT_DISPLAY_FIELDS } diff --git a/public/environment/projectParameters.ps1 b/public/environment/projectParameters.ps1 index b5d32bd..bd9894d 100644 --- a/public/environment/projectParameters.ps1 +++ b/public/environment/projectParameters.ps1 @@ -12,11 +12,11 @@ function Resolve-ProjectParameters { } if([string]::IsNullOrWhiteSpace($Owner)){ - $Owner = Get-EnvItem -Name "EnvironmentCache_Owner" + $Owner = Get-EnvItem -Name "env-owner" } if([string]::IsNullOrWhiteSpace($ProjectNumber)){ - $ProjectNumber = Get-EnvItem -Name "EnvironmentCache_ProjectNumber" + $ProjectNumber = Get-EnvItem -Name "env-ProjectNumber" } if([string]::IsNullOrWhiteSpace($ProjectNumber) -or [string]::IsNullOrWhiteSpace($Owner)){ diff --git a/public/fields/project_fields_list.ps1 b/public/fields/project_fields_list.ps1 index ec3f67f..8e62cee 100644 --- a/public/fields/project_fields_list.ps1 +++ b/public/fields/project_fields_list.ps1 @@ -30,6 +30,7 @@ Gets all fields from project 1 in the octocat repository. Get-ProjectFields -Owner "octocat" -ProjectNumber "1" -Name "status" Gets all fields from project 1 that contain "status" in their name. #> + function Get-ProjectFields{ [CmdletBinding()] [OutputType([string[]])] @@ -42,16 +43,20 @@ function Get-ProjectFields{ ($Owner,$ProjectNumber) = Resolve-ProjectParameters -Owner $Owner -ProjectNumber $ProjectNumber - $db = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber -Force:$Force -SkipItems + if(-Not $fieldList -or $Force){ - # Check if $db is null - if($null -eq $db){ - "Project not found. Check owner and projectnumber" | Write-MyError - return $null - } + $db = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber -Force:$Force -SkipItems + + # Check if $db is null + if($null -eq $db){ + "Project not found. Check owner and projectnumber" | Write-MyError + return $null + } + + # if $db is null it rill return null + $fieldList = $db.fields.Values - # if $db is null it rill return null - $fieldList = $db.fields.Values + } # if name if($Name){ diff --git a/public/integrations/Edit-ProjectItemWithValues.ps1 b/public/integrations/Edit-ProjectItemWithValues.ps1 index 761d7e8..aeb56bc 100644 --- a/public/integrations/Edit-ProjectItemWithValues.ps1 +++ b/public/integrations/Edit-ProjectItemWithValues.ps1 @@ -12,10 +12,16 @@ function Edit-ProjectItemWithValues { [Parameter(Position = 1)][string]$ProjectNumber, [Parameter(Mandatory)][string]$ItemId, [Parameter(Mandatory)][hashtable]$Values, - [Parameter()][string]$FieldSlug + [Parameter()][string]$FieldSlug, + [Parameter()][object]$Fields ) - $fields = Get-ProjectFields -Owner $owner -ProjectNumber $projectNumber + if($null -eq $Fields){ + "[Edit-ProjectItemWithValues] Retriving fields" | Write-MyDebug -Section "EditProjectItem" + $Fields = Get-ProjectFields -Owner $owner -ProjectNumber $projectNumber + } else { + "[Edit-ProjectItemWithValues] Using provided fields" | Write-MyDebug -Section "EditProjectItem" + } # forech key in data do foreach ($key in $Values.Keys) { @@ -24,10 +30,11 @@ function Edit-ProjectItemWithValues { # Check if field exists $field = $fields | Where-Object { $_.name -eq $fieldName } if ($null -eq $field) { - "Field $fieldName not found" | Write-MyVerbose + "[Edit-ProjectItemWithValues]Field $fieldName not found" | Write-MyDebug -Section "EditProjectItem" continue } - + + "[Edit-ProjectItemWithValues]Editing field $fieldName with value $($Values[$key])" | Write-MyDebug -Section "EditProjectItem" Edit-ProjectItem -Owner $owner -ProjectNumber $projectNumber -ItemId $ItemId -FieldName $fieldName -Value $Values[$key] } diff --git a/public/integrations/update-ProjectItemsWithIntegration.ps1 b/public/integrations/update-ProjectItemsWithIntegration.ps1 index 0db7187..2c3c1f7 100644 --- a/public/integrations/update-ProjectItemsWithIntegration.ps1 +++ b/public/integrations/update-ProjectItemsWithIntegration.ps1 @@ -19,15 +19,22 @@ function Update-ProjectItemsWithIntegration{ [Parameter(Mandatory)][string]$IntegrationField, [Parameter(Mandatory)][string]$IntegrationCommand, [Parameter()] [string]$Slug, - [Parameter()] [switch]$IncludeDoneItems + [Parameter()] [switch]$IncludeDoneItems, + [Parameter()] [int32]$CommitMaxItems = -1 ) ($Owner,$ProjectNumber) = Resolve-ProjectParameters -Owner $Owner -ProjectNumber $ProjectNumber - # Sync project if needed - $null = Get-Project -Owner $Owner -ProjectNumber $ProjectNumber -Force:$Force - + $params = @{ + Owner = $Owner + ProjectNumber = $ProjectNumber + IntegrationField = $IntegrationField + IntegrationCommand = $IntegrationCommand + Slug = $Slug + IncludeDoneItems = $IncludeDoneItems + CommitMaxItems = $CommitMaxItems + } # Call the injection type function - $ret = Invoke-ProjectInjectionWithIntegration -Owner $Owner -ProjectNumber $ProjectNumber -IntegrationField $IntegrationField -IntegrationCommand $IntegrationCommand -Slug $Slug -IncludeDoneItems:$IncludeDoneItems + $ret = Invoke-ProjectInjectionWithIntegration @params return $ret @@ -41,23 +48,29 @@ function Invoke-ProjectInjectionWithIntegration{ [Parameter(Mandatory)][string]$IntegrationField, [Parameter(Mandatory)][string]$IntegrationCommand, [Parameter()] [string]$Slug, - [Parameter()] [switch]$IncludeDoneItems + [Parameter()] [switch]$IncludeDoneItems, + [Parameter()] [int32]$CommitMaxItems = -1 ) ($Owner,$ProjectNumber) = Resolve-ProjectParameters -Owner $Owner -ProjectNumber $ProjectNumber + $updateCount = 0 + $items = Get-ProjectItems -Owner $Owner -ProjectNumber $ProjectNumber -IncludeDone:$IncludeDoneItems + $Fields = Get-ProjectFields -Owner $owner -ProjectNumber $projectNumber + + foreach($item in $items){ # Skip if the item does not have the integration field if(-not $item.$IntegrationField){ - "Item $($item.id) does not have the integration field $IntegrationField, skipping" | Write-MyVerbose + "[Update-ProjectItemsWithIntegration] $($item.id) does not have the integration field $IntegrationField, skipping" | Write-MyDebug -section "Integration" continue } try { - "Calling integration [ $IntegrationCommand $($item.$IntegrationField)]" | Write-MyHost + "Calling integration - $IntegrationCommand $($item.$IntegrationField)]" | Write-MyHost $command = $IntegrationCommand + " " + '"{key}"' $command = $command -replace '{key}', $item.$IntegrationField $values = Invoke-MyCommand -Command $command @@ -67,12 +80,14 @@ function Invoke-ProjectInjectionWithIntegration{ } # Call the ingetration Command with the integration field value as parameter + Write-MyDebug "[Update-ProjectItemsWithIntegration] Values" -Section "Integration" -Object $values + # Check if Values is empty or null if($null -eq $values -or $values.Count -eq 0){ "No values returned from the integration command for $($item.id)" | Write-MyVerbose continue } - + # Edit item with the value $param = @{ Owner = $owner @@ -80,8 +95,20 @@ function Invoke-ProjectInjectionWithIntegration{ ItemId = $item.id Values = $values FieldSlug = $Slug + Fields = $Fields } - + + Write-MyDebug "[Update-ProjectItemsWithIntegration] >> Editing with values" -Section "Integration" Edit-ProjectItemWithValues @param + Write-MyDebug "[Update-ProjectItemsWithIntegration] << Editing with values" -Section "Integration" + + # Commit + $updateCount++ + if(($CommitMaxItems -ne -1) -and $updateCount -ge $CommitMaxItems){ + Sync-ProjectItemStagedAsync -Owner $Owner -ProjectNumber $ProjectNumber + $updateCount = 0 + } else { + "[Update-ProjectItemsWithIntegration] Count $updateCount / $CommitMaxItems" | Write-MyDebug -section "Integration" + } } } # Do not export this function to avoid conflicts with Update-ProjectItemsWithIntegration \ No newline at end of file diff --git a/public/items/edit_project_item.ps1 b/public/items/edit_project_item.ps1 index 7b6988a..4fed57a 100644 --- a/public/items/edit_project_item.ps1 +++ b/public/items/edit_project_item.ps1 @@ -80,16 +80,6 @@ function Edit-ProjectItem { $AddComment = Get-LongText -Text $AddComment } - # NormalizeTitle - if ($NormalizeTitle) { - if([string]::IsNullOrWhiteSpace($Title)){ - $Title = "[{{RepositoryName}}] {{Title}}" - } else { - # Editing Title at the same time - $Title = "[{{RepositoryName}}] $Title" - } - } - # Default if($DefaultValues){ Write-MyWarning "No Default values are currently setup. Please use other parameters to set values or update the DefaultValues parameter with default values" @@ -174,6 +164,8 @@ function Edit-ProjectItem { } } + # With Item + if ($OpenInBrowser) { $item = Get-ProjectItem -ItemId $Id -Owner $Owner -ProjectNumber $ProjectNumber if ($null -ne $item) { @@ -182,6 +174,14 @@ function Edit-ProjectItem { Write-Warning "Item not found. Cannot open in browser." } } + + # NormalizeTitle + if ($NormalizeTitle) { + $item = Get-ProjectItem -ItemId $Id -Owner $Owner -ProjectNumber $ProjectNumber + $params.fieldname = "Title" + $params.value = Get-NormalizedTitle -Item $item + edit $params + } } end { @@ -243,4 +243,43 @@ function Edit-ProjectItemValue { Save-ProjectDatabaseSafe -Database $db } -} \ No newline at end of file +} + +# function Get-NormalizedTitle { +# param( +# [Parameter(Mandatory)][hashtable]$Item +# ) +# $title = $Item.Title +# $header = "[{0}]" -f $Item.RepositoryName + +# if($title.ToLower().Contains($header.ToLower())){ +# "The title is already normalized" | Write-MyDebug -section "Edit-ProjectItem" +# # update title with proper repository name case +# $newTitle = $title -replace "^\[[^\]]*\]\s*", "$header" +# return $newTitle +# } else { +# return "$header $title" +# } +# } + +function Get-NormalizedTitle { + param( + [Parameter(Mandatory)][hashtable]$Item + ) + $title = $Item.Title + $header = "[{0}]" -f $Item.RepositoryName + $repoEscaped = [regex]::Escape($Item.RepositoryName) + + "Original title: $title" | Write-MyDebug -section "Edit-ProjectItem NormalizedTitle" + + if($title -imatch "\[$repoEscaped\]" -or $title -imatch "^\s*\[?$repoEscaped\]\s*"){ + # Ttile contains repo name. Normalize it to proper case and formatting. This will cover the following scenarios: + $ret = ($title -ireplace "^\s*\[?$repoEscaped\]\s*", "$header ") -ireplace "\[$repoEscaped\]", $header + + } else { + $ret = "$header $title" + } + + "Normalized title: $ret" | Write-MyDebug -section "Edit-ProjectItem NormalizedTitle" + return $ret +} \ No newline at end of file diff --git a/public/items/project_item.ps1 b/public/items/project_item.ps1 index a8aaa4f..cd11a01 100644 --- a/public/items/project_item.ps1 +++ b/public/items/project_item.ps1 @@ -733,15 +733,15 @@ function Test-WhereExactField { function AreEqual { param( - [object]$Object1, - [object]$Object2 + [string]$Object1, + [string]$Object2 ) $Object1 = [string]::IsNullOrEmpty($Object1) ? $null : $Object1 $Object2 = [string]::IsNullOrEmpty($Object2) ? $null : $Object2 # Check if the objects are equal - $ret = $Object1 -eq $Object2 + $ret = $Object1 -ceq $Object2 return $ret } diff --git a/public/items/project_item_show.ps1 b/public/items/project_item_show.ps1 index 3f175fa..d193713 100644 --- a/public/items/project_item_show.ps1 +++ b/public/items/project_item_show.ps1 @@ -65,8 +65,11 @@ function Show-ProjectItem{ # URL $item.url | write -Color White - addJumpLine -message "End Url" + + # Assignee + $item.Assignees | write -color DarkGreen + addJumpLine -message "End Assignees" # Fields by line if($FieldsToShow){ diff --git a/public/project/getproject.ps1 b/public/project/getproject.ps1 index cff6374..89e2c4a 100644 --- a/public/project/getproject.ps1 +++ b/public/project/getproject.ps1 @@ -10,16 +10,20 @@ function Get-Project { ($Owner, $ProjectNumber) = Resolve-ProjectParameters -Owner $Owner -ProjectNumber $ProjectNumber if ($Force -or -Not (Test-ProjectDatabase -Owner $Owner -ProjectNumber $ProjectNumber)) { - $result = Update-Project -Owner $Owner -ProjectNumber $ProjectNumber -SkipItems:$SkipItems - if ( ! $result) { return } + "Project not found in database or force specified. Updating project for $Owner/$ProjectNumber." | Write-MyDebug -Section Get-Project + + $result = Update-Project -Owner $Owner -ProjectNumber $ProjectNumber -SkipItems:$SkipItems -Force:$Force + + if ( ! $result) { + "Failed to update project for $Owner/$ProjectNumber. Project may not exist or there was an error during update." | Write-MyError + return + } + } else { + "Project found in database for $Owner/$ProjectNumber. Loading project." | Write-MyDebug -Section Get-Project } $prj = Get-ProjectFromDatabase -Owner $Owner -ProjectNumber $ProjectNumber - # if($SkipItems){ - # $prj.items = @() - # } - return $prj } Export-ModuleMember -Function Get-Project @@ -29,17 +33,29 @@ function Update-Project{ [Parameter()][string]$Owner, [Parameter()][int]$ProjectNumber, [parameter()][string]$Query, - [Parameter()][switch]$SkipItems + [Parameter()][switch]$SkipItems, + [Parameter()][switch]$Force ) ($Owner, $ProjectNumber) = Resolve-ProjectParameters -Owner $Owner -ProjectNumber $ProjectNumber - $ret = Update-ProjectDatabase -Owner $Owner -ProjectNumber $ProjectNumber -SkipItems:$SkipItems -Query $Query - - # Check if we did a full projectupdate if([string]::IsNullOrEmpty($Query)){ - # Reset recent to today - Set-EnvItem_Last_RecentUpdate_Today -Owner $Owner -ProjectNumber $ProjectNumber + + # Update just the items that were modified unless -Force + if(! $Force){ + "Performing INCREMENTAL update for $Owner/$ProjectNumber" | Write-MyDebug -Section "Update-Project" + $recentQuery = Get-UpdateRecentQuery -Owner $Owner -ProjectNumber $ProjectNumber + + $query = $recentQuery + } else { + "Performing FULL update for $Owner/$ProjectNumber" | Write-MyDebug -Section "Update-Project" + } + $ret = Update-ProjectDatabase -Owner $Owner -ProjectNumber $ProjectNumber -SkipItems:$SkipItems + Set-EnvProjectLastUpdate_Today -Owner $Owner -ProjectNumber $ProjectNumber + } + else{ + "Performing PARTIAL update for $Owner/$ProjectNumber with query [$Query]" | Write-MyDebug -Section "Update-Project" + $ret = Update-ProjectDatabase -Owner $Owner -ProjectNumber $ProjectNumber -SkipItems:$SkipItems -Query $Query } return $ret diff --git a/public/project/updateprojectrecent.ps1 b/public/project/updateprojectrecent.ps1 index 643cb39..f356d97 100644 --- a/public/project/updateprojectrecent.ps1 +++ b/public/project/updateprojectrecent.ps1 @@ -13,10 +13,10 @@ function Update-ProjectRecent{ # Get Last update date $query = Get-UpdateRecentQuery -Owner $Owner -ProjectNumber $ProjectNumber - $ret = Update-Project -Owner $Owner -ProjectNumber $ProjectNumber -SkipItems:$SkipItems -Query $Query + $ret = Update-ProjectDatabase -Owner $Owner -ProjectNumber $ProjectNumber -Query $Query if($ret){ - Set-EnvItem_Last_RecentUpdate_Today -Owner $Owner -ProjectNumber $ProjectNumber + Set-EnvProjectLastUpdate_Today -Owner $Owner -ProjectNumber $ProjectNumber } return $ret @@ -29,7 +29,7 @@ function Get-UpdateRecentQuery{ [Parameter()][int]$ProjectNumber ) - $last = Get-EnvItem_Last_RecentUpdate -Owner $Owner -ProjectNumber $ProjectNumber + $last = Get-EnvProjectLastUpdate -Owner $Owner -ProjectNumber $ProjectNumber # If no last update return no filter to update all if ($null -eq $last){ @@ -38,24 +38,28 @@ function Get-UpdateRecentQuery{ $ret = $RECENT_QUERY -replace "{date}", $last + "Updated recent query [ $ret ]" | Write-MyDebug -Section "Update-Project" + return $ret } Export-ModuleMember -Function Get-UpdateRecentQuery -function Get-EnvItem_Last_RecentUpdate{ +function Get-EnvProjectLastUpdate{ [CmdletBinding()] param( [Parameter(Mandatory)][string]$Owner, [Parameter(Mandatory)][int]$ProjectNumber ) - $last = Get-EnvItem -Name "EnvironmentCache_Last_RecentUpdate_$($Owner)_$($ProjectNumber)" + $key = "db-$($Owner)-$($ProjectNumber)-project-LastUpdate" + + $last = Get-EnvItem -Name $key - Write-MyDebug "EnvItem_Last_RecentUpdate" "Last recent update for $Owner/$ProjectNumber is $last" + "Get last recent update for $Owner/$ProjectNumber with $last" | Write-MyDebug -Section "Update-Project" return $last } -function Set-EnvItem_Last_RecentUpdate{ +function Set-EnvProjectLastUpdate{ [CmdletBinding()] param( [Parameter(Mandatory)][string]$Owner, @@ -63,13 +67,15 @@ function Set-EnvItem_Last_RecentUpdate{ [Parameter(Mandatory)][string]$Value ) - Set-EnvItem -Name "EnvironmentCache_Last_RecentUpdate_$($Owner)_$($ProjectNumber)" -Value $Value + $key = "db-$($Owner)-$($ProjectNumber)-project-LastUpdate" + + Set-EnvItem -Name $key -Value $Value - Write-MyDebug "EnvItem_Last_RecentUpdate" "Set last recent update for $Owner/$ProjectNumber to $Value" + "Set last recent update for $Owner/$ProjectNumber to $Value" | Write-MyDebug -Section "Update-Project" } -function Set-EnvItem_Last_RecentUpdate_Today{ +function Set-EnvProjectLastUpdate_Today{ [CmdletBinding()] param( [Parameter(Mandatory)][string]$Owner, @@ -78,6 +84,6 @@ function Set-EnvItem_Last_RecentUpdate_Today{ $now = Get-DateToday - Set-EnvItem_Last_RecentUpdate -Owner $Owner -ProjectNumber $ProjectNumber -Value $now + Set-EnvProjectLastUpdate -Owner $Owner -ProjectNumber $ProjectNumber -Value $now } \ No newline at end of file diff --git a/public/projectCache/projectCache.ps1 b/public/projectCache/projectCache.ps1 index 384a0ba..fad6049 100644 --- a/public/projectCache/projectCache.ps1 +++ b/public/projectCache/projectCache.ps1 @@ -24,7 +24,7 @@ function Get-ProjectCacheFile{ ($Owner, $ProjectNumber) = Resolve-ProjectParameters -Owner $Owner -ProjectNumber $ProjectNumber - $key = Get-DatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber + $key = Get-ProjectDatabaseKey -Owner $Owner -ProjectNumber $ProjectNumber $path = Get-DatabaseFile -Key $key if($path | Test-Path ){ diff --git a/public/repository/get-repository.ps1 b/public/repository/get-repository.ps1 index 8f218b3..a84756c 100644 --- a/public/repository/get-repository.ps1 +++ b/public/repository/get-repository.ps1 @@ -9,7 +9,7 @@ function Get-Repository{ ) # Check database - $key = "$Owner-$Name" + $key = "repo-$Owner-$Name" $repodb = Get-Database -Key $key # use cache if available and not forced