Skip to content

Commit 04d9397

Browse files
authored
Merge pull request #174 from fscpscollaborative/develop
Release merge
2 parents 935a73f + 22e9734 commit 04d9397

10 files changed

Lines changed: 406 additions & 13 deletions

File tree

docs/Get-FSCPSModelVersion.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
---
2+
external help file: fscps.tools-help.xml
3+
Module Name: fscps.tools
4+
online version:
5+
schema: 2.0.0
6+
---
7+
8+
# Get-FSCPSModelVersion
9+
10+
## SYNOPSIS
11+
This gets the D365FSC model version
12+
13+
## SYNTAX
14+
15+
```
16+
Get-FSCPSModelVersion [-ModelPath] <String> [-ProgressAction <ActionPreference>] [<CommonParameters>]
17+
```
18+
19+
## DESCRIPTION
20+
This gets the D365FSC model version from the descriptor file by automatically finding the descriptor in the model path
21+
22+
## EXAMPLES
23+
24+
### EXAMPLE 1
25+
```
26+
Get-FSCPSModelVersion -ModelPath "c:\temp\metadata\TestModel"
27+
```
28+
29+
This will get the version information of the TestModel by automatically finding the descriptor file
30+
31+
### EXAMPLE 2
32+
```
33+
Get-FSCPSModelVersion -ModelPath "c:\temp\PackagesLocalDirectory\MyCustomModel"
34+
```
35+
36+
This will get the version information of MyCustomModel including layer name
37+
38+
## PARAMETERS
39+
40+
### -ModelPath
41+
Path to the model folder (automatically searches for Descriptor\*.xml inside)
42+
43+
```yaml
44+
Type: String
45+
Parameter Sets: (All)
46+
Aliases:
47+
48+
Required: True
49+
Position: 1
50+
Default value: None
51+
Accept pipeline input: False
52+
Accept wildcard characters: False
53+
```
54+
55+
### -ProgressAction
56+
{{ Fill ProgressAction Description }}
57+
58+
```yaml
59+
Type: ActionPreference
60+
Parameter Sets: (All)
61+
Aliases: proga
62+
63+
Required: False
64+
Position: Named
65+
Default value: None
66+
Accept pipeline input: False
67+
Accept wildcard characters: False
68+
```
69+
70+
### CommonParameters
71+
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
72+
73+
## INPUTS
74+
75+
## OUTPUTS
76+
77+
## NOTES
78+
Tags: D365, FO, Finance, Operations, Model, Version, Descriptor, Metadata
79+
80+
Author: Oleksandr Nikolaiev (@onikolaiev)
81+
82+
## RELATED LINKS

fscps.tools/fscps.tools.psd1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ GUID = '6b3d02bf-e176-4052-9b40-5012339c20b3'
2424
Author = 'Oleksandr Nikolaiev (@onikolaiev)'
2525

2626
# Company or vendor of this module
27-
CompanyName = 'Ciellos Inc.'
27+
CompanyName = 'Oleksandr Nikolaiev (@onikolaiev)'
2828

2929
# Copyright statement for this module
3030
Copyright = 'Copyright (c) 2025 Oleksandr Nikolaiev. All rights reserved.'
@@ -84,6 +84,7 @@ FunctionsToExport = 'Get-FSCPSSettings', 'Set-FSCPSSettings', 'Invoke-FSCPSChoco
8484
'Register-FSCPSAzureStorageConfig',
8585
'Set-FSCPSActiveAzureStorageConfig',
8686
'Invoke-FSCPSAzureStorageDownload',
87+
'Get-FSCPSModelVersion',
8788
'Invoke-FSCPSAzureStorageUpload', 'Invoke-FSCPSAzureStorageDelete',
8889
'Update-FSCPSISVSource', 'Update-FSCPSNugetsFromLCS',
8990
'Invoke-FSCPSInstallModule', 'Get-FSCPSADOTestCase',

fscps.tools/fscps.tools.psm1

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,24 @@ function Import-ModuleFile
4545
$Path
4646
)
4747

48-
$resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath
49-
if ($doDotSource) { . $resolvedPath }
50-
else { $ExecutionContext.InvokeCommand.InvokeScript($false, ([scriptblock]::Create([io.file]::ReadAllText($resolvedPath))), $null, $null) }
48+
try {
49+
$resolvedPath = $ExecutionContext.SessionState.Path.GetResolvedPSPathFromPSPath($Path).ProviderPath
50+
if ($script:doDotSource) {
51+
. $resolvedPath
52+
}
53+
else {
54+
$content = [io.file]::ReadAllText($resolvedPath)
55+
if (-not [string]::IsNullOrWhiteSpace($content)) {
56+
$scriptBlock = [scriptblock]::Create($content)
57+
if ($scriptBlock) {
58+
$ExecutionContext.InvokeCommand.InvokeScript($false, $scriptBlock, $null, $null)
59+
}
60+
}
61+
}
62+
}
63+
catch {
64+
Write-Warning "Failed to import module file '$Path': $($_.Exception.Message)"
65+
}
5166
}
5267

