...
1# cSpell:ignore LASTEXITCODE
2# cSpell:ignore errrrrorrrrr
3# cSpell:ignore sepleing
4<#
5.SYNOPSIS
6Uses cspell (from NPM) to check spelling of recently changed files
7
8.DESCRIPTION
9This script checks files that have changed relative to a base branch (default
10branch) for spelling errors. Dictionaries and spelling configurations reside
11in a configurable `cspell.json` location.
12
13This script uses `npx` and assumes that NodeJS (and by extension `npm` and
14`npx`) are installed on the machine. If it does not detect `npx` it will warn
15the user and exit with an error.
16
17The entire file is scanned, not just changed sections. Spelling errors in parts
18of the file not touched will still be shown.
19
20This script copies the config file supplied in CspellConfigPath to a temporary
21location, mutates the config file to include only the files that have changed,
22and then uses the mutated config file to call cspell. In the case of success
23the temporary file is deleted. In the case of failure the temporary file, whose
24location was logged to the console, remains on disk.
25
26.PARAMETER SpellCheckRoot
27Root folder from which to generate relative paths for spell checking. Mostly
28used in testing.
29
30.PARAMETER CspellConfigPath
31Optional location to use for cspell.json path. Default value is
32`./.vscode/cspell.json`
33
34.PARAMETER ExitWithError
35Exit with error code 1 if spelling errors are detected.
36
37.PARAMETER Test
38Run test functions against the script logic
39
40.EXAMPLE
41./eng/common/scripts/check-spelling-in-changed-files.ps1
42
43This will run spell check with changes in the current branch with respect to
44`target_branch_name`
45
46#>
47
48[CmdletBinding()]
49Param (
50 [Parameter()]
51 [string] $CspellConfigPath = (Resolve-Path "$PSScriptRoot/../../../.vscode/cspell.json"),
52
53 [Parameter()]
54 [string] $SpellCheckRoot = (Resolve-Path "$PSScriptRoot/../../../"),
55
56 [Parameter()]
57 [switch] $ExitWithError,
58
59 [Parameter()]
60 [switch] $Test
61)
62
63Set-StrictMode -Version 3.0
64
65function TestSpellChecker() {
66 Test-Exit0WhenAllFilesExcluded
67 ResetTest
68 Test-Exit1WhenIncludedFileHasSpellingError
69 ResetTest
70 Test-Exit0WhenIncludedFileHasNoSpellingError
71 ResetTest
72 Test-Exit1WhenChangedFileAlreadyHasSpellingError
73 ResetTest
74 Test-Exit0WhenUnalteredFileHasSpellingError
75 ResetTest
76 Test-Exit0WhenSpellingErrorsAndNoExitWithError
77}
78
79function Test-Exit0WhenAllFilesExcluded() {
80 # Arrange
81 "sepleing errrrrorrrrr" > ./excluded/excluded-file.txt
82 git add -A
83 git commit -m "One change"
84
85 # Act
86 &"$PSScriptRoot/check-spelling-in-changed-files.ps1" `
87 -CspellConfigPath "./.vscode/cspell.json" `
88 -SpellCheckRoot "./" `
89 -ExitWithError
90
91 # Assert
92 if ($LASTEXITCODE -ne 0) {
93 throw "`$LASTEXITCODE != 0"
94 }
95}
96
97function Test-Exit1WhenIncludedFileHasSpellingError() {
98 # Arrange
99 "sepleing errrrrorrrrr" > ./included/included-file.txt
100 git add -A
101 git commit -m "One change"
102
103 # Act
104 &"$PSScriptRoot/check-spelling-in-changed-files.ps1" `
105 -CspellConfigPath "./.vscode/cspell.json" `
106 -SpellCheckRoot "./" `
107 -ExitWithError
108
109 # Assert
110 if ($LASTEXITCODE -ne 1) {
111 throw "`$LASTEXITCODE != 1"
112 }
113}
114
115function Test-Exit0WhenIncludedFileHasNoSpellingError() {
116 # Arrange
117 "correct spelling" > ./included/included-file.txt
118 git add -A
119 git commit -m "One change"
120
121 # Act
122 &"$PSScriptRoot/check-spelling-in-changed-files.ps1" `
123 -CspellConfigPath "./.vscode/cspell.json" `
124 -SpellCheckRoot "./" `
125 -ExitWithError
126
127 # Assert
128 if ($LASTEXITCODE -ne 0) {
129 throw "`$LASTEXITCODE != 0"
130 }
131}
132
133function Test-Exit1WhenChangedFileAlreadyHasSpellingError() {
134 # Arrange
135 "sepleing errrrrorrrrr" > ./included/included-file.txt
136 git add -A
137 git commit -m "First change"
138
139 "A statement without spelling errors" >> ./included/included-file.txt
140 git add -A
141 git commit -m "Second change"
142
143 # Act
144 &"$PSScriptRoot/check-spelling-in-changed-files.ps1" `
145 -CspellConfigPath "./.vscode/cspell.json" `
146 -SpellCheckRoot "./" `
147 -ExitWithError
148
149 # Assert
150 if ($LASTEXITCODE -ne 1) {
151 throw "`$LASTEXITCODE != 1"
152 }
153}
154
155function Test-Exit0WhenUnalteredFileHasSpellingError() {
156 # Arrange
157 "sepleing errrrrorrrrr" > ./included/included-file-1.txt
158 git add -A
159 git commit -m "One change"
160
161 "A statement without spelling errors" > ./included/included-file-2.txt
162 git add -A
163 git commit -m "Second change"
164
165 # Act
166 &"$PSScriptRoot/check-spelling-in-changed-files.ps1" `
167 -CspellConfigPath "./.vscode/cspell.json" `
168 -SpellCheckRoot "./" `
169 -ExitWithError
170
171 # Assert
172 if ($LASTEXITCODE -ne 0) {
173 throw "`$LASTEXITCODE != 0"
174 }
175}
176
177function Test-Exit0WhenSpellingErrorsAndNoExitWithError() {
178 # Arrange
179 "sepleing errrrrorrrrr" > ./included/included-file-1.txt
180 git add -A
181 git commit -m "One change"
182
183 # Act
184 &"$PSScriptRoot/check-spelling-in-changed-files.ps1" `
185 -CspellConfigPath "./.vscode/cspell.json" `
186 -SpellCheckRoot "./"
187
188 # Assert
189 if ($LASTEXITCODE -ne 0) {
190 throw "`$LASTEXITCODE != 0"
191 }
192}
193
194function SetupTest($workingDirectory) {
195 Write-Host "Create test temp dir: $workingDirectory"
196 New-Item -ItemType Directory -Force -Path $workingDirectory | Out-Null
197
198 Push-Location $workingDirectory | Out-Null
199 git init
200
201 New-Item -ItemType Directory -Force -Path "./excluded"
202 New-Item -ItemType Directory -Force -Path "./included"
203 New-Item -ItemType Directory -Force -Path "./.vscode"
204
205 "Placeholder" > "./excluded/placeholder.txt"
206 "Placeholder" > "./included/placeholder.txt"
207
208 $configJsonContent = @"
209{
210 "version": "0.1",
211 "language": "en",
212 "ignorePaths": [
213 ".vscode/cspell.json",
214 "excluded/**"
215 ]
216}
217"@
218 $configJsonContent > "./.vscode/cspell.json"
219
220 git add -A
221 git commit -m "Init"
222}
223
224function ResetTest() {
225 # Empty out the working tree
226 git checkout .
227 git clean -xdf
228
229 $revCount = git rev-list --count HEAD
230 if ($revCount -gt 1) {
231 # Reset N-1 changes so there is only the initial commit
232 $revisionsToReset = $revCount - 1
233 git reset --hard HEAD~$revisionsToReset
234 }
235}
236
237function TeardownTest($workingDirectory) {
238 Pop-Location | Out-Null
239 Write-Host "Remove test temp dir: $workingDirectory"
240 Remove-Item -Path $workingDirectory -Recurse -Force | Out-Null
241}
242
243if ($Test) {
244 $workingDirectory = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName())
245
246 SetupTest $workingDirectory
247 TestSpellChecker
248 TeardownTest $workingDirectory
249 Write-Host "Test complete"
250 exit 0
251}
252
253$ErrorActionPreference = "Continue"
254. $PSScriptRoot/common.ps1
255
256if ((Get-Command git | Measure-Object).Count -eq 0) {
257 LogError "Could not locate git. Install git https://git-scm.com/downloads"
258 exit 1
259}
260
261if (!(Test-Path $CspellConfigPath)) {
262 LogError "Could not locate config file $CspellConfigPath"
263 exit 1
264}
265
266# Lists names of files that were in some way changed between the
267# current branch and default target branch. Excludes files that were deleted to
268# prevent errors in Resolve-Path
269$changedFilesList = Get-ChangedFiles
270
271$changedFiles = @()
272foreach ($file in $changedFilesList) {
273 $changedFiles += Resolve-Path $file
274}
275
276$changedFilesCount = ($changedFiles | Measure-Object).Count
277Write-Host "Git Detected $changedFilesCount changed file(s). Files checked by cspell may exclude files according to cspell.json"
278
279if ($changedFilesCount -eq 0) {
280 Write-Host "No changes detected"
281 exit 0
282}
283
284$changedFilePaths = @()
285foreach ($file in $changedFiles) {
286 $changedFilePaths += $file.Path
287}
288
289$spellingErrors = &"$PSScriptRoot/../spelling/Invoke-Cspell.ps1" `
290 -CspellConfigPath $CspellConfigPath `
291 -SpellCheckRoot $SpellCheckRoot `
292 -ScanGlobs $changedFilePaths
293
294if ($spellingErrors) {
295 $errorLoggingFunction = Get-Item 'Function:LogWarning'
296 if ($ExitWithError) {
297 $errorLoggingFunction = Get-Item 'Function:LogError'
298 }
299
300 foreach ($spellingError in $spellingErrors) {
301 &$errorLoggingFunction $spellingError
302 }
303 &$errorLoggingFunction "Spelling errors detected. To correct false positives or learn about spell checking see: https://aka.ms/azsdk/engsys/spellcheck"
304
305 if ($ExitWithError) {
306 exit 1
307 }
308} else {
309 Write-Host "No spelling errors detected"
310}
311
312exit 0
View as plain text