Skip to content

(GH-538) Update version types#1442

Open
michaeltlombardi wants to merge 6 commits intoPowerShell:mainfrom
michaeltlombardi:gh-538/main/resource-version-redux
Open

(GH-538) Update version types#1442
michaeltlombardi wants to merge 6 commits intoPowerShell:mainfrom
michaeltlombardi:gh-538/main/resource-version-redux

Conversation

@michaeltlombardi
Copy link
Collaborator

PR Summary

This change set:

  • Updates the parsing/validation logic for the version types to collect validation errors on input data instead of always returning the first encountered error.

  • Defines new types for each version that implement the Error and Diagnostic traits and enable us to keep error definitions close to the code that emits them. This also makes the types more readily reusable and extractable. The errors are still usable with DscError because this change uses transparent passthrough variants for each newly defined error/diagnostic type.

    This also prepares us for better linting and static analysis reporting instead of failing the first invalid value.

  • Updates the SemanticVersionReq to be more restrictive, making comparator operators mandatatory and forbidding implicit version requirements.

  • Updates ResourceVersion and ResourceVersionReq to use the Date variant for a DateVersion instead of Arbitrary.

PR Context

Prior to this change:

  • The preview implementation for ResourceVersion and ResourceVersionReq defined the Semantic and Arbitrary variants. The working group decided to make the versioning more restrictive by:

    1. Forbidding arbitrary string versions. A resource version must be either a semantic version or a date version. The date version is only supported for compatibility scenarios.
    2. Requiring explicit operators for semantic version requirement comparators to reduce ambiguity and unexpected behavior.
  • The error messaging for deserialization failures for the various types was hidden by the default error for a value that doesn't match any variant of an untagged enum.

  • The error messaging for parsing the version types returned only the first validation/parsing error, meaning that a user who fixed the reported error was likely to have an operation fail anyway because the remaining errors were not reported.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates version parsing/validation to use dedicated error/diagnostic types, report multiple validation issues at once, and tighten accepted syntax (notably requiring explicit operators for semantic version requirements and replacing arbitrary resource versions with date versions).

Changes:

  • Introduces new *Error types implementing Error/Diagnostic and wires them through DscError transparently.
  • Makes SemanticVersionReq parsing stricter (explicit operator required; additional comparator validation for wildcards/build metadata).
  • Reworks ResourceVersion/ResourceVersionReq to support DateVersion instead of arbitrary strings, updating parsing, serde behavior, and tests.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
lib/dsc-lib/src/types/semantic_version_req.rs Adds structured diagnostics and stricter parsing/validation for semantic version requirements
lib/dsc-lib/src/types/semantic_version.rs Introduces SemanticVersionError and updates parsing/conversion errors
lib/dsc-lib/src/types/date_version.rs Introduces DateVersionError with aggregated validation diagnostics
lib/dsc-lib/src/types/resource_version.rs Replaces arbitrary string versions with DateVersion, adds parse errors and ordering semantics
lib/dsc-lib/src/types/resource_version_req.rs Replaces arbitrary requirements with DateVersion, adds parse errors and conversion errors
lib/dsc-lib/src/types/mod.rs Re-exports newly introduced *Error types
lib/dsc-lib/src/dscerror.rs Switches to transparent passthrough variants for typed errors and derives Diagnostic
lib/dsc-lib/locales/en-us.toml Adds/updates localized error strings for new error types
lib/dsc-lib/locales/schemas.definitions.yaml Updates schema documentation text to reflect date versions and stricter semver reqs
lib/dsc-lib/Cargo.toml Adds miette dependency
Cargo.toml Adds workspace dependency on miette
lib/dsc-lib/tests/integration/types/semantic_version_req.rs Updates tests for mandatory operators and new error type
lib/dsc-lib/tests/integration/types/semantic_version.rs Updates tests for new error type and schema assertions
lib/dsc-lib/tests/integration/types/resource_version.rs Updates tests for date-version support and new parsing behavior
lib/dsc-lib/tests/integration/types/resource_version_req.rs Updates tests for date-version requirements and new parsing behavior
lib/dsc-lib/tests/integration/types/date_version.rs Updates tests to use DateVersionError and updated parsing behavior

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

This comment was marked as outdated.

This comment was marked as outdated.

Prior to this change, we had no way to collect errors for validation reporting
to the user. Instead, all of our errors followed a fail-fast model that would
halt execution for a code path on the first error and report that to the user.

This works generally for _execution_ errors but presents a frustrating problem
for users when the errors are for validating a configuration document or a
manifest, where the data has `n` errors but only the first encountered error
is reported.

This change adds the [`miette`][01] library as a workspace dependency and to the
`dsc-lib` crate. This change does not modify any functional code. Future changes
will be needed to wire up diagnostics for different errors.

This change is required in the short term for effectively collecting validation
errors when deserializing data, even if the fancy output is not wired up in `dsc`.

This change will also help us migrate towards providing better error messages for
validation failures in other contexts, like linting.
Prior to this change, the `DateVersion` type passed a string message
to the `DscError::InvalidDateVersion` variant when parsing failed.

This change:

- Defines a new error and diagnostic type `DateVersionError` that has
  variants for different validation and conversion failures.
- Updates the `DscError` enum to derive the diagnostic trait and
  replaces the `InvalidDateVersion` variant with the `DateVersion`
  variant, which is a transparent wrapper for `DateVersionError`.

  This keeps the error definition close to the relevant code and
  minimizes the complexity of the top-level error type.
- Updates the `validate_date` function to return a `DateVersionError`
  with a collection of validation errors instead of returning only the
  first error encountered.
- Returns the `DateVersionError` for parsing, validation, and
  conversion errors related to `DateVersion` instead of `DscError`.
  Because we implemented the transparent variant for this type in
  `DscError`, you can still use the `?` operator to return these errors
  as `DscError` in contexts where that's expected.
