From 5dae90015890200caaf6f7596aaf9eb194d268a7 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Fri, 28 Jul 2023 14:16:05 -0700 Subject: [PATCH 1/3] add support for tags and description in manifest and searching --- dsc/src/args.rs | 4 ++ dsc/src/main.rs | 58 ++++++++++++++++++- dsc/tests/dsc_resource_list.tests.ps1 | 42 ++++++++++++++ dsc_lib/src/dscresources/resource_manifest.rs | 2 + osinfo/osinfo.dsc.resource.json | 7 +++ .../powershellgroup.dsc.resource.json | 4 +- registry/registry.dsc.resource.json | 5 ++ 7 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 dsc/tests/dsc_resource_list.tests.ps1 diff --git a/dsc/src/args.rs b/dsc/src/args.rs index 3ee325b3d..9bae02668 100644 --- a/dsc/src/args.rs +++ b/dsc/src/args.rs @@ -58,6 +58,10 @@ pub enum ResourceSubCommand { List { /// Optional filter to apply to the list of resources resource_name: Option, + #[clap(short, long, help = "Description keyword to search for in the resource description")] + description: Option, + #[clap(short, long, help = "Tag to search for in the resource tags")] + tags: Option>, }, #[clap(name = "get", about = "Invoke the get operation to a resource", arg_required_else_help = true)] Get { diff --git a/dsc/src/main.rs b/dsc/src/main.rs index a75d5ce53..a35a71421 100644 --- a/dsc/src/main.rs +++ b/dsc/src/main.rs @@ -342,7 +342,7 @@ fn handle_resource_subcommand(subcommand: &ResourceSubCommand, format: &Option { + ResourceSubCommand::List { resource_name, description, tags } => { match dsc.initialize_discovery() { Ok(_) => (), Err(err) => { @@ -357,6 +357,47 @@ fn handle_resource_subcommand(subcommand: &ResourceSubCommand, format: &Option(resource.clone().manifest.unwrap().clone()) { + Ok(resource_manifest) => resource_manifest, + Err(err) => { + eprintln!("Error in manifest for {0}: {err}", resource.type_name); + continue; + } + }; + + if description.is_some() { + if resource_manifest.description.is_none() { + continue; + } + + if !resource_manifest.description.unwrap().to_lowercase().contains(&description.as_ref().unwrap().to_lowercase()) { + continue; + } + } + + // if tags is specified, skip if resource tags do not contain the tags + if tags.is_some() { + if resource_manifest.tags.is_none() { + continue; + } + + let mut found = false; + for tag_to_find in tags.clone().unwrap() { + for tag in resource_manifest.tags.clone().unwrap() { + if tag.to_lowercase() == tag_to_find.to_lowercase() { + found = true; + break; + } + } + } + if !found { + continue; + } + } + } + if write_table { table.add_row(vec![ resource.type_name, @@ -379,6 +420,21 @@ fn handle_resource_subcommand(subcommand: &ResourceSubCommand, format: &Option json, + Err(err) => { + eprintln!("JSON Error: {err}"); + exit(EXIT_JSON_ERROR); + } + }; + write_output(&json, format); + // insert newline separating instances if writing to console + if atty::is(Stream::Stdout) { + println!(); + } + } } } diff --git a/dsc/tests/dsc_resource_list.tests.ps1 b/dsc/tests/dsc_resource_list.tests.ps1 new file mode 100644 index 000000000..b3b4a5937 --- /dev/null +++ b/dsc/tests/dsc_resource_list.tests.ps1 @@ -0,0 +1,42 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'Tests for listing resources' { + It 'dsc resource list' { + $resources = dsc resource list | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $resources | Should -Not -BeNullOrEmpty + $resources.Count | Should -BeGreaterThan 0 + $resources.type | Should -Contain 'DSC/AssertionGroup' + $resources.type | Should -Contain 'DSC/Group' + $resources.type | Should -Contain 'DSC/ParallelGroup' + $resources.type | Should -Contain 'Microsoft/OSInfo' + } + + It 'dsc resource list --tags "" and --description " work' -TestCases @( + @{ tags = 'linux'; description = $null; expectedCount = 1; expectedType = 'Microsoft/OSInfo' } + @{ tags = $null; description = 'operating system'; expectedCount = 1; expectedType = 'Microsoft/OSInfo' } + @{ tags = 'linux'; description = 'operating system'; expectedCount = 1; expectedType = 'Microsoft/OSInfo' } + @{ tags = 'notfound'; description = 'operating system'; expectedCount = 0; expectedType = $null } + @{ tags = 'linux'; description = 'notfound'; expectedCount = 0; expectedType = $null } + @{ tags = 'notfound'; description = 'notfound'; expectedCount = 0; expectedType = $null } + ) { + param($tags, $description, $expectedCount, $expectedType) + + if ($tags -and $description) { + $resources = dsc resource list --tags $tags --description $description | ConvertFrom-Json + } + elseif ($tags) { + $resources = dsc resource list --tags $tags | ConvertFrom-Json + } + else { + $resources = dsc resource list --description $description | ConvertFrom-Json + } + + $LASTEXITCODE | Should -Be 0 + $resources.Count | Should -Be $expectedCount + if ($expectedCount -gt 0) { + $resources.type | Should -BeExactly $expectedType + } + } +} diff --git a/dsc_lib/src/dscresources/resource_manifest.rs b/dsc_lib/src/dscresources/resource_manifest.rs index 35803c485..d668a677f 100644 --- a/dsc_lib/src/dscresources/resource_manifest.rs +++ b/dsc_lib/src/dscresources/resource_manifest.rs @@ -19,6 +19,8 @@ pub struct ResourceManifest { pub version: String, /// The description of the resource. pub description: Option, + /// Tags for the resource. + pub tags: Option>, /// Details how to call the Get method of the resource. pub get: GetMethod, /// Details how to call the Set method of the resource. diff --git a/osinfo/osinfo.dsc.resource.json b/osinfo/osinfo.dsc.resource.json index fab074db3..c1be81c1a 100644 --- a/osinfo/osinfo.dsc.resource.json +++ b/osinfo/osinfo.dsc.resource.json @@ -1,5 +1,12 @@ { "manifestVersion": "1.0", + "description": "Returns information about the operating system.", + "tags": [ + "os", + "linux", + "windows", + "macos" + ], "type": "Microsoft/OSInfo", "version": "0.1.0", "get": { diff --git a/powershellgroup/powershellgroup.dsc.resource.json b/powershellgroup/powershellgroup.dsc.resource.json index e067b8eeb..bdf08cf18 100644 --- a/powershellgroup/powershellgroup.dsc.resource.json +++ b/powershellgroup/powershellgroup.dsc.resource.json @@ -3,6 +3,9 @@ "type": "DSC/PowerShellGroup", "version": "0.1.0", "description": "Resource provider to classic DSC Powershell resources.", + "tags": [ + "PowerShell" + ], "provider": { "list": { "executable": "pwsh", @@ -56,4 +59,3 @@ "1": "Error" } } - \ No newline at end of file diff --git a/registry/registry.dsc.resource.json b/registry/registry.dsc.resource.json index e1c1833c0..70995932b 100644 --- a/registry/registry.dsc.resource.json +++ b/registry/registry.dsc.resource.json @@ -1,6 +1,11 @@ { "manifestVersion": "1.0", "type": "Microsoft.Windows/Registry", + "description": "Registry configuration provider for the Windows Registry", + "tags": [ + "Windows", + "NT" + ], "version": "0.1.0", "get": { "executable": "registry", From e914cf4be99a79a44d3747c75e125ed7d6d201c2 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Fri, 28 Jul 2023 16:00:17 -0700 Subject: [PATCH 2/3] fix logic to not return instances that don't have manifest --- dsc/src/main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dsc/src/main.rs b/dsc/src/main.rs index a35a71421..15ec09be7 100644 --- a/dsc/src/main.rs +++ b/dsc/src/main.rs @@ -358,7 +358,11 @@ fn handle_resource_subcommand(subcommand: &ResourceSubCommand, format: &Option(resource.clone().manifest.unwrap().clone()) { Ok(resource_manifest) => resource_manifest, Err(err) => { From 5e8565095c3ca9b975f07f123104ce2ea02e846a Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 1 Aug 2023 17:02:42 -0700 Subject: [PATCH 3/3] fix incorrect merge --- dsc/src/main.rs | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/dsc/src/main.rs b/dsc/src/main.rs index 15ec09be7..a52953ec3 100644 --- a/dsc/src/main.rs +++ b/dsc/src/main.rs @@ -424,21 +424,6 @@ fn handle_resource_subcommand(subcommand: &ResourceSubCommand, format: &Option json, - Err(err) => { - eprintln!("JSON Error: {err}"); - exit(EXIT_JSON_ERROR); - } - }; - write_output(&json, format); - // insert newline separating instances if writing to console - if atty::is(Stream::Stdout) { - println!(); - } - } } }