WIP: DSC v3 resource for PSResourceGet#1852
WIP: DSC v3 resource for PSResourceGet#1852adityapatwardhan wants to merge 16 commits intomasterfrom
Conversation
michaeltlombardi
left a comment
There was a problem hiding this comment.
Quick review pass on the manifests, looking at resource implementation next.
src/dsc/psresourceget.ps1
Outdated
| Add-Type -AssemblyName "$PSScriptRoot/dependencies/NuGet.Versioning.dll" | ||
|
|
||
| foreach ($resource in $allPSResources) { | ||
| foreach ($inputResource in $inputObj.resources) { | ||
| if ($resource.Name -eq $inputResource.Name) { | ||
| if ($inputResource.Version) { | ||
| # Use the NuGet.Versioning package if available, otherwise do a simple comparison | ||
| try { | ||
| $versionRange = [NuGet.Versioning.VersionRange]::Parse($inputResource.Version) | ||
| $resourceVersion = [NuGet.Versioning.NuGetVersion]::Parse($resource.Version.ToString()) | ||
| if ($versionRange.Satisfies($resourceVersion)) { | ||
| $resourcesExist += $resource | ||
| } | ||
| } | ||
| catch { | ||
| # Fallback: simple string comparison (not full NuGet range support) | ||
| if ($resource.Version.ToString() -eq $inputResource.Version) { | ||
| $resourcesExist += $resource | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
This code seems very similar across different operations, can it be a helper function?
There was a problem hiding this comment.
There are subtle differences, but I will see if I can refactor
src/dsc/psresourceget.ps1
Outdated
| if ($inputObj.Name) { | ||
| $splatt['Name'] = $inputObj.Name | ||
| } | ||
|
|
||
| if ($inputObj.Uri) { | ||
| $splatt['Uri'] = $inputObj.Uri | ||
| } | ||
|
|
||
| if ($inputObj.Trusted) { | ||
| $splatt['Trusted'] = $inputObj.Trusted | ||
| } | ||
|
|
||
| if ($null -ne $inputObj.Priority ) { | ||
| $splatt['Priority'] = $inputObj.Priority | ||
| } |
There was a problem hiding this comment.
Can this just be a loop like:
$properties = @('Name', 'Uri', 'Trusted', 'Priority')
for ($property in $properties) {
if ($null -ne $inputObject.$property) {
$splatt[$property] = $inputObject.$property
}
}
michaeltlombardi
left a comment
There was a problem hiding this comment.
A few more comments on the schema and implementation.
| [string]$ResourceType | ||
| ) | ||
|
|
||
| $inputObj = $stdinput | ConvertFrom-Json -ErrorAction Stop |
There was a problem hiding this comment.
I would probably recommend defining a class for both the various input types and a function to handle both converting the input into the appropriate type and validating the input.
Right now reading $inputObj.<property> and trying to keep track is very difficult, plus we lose the IntelliSense/etc we would get from stronger typing.
| # catch any un-caught exception and write it to the error stream | ||
| trap { | ||
| Write-Trace -Level Error -message $_.Exception.Message | ||
| exit 1 |
There was a problem hiding this comment.
Future enhancement - specific exit codes for specific issues/exceptions.
|
Is the plan to add a discover extension in DSC to be able to find these resource manifests? If so, is there an issue/pr for that? |
| "type": "Microsoft.PowerShell.PSResourceGet/PSResources", | ||
| "version": "0.0.1", | ||
| "get": { | ||
| "executable": "pwsh", |
There was a problem hiding this comment.
How is Windows PowerShell handled? PSResourceGet supports both. For PSScript DSC v3 resource there are actually two different resources to account for different versions of PowerShell.
| "type": "Microsoft.PowerShell.PSResourceGet/Repository", | ||
| "version": "0.0.1", | ||
| "get": { | ||
| "executable": "pwsh", |
There was a problem hiding this comment.
How is Windows PowerShell handled? PSResourceGet supports both. For PSScript DSC v3 resource there are actually two different resources to account for different versions of PowerShell.
@ThomasNieto yup! PowerShell/DSC#913 proposes a discovery extension for finding resource and extension manifests through the |
|
I logged PowerShell/DSC#1024 issue. PSResourceGet will also have the same issue since it uses NuGet version range syntax containing square brackets. |
|
@adityapatwardhan - I think you've followed the news, but you should be able to define a single resource manifest now e.g.,: // psresourceget.dsc.manifests.json
{
"resources": [
{
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json",
"description": "Manage PowerShell resources using PSResourceGet.",
"tags": [
"linux",
"windows",
"macos",
"powershell",
"nuget"
],
"type": "Microsoft.PowerShell.PSResourceGet/PSResourceList",
"version": "0.0.1",
"get": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'psresourcelist' -operation 'get'"
],
"input": "stdin"
},
"set": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'psresourcelist' -operation set"
],
"input": "stdin",
"return": "stateAndDiff"
},
"export": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"./psresourceget.ps1 -resourcetype 'psresourcelist' -operation export"
],
"input": "stdin"
},
"test": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'psresourcelist' -operation test"
],
"input": "stdin",
"return": "stateAndDiff"
},
"schema": {
"embedded": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "PSResourceList",
"type": "object",
"additionalProperties": false,
"required": [
"repositoryName"
],
"properties": {
"repositoryName": {
"title": "Repository Name",
"description": "The name of the repository from where the resources are acquired.",
"type": "string"
},
"resources": {
"title": "Resources",
"description": "The list of resources to manage.",
"type": "array",
"items": {
"$ref": "#/$defs/PSResource"
},
"minItems": 0
},
"_exist": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json"
},
"_inDesiredState": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json"
}
},
"$defs": {
"Scope": {
"type": "string",
"title": "Scope",
"description": "Scope of the resource installation.",
"enum": [
"CurrentUser",
"AllUsers"
]
},
"PSResource": {
"type": "object",
"additionalProperties": false,
"required": [
"name"
],
"properties": {
"name": {
"title": "Name",
"description": "The name of the resource.",
"type": "string"
},
"version": {
"title": "Version",
"description": "The version range of the resource.",
"type": "string",
"pattern": "^(\\[|\\()\\s*\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?\\s*(,\\s*(\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?)?\\s*(\\]|\\)))?$"
},
"scope": {
"title": "Scope",
"description": "The scope of the resource. Can be 'CurrentUser' or 'AllUsers'.",
"$ref": "#/$defs/Scope"
},
"repositoryName": {
"title": "Repository Name",
"description": "The name of the repository from where the resource is acquired.",
"type": "string"
},
"preRelease": {
"title": "Pre-Release version",
"description": "Indicates whether to include pre-release versions of the resource.",
"type": "boolean",
"default": false
},
"_exist": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json"
},
"_inDesiredState": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json"
}
}
},
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json",
"title": "Instance should exist",
"description": "Indicates whether the DSC resource instance should exist.",
"type": "boolean",
"default": true,
"enum": [
false,
true
]
},
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/inDesiredState.json",
"title": "Instance is in desired state",
"description": "Indicates whether the DSC resource instance is in the desired state.",
"type": "boolean",
"default": true,
"enum": [
false,
true
]
}
}
}
}
},
{
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json",
"description": "Manage PowerShell repositories using PSResourceGet.",
"tags": [
"linux",
"windows",
"macos",
"powershell",
"nuget"
],
"type": "Microsoft.PowerShell.PSResourceGet/Repository",
"version": "0.0.1",
"get": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'repository' -operation 'get'"
],
"input": "stdin"
},
"set": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'repository' -operation set"
],
"input": "stdin"
},
"delete": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psresourceget.ps1 -resourcetype 'repository' -operation delete"
],
"input": "stdin"
},
"export": {
"executable": "pwsh",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"./psresourceget.ps1 -resourcetype 'repository' -operation export"
],
"input": "stdin"
},
"schema": {
"embedded": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Repository",
"description": "A PowerShell Resource repository from where to acquire the resources.",
"type": "object",
"additionalProperties": false,
"allOf": [
{
"if": {
"properties": {
"_exist": {
"const": false
}
}
},
"then": {
"required": [
"name"
]
},
"else": {
"required": [
"name",
"uri"
]
}
}
],
"properties": {
"name": {
"title": "Name",
"description": "The name of the repository.",
"type": "string"
},
"uri": {
"title": "URI",
"description": "The URI of the repository.",
"type": "string",
"format": "uri"
},
"trusted": {
"title": "Trusted",
"description": "Indicates whether the repository is trusted.",
"type": "boolean"
},
"priority": {
"title": "Priority",
"description": "The priority of the repository. Lower numbers indicate higher priority.",
"type": "integer",
"minimum": 0,
"maximum": 100
},
"repositoryType": {
"title": "Repository Type",
"description": "The type of the repository.",
"$ref": "#/$defs/RepositoryType"
},
"_exist": {
"$ref": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json"
}
},
"$defs": {
"RepositoryType": {
"type": "string",
"title": "Repository Type",
"description": "The type of the repository. Can be 'Unknown', 'V2', 'V3', 'Local', 'NugetServer', or 'ContainerRegistry'.",
"enum": [
"Unknown",
"V2",
"V3",
"Local",
"NugetServer",
"ContainerRegistry"
]
},
"https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/resource/properties/exist.json",
"title": "Instance should exist",
"description": "Indicates whether the DSC resource instance should exist.",
"type": "boolean",
"default": true,
"enum": [
false,
true
]
}
}
}
}
}
]
} |
|
I think the pattern for version should also slightly change to: "pattern": "^((\\[|\\()[ \\t]*(>=|>|<=|<)?[ \\t]*\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?[ \\t]*(,[ \\t]*(>=|>|<=|<)?[ \\t]*(\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?)?[ \\t]*)?(\\]|\\))|\\d+(\\.\\d+){0,2}(-[0-9A-Za-z-.]+)?)$" |
PR Summary
The initial implementation of DSC v3 resource for PSResourceGet. It include two resources, Repository and PSResources.
PR Context
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:or[ WIP ]to the beginning of the title (theWIPbot will keep its status check atPendingwhile the prefix is present) and remove the prefix when the PR is ready.