5368

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
2+
<#
3+
.SYNOPSIS
4+
This gets the D365FSC model version
5+
6+
.DESCRIPTION
7+
This gets the D365FSC model version from the descriptor file by automatically finding the descriptor in the model path
8+
9+
.PARAMETER ModelPath
10+
Path to the model folder (automatically searches for Descriptor\*.xml inside)
11+
12+
.EXAMPLE
13+
PS C:\> Get-FSCPSModelVersion -ModelPath "c:\temp\metadata\TestModel"
14+
15+
This will get the version information of the TestModel by automatically finding the descriptor file
16+
17+
.EXAMPLE
18+
PS C:\> Get-FSCPSModelVersion -ModelPath "c:\temp\PackagesLocalDirectory\MyCustomModel"
19+
20+
This will get the version information of MyCustomModel including layer name
21+
22+
.NOTES
23+
Tags: D365, FO, Finance, Operations, Model, Version, Descriptor, Metadata
24+
25+
Author: Oleksandr Nikolaiev (@onikolaiev)
26+
27+
#>
28+
29+
function Get-FSCPSModelVersion {
30+
[CmdletBinding()]
31+
param(
32+
[Parameter(Mandatory)]
33+
[string]$ModelPath
34+
)
35+
36+
begin{
37+
Invoke-TimeSignal -Start
38+
Write-PSFMessage -Level Important -Message "ModelPath: $ModelPath"
39+
40+
# Validate that the model path exists
41+
if (-not (Test-Path -LiteralPath $ModelPath -PathType Container)) {
42+
throw "Model path '$ModelPath' does not exist or is not a directory"
43+
}
44+
45+
# Helper function to convert layer number to layer name
46+
function Get-LayerName {
47+
param([int]$LayerNumber)
48+
49+
switch ($LayerNumber) {
50+
0 { return "SYS" }
51+
1 { return "SYP" }
52+
2 { return "GLS" }
53+
3 { return "GLP" }
54+
4 { return "FPK" }
55+
5 { return "FPP" }
56+
6 { return "SLN" }
57+
7 { return "SLP" }
58+
8 { return "ISV" }
59+
9 { return "ISP" }
60+
10 { return "VAR" }
61+
11 { return "VAP" }
62+
12 { return "CUS" }
63+
13 { return "CUP" }
64+
14 { return "USR" }
65+
15 { return "USP" }
66+
default { return "Unknown" }
67+
}
68+
}
69+
}
70+
71+
process{
72+
# Look for descriptor file in the model path
73+
$descriptorPath = Join-Path -Path $ModelPath -ChildPath "Descriptor"
74+
$descriptorFiles = @()
75+
76+
if (Test-Path -Path $descriptorPath -PathType Container) {
77+
$descriptorFiles = Get-ChildItem -Path $descriptorPath -Filter "*.xml" -File
78+
}
79+
80+
if ($descriptorFiles.Count -eq 0) {
81+
Write-PSFMessage -Level Warning -Message "No descriptor XML files found in '$descriptorPath'"
82+
return $null
83+
}
84+
85+
if ($descriptorFiles.Count -gt 1) {
86+
Write-PSFMessage -Level Warning -Message "Multiple descriptor files found, using the first one: $($descriptorFiles[0].Name)"
87+
}
88+
89+
$descriptorFile = $descriptorFiles[0].FullName
90+
Write-PSFMessage -Level Verbose -Message "Found descriptor file: $descriptorFile"
91+
92+
try {
93+
[xml]$xml = Get-Content $descriptorFile -Encoding UTF8
94+
95+
$modelInfo = $xml.SelectNodes("/AxModelInfo")
96+
if ($modelInfo.Count -ne 1) {
97+
throw "File '$descriptorFile' is not a valid model descriptor file"
98+
}
99+
100+
# Extract model information
101+
$modelName = ($xml.SelectNodes("/AxModelInfo/Name")).InnerText
102+
$layerId = [int]($xml.SelectNodes("/AxModelInfo/Layer")[0].InnerText)
103+
$layerName = Get-LayerName -LayerNumber $layerId
104+
105+
$versionMajor = ($xml.SelectNodes("/AxModelInfo/VersionMajor")).InnerText
106+
$versionMinor = ($xml.SelectNodes("/AxModelInfo/VersionMinor")).InnerText
107+
$versionBuild = ($xml.SelectNodes("/AxModelInfo/VersionBuild")).InnerText
108+
$versionRevision = ($xml.SelectNodes("/AxModelInfo/VersionRevision")).InnerText
109+
110+
$fullVersion = "$versionMajor.$versionMinor.$versionBuild.$versionRevision"
111+
112+
$modelVersion = [PSCustomObject]@{
113+
ModelName = $modelName
114+
Version = $fullVersion
115+
LayerId = $layerId
116+
LayerName = $layerName
117+
DescriptorPath = $descriptorFile
118+
ModelPath = $ModelPath
119+
VersionMajor = [int]$versionMajor
120+
VersionMinor = [int]$versionMinor
121+
VersionBuild = [int]$versionBuild
122+
VersionRevision = [int]$versionRevision
123+
}
124+
125+
Write-PSFMessage -Level Important -Message "Found model '$modelName' version $fullVersion in layer $layerName ($layerId)"
126+
return $modelVersion
127+
}
128+
catch {
129+
Write-PSFMessage -Level Host -Message "Something went wrong while reading D365FSC model version from '$descriptorFile'" -Exception $PSItem.Exception
130+
Stop-PSFFunction -Message "Stopping because of errors" -EnableException $true
131+
return
132+
}
133+
}
134+
135+
end{
136+
Invoke-TimeSignal -End
137+
}
138+
}
139+
140+
$curModelVersion = Get-FSCPSModelVersion -ModelPath "D:\Sources\vertex\connector-d365-unified-connector\PackagesLocalDirectory\Vertex"
141+
$curModelVersion.Version

