diff --git a/dsc/tests/dsc_discovery.tests.ps1 b/dsc/tests/dsc_discovery.tests.ps1 index bee5efdb..8c1c4897 100644 --- a/dsc/tests/dsc_discovery.tests.ps1 +++ b/dsc/tests/dsc_discovery.tests.ps1 @@ -2,6 +2,18 @@ # Licensed under the MIT License. Describe 'tests for resource discovery' { + BeforeAll { + $env:DSC_RESOURCE_PATH = $testdrive + } + + AfterEach { + Remove-Item -Path "$testdrive/test.dsc.resource.*" -ErrorAction SilentlyContinue + } + + AfterAll { + $env:DSC_RESOURCE_PATH = $null + } + It 'Use DSC_RESOURCE_PATH instead of PATH when defined' { $resourceJson = @' { @@ -14,15 +26,45 @@ Describe 'tests for resource discovery' { } '@ - try { - $env:DSC_RESOURCE_PATH = $testdrive - Set-Content -Path "$testdrive/test.dsc.resource.json" -Value $resourceJson - $resources = dsc resource list | ConvertFrom-Json - $resources.Count | Should -Be 1 - $resources.type | Should -BeExactly 'DSC/TestPathResource' - } - finally { - $env:DSC_RESOURCE_PATH = $null - } + Set-Content -Path "$testdrive/test.dsc.resource.json" -Value $resourceJson + $resources = dsc resource list | ConvertFrom-Json + $resources.Count | Should -Be 1 + $resources.type | Should -BeExactly 'DSC/TestPathResource' + } + + It 'support discovering ' -TestCases @( + @{ extension = 'yaml' } + @{ extension = 'yml' } + ) { + param($extension) + + $resourceYaml = @' + $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json + type: DSC/TestYamlResource + version: 0.1.0 + get: + executable: dsc +'@ + + Set-Content -Path "$testdrive/test.dsc.resource.$extension" -Value $resourceYaml + $resources = dsc resource list | ConvertFrom-Json + $resources.Count | Should -Be 1 + $resources.type | Should -BeExactly 'DSC/TestYamlResource' + } + + It 'does not support discovering a file with an extension that is not json or yaml' { + param($extension) + + $resourceInput = @' + $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json + type: DSC/TestYamlResource + version: 0.1.0 + get: + executable: dsc +'@ + + Set-Content -Path "$testdrive/test.dsc.resource.txt" -Value $resourceInput + $resources = dsc resource list | ConvertFrom-Json + $resources.Count | Should -Be 0 } } diff --git a/dsc_lib/Cargo.toml b/dsc_lib/Cargo.toml index ad4c2f50..f32d78c4 100644 --- a/dsc_lib/Cargo.toml +++ b/dsc_lib/Cargo.toml @@ -12,6 +12,7 @@ reqwest = { version = "0.11", features = ["blocking"] } schemars = { version = "0.8.12", features = ["preserve_order"] } serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } +serde_yaml = { version = "0.9.3" } thiserror = "1.0" chrono = "0.4.26" tracing = "0.1.37" diff --git a/dsc_lib/src/discovery/command_discovery.rs b/dsc_lib/src/discovery/command_discovery.rs index a7a939c0..5b13f4a5 100644 --- a/dsc_lib/src/discovery/command_discovery.rs +++ b/dsc_lib/src/discovery/command_discovery.rs @@ -8,6 +8,7 @@ use crate::dscresources::command_resource::invoke_command; use crate::dscerror::DscError; use std::collections::BTreeMap; use std::env; +use std::ffi::OsStr; use std::fs::File; use std::io::BufReader; use std::path::Path; @@ -50,7 +51,10 @@ impl CommandDiscovery { let path = entry.path(); if path.is_file() { let file_name = path.file_name().unwrap().to_str().unwrap(); - if file_name.to_lowercase().ends_with(".dsc.resource.json") { + let file_name_lowercase = file_name.to_lowercase(); + if file_name_lowercase.ends_with(".dsc.resource.json") || + file_name_lowercase.ends_with(".dsc.resource.yaml") || + file_name_lowercase.ends_with(".dsc.resource.yml") { let resource = match load_manifest(&path) { Ok(r) => r, @@ -203,12 +207,23 @@ impl ResourceDiscovery for CommandDiscovery { fn load_manifest(path: &Path) -> Result { let file = File::open(path)?; let reader = BufReader::new(file); - let manifest: ResourceManifest = match serde_json::from_reader(reader) { - Ok(manifest) => manifest, - Err(err) => { - return Err(DscError::Manifest(path.to_string_lossy().to_string(), err)); + let manifest: ResourceManifest = if path.extension() == Some(OsStr::new("json")) { + match serde_json::from_reader(reader) { + Ok(manifest) => manifest, + Err(err) => { + return Err(DscError::Manifest(path.to_string_lossy().to_string(), err)); + } + } + } + else { + match serde_yaml::from_reader(reader) { + Ok(manifest) => manifest, + Err(err) => { + return Err(DscError::ManifestYaml(path.to_string_lossy().to_string(), err)); + } } }; + let resource = DscResource { type_name: manifest.resource_type.clone(), implemented_as: ImplementedAs::Command, diff --git a/dsc_lib/src/dscerror.rs b/dsc_lib/src/dscerror.rs index b5bb1fdb..214be45f 100644 --- a/dsc_lib/src/dscerror.rs +++ b/dsc_lib/src/dscerror.rs @@ -52,6 +52,9 @@ pub enum DscError { #[error("Manifest: {0}\nJSON: {1}")] Manifest(String, serde_json::Error), + #[error("Manifest: {0}\nYAML: {1}")] + ManifestYaml(String, serde_yaml::Error), + #[error("Missing manifest: {0}")] MissingManifest(String),