- Ensures that the current error messaging model is able to provide the
  user with the error information. In the future, we may be able to
  migrate to using the `miette` reporting to provide a more delightful
  experience for users, but for now we want to ensure that the error
  information is surfaced as normal.
Prior to this change, the `SemanticVersion` type forwarded any errors
from the underlying `semver` crate directly to callers in the
`DscError::SemVer` variant.

This change:

- Defines a new `SemanticVersionError` enum that implements the `Error`
  and `Diagnostic` traits. Currently, it only defines a single variant
  for parse errors.
- Updates the `DscError::SemVer` variant to transparently wrap the
  `SemanticVersionError` instead of the original `semver::Error`.
- Updates the `SemanticVersion::parse` method to return a
  `SemanticVersionError` with the original error and the input text
  when parsing fails.

  Because `DscError::SemVer` now transparently wraps
  `SemanticVersionError`, you can still use the `?` operator to
  propagate errors from `SemanticVersion::parse` without needing to
  manually convert them.
Prior to this change, the `SemanticVersionReq` type was implemented
with some restrictions on the syntax of semantic version requirements it
would accept, but allowed implicit operators.

This change:

- Updates the validation for `SemanticVersionReq` to require explicit
  operators for comparators.
- Adds the `SemanticVersionReqError` type for more specific error
  handling of semantic version requirement parsing and validation
  errors. The type implements the `Error` and `Diagnostic` traits to
  provide better error messaging for invalid requirements.
- Updates the validation logic to collect validation failures instead
  of returning early, allowing for more comprehensive error reporting on
  invalid requirements with multiple issues.
- Replaces the error variants in `DscError` related to semantic version
  requirement parsing and validation with a single `SemanticVersionReq`
  variant that transparently wraps `SemanticVersionReqError`.
Prior to this change, `ResourceVersion` defined the `Semantic` and
`Arbitrary` variants, where the arbitrary variant was a fall-through
for any version defined as a non-semantic version.

This change:

- Replaces the `Arbitrary` variant with a `Date` variant that wraps a
  `DateVersion` type. This allows us to maintain the distinction between
  semantic versions and date versions in the type system, which is
  preferable to having a catch-all arbitrary version type.
- Defines the `ResourceVersionError` type with the `Error` and
  `Diagnostic` traits to represent errors that can occur when parsing
  and converting resource versions. This allows us to provide more
  detailed error messages and diagnostics when resource version parsing
  fails.

  To ensure these errors are properly surfaced during deserialization,
  this change also tells serde explicitly to deserialize from and
  serialize into strings, avoiding the untagged enum variant generic
  error message.
- Replaces the `ResourceVersionToSemverConversion` variant for `DscError`
  with the `ResourceVersion` variant that transparently wraps
  `ResourceVersionError`.
Prior to this change, the `ResourceVersionReq` type defined the
`Semantic` and `Arbitrary` variants, mapping to the variants for
`ResourceVersion`.

This change:

- Replaces the `Arbitrary` variant with a `Date` variant that wraps
  a `DateVersion` to enable version pinning for resources that use
  date-based versioning.
- Defines the `ResourceVersionReqError` type to implement the `Error`
  and `Diagnostic` traits for errors related to parsing and working
  with `ResourceVersionReq`s.
- Updates the parsing logic to determine the shape of the input string
  before trying to parse as a `SemanticVersionReq` or `DateVersion` and
  provide better diagnostics when parsing fails.
- Updates the serde logic to explicitly deserialize from and serialize
  to strings to avoid the ambiguity of the untagged enum error raised
  when deserialization fails for both variants.
- Replaces the `ResourceVersionReqToSemverConversion` variant for
  `DscError` with `ResourceVersionReq`, which transparently wraps
  `ResourceVersionReqError`.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 18 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 43 to 47
/// # Examples
///
/// The following example shows how different instances of [`ResourceVersion`] compare to other
/// instances of `ResourceVersion`, [`SemanticVersion`], [`String`], and [`str`].
/// instances of `ResourceVersion`, [`SemanticVersion`], [`DateVersion`], [`String`], and [`str`].
///
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The examples section was updated to use DateVersion, but the rustdoc earlier in this same comment block still talks about an Arbitrary variant / arbitrary string versioning. Please update the surrounding ResourceVersion documentation to consistently describe Date (and remove the ResourceVersion::Arbitrary reference, which will be a broken intra-doc link).

Copilot uses AI. Check for mistakes.
}
}

// Parsing from a string is just calling `Self::new()`
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment still says parsing from a string calls Self::new(), but the constructor is now ResourceVersionReq::parse() (and new() no longer exists here). Please update the comment to match the current implementation to avoid confusion.

Suggested change
// Parsing from a string is just calling `Self::new()`
// Parsing from a string simply delegates to `Self::parse()`.

Copilot uses AI. Check for mistakes.
@SteveL-MSFT SteveL-MSFT added this to the 3.2-Consider milestone Mar 20, 2026
Copy link
Member

@SteveL-MSFT SteveL-MSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just address copilot feedback. One comment to think about.

Rust technically supports specifying a wildcard-only version requirement (`*`). DSC forbids
specifying this version requirement as it maps to the default version selection and is
discouraged when specifying version requirements for production systems.
1. DSC semantic version requirements _must_ explicitly define an operator for every comparator.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we think about how this will work with our proposed PS cmdlets for authoring config? For example, in PS, -Version 1.2.3 means =1.2.3, but requiring it in PS would make it not idiomatic PS. So one option is to accept that in PS 1.2.3 gets transformed to =1.2.3 in the config which seems acceptable to me, but just want to think about this before we're locked into it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants