Skip to content

Commit

Permalink
Add lock file support microsoft#1660 (microsoft#1661)
Browse files Browse the repository at this point in the history
  • Loading branch information
BernieWhite authored Nov 12, 2023
1 parent 3ee8c19 commit 280508e
Show file tree
Hide file tree
Showing 27 changed files with 1,068 additions and 63 deletions.
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
"/**/**.Rule.jsonc"
],
"url": "./schemas/PSRule-resources.schema.json"
},
{
"fileMatch": [
"/**/ps-rule.lock.json"
],
"url": "./schemas/PSRule-lock.schema.json"
}
],
"[json]": {
Expand Down
4 changes: 4 additions & 0 deletions docs/CHANGELOG-v3.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers

What's changed since release v2.9.0:

- New features:
- Added lock file support when using CLI and related tools by @BernieWhite.
[#1660](https://github.com/microsoft/PSRule/issues/1660)
- The lock file used used during analysis and when installing modules to select a specific version.
- General improvements:
- **Breaking change:** Switch to use SHA-512 for generating unbound objects by @BernieWhite.
[#1155](https://github.com/microsoft/PSRule/issues/1155)
Expand Down
25 changes: 25 additions & 0 deletions docs/concepts/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# PSRule CLI

!!! Abstract
PSRule provides a command-line interface (CLI) to run rules and analyze results.
This article describes the commands available in the CLI.

## `analyze`

Run rule analysis.

## `module add`

Add one or more modules to the lock file.

## `module remove`

Remove one or more modules from the lock file.

## `module upgrade`

Upgrade to the latest versions any modules within the lock file.

## `restore`

Restore modules defined in configuration locally.
33 changes: 33 additions & 0 deletions docs/concepts/lockfile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Lock file

!!! Abstract
PSRule v3 and later uses a lock file to define the modules and versions used to run analysis.
This article describes the lock file and how to manage it.

## Overview

An optional lock file can be used to define the modules and versions used to run analysis.
Using the lock file ensures that the same modules and versions are used across multiple machines, improving consistency.

- **Lock file is present** - PSRule will use the module versions defined in the lock file.
- **Lock file is not present** - PSRule will use the latest version of each module installed locally.

Name | Supports lock file
---- | ------------------
PowerShell | No
CLI | Yes, v3 and later
GitHub Actions | Yes, v3 and later
Azure Pipelines | Yes, v3 task and later
Visual Studio Code | Yes, v3 and later

!!! Important
The lock file only applies to PSRule outside of PowerShell.
When using PSRule as a PowerShell module, the lock file is ignored.

## Restoring modules

When the lock file is present, PSRule will restore the modules and versions defined in the lock file.

<!-- Modules are automatically restored by PSRule when:
- Running analysis with -->
4 changes: 3 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ nav:
- Functions: expressions/functions.md
- Grouping rules: concepts/grouping-rules.md
- Sub-selectors: expressions/sub-selectors.md
- Lock file: concepts/lockfile.md
- Scenarios:
- Using within continuous integration: scenarios/validation-pipeline/validation-pipeline.md
- Troubleshooting: troubleshooting.md
Expand All @@ -85,7 +86,7 @@ nav:
# - Configuring rule defaults: setup/configuring-rules.md
# - Configuring expansion: setup/configuring-expansion.md
- Reference:
- Commands:
- PowerShell cmdlets:
- Assert-PSRule: commands/PSRule/en-US/Assert-PSRule.md
- Export-PSRuleBaseline: commands/PSRule/en-US/Export-PSRuleBaseline.md
- Get-PSRule: commands/PSRule/en-US/Get-PSRule.md
Expand All @@ -96,6 +97,7 @@ nav:
- New-PSRuleOption: commands/PSRule/en-US/New-PSRuleOption.md
- Set-PSRuleOption: commands/PSRule/en-US/Set-PSRuleOption.md
- Test-PSRuleTarget: commands/PSRule/en-US/Test-PSRuleTarget.md
- CLI commands: concepts/cli.md
- Assertion methods: concepts/PSRule/en-US/about_PSRule_Assert.md
- Baselines: concepts/PSRule/en-US/about_PSRule_Baseline.md
- Badges: concepts/PSRule/en-US/about_PSRule_Badges.md
Expand Down
10 changes: 10 additions & 0 deletions ps-rule.lock.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"modules": {
"PSRule.Rules.MSFT.OSS": {
"version": "1.1.0"
},
"PSRule.Rules.Azure": {
"version": "1.30.0"
}
}
}
29 changes: 29 additions & 0 deletions schemas/PSRule-lock.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"title": "PSRule lock",
"description": "A schema for the PSRule lock file.",
"properties": {
"modules": {
"type": "object",
"title": "Modules",
"additionalProperties": {
"type": "object",
"properties": {
"version": {
"type": "string",
"title": "Version"
}
},
"required": [
"version"
],
"additionalProperties": false
}
}
},
"required": [
"modules"
],
"additionalProperties": false
}
113 changes: 110 additions & 3 deletions src/PSRule.Tool/ClientBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.

using System.CommandLine;
using System.CommandLine.Builder;
using System.Reflection;
using PSRule.Tool.Resources;

Expand All @@ -15,6 +16,9 @@ internal sealed class ClientBuilder
private readonly Option<bool> _Verbose;
private readonly Option<bool> _Debug;
private readonly Option<bool> _RestoreForce;
private readonly Option<string> _ModuleAddVersion;
private readonly Option<bool> _ModuleAddForce;
private readonly Option<bool> _ModuleAddSkipVerification;
private readonly Option<string[]> _Path;
private readonly Option<DirectoryInfo> _OutputPath;
private readonly Option<string> _OutputFormat;
Expand All @@ -27,7 +31,8 @@ private ClientBuilder(RootCommand cmd)
Command = cmd;
_Option = new Option<string>(
new string[] { "--option" },
CmdStrings.Options_Option_Description
getDefaultValue: () => "ps-rule.yaml",
description: CmdStrings.Options_Option_Description
);
_Verbose = new Option<bool>(
new string[] { "--verbose" },
Expand All @@ -38,7 +43,8 @@ private ClientBuilder(RootCommand cmd)
CmdStrings.Options_Debug_Description
);
_Path = new Option<string[]>(
new string[] { "-p", "--path" }
new string[] { "-p", "--path" },
CmdStrings.Options_Path_Description
);
_OutputPath = new Option<DirectoryInfo>(
new string[] { "--output-path" }
Expand All @@ -50,7 +56,8 @@ private ClientBuilder(RootCommand cmd)
new string[] { "-f", "--input-path" }
);
_Module = new Option<string[]>(
new string[] { "-m", "--module" }
new string[] { "-m", "--module" },
CmdStrings.Options_Module_Description
);
_Baseline = new Option<string>(
new string[] { "--baseline" }
Expand All @@ -59,6 +66,19 @@ private ClientBuilder(RootCommand cmd)
new string[] { "--force" },
CmdStrings.Restore_Force_Description
);
_ModuleAddVersion = new Option<string>
(
new string[] { "--version" },
CmdStrings.Module_Add_Version_Description
);
_ModuleAddForce = new Option<bool>(
new string[] { "--force" },
CmdStrings.Module_Add_Force_Description
);
_ModuleAddSkipVerification = new Option<bool>(
new string[] { "--skip-verification" },
CmdStrings.Module_Add_SkipVerification_Description
);

cmd.AddGlobalOption(_Option);
cmd.AddGlobalOption(_Verbose);
Expand All @@ -75,6 +95,7 @@ public static Command New()
};
var builder = new ClientBuilder(cmd);
builder.AddAnalyze();
builder.AddModule();
builder.AddRestore();
return builder.Command;
}
Expand Down Expand Up @@ -126,5 +147,91 @@ private void AddRestore()
});
Command.AddCommand(cmd);
}