fscps.tools/internal/configurations/configuration.ps1

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ Set-PSFConfig -FullName 'fscps.tools.settings.all.artifactsFolderName' -Value 'a
9191
Set-PSFConfig -FullName 'fscps.tools.settings.all.generatePackages' -Value $true -Initialize -Description 'Option to enable a packages generation functionality. Default / TRUE'
9292
Set-PSFConfig -FullName 'fscps.tools.settings.all.createRegularPackage' -Value $true -Initialize -Description 'Option to generate an LCS Deployable Package after build. The "generatePackages" option should be enabled. Default / TRUE'
9393
Set-PSFConfig -FullName 'fscps.tools.settings.all.createCloudPackage' -Value $false -Initialize -Description 'Option to generate a Power Platform Unified Package after build. The "generatePackages" option should be enabled. Default / FALSE'
94-
Set-PSFConfig -FullName 'fscps.tools.settings.all.namingStrategy' -Value 'Default' -Initialize -Description 'The package naming strategy. Custom value means the result package will have the name specified in the packageName variable. Default / Custom'
94+
Set-PSFConfig -FullName 'fscps.tools.settings.all.namingStrategy' -Value 'Default' -Initialize -Description 'The package naming strategy. Custom value means the result package will have the name specified in the packageName variable. Default / Custom / ModelVersion'
95+
Set-PSFConfig -FullName 'fscps.tools.settings.all.versionSourceModelName' -Value '' -Initialize -Description 'The model name to be used for naming the package. This model will be used to receive the metadata number.'
96+
9597
Set-PSFConfig -FullName 'fscps.tools.settings.all.packageNamePattern' -Value 'BRANCHNAME-PACKAGENAME-FNSCMVERSION_DATE.RUNNUMBER' -Initialize -Description ''
9698
Set-PSFConfig -FullName 'fscps.tools.settings.all.packageName' -Value '' -Initialize -Description 'Name of the package'
9799

fscps.tools/internal/functions/invoke-commercecompile.ps1

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ function Invoke-CommerceCompile {
138138
}
139139

140140
# Gather version info
141-
#$versionData = Get-FSCPSVersionInfo -Version $Version @CMDOUT
141+
$versionData = Get-FSCPSVersionInfo -Version $Version @CMDOUT
142142

