Skip to content

Instantly share code, notes, and snippets.

@bic742
Created August 9, 2023 13:45
Show Gist options
  • Save bic742/f77783c643420b704535d88fcbb5b18e to your computer and use it in GitHub Desktop.
Save bic742/f77783c643420b704535d88fcbb5b18e to your computer and use it in GitHub Desktop.
This is a PowerShell script that will parse TDS scproj files and generate corresponding SCS module.json files. This process includes consolidation of paths to prevent overly prescriptive configurations. It also supports providing path exclusions to ignore things that should no longer be tracked in a newer tool.
Param(
[string]$srcPath
)
function Invoke-DedupeOutput {
Param(
[System.Collections.ArrayList]$includes
)
$dedupedIncludes = [System.Collections.ArrayList]@()
$json = $includes | ConvertFrom-Json
$currentPath = ""
$currentInclude = "{}" | ConvertFrom-Json
foreach ($include in $json) {
$includePath = $include.path
if ($currentPath -eq "") {
$currentPath = $includePath
$currentInclude = $include
continue
}
if ($includePath.StartsWith($currentPath) -and $includePath -ne $currentPath) {
Write-Host " -- $includePath"
# We need to ensure this is set to sync children, since there are children that match
$currentInclude.scope = "ItemAndDescendants"
$currentInclude.allowedPushOperations = "CreateUpdateAndDelete"
}
else {
Write-Host " ++ $($currentInclude.Path)"
$dedupedIncludes.Add("$($currentInclude | ConvertTo-Json)") | Out-Null
$currentPath = $includePath
$currentInclude = $include
}
}
# The last include isn't getting added if it is non-unique
Write-Host " ++ $($currentInclude.Path)"
$dedupedIncludes.Add("$($currentInclude | ConvertTo-Json)") | Out-Null
return $dedupedIncludes
}
if ([string]::IsNullOrEmpty($srcPath)) {
$srcPath = Read-Host "Provide a source path"
}
$tdsProjects = Get-ChildItem -Path $srcPath -Recurse -Filter *.scproj
# Uncomment this sequence to do small scope testing and verification
#$singleProject = Get-Item -Path "path/to/scproj.scproj"
#$otherProject = Get-Item -Path "path/to/different/scproj.scproj"
#$tdsProjects = @($singleProject, $otherProject)
# This exclusion list is used as an ignore list.
# If the process finds these paths in any of the TDS projects, they will not be added to the module.json.
# A good example of when to use these is for OOTB paths.
# TDS tracks ALL items along a path, including OOTB items. SCS and Unicorn don't need to do this.
$exclusionList = [System.Collections.ArrayList]@(
# master items
"sitecore/layout.item",
"sitecore/layout/Layouts.item",
"sitecore/layout/Layouts/Foundation.item",
"sitecore/layout/Layouts/Feature.item",
"sitecore/layout/Layouts/Project.item",
"sitecore/layout/Placeholder Settings.item",
"sitecore/layout/Placeholder Settings/Foundation.item",
"sitecore/layout/Placeholder Settings/Feature.item",
"sitecore/layout/Placeholder Settings/Project.item",
"sitecore/layout/Renderings.item",
"sitecore/layout/Renderings/Foundation.item",
"sitecore/layout/Renderings/Feature.item",
"sitecore/layout/Renderings/Project.item",
"sitecore/media library.item",
"sitecore/media library/Foundation.item",
"sitecore/media library/Feature.item",
"sitecore/media library/Project.item",
"sitecore/media library/Themes.item",
"sitecore/media library/Base Themes.item",
"sitecore/media library/Images.item",
"sitecore/system.item",
"sitecore/system/Dictionary.item",
"sitecore/system/Settings.item",
"sitecore/system/Modules.item",
"sitecore/system/Publishing targets.item",
"sitecore/system/Languages.item",
"sitecore/system/Tasks.item",
"sitecore/system/Tasks/Commands.item",
"sitecore/system/Tasks/Schedules.item",
"sitecore/system/Workflows.item",
"sitecore/system/Settings/Foundation.item",
"sitecore/system/Settings/Feature.item",
"sitecore/system/Settings/Project.item",
"sitecore/system/Settings/Validation Rules.item",
"sitecore/system/Settings/Validation Rules/Field Rules.item",
"sitecore/templates.item",
"sitecore/templates/Branches.item",
"sitecore/templates/Branches/Foundation.item",
"sitecore/templates/Branches/Feature.item",
"sitecore/templates/Branches/Project.item",
"sitecore/templates/Foundation.item",
"sitecore/templates/Feature.item",
"sitecore/templates/Project.item",
"sitecore/templates/System.item",
# Core items
"sitecore/content/Applications.item",
"sitecore/content/Applications/WebEdit.item",
"sitecore/content/Applications/WebEdit/Default Rendering Buttons.item",
"sitecore/content/Applications/Content Editor.item",
"sitecore/content/Applications/Content Editor/Ribbons.item",
"sitecore/content/Applications/Content Editor/Ribbons/Chunks.item",
"sitecore/content/Applications/Content Editor/Ribbons/Ribbons.item",
"sitecore/content/Applications/Content Editor/Ribbons/Ribbons/Default.item",
"sitecore/content/Applications/Content Editor/Ribbons/Strips.item",
"sitecore/content/Documents and settings.item",
"sitecore/client/Applications.item",
"sitecore/client/Applications/FormsBuilder.item",
"sitecore/client/Applications/FormsBuilder/Components.item",
"sitecore/client/Applications/FormsBuilder/Components/Layouts.item",
"sitecore/client/Applications/FormsBuilder/Components/Layouts/Actions.item",
"sitecore/system.item",
"sitecore/system/Field types.item",
"sitecore/system/Field types/Link Types.item",
"sitecore/system/Field types/Link Types/General Link.item",
"sitecore/system/Field types/Link Types/General Link/WebEdit Buttons.item",
"sitecore/system/Field types/Link Types/Droptree.item",
"sitecore/system/Field types/Link Types/Droptree/WebEdit Buttons.item",
"sitecore/system/Field types/Simple Types.item",
"sitecore/system/Field types/Simple Types/Image.item",
"sitecore/system/Field types/Simple Types/Image/WebEdit Buttons.item",
"sitecore/system/Settings.item",
"sitecore/system/Settings/Html Editor Profiles.item",
"sitecore/system/Settings/Html Editor Profiles/Rich Text Default.item",
"sitecore/system/Settings/Html Editor Profiles/Rich Text Default/WebEdit Buttons.item",
)
$contentExclusionList = @()
Write-Host "Processing $($tdsProjects.Count) TDS Projects"
foreach ($tdsProject in $tdsProjects) {
Write-Host " Processing $($tdsProject.Name)"
$database = "master"
if ($tdsProject.Name -like "*.Core.*") {
$database = "core"
}
$includes = [System.Collections.ArrayList]@()
# The namespace included in the project breaks the default XML methods.
# We don't need the namespace, since these files are ultimately going away
# So, strip the namespace, convert to XML, profit!
$baseContent = Get-Content $tdsProject
$baseContent = $baseContent.Replace("xmlns=`"http://schemas.microsoft.com/developer/msbuild/2003`"", "")
$xmlContent = [xml]$baseContent
$items = $xmlContent.SelectNodes("//SitecoreItem")
foreach ($item in $items) {
# This is likely an OOTB Sitecore item, which we don't need to track with other tools
if ($item.ItemDeployment -eq "NeverDeploy") {
continue
}
$path = $item.Include.Replace('\', '/')
if ($exclusionList.Contains($path)) {
continue
}
$skip = $false
foreach ($contentExclusion in $contentExclusionList) {
if ($path.StartsWith($contentExclusion)) {
$skip = $true
break;
}
}
if ($skip) {
continue
}
$pathParts = $path.Split('/')
# We need to generate a unique-ish name for each include in a json file.
# First letter of each path part, plus full name of last part
$includeName = ""
foreach ($pathPart in $pathParts) {
if ($pathPart -eq $pathParts[-1]) {
continue
}
$lowerPathPart = $pathPart.ToLower()
$includeName = "$includeName$($lowerPathPart[0])"
}
$includeName = "$includeName-$(($pathParts[-1].Replace('.item', '').Replace(' ', '')))"
$scope = "SingleItem"
$allowedPushOperations = "CreateOnly"
switch ($item.ItemDeployment) {
"DeployOnce" { $allowedPushOperations = "CreateOnly" }
"AlwaysUpdate" { $allowedPushOperations = "CreateUpdateAndDelete" }
}
switch ($item.ChildItemSynchronization) {
"NoChildSynchronization" { $scope = "SingleItem" }
"KeepAllChildrenSynchronized" { $scope = "ItemAndDescendants" }
}
$include = @"
{
"name": "$includeName",
"path": "/$($path.Replace('.item', ''))",
"database": "$database",
"scope": "$scope",
"allowedPushOperations": "$allowedPushOperations"
}
"@
$includes.Add($include) | Out-Null
}
if ($includes.Count -eq 0) {
continue
}
Write-Host " De-duping paths"
$dedupedOutput = Invoke-DedupeOutput -includes $includes
# This namespace name can produce a long file path, so lets shorten that by removing unnecessary things.
$namespaceName = $tdsProject.Name.Replace(".scproj", "").Replace("Sitecore.", "")
$namespaceName = $namespaceName.Replace("Foundation.", "").Replace("Feature.", "").Replace("Project.", "")
$namespaceName = $namespaceName.Replace(".Master", "")
$output = @"
{
"namespace": "$namespaceName",
"description": "$(($tdsProject.Name).Replace(".scproj", ""))",
"items": {
"includes": [
$($dedupedOutput -join ",")
]
}
}
"@
$outputBasePath = $($tdsProject.DirectoryName).Replace($tdsProject.Directory.Name, "").Replace("tds", "")
$outputPath = "$outputBasePath/code/$($tdsProject.Directory.Name.Replace('Sitecore.', '')).module.json"
Write-Host " Generating json file: $outputPath"
$output | ConvertFrom-Json -Depth 10 | ConvertTo-Json -Depth 10 | Out-File -Path $outputPath
}
Write-Host "Done!"
@RamiroPrather
Copy link

Very high quality work done. I want to contact you. Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment