Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ jobs:
- **File Handling**:
- Checks only files that were added, modified, or renamed
- Skips deleted files
- **Filters out `*.cs` files** (C# files are excluded from merge conflict checking)
- Skips binary/unreadable files
- Skips directories
- **Empty File List**: Gracefully handles cases where no files need checking (e.g., PRs that only delete files)

## Example Output

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ runs:
run: |
# Get changed files from environment variable (secure against injection)
$changedFilesJson = $env:CHANGED_FILES_JSON
$changedFiles = $changedFilesJson | ConvertFrom-Json
# Ensure we always have an array (ConvertFrom-Json returns null for empty JSON arrays)
$changedFiles = @($changedFilesJson | ConvertFrom-Json)

# Import ci.psm1 and run the check
Import-Module "$env:GITHUB_WORKSPACE/tools/ci.psm1" -Force
Expand Down
14 changes: 10 additions & 4 deletions test/infrastructure/ciModule.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,17 @@ Describe "Test-MergeConflictMarker" {
}

Context "When no files are provided" {
It "Should handle empty file array" {
# The function parameter has Mandatory validation which rejects empty arrays by design
# This test verifies that behavior
It "Should handle empty file array gracefully" {
# The function now accepts empty arrays to handle cases like delete-only PRs
$emptyArray = @()
{ Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath } | Should -Throw -ExpectedMessage "*empty array*"
Test-MergeConflictMarker -File $emptyArray -WorkspacePath $script:testWorkspace -OutputPath $script:testOutputPath -SummaryPath $script:testSummaryPath

$outputs = Get-Content $script:testOutputPath
$outputs | Should -Contain "files-checked=0"
$outputs | Should -Contain "conflicts-found=0"

$summary = Get-Content $script:testSummaryPath -Raw
$summary | Should -Match "No Files to Check"
}
}

Expand Down
72 changes: 63 additions & 9 deletions tools/ci.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -932,12 +932,12 @@ function New-LinuxPackage
} else {
"${env:BUILD_ARTIFACTSTAGINGDIRECTORY}"
}

# Ensure artifacts directory exists
if (-not (Test-Path $artifactsDir)) {
New-Item -ItemType Directory -Path $artifactsDir -Force | Out-Null
}

Write-Log -message "Artifacts directory: $artifactsDir"
Copy-Item $packageObj.FullName -Destination $artifactsDir -Force
}
Expand All @@ -950,7 +950,7 @@ function New-LinuxPackage
} else {
"${env:BUILD_ARTIFACTSTAGINGDIRECTORY}"
}

# Create and package Raspbian .tgz
# Build must be clean for Raspbian
Start-PSBuild -PSModuleRestore -Clean -Runtime linux-arm -Configuration 'Release'
Expand Down Expand Up @@ -1039,8 +1039,9 @@ Function Test-MergeConflictMarker
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string[]] $File,
[Parameter()]
[AllowEmptyCollection()]
[string[]] $File = @(),

[Parameter()]
[string] $WorkspacePath = $PWD,
Expand All @@ -1054,10 +1055,63 @@ Function Test-MergeConflictMarker

Write-Host "Starting merge conflict marker check..." -ForegroundColor Cyan

Write-Host "Checking $($File.Count) changed files for merge conflict markers" -ForegroundColor Cyan
# Helper function to write outputs when no files to check
function Write-NoFilesOutput {
param(
[string]$Message,
[string]$OutputPath,
[string]$SummaryPath
)

# Output results to GitHub Actions
if ($OutputPath) {
"files-checked=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8
"conflicts-found=0" | Out-File -FilePath $OutputPath -Append -Encoding utf8
}

# Create GitHub Actions job summary
if ($SummaryPath) {
$summaryContent = @"
# Merge Conflict Marker Check Results

## Summary
- **Files Checked:** 0
- **Files with Conflicts:** 0

## ℹ️ No Files to Check

$Message

"@
$summaryContent | Out-File -FilePath $SummaryPath -Encoding utf8
}
}

# Handle empty file list (e.g., when PR only deletes files)
if ($File.Count -eq 0) {
Write-Host "No files to check (empty file list)" -ForegroundColor Yellow
Write-NoFilesOutput -Message "No files were provided for checking (this can happen when a PR only deletes files)." -OutputPath $OutputPath -SummaryPath $SummaryPath
return
}

# Filter out *.cs files from merge conflict checking
$filesToCheck = @($File | Where-Object { $_ -notlike "*.cs" })
$filteredCount = $File.Count - $filesToCheck.Count

if ($filteredCount -gt 0) {
Write-Host "Filtered out $filteredCount *.cs file(s) from merge conflict checking" -ForegroundColor Yellow
}

if ($filesToCheck.Count -eq 0) {
Write-Host "No files to check after filtering (all files were *.cs)" -ForegroundColor Yellow
Write-NoFilesOutput -Message "All $filteredCount file(s) were filtered out (*.cs files are excluded from merge conflict checking)." -OutputPath $OutputPath -SummaryPath $SummaryPath
return
}

Write-Host "Checking $($filesToCheck.Count) changed files for merge conflict markers" -ForegroundColor Cyan

# Convert relative paths to absolute paths for processing
$absolutePaths = $File | ForEach-Object {
$absolutePaths = $filesToCheck | ForEach-Object {
if ([System.IO.Path]::IsPathRooted($_)) {
$_
} else {
Expand All @@ -1081,14 +1135,14 @@ Function Test-MergeConflictMarker
}

$filesChecked++

# Get relative path for display
$relativePath = if ($WorkspacePath -and $filePath.StartsWith($WorkspacePath)) {
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The StartsWith method should use case-insensitive comparison for cross-platform path compatibility. According to codebase conventions, use [System.StringComparison]::OrdinalIgnoreCase for path comparisons. Change to: $filePath.StartsWith($WorkspacePath, [System.StringComparison]::OrdinalIgnoreCase)

Suggested change
$relativePath = if ($WorkspacePath -and $filePath.StartsWith($WorkspacePath)) {
$relativePath = if ($WorkspacePath -and $filePath.StartsWith($WorkspacePath, [System.StringComparison]::OrdinalIgnoreCase)) {

Copilot uses AI. Check for mistakes.
$filePath.Substring($WorkspacePath.Length).TrimStart([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar)
} else {
$filePath
}

Write-Host " Checking: $relativePath" -ForegroundColor Gray

# Search for conflict markers using Select-String
Expand Down
Loading