From 2d79dc2a38e3efab84d434ee19d11cd352e0087d Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Wed, 22 Oct 2025 17:24:51 -0500 Subject: [PATCH 1/2] (MAINT) Disable docs tests for library crates by default Prior to this change, invoking `cargo test` for library crates without specifically choosing a test subset (unit, integration, etc) would always run the documentation tests. Documentation tests are particularly slow because Rust compiles a binary for every codeblock in your documentation. This is the slowest part of the rust tests when working on a library with extensive examples. This change adds the `doctest` setting to the crate manifests as `false` to disable documentation tests by default. These tests can still be invoked by passing the `--doc` flag to `cargo test`. Future changes will provide simplified access to generating and testing the docs from the build script, as well as validating documentation in CI. --- grammars/tree-sitter-dscexpression/Cargo.toml | 1 + .../tree-sitter-ssh-server-config/Cargo.toml | 1 + .../src/vscode/vscode_schema_extensions.rs | 32 +++++++++++++++++++ lib/dsc-lib-osinfo/Cargo.toml | 3 ++ lib/dsc-lib-pal/Cargo.toml | 3 ++ lib/dsc-lib-registry/Cargo.toml | 3 ++ lib/dsc-lib-security_context/Cargo.toml | 3 ++ lib/dsc-lib/Cargo.toml | 3 ++ 8 files changed, 49 insertions(+) create mode 100644 lib/dsc-lib-jsonschema/src/vscode/vscode_schema_extensions.rs diff --git a/grammars/tree-sitter-dscexpression/Cargo.toml b/grammars/tree-sitter-dscexpression/Cargo.toml index 48fdec439..9e942f8fd 100644 --- a/grammars/tree-sitter-dscexpression/Cargo.toml +++ b/grammars/tree-sitter-dscexpression/Cargo.toml @@ -18,6 +18,7 @@ include = [ [lib] path = "bindings/rust/lib.rs" +doctest = false [dependencies] tree-sitter-rust = { workspace = true } diff --git a/grammars/tree-sitter-ssh-server-config/Cargo.toml b/grammars/tree-sitter-ssh-server-config/Cargo.toml index 2022200f9..c6682c1ea 100644 --- a/grammars/tree-sitter-ssh-server-config/Cargo.toml +++ b/grammars/tree-sitter-ssh-server-config/Cargo.toml @@ -18,6 +18,7 @@ include = [ [lib] path = "bindings/rust/lib.rs" +doctest = false [dependencies] tree-sitter-rust = { workspace = true } diff --git a/lib/dsc-lib-jsonschema/src/vscode/vscode_schema_extensions.rs b/lib/dsc-lib-jsonschema/src/vscode/vscode_schema_extensions.rs new file mode 100644 index 000000000..bcacd953c --- /dev/null +++ b/lib/dsc-lib-jsonschema/src/vscode/vscode_schema_extensions.rs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +//! Provides helper functions for working with VS Code's extended JSON Schema keywords with +//! [`schemars::Schema`] instances. +//! +//! The `get_keyword_as_*` functions simplify retrieving the value of a keyword for a given type. +//! If the schema defines the keyword with the expected type, those functions return a reference to +//! that value as the correct type. If the keyword doesn't exist or has the wrong value type, the +//! functions return [`None`]. +//! +//! The rest of the utility methods work with specific keywords, like `$id` and `$defs`. + +use core::{clone::Clone, iter::Iterator, option::Option::None}; +use std::string::String; + +use schemars::Schema; +use serde_json::{Map, Number, Value}; +use url::{Position, Url}; + +type Array = Vec; +type Object = Map; + +pub trait VSCodeSchemaExtensions { + fn has_markdown_description(&self) -> bool; +} + +impl VSCodeSchemaExtensions for Schema { + fn has_markdown_description(&self) -> bool { + self.get("markdownDescription").is_some() + } +} \ No newline at end of file diff --git a/lib/dsc-lib-osinfo/Cargo.toml b/lib/dsc-lib-osinfo/Cargo.toml index 2135dff4c..184993af9 100644 --- a/lib/dsc-lib-osinfo/Cargo.toml +++ b/lib/dsc-lib-osinfo/Cargo.toml @@ -3,6 +3,9 @@ name = "dsc-lib-osinfo" version = "1.0.0" edition = "2021" +[lib] +doctest = false + [dependencies] os_info = { workspace = true } serde = { workspace = true } diff --git a/lib/dsc-lib-pal/Cargo.toml b/lib/dsc-lib-pal/Cargo.toml index ea7ce0998..8f64cd018 100644 --- a/lib/dsc-lib-pal/Cargo.toml +++ b/lib/dsc-lib-pal/Cargo.toml @@ -5,5 +5,8 @@ name = "dsc-lib-pal" version = "0.1.0" edition = "2021" +[lib] +doctest = false + [build-dependencies] cc = { workspace = true } diff --git a/lib/dsc-lib-registry/Cargo.toml b/lib/dsc-lib-registry/Cargo.toml index 2873c3ac1..f72e50347 100644 --- a/lib/dsc-lib-registry/Cargo.toml +++ b/lib/dsc-lib-registry/Cargo.toml @@ -8,6 +8,9 @@ available-locales = ["en-us"] default-locale = "en-us" load-path = "locales" +[lib] +doctest = false + [dependencies] crossterm = { workspace = true } registry = { workspace = true } diff --git a/lib/dsc-lib-security_context/Cargo.toml b/lib/dsc-lib-security_context/Cargo.toml index 20c7d369e..f409f83bd 100644 --- a/lib/dsc-lib-security_context/Cargo.toml +++ b/lib/dsc-lib-security_context/Cargo.toml @@ -3,6 +3,9 @@ name = "dsc-lib-security_context" version = "0.1.0" edition = "2021" +[lib] +doctest = false + [target.'cfg(target_os = "windows")'.dependencies] is_elevated = { workspace = true } diff --git a/lib/dsc-lib/Cargo.toml b/lib/dsc-lib/Cargo.toml index bc0bea436..b9eb58fad 100644 --- a/lib/dsc-lib/Cargo.toml +++ b/lib/dsc-lib/Cargo.toml @@ -3,6 +3,9 @@ name = "dsc-lib" version = "3.2.0" edition = "2021" +[lib] +doctest = false + [dependencies] # external dependencies base32 = { workspace = true } From 1fa3d7154a687f0ba86608a831c06471b3b2f113 Mon Sep 17 00:00:00 2001 From: Mikey Lombardi Date: Wed, 22 Oct 2025 17:29:10 -0500 Subject: [PATCH 2/2] (MAINT) Enable generating/testing docs in CI This change updates the build helpers module to enable separately generating documentation for Rust crates and testing the examples in that documentation. It also adds a new workflow job for generating and testing documentation separately from the rest of the build and test scripts. While these jobs failing won't prevent the continued unit/integration/acceptance tests, it will still fail the build. This should help ensure that any examples in our documentation remain valid. It _doesn't_ test to ensure that public APIs are documented, only that the documentation that exists is minimally valid. --- .github/workflows/rust.yml | 22 ++++++++++++++ build.helpers.psm1 | 59 ++++++++++++++++++++++++++++++++++++-- build.new.ps1 | 44 +++++++++++++++++++++------- 3 files changed, 113 insertions(+), 12 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b37c1c037..cbc8cf25a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -19,6 +19,28 @@ defaults: shell: pwsh jobs: + docs: + strategy: + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{matrix.platform}} + steps: + - uses: actions/checkout@v5 + - name: Install prerequisites + run: ./build.new.ps1 -SkipBuild -Clippy -Verbose + - name: Generate documentation + run: ./build.new.ps1 -RustDocs -Verbose + - name: Test documentation + run: |- + $testParams = @{ + SkipBuild = $true + RustDocs = $true + Test = $true + ExcludeRustTests = $true + ExcludePesterTests = $true + Verbose = $true + } + ./build.new.ps1 @testParams linux-build: runs-on: ubuntu-latest steps: diff --git a/build.helpers.psm1 b/build.helpers.psm1 index bbb575915..6e56119e4 100644 --- a/build.helpers.psm1 +++ b/build.helpers.psm1 @@ -1229,6 +1229,53 @@ function Copy-BuildArtifact { } #endregion Build project functions +#region Documenting project functions +function Export-RustDocs { + [CmdletBinding()] + param( + [DscProjectDefinition[]]$Project, + [ValidateSet('current','aarch64-pc-windows-msvc','x86_64-pc-windows-msvc','aarch64-apple-darwin','x86_64-apple-darwin','aarch64-unknown-linux-gnu','aarch64-unknown-linux-musl','x86_64-unknown-linux-gnu','x86_64-unknown-linux-musl')] + $Architecture = 'current', + [switch]$Release, + [switch]$IncludeDependencies + ) + + begin { + $flags = @($Release ? '-r' : $null) + if ($Architecture -ne 'current') { + $flags += '--target' + $flags += $Architecture + } else { + $memberGroup = if ($IsLinux) { + 'Linux' + } elseif ($IsMacOS) { + 'macOS' + } elseif ($IsWindows) { + 'Windows' + } + Set-DefaultWorkspaceMemberGroup -MemberGroup $memberGroup + } + if (-not $IncludeDependencies) { + $flags += '--no-deps' + } + } + + process { + $members = Get-DefaultWorkspaceMemberGroup + Write-Verbose -Verbose "Exporting documentation for rust projects: [$members]" + cargo doc @flags + + if ($null -ne $LASTEXITCODE -and $LASTEXITCODE -ne 0) { + Write-Error "Last exit code is $LASTEXITCODE, 'cargo doc' failed" + } + } + + clean { + Reset-DefaultWorkspaceMemberGroup + } +} +#endregion Documenting project functions + #region Test project functions function Test-RustProject { [CmdletBinding()] @@ -1236,7 +1283,8 @@ function Test-RustProject { [DscProjectDefinition[]]$Project, [ValidateSet('current','aarch64-pc-windows-msvc','x86_64-pc-windows-msvc','aarch64-apple-darwin','x86_64-apple-darwin','aarch64-unknown-linux-gnu','aarch64-unknown-linux-musl','x86_64-unknown-linux-gnu','x86_64-unknown-linux-musl')] $Architecture = 'current', - [switch]$Release + [switch]$Release, + [switch]$Docs ) begin { @@ -1254,11 +1302,18 @@ function Test-RustProject { } Set-DefaultWorkspaceMemberGroup -MemberGroup $memberGroup } + if ($Docs) { + $flags += '--doc' + } } process { $members = Get-DefaultWorkspaceMemberGroup - Write-Verbose -Verbose "Testing rust projects: [$members]" + if ($Docs) { + Write-Verbose -Verbose "Testing documentation for rust projects: [$members]" + } else { + Write-Verbose -Verbose "Testing rust projects: [$members]" + } cargo test @flags if ($null -ne $LASTEXITCODE -and $LASTEXITCODE -ne 0) { diff --git a/build.new.ps1 b/build.new.ps1 index dd697fe30..68a47e201 100644 --- a/build.new.ps1 +++ b/build.new.ps1 @@ -97,6 +97,7 @@ param( [switch]$UseCFSAuth, [switch]$Clean, [switch]$CacheRustBuild, + [switch]$RustDocs, [switch]$Quiet ) @@ -221,18 +222,31 @@ process { if (!$SkipBuild) { $progressParams.Activity = 'Building the projects' Write-BuildProgress @progressParams - $buildParams = @{ - Project = $BuildData.Projects - Architecture = $Architecture - Release = $Release - Clean = $Clean - } Write-BuildProgress @progressParams -Status 'Generating grammar bindings' Export-GrammarBinding -Project $BuildData.Projects @VerboseParam - Write-BuildProgress @progressParams -Status 'Compiling Rust' - Build-RustProject @buildParams -Audit:$Audit -Clippy:$Clippy @VerboseParam - Write-BuildProgress @progressParams -Status "Copying build artifacts" - Copy-BuildArtifact @buildParams -ExecutableFile $BuildData.PackageFiles.Executable @VerboseParam + + if ($RustDocs) { + $progressParams.Activity = 'Generating Rust documentation' + Write-BuildProgress @progressParams + + $docsParams = @{ + Project = $BuildData.Projects + Architecture = $Architecture + Release = $Release + } + Export-RustDocs @docsParams @VerboseParam + } else { + $buildParams = @{ + Project = $BuildData.Projects + Architecture = $Architecture + Release = $Release + Clean = $Clean + } + Write-BuildProgress @progressParams -Status 'Compiling Rust' + Build-RustProject @buildParams -Audit:$Audit -Clippy:$Clippy @VerboseParam + Write-BuildProgress @progressParams -Status "Copying build artifacts" + Copy-BuildArtifact @buildParams -ExecutableFile $BuildData.PackageFiles.Executable @VerboseParam + } } # Ensure PATH includes the output artifacts after building and before testing. @@ -255,6 +269,16 @@ process { Write-BuildProgress @progressParams -Status "Testing Rust projects" Test-RustProject @rustTestParams @VerboseParam } + if ($RustDocs) { + $docTestParams = @{ + Project = $BuildData.Projects + Architecture = $Architecture + Release = $Release + Docs = $true + } + Write-BuildProgress @progressParams -Status "Testing documentation for Rust projects" + Test-RustProject @docTestParams @VerboseParam + } if (-not $ExcludePesterTests) { $installParams = @{ UsingADO = $usingADO