Skip to content

Commit f80cd71

Browse files
authored
Merge pull request #1442 from michaeltlombardi/gh-538/main/resource-version-redux
(GH-538) Update version types
2 parents 61d53a5 + efa4b6f commit f80cd71

18 files changed

Lines changed: 2390 additions & 1099 deletions

Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ jsonschema = { version = "0.38", default-features = false }
172172
# dsc-lib
173173
linked-hash-map = { version = "0.5" }
174174
# dsc-lib
175+
miette = { version = "7.6.0" }
176+
# dsc-lib
175177
murmurhash64 = { version = "0.3" }
176178
# dsc-lib-security_context::not_windows
177179
nix = { version = "0.31" }

dsc/tests/dsc_version.tests.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Describe 'tests for metadata versioning' {
2222
$config_yaml = @"
2323
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
2424
directives:
25-
version: 999.0.0
25+
version: '=999.0.0'
2626
resources:
2727
- name: Echo
2828
type: Microsoft.DSC.Debug/Echo
@@ -31,7 +31,7 @@ Describe 'tests for metadata versioning' {
3131
"@
3232
$null = $config_yaml | dsc config get -f - 2>$testdrive/error.log
3333
$errorLog = Get-Content -Path $testdrive/error.log -Raw
34-
$errorLog | Should -BeLike "*Validation*Configuration requires DSC version '999.0.0', but the current version is '*"
34+
$errorLog | Should -BeLike "*Validation*Configuration requires DSC version '=999.0.0', but the current version is '*"
3535
$LASTEXITCODE | Should -Be 2
3636
}
3737

lib/dsc-lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ derive_builder = { workspace = true }
1717
indicatif = { workspace = true }
1818
jsonschema = { workspace = true }
1919
linked-hash-map = { workspace = true }
20+
miette = { workspace = true }
2021
murmurhash64 = { workspace = true }
2122
num-traits = { workspace = true }
2223
path-absolutize = { workspace = true }

lib/dsc-lib/locales/en-us.toml

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -792,14 +792,9 @@ parser = "Parser"
792792
progress = "Progress"
793793
resourceNotFound = "Resource not found"
794794
resourceManifestNotFound = "Resource manifest not found"
795-
resourceVersionToSemverConversion = "Unable to convert arbitrary string resource version to semantic version"
796-
resourceVersionReqToSemverConversion = "Unable to convert arbitrary string resource version requirement to semantic version requirement"
797795
schema = "Schema"
798796
schemaNotAvailable = "No Schema found and `validate` is not supported"
799797
securityContext = "Security context"
800-
semverReqWithBuildMetadataPrefix = "Invalid semantic version requirement: version"
801-
semverReqWithBuildMetadataInfix = "contains the build metadata segment"
802-
semverReqWithBuildMetadataSuffix = "DSC semantic version requirements must not include build metadata."
803798
utf8Conversion = "UTF-8 conversion"
804799
unknown = "Unknown"
805800
validation = "Validation"
@@ -827,13 +822,39 @@ executableNotFoundInWorkingDirectory = "Executable '%{executable}' not found wit
827822
executableNotFound = "Executable '%{executable}' not found"
828823

829824
[types.date_version]
830-
invalidDay = "Day `%{day}` for month `%{month}` is invalid - the day for that month must be between `01` and `%{max_days}`."
831-
invalidLeapDay = "Invalid version date '%{year}-%{month}-%{day}' - the specified date is for a leap day in a year that doesn't have a leap day. Only leap years, like 2024 and 2028, have February 29th. %{year} is not a leap year."
832-
invalidMonth = "Month `%{month}` is invalid. Date version months must be between `01` and `12` inclusive."
833-
invalidYear = "Year `%{year}` is invalid. Date version years must be between `1000` and `9999` inclusive."
834-
notMatchPattern = "Input string '%{text}' didn't match the validating pattern '%{pattern}'"
835-
parseError = "Unable to parse '%{text}' as a date version: %{details}"
825+
invalidDay = "day `%{day}` for month `%{month}` is invalid - must be between `01` and `%{max_days}`"
826+
invalidLeapDay = "specified date '%{year}-02-29' is a leap day but %{year} isn't a leap year"
827+
invalidMonth = "month `%{month}` is invalid - must be between `01` and `12` inclusive"
828+
invalidYear = "year `%{year}` is invalid - must be between `1000` and `9999` inclusive"
829+
notMatchPattern = "input string '%{text}' didn't match the validating pattern '%{pattern}'"
830+
invalidDate = "unable to parse '%{text}' as a date version - %{errors}"
836831

837832
[types.exit_codes_map]
838833
successText = "Success"
839834
failureText = "Error"
835+
836+
[types.resource_version]
837+
unparseableVersion = "unable to parse '%{text}' as resource version - input doesn't seem to be a semantic or date version"
838+
invalidDateVersion = "invalid date resource version: %{err}"
839+
invalidSemanticVersion = "invalid semantic resource version: %{err}"
840+
invalidConversionToSemanticVersion = "unable to convert date resource version '%{version}' to semantic version"
841+
invalidConversionToDateVersion = "unable to convert semantic resource version '%{version}' to date version"
842+
843+
[types.resource_version_req]
844+
invalidConversionToSemanticVersionReq = "unable to convert date resource version requirement to semantic version requirement"
845+
invalidConversionToDateVersion = "unable to convert semantic resource version requirement to date version requirement"
846+
invalidDateVersionRequirement = "invalid date resource version requirement: %{err}"
847+
invalidSemanticVersionRequirement = "invalid semantic resource version requirement: %{err}"
848+
unparseableRequirement = "unable to parse '%{text}' as a resource version requirement - input doesn't seem to be a semantic or date version requirement"
849+
850+
[types.semantic_version]
851+
invalidSemanticVersion = "invalid semantic version '%{text}': %{err}"
852+
853+
[types.semantic_version_req]
854+
unparseableReq = "unable to parse semantic version requirement: %{err}"
855+
invalidReq = "invalid semantic version requirement '%{requirement}': %{err}"
856+
invalidComparator = "invalid comparator '%{comparator}': %{err}"
857+
forbiddenBuildMetadata = "comparator '%{comparator}' is defined with forbidden build metadata segment '%{build}'"
858+
missingOperator = "comparator '%{comparator}' doesn't define an operator"
859+
invalidWildcards = "comparator '%{comparator}' has invalid wildcard characters - must define wildcards as asterisks (`*`), not `x` or `X`"
860+
wildcardMajorVersion = "comparator '%{comparator}' defines the major version segment as a wildcard `%{wildcard}` instead of a literal number"

lib/dsc-lib/locales/schemas.definitions.yaml

Lines changed: 58 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ schemas:
7676
You can't use alternate formats for the exit code. For example, instead of the
7777
hexadecimal value `0x80070005` for "Access denied", specify the exit code as
7878
`-2147024891`.
79-
79+
8080
If you're authoring your resource manifest in YAML, be sure to wrap the exit code in
8181
single quotes, like `'0': Success` instead of `0: Success` to ensure the YAML file can be
8282
parsed correctly.
@@ -130,26 +130,24 @@ schemas:
130130
en-us: |-
131131
Defines the version of a DSC resource.
132132
133-
DSC supports both semantic versioning and arbitrary versioning for resources. Semantic
133+
DSC supports both semantic versioning and date versioning for resources. Semantic
134134
versioning is the preferred and recommended versioning strategy. DSC only supports
135-
arbitrary versioning for compatibility scenarios.
135+
date versioning for compatibility scenarios.
136136
137137
When the version is defined as a valid [semantic version][01], DSC can correctly compare
138138
versions to determine the latest version or match a [semantic version requirement][02].
139139
Where possible, resource and extension authors should follow semantic versioning for the
140140
best user experience.
141141
142-
When the version is an arbitrary string, DSC compares the strings
143-
[lexicographically][03]. Arbitrary string versions are only equivalent when they contain
144-
exactly the same characters - the comparison is case-sensitive. If you're defining a
145-
resource that doesn't follow semantic versioning, consider defining the version as an
146-
[ISO 8601 date][04], like `2026-01-15`. When you do, DSC can correctly determine that a
147-
later date should be treated as a newer version.
142+
When the version is defined as a valid [date version][03], DSC compares the dates to see
143+
which one is newer. Date versions are only equivalent when they define the same date and
144+
optional prerelease segment. Both versions must define or omit the prerelease segment. If
145+
the prerelease segment is defined, the segments must be identical - the comparison is
146+
case sensitive.
148147
149148
[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/definitions/semver
150-
[02]: https://learn.microsoft.com/powershell/dsc/reference/schemas/definitions/semverReq
151-
[03]: https://doc.rust-lang.org/std/cmp/trait.Ord.html#lexicographical-comparison
152-
[04]: https://www.iso.org/iso-8601-date-and-time-format.html
149+
[02]: https://learn.microsoft.com/en-us/powershell/dsc/concepts/defining-semver-reqs.md
150+
[03]: https://learn.microsoft.com/powershell/dsc/reference/schemas/definitions/dateVersion
153151
semanticVariant:
154152
title:
155153
en-us: Semantic resource version
@@ -167,36 +165,31 @@ schemas:
167165
168166
[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/definitions/semver
169167
[02]: https://semver.org
170-
arbitraryVariant:
168+
dateVariant:
171169
title:
172-
en-us: Arbitrary string resource version
170+
en-us: Date resource version
173171
description:
174172
en-us: >-
175-
Defines the resource's version as an arbitrary string.
173+
Defines the resource's version as a date version.
176174
deprecationMessage:
177175
en-us: >-
178-
Defining a resource version as an arbitrary string is supported only for compatibility
176+
Defining a resource version as a date version is supported only for compatibility
179177
purposes. If possible, define your resource version as a valid semantic version. For
180178
more information about defining a semantic version, see [semver.org](https://semver.org).
181179
markdownDescription:
182180
en-us: |-
183-
Defines the resource's version as an arbitrary string.
181+
Defines the resource's version as a date version.
184182
185-
DSC uses this variant for the version of any DSC resource that defines its version as a
186-
string that can't be parsed as a semantic version. This variant remains supported for
187-
compatibility purposes but is _not_ recommended for production usage.
183+
This variant remains supported for compatibility purposes but is _not_ recommended for
184+
production usage.
188185
189-
When a resource defines the version as an arbitrary string:
186+
When a resource defines the version as a date version:
190187
191-
1. You can only use exact match version requirements for that resource.
192-
1. When a resource defines the version as an arbitrary string, DSC uses Rust's
193-
[lexicographic comparison][01] logic to determine the "latest" version of the
194-
resource to use as the default version when no version requirement is specified.
188+
1. The resource only matches a resource version requirement that is defined as a date
189+
version when the date and optional prerelease segments are exactly the same. The
190+
comparison is case-sensitive for the prerelease segment.
195191
1. When DSC discovers a multiple manifests for a resource, DSC always treats
196-
semantically versioned resources as newer than resources with an arbitrary string
197-
version.
198-
199-
[01]: https://doc.rust-lang.org/std/cmp/trait.Ord.html#lexicographical-comparison
192+
semantically versioned resources as newer than resources with a date version.
200193
201194
resourceVersionReq:
202195
title:
@@ -208,24 +201,23 @@ schemas:
208201
en-us: |-
209202
Defines one or more limitations for a [resource version][01] to enable version pinning.
210203
211-
DSC supports both semantic versioning and arbitrary versioning for resources. Semantic
204+
DSC supports both semantic versioning and date versioning for resources. Semantic
212205
versioning is the preferred and recommended versioning strategy. DSC only supports
213-
arbitrary versioning for compatibility scenarios.
206+
date versioning for compatibility scenarios.
214207
215-
Because DSC supports arbitrary string versions for compatibility, version requirements
216-
must also support arbitrary string versions.
208+
Because DSC supports date versions for compatibility, version requirements
209+
must also support date versions as a valid requirement.
217210
218211
When a resource version requirement is semantic, it behaves like a
219212
[semantic version requirement][02] and only matches resource versions that are semantic
220-
_and_ valid for the given requirement. Arbitrary string versions never match a semantic
213+
_and_ valid for the given requirement. Date versions never match a semantic
221214
resource version requirement.
222215
223-
Similarly, when a resource version requirement is an arbitrary string, it can never match
224-
a semantically versioned resource. Instead, it matches an arbitrary resource version when
225-
the arbitrary string version is _exactly_ the same as the arbitrary resource version
226-
requirement.
216+
Similarly, when a resource version requirement is a date version, it can never match
217+
a semantically versioned resource. Instead, it matches a date resource version when
218+
the date version is _exactly_ the same as the date resource version requirement.
227219
228-
Arbitrary resource versions and resource version requirements are only defined for
220+
Date resource versions and date resource version requirements are only defined for
229221
compatibility scenarios. You should use semantic versions for resources and resource
230222
version requirements.
231223
@@ -247,33 +239,33 @@ schemas:
247239
[Defining semantic version requirements][01].
248240
249241
[01]: https://learn.microsoft.com/en-us/powershell/dsc/concepts/defining-semver-reqs.md
250-
arbitraryVariant:
242+
dateVariant:
251243
title:
252-
en-us: Arbitrary resource version requirement
244+
en-us: Date resource version requirement
253245
description:
254246
en-us: >-
255-
Defines the required version for the resource as an arbitrary string.
247+
Defines the required version for the resource as a date version.
256248
deprecationMessage:
257249
en-us: >-
258-
Defining a resource version requirement as an arbitrary string is supported only for
250+
Defining a resource version requirement as a date version is supported only for
259251
compatibility purposes. If possible, define your version requirement as a valid
260252
semantic version requirement. For more information about defining semantic version
261253
requirements with DSC, see
262254
[Defining semantic version requirements](https://learn.microsoft.com/en-us/powershell/dsc/concepts/defining-semver-reqs.md)
263255
markdownDescription:
264256
en-us: |-
265-
Defines the required version for the resource as an arbitrary string.
257+
Defines the required version for the resource as a date version.
266258
267-
DSC considers any requirement that can't be parsed as a semantic version requirement as
268-
an arbitrary resource version requirement. This kind of requirement remains supported
269-
for compatibility purposes but is _not_ recommended for production usage.
259+
Date version requirements are supported for compatibility purposes but are _not_
260+
recommended for production usage.
270261
271-
When a resource version requirement is defined as an arbitrary string:
262+
When a resource version requirement is defined as a date version:
272263
273264
1. It can never match a semantically versioned resource.
274-
1. It only matches a resource with an [arbitrary string version][01] when the resource
265+
1. It only matches a resource with a [date resource version][01] when the resource
275266
version and this version requirement are exactly the same. The comparison is
276-
case-sensitive.
267+
case-sensitive when comparing the prerelease segments for date versions and the
268+
date version requirement.
277269
278270
[01]: https://learn.microsoft.com/powershell/dsc/reference/schemas/definitions/resourceVersion
279271
@@ -338,6 +330,22 @@ schemas:
338330
Rust technically supports specifying a wildcard-only version requirement (`*`). DSC forbids
339331
specifying this version requirement as it maps to the default version selection and is
340332
discouraged when specifying version requirements for production systems.
333+
1. DSC semantic version requirements _must_ explicitly define an operator for every comparator.
334+
335+
DSC forbids defining a comparator without an operator, like `1.*` or `1.2.3, <1.5`, to
336+
reduce ambiguity and unexpected behavior for version pinning. For example, in all other
337+
cases, omitting version segments and specifying them as a wildcard has the same behavior
338+
_except_ for the comparators `1.2` and `1.2.*`:
339+
340+
- `1`, `1.*`, and `1.*.*` all have an effective requirement of `>=1.0.0, <2.0.0`.
341+
- `>1.2` and `>1.2.*` both have an effective requirement of `>1.2.0`.
342+
- `1.2` has an effective requirement of `>=1.2.0, <2.0.0` but `1.2.*` has an effective
343+
requirement of `>=1.2.0, <1.3.0`.
344+
345+
Similarly, it is not immediately obvious to a user who isn't familiar with Rust semantic
346+
version requirements that `1.2.3` will match `1.5.7`. It's more common across version
347+
requirements to expect an exactly specified version to be an exact match requirement, not
348+
a semantically compatible requirement.
341349
1. DSC semantic version requirements only support the asterisk (`*`) character for wildcards,
342350
not `x` or `X`.
343351

0 commit comments

Comments
 (0)