diff --git a/eng/scripts/Analyze-Code.ps1 b/eng/scripts/Analyze-Code.ps1 index 087f1a6984..bb2e188935 100644 --- a/eng/scripts/Analyze-Code.ps1 +++ b/eng/scripts/Analyze-Code.ps1 @@ -84,6 +84,17 @@ try { Write-Host "✅ Tool id validation passed." } + # Run namespace validation + $namespaceResult = & "$PSScriptRoot/Test-Namespace.ps1" + + if ($LASTEXITCODE -ne 0) { + Write-Host "❌ Namespace validation failed" + Write-Host "$($namespaceResult.ViolationCount) file(s) missing namespace declarations. Review the above output for details." + $hasErrors = $true + } else { + Write-Host "✅ Namespace validation passed." + } + if($hasErrors) { exit 1 } diff --git a/eng/scripts/Test-Namespace.ps1 b/eng/scripts/Test-Namespace.ps1 new file mode 100644 index 0000000000..4d7e55fbd0 --- /dev/null +++ b/eng/scripts/Test-Namespace.ps1 @@ -0,0 +1,90 @@ +#!/usr/bin/env pwsh +#Requires -Version 7 + +<# +.SYNOPSIS + Validates that all C# class files have a namespace declaration. + +.DESCRIPTION + Scans all .cs files under core/, servers/, and tools/ directories (excluding + obj/, bin/, and auto-generated files) and ensures each file contains a + namespace declaration. Files without a namespace cause compilation issues + and pollute the global namespace. + +.PARAMETER Path + Root directory to scan. Defaults to the repository root. + +.OUTPUTS + Returns an object with ViolationCount property. Sets exit code 1 if violations found. +#> + +param( + [string]$Path +) + +$ErrorActionPreference = 'Stop' + +. "$PSScriptRoot/../common/scripts/common.ps1" + +if (-not $Path) { + $Path = $RepoRoot +} + +$rootPath = (Resolve-Path $Path).Path.TrimEnd('\', '/') + +$searchDirs = @( + Join-Path $rootPath "core" + Join-Path $rootPath "servers" + Join-Path $rootPath "tools" +) + +$violations = @() + +foreach ($dir in $searchDirs) { + if (-not (Test-Path $dir)) { + continue + } + + $csFiles = Get-ChildItem -Path $dir -Filter "*.cs" -Recurse | Where-Object { + $_.FullName -notmatch '[/\\](obj|bin)[/\\]' -and + $_.FullName -notmatch '\.g\.cs$' -and + $_.FullName -notmatch '\.generated\.cs$' -and + $_.FullName -notmatch 'GlobalUsings\.cs$' -and + $_.FullName -notmatch 'AssemblyInfo\.cs$' -and + $_.FullName -notmatch 'AssemblyAttributes\.cs$' -and + $_.Name -ne 'Program.cs' -and + $_.Name -ne 'Usings.cs' -and + $_.FullName -notmatch '[/\\]templates[/\\]' + } + + foreach ($file in $csFiles) { + $content = Get-Content $file.FullName -Raw + + if ([string]::IsNullOrWhiteSpace($content)) { + continue + } + + if ($content -notmatch '(?m)^\s*namespace\s+[A-Za-z_][A-Za-z0-9_.]*\s*;') { + $relativePath = [System.IO.Path]::GetRelativePath($rootPath, $file.FullName) + $violations += $relativePath + } + } +} + +if ($violations.Count -gt 0) { + Write-Host "❌ Found $($violations.Count) C# file(s) missing a namespace declaration:" + Write-Host "" + foreach ($v in $violations) { + Write-Host " - $v" + } + Write-Host "" + Write-Host "All C# class files must declare a namespace. Use file-scoped namespaces:" + Write-Host " namespace Azure.Mcp.Tools.MyToolset.Commands;" + Write-Host "" + + $result = [PSCustomObject]@{ ViolationCount = $violations.Count } + Write-Output $result + exit 1 +} else { + Write-Output ([PSCustomObject]@{ ViolationCount = 0 }) +} diff --git a/tools/Azure.Mcp.Tools.Speech/src/Commands/SpeechJsonContext.cs b/tools/Azure.Mcp.Tools.Speech/src/Commands/SpeechJsonContext.cs index 7af05dc6e7..68a45a4874 100644 --- a/tools/Azure.Mcp.Tools.Speech/src/Commands/SpeechJsonContext.cs +++ b/tools/Azure.Mcp.Tools.Speech/src/Commands/SpeechJsonContext.cs @@ -8,6 +8,8 @@ using Azure.Mcp.Tools.Speech.Models.FastTranscription; using Azure.Mcp.Tools.Speech.Models.Realtime; +namespace Azure.Mcp.Tools.Speech.Commands; + [JsonSerializable(typeof(RealtimeRecognitionContinuousResult))] [JsonSerializable(typeof(RealtimeRecognitionDetailedResult))] [JsonSerializable(typeof(RealtimeRecognitionNBestResult))] diff --git a/tools/Fabric.Mcp.Tools.OneLake/src/Commands/File/BlobGetCommand.cs b/tools/Fabric.Mcp.Tools.OneLake/src/Commands/File/BlobGetCommand.cs index 1d0a333cfe..994eee7381 100644 --- a/tools/Fabric.Mcp.Tools.OneLake/src/Commands/File/BlobGetCommand.cs +++ b/tools/Fabric.Mcp.Tools.OneLake/src/Commands/File/BlobGetCommand.cs @@ -14,6 +14,8 @@ using Microsoft.Mcp.Core.Models.Option; using Microsoft.Mcp.Core.Options; +namespace Fabric.Mcp.Tools.OneLake.Commands.File; + [CommandMetadata( Id = "75d6cb4c-4e81-4e69-a4ec-eca53a7dacd9", Name = "download_file",