private void AddModule()
{
var cmd = new Command("module", CmdStrings.Module_Description);

var moduleArg = new Argument<string[]>
(
"module",
CmdStrings.Module_Module_Description
);
moduleArg.Arity = ArgumentArity.OneOrMore;

// Add
var add = new Command(
"add",
CmdStrings.Module_Add_Description
);
add.AddArgument(moduleArg);
add.AddOption(_ModuleAddVersion);
add.AddOption(_ModuleAddForce);
add.AddOption(_ModuleAddSkipVerification);
add.SetHandler((invocation) =>
{
var option = new ModuleOptions
{
Path = invocation.ParseResult.GetValueForOption(_Path),
Option = invocation.ParseResult.GetValueForOption(_Option),
Verbose = invocation.ParseResult.GetValueForOption(_Verbose),
Debug = invocation.ParseResult.GetValueForOption(_Debug),
Module = invocation.ParseResult.GetValueForArgument(moduleArg),
Version = invocation.ParseResult.GetValueForOption(_ModuleAddVersion),
Force = invocation.ParseResult.GetValueForOption(_ModuleAddForce),
SkipVerification = invocation.ParseResult.GetValueForOption(_ModuleAddSkipVerification),
};

var client = new ClientContext();
invocation.ExitCode = ClientHelper.AddModule(option, client, invocation);
});

// Remove
var remove = new Command(
"remove",
CmdStrings.Module_Remove_Description
);
remove.AddArgument(moduleArg);
remove.SetHandler((invocation) =>
{
var option = new ModuleOptions
{
Path = invocation.ParseResult.GetValueForOption(_Path),
Option = invocation.ParseResult.GetValueForOption(_Option),
Verbose = invocation.ParseResult.GetValueForOption(_Verbose),
Debug = invocation.ParseResult.GetValueForOption(_Debug),
Module = invocation.ParseResult.GetValueForArgument(moduleArg)
};

var client = new ClientContext();
invocation.ExitCode = ClientHelper.RemoveModule(option, client, invocation);
});

// Upgrade
var upgrade = new Command(
"upgrade",
CmdStrings.Module_Upgrade_Description
);
upgrade.SetHandler((invocation) =>
{
var option = new ModuleOptions
{
Path = invocation.ParseResult.GetValueForOption(_Path),
Option = invocation.ParseResult.GetValueForOption(_Option),
Verbose = invocation.ParseResult.GetValueForOption(_Verbose),
Debug = invocation.ParseResult.GetValueForOption(_Debug)
};

var client = new ClientContext();
invocation.ExitCode = ClientHelper.UpgradeModule(option, client, invocation);
});

cmd.AddCommand(add);
cmd.AddCommand(remove);
cmd.AddCommand(upgrade);

cmd.AddOption(_Path);
Command.AddCommand(cmd);
}
}
}
Loading

0 comments on commit 280508e

Please sign in to comment.