Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aadesola/ea3cd4f1cb1b9ec787585b5bc15cec22 to your computer and use it in GitHub Desktop.
Save aadesola/ea3cd4f1cb1b9ec787585b5bc15cec22 to your computer and use it in GitHub Desktop.
AutoFix-VisualStudioFiles.ps1 which formats and alphabetically organises elements in .config & .csproj files which commonly cause git merge conflicts
<#
.SYNOPSIS
Scans the solution folder (the parent of the .git folder) for all app.config, web.config and *.csproj files
and auto-formats them to minimise the possibility of getting merge conflicts based on the ordering of
elements within these files.
N.B. Use of this script is entirely at your own risk. We shall not be liable for any damage which may
result from using it.
.DESCRIPTION
app.config & web.config files - sorts appSettings elements by key, in alphabetic order, sorts
assemblyBinding.dependentAssembly elements alphabetically based on the assemblyIdentity.name
attribute
.csproj files - sorts appSettings elements by key, in alphabetic order, sorts Reference,
ProjectReference & Compile elements
.NOTES
File Name : AutoFix-VisualStudioFiles.ps1
Author : Howard van Rooijen (@HowardvRooijen)
Requires : PowerShell v3
.LINK
#>
Function AutoFix-WebConfig([string] $rootDirectory)
{
$files = Get-ChildItem -Path $rootDirectory -Filter web.config -Recurse
return Scan-ConfigFiles($files)
}
Function AutoFix-AppConfig([string] $rootDirectory)
{
$files = Get-ChildItem -Path $rootDirectory -Filter app.config -Recurse
return Scan-ConfigFiles($files)
}
Function Scan-ConfigFiles([System.IO.FileInfo[]] $files)
{
$modifiedfiles = @()
foreach($file in $files)
{
$original = [xml] (Get-Content $file.FullName)
$workingCopy = $original.Clone()
if ($workingCopy.configuration.appSettings -ne $null){
$sorted = $workingCopy.configuration.appSettings.add | sort { [string]$_.key }
$lastChild = $sorted[-1]
$sorted[0..($sorted.Length-2)] | foreach {$workingCopy.configuration.appSettings.InsertBefore($_, $lastChild)} | Out-Null
}
if ($workingCopy.configuration.runtime.assemblyBinding -ne $null){
$sorted = $workingCopy.configuration.runtime.assemblyBinding.dependentAssembly | sort { [string]$_.assemblyIdentity.name }
$lastChild = $sorted[-1]
$sorted[0..($sorted.Length-2)] | foreach {$workingCopy.configuration.runtime.assemblyBinding.InsertBefore($_,$lastChild)} | Out-Null
}
$differencesCount = (Compare-Object -ReferenceObject (Select-Xml -Xml $original -XPath "//*") -DifferenceObject (Select-Xml -Xml $workingCopy -XPath "//*")).Length
if ($differencesCount -ne 0)
{
$workingCopy.Save($file.FullName) | Out-Null
$modifiedfiles += $file.FullName
}
}
return $modifiedfiles
}
Function AutoFix-CsProj([string] $rootDirectory)
{
$files = Get-ChildItem -Path $rootDirectory -Filter *.csproj -Recurse
$modifiedfiles = @()
foreach($file in $files)
{
$original = [xml] (Get-Content $file.FullName)
$workingCopy = $original.Clone()
foreach($itemGroup in $workingCopy.Project.ItemGroup){
# Sort the reference elements
if ($itemGroup.Reference -ne $null){
$sorted = $itemGroup.Reference | sort { [string]$_.Include }
$itemGroup.RemoveAll() | Out-Null
foreach($item in $sorted){
$itemGroup.AppendChild($item) | Out-Null
}
}
# Sort the compile elements
if ($itemGroup.Compile -ne $null){
$sorted = $itemGroup.Compile | sort { [string]$_.Include }
$itemGroup.RemoveAll() | Out-Null
foreach($item in $sorted){
$itemGroup.AppendChild($item) | Out-Null
}
}
# Sort the project references elements
if ($itemGroup.ProjectReference -ne $null){
$sorted = $itemGroup.ProjectReference | sort { [string]$_.Include }
$itemGroup.RemoveAll() | Out-Null
foreach($item in $sorted){
$itemGroup.AppendChild($item) | Out-Null
}
}
}
$differencesCount = (Compare-Object -ReferenceObject (Select-Xml -Xml $original -XPath "//*") -DifferenceObject (Select-Xml -Xml $workingCopy -XPath "//*")).Length
if ($differencesCount -ne 0)
{
$workingCopy.Save($file.FullName) | Out-Null
$modifiedfiles += $file.FullName
}
}
return $modifiedfiles
}
$rootDirectory = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "\..\..\"
$exitCode = 0;
$changedfiles = @()
$changedfiles += AutoFix-AppConfig($rootDirectory)
$changedfiles += AutoFix-CsProj($rootDirectory)
$changedfiles += AutoFix-WebConfig($rootDirectory)
if ($changedfiles.Count -gt 0)
{
Write-Host "=== endjin git hooks ==="
Write-Host "The following files have been auto-formatted"
Write-Host "to reduce the likelyhood of merge conflicts:"
foreach($file in $changedfiles)
{
Write-Host $file
}
$exitCode = 1;
}
exit $exitcode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment