Skip to content

Commit

Permalink
Fix CLI module versions and version pre-release handling #2557 (#2558)
Browse files Browse the repository at this point in the history
  • Loading branch information
BernieWhite authored Sep 23, 2024
1 parent 6536998 commit 0570e0e
Show file tree
Hide file tree
Showing 27 changed files with 675 additions and 277 deletions.
9 changes: 8 additions & 1 deletion PSRule.sln
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSRule.Tool.Tests", "tests\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSRule.CommandLine", "src\PSRule.CommandLine\PSRule.CommandLine.csproj", "{9A556814-8E9D-4C76-8F6D-1AF2DA23A9E0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PSRule.CommandLine.Tests", "tests\PSRule.CommandLine.Tests\PSRule.CommandLine.Tests.csproj", "{C25E2FC1-E306-4D99-925C-15E5DD51F6A2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSRule.CommandLine.Tests", "tests\PSRule.CommandLine.Tests\PSRule.CommandLine.Tests.csproj", "{C25E2FC1-E306-4D99-925C-15E5DD51F6A2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PSRule.Types.Tests", "tests\PSRule.Types.Tests\PSRule.Types.Tests.csproj", "{34095F78-CDA3-4E72-B64C-6366EA4B3EAF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -88,6 +90,10 @@ Global
{C25E2FC1-E306-4D99-925C-15E5DD51F6A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C25E2FC1-E306-4D99-925C-15E5DD51F6A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C25E2FC1-E306-4D99-925C-15E5DD51F6A2}.Release|Any CPU.Build.0 = Release|Any CPU
{34095F78-CDA3-4E72-B64C-6366EA4B3EAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34095F78-CDA3-4E72-B64C-6366EA4B3EAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34095F78-CDA3-4E72-B64C-6366EA4B3EAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34095F78-CDA3-4E72-B64C-6366EA4B3EAF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -96,6 +102,7 @@ Global
{D3488CE2-779F-4474-B38A-F894A4B689F7} = {E0EA0CBA-96C5-4447-8B69-BC13EF0D7A4A}
{DA46C891-08F1-4D01-9F98-1F8BB10CAFEC} = {E0EA0CBA-96C5-4447-8B69-BC13EF0D7A4A}
{C25E2FC1-E306-4D99-925C-15E5DD51F6A2} = {E0EA0CBA-96C5-4447-8B69-BC13EF0D7A4A}
{34095F78-CDA3-4E72-B64C-6366EA4B3EAF} = {E0EA0CBA-96C5-4447-8B69-BC13EF0D7A4A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {533491EB-BAE9-472E-B57F-A675ECD335B5}
Expand Down
11 changes: 11 additions & 0 deletions docs/CHANGELOG-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers

## Unreleased

What's changed since pre-release v3.0.0-B0267:

- General improvements:
- **Breaking change**: Empty version comparison only accepts stable versions by default by @BernieWhite.
[#2557](https://github.com/microsoft/PSRule/issues/2557)
- `version` and `apiVersion` assertions only accept stable versions by default for all cases.
- Pre-release versions can be accepted by setting `includePrerelease` to `true`.
- Bug fixes:
- Fixed CLI upgrade uses pre-release module by @BernieWhite.
[#2549](https://github.com/microsoft/PSRule/issues/2549)

## v3.0.0-B0267 (pre-release)

What's changed since pre-release v3.0.0-B0203:
Expand Down
56 changes: 33 additions & 23 deletions docs/concepts/PSRule/en-US/about_PSRule_Assert.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,19 +141,20 @@ Notable differences between object paths and JSONPath are:

### APIVersion

The `APIVersion` assertion method checks the field value is a valid date version.
The `APIVersion` assertion method checks the field value is a valid stable date version.
A constraint can optionally be provided to require the date version to be within a range.
By default, only stable versions are accepted unless pre-releases are included.

A date version uses the format `yyyy-MM-dd` (`2015-10-01`).
Additionally an optional string prerelease identifier can be used `yyyy-MM-dd-prerelease` (`2015-10-01-preview.1`).
Additionally an optional string pre-release identifier can be used `yyyy-MM-dd-prerelease` (`2015-10-01-preview.1`).

The following parameters are accepted:

- `inputObject` - The object being checked for the specified field.
- `field` - The name of the field to check.
This is a case insensitive compare.
- `constraint` (optional) - A version constraint, see below for details of version constrain format.
- `includePrerelease` (optional) - Determines if prerelease versions are included.
- `includePrerelease` (optional) - Determines if pre-release versions are included.
Unless specified this defaults to `$False`.

The following are supported constraints:
Expand Down Expand Up @@ -183,14 +184,14 @@ By example:
- Pass: `2014-01-01`, `2015-10-01`, `2019-06-30`, `2022-02-01`.
- Fail: `2015-01-01`, `2022-09-01`.

Handling for prerelease versions:
Handling for pre-release versions:

- Constraints and versions containing prerelease identifiers are supported.
- Constraints and versions containing pre-release identifiers are supported.
i.e. `>=2015-10-01-preview` or `2015-10-01-preview`.
- A version containing a prerelease identifer follows similar ordering to semantic versioning.
- A version containing a pre-release identifier follows similar ordering to semantic versioning.
i.e. `2015-10-01-preview` < `2015-10-01-preview.1` < `2015-10-01` < `2022-03-01-preview` < `2022-03-01`.
- A constraint without a prerelease identifer will only match a stable version by default.
Set `includePrerelease` to `$True` to include prerelease versions.
- A constraint without a pre-release identifier will only match a stable version by default.
Set `includePrerelease` to `$True` to include pre-;release versions.
Alternatively use the `@pre` or `@prerelease` flag in a constraint.

Reasons include:
Expand All @@ -204,10 +205,14 @@ Reasons include:
Examples:

```powershell
Rule 'ValidAPIVersion' {
Rule 'ValidStableAPIVersion' {
$Assert.APIVersion($TargetObject, 'apiVersion')
}
Rule 'AnyValidAPIVersion' {
$Assert.APIVersion($TargetObject, 'apiVersion', '', $True)
}
Rule 'MinimumAPIVersion' {
$Assert.APIVersion($TargetObject, 'apiVersion', '>=2015-10-01')
}
Expand Down Expand Up @@ -1584,17 +1589,18 @@ Rule 'Subset' {

### Version

The `Version` assertion method checks the field value is a valid semantic version.
The `Version` assertion method checks the field value is a valid stable semantic version.
A constraint can optionally be provided to require the semantic version to be within a range.
By default, only stable versions are accepted unless pre-releases are included.

The following parameters are accepted:

- `inputObject` - The object being checked for the specified field.
- `field` - The name of the field to check.
This is a case insensitive compare.
This is a case insensitive compare.
- `constraint` (optional) - A version constraint, see below for details of version constrain format.
- `includePrerelease` (optional) - Determines if prerelease versions are included.
Unless specified this defaults to `$False`.
- `includePrerelease` (optional) - Determines if pre-release versions are included.
Unless specified this defaults to `$False`.

The following are supported constraints:

Expand Down Expand Up @@ -1627,17 +1633,17 @@ By example:
- Pass: `1.2.3`, `3.4.5`, `3.5.0`, `4.9.9`.
- Fail: `3.0.0`, `5.0.0`.

Handling for prerelease versions:
Handling for pre-release versions:

- Constraints and versions containing prerelease identifiers are supported.
i.e. `>=1.2.3-build.1` or `1.2.3-build.1`.
- A version containing a prerelease identifer follows semantic versioning rules.
- Constraints and versions containing pre-release identifiers are supported.
i.e. `>=1.2.3-build.1` or `1.2.3-build.1`.
- A version containing a pre-release identifier follows semantic versioning rules.
i.e. `1.2.3-alpha` < `1.2.3-alpha.1` < `1.2.3-alpha.beta` < `1.2.3-beta` < `1.2.3-beta.2` < `1.2.3-beta.11` < `1.2.3-rc.1` < `1.2.3`.
- A constraint without a prerelease identifer will only match a stable version by default.
Set `includePrerelease` to `$True` to include prerelease versions.
- Constraints with a prerelease identifer will only match:
- Matching prerelease versions of the same major.minor.patch version by default.
Set `includePrerelease` to `$True` to include prerelease versions of all matching versions.
- A constraint without a pre-release identifier will only match a stable version by default.
Set `includePrerelease` to `$True` to include pre-release versions.
- Constraints with a pre-release identifier will only match:
- Matching pre-release versions of the same major.minor.patch version by default.
Set `includePrerelease` to `$True` to include pre-release versions of all matching versions.
Alternatively use the `@pre` or `@prerelease` flag in a constraint.
- Matching stable versions.

Expand Down Expand Up @@ -1672,10 +1678,14 @@ Reasons include:
Examples:

```powershell
Rule 'ValidVersion' {
Rule 'ValidStableVersion' {
$Assert.Version($TargetObject, 'version')
}
Rule 'AnyValidVersion' {
$Assert.Version($TargetObject, 'version', '', $True)
}
Rule 'MinimumVersion' {
$Assert.Version($TargetObject, 'version', '>=1.2.3')
}
Expand Down
37 changes: 37 additions & 0 deletions docs/upgrade-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,43 @@ From _v3.0.0_, the `module restore` command installs modules based on:
[5]: concepts/cli/module.md
[6]: concepts/lockfile.md

### Version and APIVersion accept stable

Prior to _v3.0.0_, some usage of `version` and `apiVersion` accepted pre-release versions by default.
For example:

```yaml
---
# Synopsis: Any version example
apiVersion: github.com/microsoft/PSRule/v1
kind: Selector
metadata:
name: PreviousAnyVersionExample
spec:
if:
field: dateVersion
apiVersion: ''
```
When `apiVersion` is empty any version is accepted including pre-releases.

From _v3.0.0_ pre-release versions are not accepted by default.
Set the `includePrerelease` property to `true`.

```yaml
---
# Synopsis: Test comparison with apiVersion.
apiVersion: github.com/microsoft/PSRule/v1
kind: Selector
metadata:
name: AnyVersion
spec:
if:
field: dateVersion
apiVersion: ''
includePrerelease: true
```

## Upgrading to v2.0.0

### Resources naming restrictions
Expand Down
14 changes: 7 additions & 7 deletions src/PSRule.CommandLine/Commands/ModuleCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public static async Task<int> ModuleRestoreAsync(RestoreOptions operationOptions
// Check if the installed version matches the constraint.
if (IsInstalled(pwsh, includeModule, null, out var installedVersion) &&
!operationOptions.Force &&
(moduleConstraint == null || moduleConstraint.Equals(installedVersion)))
(moduleConstraint == null || moduleConstraint.Accepts(installedVersion)))
{
// invocation.Log(Messages.UsingModule, includeModule, installedVersion.ToString());
clientContext.LogVerbose($"The module {includeModule} is already installed.");
Expand Down Expand Up @@ -224,13 +224,13 @@ public static async Task<int> ModuleAddAsync(ModuleOptions operationOptions, Cli
if (!file.Modules.TryGetValue(module, out var item) || operationOptions.Force)
{
// Get a constraint if set from options.
var moduleConstraint = requires.TryGetValue(module, out var c) ? c : null;
var moduleConstraint = requires.TryGetValue(module, out var c) ? c : ModuleConstraint.Any(module, includePrerelease: false);

// Get target version if specified in command-line.
var targetVersion = !string.IsNullOrEmpty(operationOptions.Version) && SemanticVersion.TryParseVersion(operationOptions.Version, out var v) && v != null ? v : null;

// Check if the target version is valid with the constraint if set.
if (targetVersion != null && moduleConstraint != null && !moduleConstraint.Constraint.Equals(targetVersion))
if (targetVersion != null && moduleConstraint != null && !moduleConstraint.Constraint.Accepts(targetVersion))
{
clientContext.LogError(Messages.Error_503, operationOptions.Version!);
return ERROR_MODULE_ADD_VIOLATES_CONSTRAINT;
Expand Down Expand Up @@ -316,7 +316,7 @@ public static async Task<int> ModuleUpgradeAsync(ModuleOptions operationOptions,
foreach (var kv in file.Modules)
{
// Get a constraint if set from options.
var moduleConstraint = requires.TryGetValue(kv.Key, out var c) ? c : null;
var moduleConstraint = requires.TryGetValue(kv.Key, out var c) ? c : ModuleConstraint.Any(kv.Key, includePrerelease: false);

// Find the ideal version.
var idealVersion = await FindVersionAsync(kv.Key, moduleConstraint, null, null, cancellationToken);
Expand Down Expand Up @@ -408,7 +408,7 @@ private static bool IsInstalled(PowerShell pwsh, string module, SemanticVersion.
versionString != null &&
SemanticVersion.TryParseVersion(versionString, out var v) &&
v != null &&
(targetVersion == null || targetVersion.Equals(v)) &&
(targetVersion == null || targetVersion.CompareTo(v) == 0) &&
v.CompareTo(installedVersion) > 0)
installedVersion = v;
}
Expand Down Expand Up @@ -452,8 +452,8 @@ private static bool TryPrivateData(PSModuleInfo info, string propertyName, out H
if (version.ToFullString() is string versionString &&
SemanticVersion.TryParseVersion(versionString, out var v) &&
v != null &&
(constraint == null || constraint.Constraint.Equals(v)) &&
(targetVersion == null || targetVersion.Equals(v)) &&
(constraint == null || constraint.Accepts(v)) &&
(targetVersion == null || targetVersion.CompareTo(v) == 0) &&
v.CompareTo(result) > 0 &&
v.CompareTo(installedVersion) > 0)
result = v;
Expand Down
9 changes: 7 additions & 2 deletions src/PSRule.Tool/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"profiles": {
"ps-rule module add": {
"commandName": "Project",
"commandLineArgs": "module add abc --version 1.0.0",
"commandLineArgs": "module add PSRule.Rules.Azure",
"workingDirectory": "../../"
},
"ps-rule run": {
Expand All @@ -14,6 +14,11 @@
"commandName": "Project",
"commandLineArgs": "module restore",
"workingDirectory": "../../"
},
"ps-rule module upgrade": {
"commandName": "Project",
"commandLineArgs": "module upgrade",
"workingDirectory": "../../"
}
}
}
}
Loading

0 comments on commit 0570e0e

Please sign in to comment.