Private/TestCaseManagement/Get-TcmTestCaseSyncStatus.ps1
function Get-TcmTestCaseSyncStatus { <# .SYNOPSIS Determines the sync status of a test case by comparing local and remote states. .PARAMETER Id The local ID of the test case. .PARAMETER Config Configuration object from Get-TcmTestCaseConfig. .PARAMETER TestCaseData The local test case data object (optional, will be loaded if not provided). .PARAMETER RemoteWorkItem The remote work item from Azure DevOps (optional, will be fetched if not provided). .OUTPUTS String representing the sync status: 'synced', 'local-changes', 'remote-changes', 'conflict', 'new-local', 'new-remote' #> [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Id, [Parameter(Mandatory)] [hashtable] $Config, [object] $TestCaseData, [object] $RemoteWorkItem ) try { # If ID is not numeric, it's a new local test case (not synced yet) if (-not ($Id -match '^\d+$')) { return "new-local" } # For numeric IDs, check if local file exists $localFileExists = $false $localFilePath = $null if (-not $TestCaseData) { # Find local file by scanning directory $yamlFiles = Get-ChildItem -Path $Config.TestCasesRoot -Filter "*.yaml" -Recurse -File foreach ($file in $yamlFiles) { try { $fileData = Get-TcmTestCaseFromFile -FilePath $file.FullName -IncludeMetadata if ($fileData.testCase.id -eq $Id) { $TestCaseData = $fileData $localFilePath = $file.FullName $localFileExists = $true break } } catch { # Skip files that can't be parsed continue } } } else { $localFileExists = $true } # If no local file exists with this ID, it's new-remote if (-not $localFileExists) { return "new-remote" } # Load local test case if not provided if (-not $TestCaseData) { $TestCaseData = Get-TcmTestCaseFromFile -FilePath $localFilePath -IncludeMetadata } # Calculate current local hash $localHash = Get-TcmStringHash -InputObject $TestCaseData.testCase Write-Verbose "Local hash for test case '$Id': $localHash" # Fetch remote work item if not provided if (-not $RemoteWorkItem) { try { # Pass parameters expected by Get-WorkItem: use -WorkItem and include collection/project $collection = $null $project = $null if ($Config.azureDevOps) { $collection = $Config.azureDevOps.collectionUri $project = $Config.azureDevOps.project } $RemoteWorkItem = Get-WorkItem -WorkItem $Id -CollectionUri $collection -Project $project -ErrorAction Stop } catch { Write-Warning "Failed to fetch remote work item ${Id}: $($_.Exception.Message)" # If we can't fetch remote, assume local changes (since we have local file) return "local-changes" } } # Calculate remote hash if we have remote work item $remoteChanged = $false if ($RemoteWorkItem) { # Convert remote work item to comparable format $remoteTestCaseData = ConvertFrom-TcmWorkItemToTestCase -WorkItem $RemoteWorkItem $remoteHash = Get-TcmStringHash -InputObject $remoteTestCaseData Write-Verbose "Remote hash for test case '$Id': $remoteHash" $remoteChanged = $false # We just fetched remote, so no remote changes detected } # Compare local hash with remote hash $localChanged = $false if ($RemoteWorkItem) { $localChanged = ($localHash -ne $remoteHash) Write-Verbose "Hash comparison for test case '$Id': localChanged=$localChanged, remoteChanged=$remoteChanged" } else { # If no remote work item, local is new $localChanged = $true } # Determine sync status based on changes if ($localChanged -and $remoteChanged) { return "conflict" } elseif ($localChanged) { return "local-changes" } elseif ($remoteChanged) { return "remote-changes" } else { return "synced" } } catch { throw "Failed to determine sync status for test case '$Id': $($_.Exception.Message)" } } |