143143
$SolutionBuildFolderPath = (Join-Path $BuildFolderPath "$($Version)_build")
144144
$responseObject.BUILD_FOLDER_PATH = $SolutionBuildFolderPath
@@ -239,6 +239,61 @@ function Invoke-CommerceCompile {
239239

240240
break;
241241
}
242+
{ $settings.namingStrategy -eq "ModelVersion" }
243+
{
244+
# New naming strategy: "Contoso D365 Commerce A10.0.45 PU66 - V2.2.78.1"
245+
try {
246+
$basePackageName = $settings.packageName
247+
$buildVersion = $Version
248+
$platformUpdate = $versionData.data.PlatformUpdate
249+
250+
# Get commerce version from repo.props file
251+
$commerceVersion = ""
252+
$repoPropsPath = Join-Path $SourcesPath "repo.props"
253+
254+
if (Test-Path $repoPropsPath) {
255+
try {
256+
[xml]$repoPropsXml = Get-Content $repoPropsPath -Encoding UTF8
257+
258+
$majorVersionNode = $repoPropsXml.SelectNodes("//MajorVersion")
259+
$buildNumberNode = $repoPropsXml.SelectNodes("//BuildNumber")
260+
261+
if ($majorVersionNode -and $buildNumberNode) {
262+
$majorVersion = $majorVersionNode[0].InnerText
263+
$buildNumber = $buildNumberNode[0].InnerText
264+
$commerceVersion = "$majorVersion.$buildNumber"
265+
Write-PSFMessage -Level Important -Message "Found commerce version from repo.props: $commerceVersion"
266+
}
267+
else {
268+
Write-PSFMessage -Level Warning -Message "Could not find MajorVersion or BuildNumber in repo.props"
269+
}
270+
}
271+
catch {
272+
Write-PSFMessage -Level Warning -Message "Error parsing repo.props: $($_.Exception.Message)"
273+
}
274+
}
275+
else {
276+
Write-PSFMessage -Level Warning -Message "repo.props file not found at: $repoPropsPath"
277+
}
278+
279+
if ([string]::IsNullOrEmpty($commerceVersion)) {
280+
Write-PSFMessage -Level Warning -Message "Commerce version not found, using build version as fallback"
281+
$commerceVersion = $buildVersion
282+
}
283+
284+
# Construct the package name: "Contoso D365 Commerce A10.0.45 PU66 - V2.2.78.1"
285+
$packageName = "$basePackageName D365 Commerce A$buildVersion PU$platformUpdate - V$commerceVersion"
286+
287+
Write-PSFMessage -Level Important -Message "Generated package name: $packageName"
288+
}
289+
catch {
290+
Write-PSFMessage -Level Warning -Message "Error generating ModelVersion package name: $($_.Exception.Message). Falling back to settings package name."
291+
$packageName = if($settings.packageName.Contains('.zip')) { $settings.packageName } else { $settings.packageName + ".zip" }
292+
}
293+
294+
break;
295+
}
296+
242297
Default {
243298
$packageName = $settings.packageName
244299
break;

fscps.tools/internal/functions/invoke-fsccompile.ps1

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,45 @@ function Invoke-FSCCompile {
425425

426426
break;
427427
}
428+
{ $settings.namingStrategy -eq "ModelVersion" }
429+
{
430+
# New naming strategy: "Contoso D365 FnSCM A10.0.42 PU66 - V2.2.77.1.zip"
431+
try {
432+
$basePackageName = $settings.packageName
433+
$buildVersion = $Version
434+
$platformUpdate = $versionData.data.PlatformUpdate
435+
436+
# Get model version if versionSourceModelName is specified
437+
$modelVersion = ""
438+
if (-not [string]::IsNullOrEmpty($settings.versionSourceModelName)) {
439+
$modelPath = Join-Path $SourceMetadataPath $settings.versionSourceModelName
440+
if (Test-Path $modelPath) {
441+
$curModelVersion = Get-FSCPSModelVersion -ModelPath $modelPath
442+
if ($curModelVersion) {
443+
$modelVersion = $curModelVersion.Version
444+
}
445+
}
446+
else {
447+
Write-PSFMessage -Level Warning -Message "Model path not found for naming: $modelPath"
448+
}
449+
}
450+
451+
if ([string]::IsNullOrEmpty($modelVersion)) {
452+
Write-PSFMessage -Level Warning -Message "Model version not found, using build version as fallback"
453+
$modelVersion = $buildVersion
454+
}
455+
456+
$packageName = "$basePackageName D365 FnSCM A$buildVersion PU$platformUpdate - V$modelVersion.zip"
457+
458+
Write-PSFMessage -Level Important -Message "Generated package name: $packageName"
459+
}
460+
catch {
461+
Write-PSFMessage -Level Warning -Message "Error generating ModelVersion package name: $($_.Exception.Message). Falling back to settings package name."
462+
$packageName = if($settings.packageName.Contains('.zip')) { $settings.packageName } else { $settings.packageName + ".zip" }
463+
}
464+
465+
break;
466+
}
428467
Default {
429468
$packageName = $settings.packageName
430469
break;

0 commit comments

Comments
 (0)