diff --git a/build.ps1 b/build.ps1 index ad8e86a32..107785251 100755 --- a/build.ps1 +++ b/build.ps1 @@ -263,9 +263,9 @@ if ($null -ne $packageType) { if ($null -eq (Get-Command tree-sitter -ErrorAction Ignore)) { Write-Verbose -Verbose "tree-sitter not found, installing..." if ($UseCFS) { - cargo install tree-sitter-cli --config .cargo/config.toml + cargo install tree-sitter-cli --config .cargo/config.toml --version 0.25.10 } else { - cargo install tree-sitter-cli + cargo install tree-sitter-cli --version 0.25.10 } if ($LASTEXITCODE -ne 0) { throw "Failed to install tree-sitter-cli" @@ -349,8 +349,8 @@ if (!$SkipBuild) { "y2j" ) $pedantic_unclean_projects = @() - $clippy_unclean_projects = @("grammars/tree-sitter-dscexpression", "grammars/tree-sitter-ssh-server-config") - $skip_test_projects_on_windows = @("grammars/tree-sitter-dscexpression", "grammars/tree-sitter-ssh-server-config") + $clippy_unclean_projects = @("tree-sitter-dscexpression") + $skip_test_projects_on_windows = @("tree-sitter-dscexpression") if ($IsWindows) { $projects += $windows_projects diff --git a/dsc/Cargo.lock b/dsc/Cargo.lock index 6af068d49..2481323e2 100644 --- a/dsc/Cargo.lock +++ b/dsc/Cargo.lock @@ -551,7 +551,7 @@ dependencies = [ [[package]] name = "dsc" -version = "3.1.2" +version = "3.1.3" dependencies = [ "clap", "clap_complete", diff --git a/dsc/Cargo.toml b/dsc/Cargo.toml index 469757db5..7e8c8d7c6 100644 --- a/dsc/Cargo.toml +++ b/dsc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dsc" -version = "3.1.2" +version = "3.1.3" edition = "2021" [profile.release] diff --git a/dsc/tests/dsc_discovery.tests.ps1 b/dsc/tests/dsc_discovery.tests.ps1 index d4489ec6f..1695cdff3 100644 --- a/dsc/tests/dsc_discovery.tests.ps1 +++ b/dsc/tests/dsc_discovery.tests.ps1 @@ -74,7 +74,7 @@ Describe 'tests for resource discovery' { $resources.Count | Should -Be 0 } - It 'warns on invalid semver' { + It 'info on invalid semver' { $manifest = @' { "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", @@ -94,9 +94,8 @@ Describe 'tests for resource discovery' { try { $env:DSC_RESOURCE_PATH = $testdrive Set-Content -Path "$testdrive/test.dsc.resource.json" -Value $manifest - $out = dsc resource list 2>&1 - write-verbose -verbose ($out | Out-String) - $out | Should -Match 'WARN.*?Validation.*?invalid version' -Because ($out | Out-String) + $out = dsc -l info resource list 2>&1 | Out-String + $out | Should -BeLike '*INFO*Validation*invalid version*' -Because ($out | Out-String) } finally { $env:DSC_RESOURCE_PATH = $oldPath @@ -302,4 +301,32 @@ Describe 'tests for resource discovery' { $env:DSC_RESOURCE_PATH = $null } } + + It 'Invalid resource manifest will generate info message' { + $invalidManifest = @' + { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/InvalidManifest", + "version": "0.1.0", + "get": { + "executable": "dsctest", + "unexpectedField": "This field is not expected in the get section and should be ignored by the discovery process" + }, + "newProperty": "This property is not expected in the manifest and should be ignored by the discovery process" + } +'@ + Set-Content -Path "$testdrive/test.dsc.resource.json" -Value $invalidManifest + $oldPath = $env:DSC_RESOURCE_PATH + try { + $env:DSC_RESOURCE_PATH = $testdrive + [System.IO.Path]::PathSeparator + $env:PATH + + $out = dsc -l info resource list 'Test/InvalidManifest' 2> "$testdrive/error.txt" | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out | Should -BeNullOrEmpty -Because (Get-Content -Raw -Path "$testdrive/error.txt") + $errorLog = Get-Content -Raw -Path "$testdrive/error.txt" + $errorLog | Should -BeLike "*INFO Failed to load manifest: Manifest: Invalid manifest for resource '*test.dsc.resource.json'*" -Because $errorLog + } finally { + $env:DSC_RESOURCE_PATH = $oldPath + } + } } diff --git a/dsc/tests/dsc_extension_discover.tests.ps1 b/dsc/tests/dsc_extension_discover.tests.ps1 index d865c9599..988898768 100644 --- a/dsc/tests/dsc_extension_discover.tests.ps1 +++ b/dsc/tests/dsc_extension_discover.tests.ps1 @@ -101,4 +101,61 @@ Describe 'Discover extension tests' { } $foundWideLine | Should -BeTrue } + + It 'Invalid manifest from extension discovery should not fail overall discovery' { + $invalidManifest = @' + { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/InvalidManifest", + "version": "0.1.0", + "get": { + "executable": "dsctest", + "unexpectedField": "This field is not expected in the get section and should be ignored by the discovery process" + }, + "newProperty": "This property is not expected in the manifest and should be ignored by the discovery process" + } +'@ + $resourceScript = @' + $resource = @{ + manifestPath = "$env:TestDrive" + [System.IO.Path]::DirectorySeparatorChar + 'invalidManifest.dsc.resource.json' + } + $resource | ConvertTo-Json -Compress +'@ + $extensionManifest = @' + { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/DiscoverInvalid", + "version": "0.1.0", + "description": "Test discover resource, this is a really long description to test that the table can be rendered without truncating the description text from this extension.", + "discover": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-Command", + "./discover.ps1" + ] + } + } +'@ + + Set-Content -Path "$TestDrive/invalidManifest.dsc.resource.json" -Value $invalidManifest + Set-Content -Path "$TestDrive/discover.ps1" -Value $resourceScript + Set-Content -Path "$TestDrive/extension.dsc.extension.json" -Value $extensionManifest + try { + $env:DSC_RESOURCE_PATH = $TestDrive + [System.IO.Path]::PathSeparator + $env:PATH + $env:TestDrive = $TestDrive + $out = dsc -l info resource list 2> $TestDrive/error.log | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Path "$TestDrive/error.log" -Raw | Out-String) + # The invalid manifest should be skipped and not included in the discovered resources + foreach ($resource in $out) { + $resource.type | Should -Not -Be 'Test/InvalidManifest' + } + (Get-Content -Path "$TestDrive/error.log" -Raw) | Should -BeLike "*INFO Extension 'Test/DiscoverInvalid' failed: Manifest: Invalid manifest for resource '*invalidManifest.dsc.resource.json'*" -Because (Get-Content -Path "$TestDrive/error.log" -Raw | Out-String) + } finally { + $env:DSC_RESOURCE_PATH = $null + $env:TestDrive = $null + } + } } diff --git a/dsc_lib/locales/en-us.toml b/dsc_lib/locales/en-us.toml index 92fe7f513..4bf59e323 100644 --- a/dsc_lib/locales/en-us.toml +++ b/dsc_lib/locales/en-us.toml @@ -91,6 +91,7 @@ extensionResourceFound = "Extension found resource '%{resource}'" callingExtension = "Calling extension '%{extension}' to discover resources" extensionFoundResources = "Extension '%{extension}' found %{count} resources" invalidManifestVersion = "Manifest '%{path}' has invalid version: %{err}" +failedLoadManifest = "Failed to load manifest: %{err}" [dscresources.commandResource] invokeGet = "Invoking get for '%{resource}'" @@ -173,6 +174,7 @@ resourceManifestSchemaDescription = "Defines the JSON Schema the resource manife discoverNoResults = "No results returned for discovery extension '%{extension}'" discoverNotAbsolutePath = "Resource path from extension '%{extension}' is not an absolute path: %{path}" extensionReturned = "Extension '%{extension}' returned line: %{line}" +failedLoadManifest = "Extension '%{extension}' failed: %{err}" [extensions.extension_manifest] extensionManifestSchemaTitle = "Extension manifest schema URI" diff --git a/dsc_lib/src/discovery/command_discovery.rs b/dsc_lib/src/discovery/command_discovery.rs index 2a8208b40..3d630d52e 100644 --- a/dsc_lib/src/discovery/command_discovery.rs +++ b/dsc_lib/src/discovery/command_discovery.rs @@ -247,9 +247,9 @@ impl ResourceDiscovery for CommandDiscovery { Err(e) => { // At this point we can't determine whether or not the bad manifest contains // resource that is requested by resource/config operation - // if it is, then "ResouceNotFound" error will be issued later - // and here we just write as warning - warn!("{e}"); + // if it is, then "ResourceNotFound" error will be issued later + // and here we just write as information + info!("{}", t!("discovery.commandDiscovery.failedLoadManifest", err = e)); continue; }, }; diff --git a/dsc_lib/src/dscerror.rs b/dsc_lib/src/dscerror.rs index f93923013..6b3c751b8 100644 --- a/dsc_lib/src/dscerror.rs +++ b/dsc_lib/src/dscerror.rs @@ -6,7 +6,6 @@ use std::str::Utf8Error; use indicatif::style::TemplateError; use thiserror::Error; -use tracing::error; use tree_sitter::LanguageError; #[derive(Error, Debug)] diff --git a/dsc_lib/src/extensions/dscextension.rs b/dsc_lib/src/extensions/dscextension.rs index 01f6db7d1..2662d47e0 100644 --- a/dsc_lib/src/extensions/dscextension.rs +++ b/dsc_lib/src/extensions/dscextension.rs @@ -111,9 +111,17 @@ impl DscExtension { } let manifest_path = Path::new(&discover_result.manifest_path); // Currently we don't support extensions discovering other extensions - if let ImportedManifest::Resource(resource) = load_manifest(manifest_path)? { - resources.push(resource); - } + let resource = match load_manifest(manifest_path) { + Ok(ImportedManifest::Resource(resource)) => resource, + Ok(_) => continue, + Err(err) => { + // For invalid manifest, we write an information and skip it + info!("{}", t!("extensions.dscextension.failedLoadManifest", extension = self.type_name, path = discover_result.manifest_path.clone(), err = err)); + continue; + } + }; + + resources.push(resource); } }