Skip to content

Commit

Permalink
Speedup CI (#2352)
Browse files Browse the repository at this point in the history
* Test refactoring exercises via solution

* Test using solution and in-place
  • Loading branch information
ErikSchierboom authored Jan 29, 2025
1 parent 03de5bc commit ac83aa5
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 62 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ build/

# Other files
.DS_Store

# Temporary files
exercises/**/*.tmp
158 changes: 96 additions & 62 deletions bin/test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -26,97 +26,131 @@ param (
$ErrorActionPreference = "Stop"
$PSNativeCommandUseErrorActionPreference = $true

function Invoke-Build-Generators {
Write-Output "Building generators"
& dotnet build ./generators
function Invoke-Tests($Path) {
& dotnet test $Path
}

function Clean($BuildDir) {
Write-Output "Cleaning previous build"
Remove-Item -Recurse -Force $BuildDir -ErrorAction Ignore
}
function Prepare-Exercise($Path) {
$files = Get-Content (Join-Path $Path ".meta" "config.json") -Raw | ConvertFrom-Json | Select-Object -ExpandProperty files

function Copy-Exercise($SourceDir, $BuildDir) {
Write-Output "Copying exercises"
Copy-Item $SourceDir -Destination $BuildDir -Recurse
}
foreach ($fileType in @("example", "exemplar")) {
for (($i = 0); $i -lt $files.$fileType.length; $i++) {
$exampleFile = Join-Path $Path $files.$fileType[$i]
$solutionFile = Join-Path $Path $files.solution[$i]

function Enable-All-UnitTests($BuildDir) {
Write-Output "Enabling all tests"
Get-ChildItem -Path $BuildDir -Include "*Tests.cs" -Recurse | ForEach-Object {
(Get-Content $_.FullName) -replace "Skip = ""Remove this Skip property to run this test""", "" | Set-Content $_.FullName
Copy-Item -Path $solutionFile -Destination "${solutionFile}.tmp"
Copy-Item -Path $exampleFile -Destination $solutionFile
}
}
}

function Test-Refactoring-Projects($PracticeExercisesDir) {
Write-Output "Testing refactoring projects"
@("tree-building", "ledger", "markdown") | ForEach-Object {
Invoke-Tests -Path "${PracticeExercisesDir}/${_}"
foreach ($testFile in $files.test) {
$testFile = Join-Path $Path $testFile
Copy-Item -Path $testFile -Destination "${testFile}.tmp"
(Get-Content $testFile) -replace "Skip = ""Remove this Skip property to run this test""", "" | Set-Content $testFile
}
}

function Set-ExampleImplementation {
[CmdletBinding(SupportsShouldProcess)]
param($ExercisesDir, $ReplaceFileName)

if ($PSCmdlet.ShouldProcess("Exercise ${ReplaceFileName}", "replace solution with example")) {
Get-ChildItem -Path $ExercisesDir -Include "*.csproj" -Recurse | ForEach-Object {
$stub = Join-Path -Path $_.Directory ($_.BaseName + ".cs")
$example = Join-Path -Path $_.Directory ".meta" $ReplaceFileName
function Restore-Exercise($Path) {
Get-ChildItem -Path $Path -Include "*.tmp" -Recurse | ForEach-Object {
$tmpFile = $_.FullName
$originalFile = ($tmpFile -replace "\.tmp$", "")
Move-Item -Path $tmpFile -Destination $originalFile -Force
}
}

Move-Item -Path $example -Destination $stub -Force
function Process-Exercises($Exercises, [ScriptBlock]$Action) {
foreach ($ExerciseType in @("practice", "concept")) {
$Exercises.$ExerciseType | ForEach-Object {
&$Action (Join-Path "exercises" $ExerciseType $_)
}
}
}

function Use-ExampleImplementation {
[CmdletBinding(SupportsShouldProcess)]
param($ConceptExercisesDir, $PracticeExercisesDir)

if ($PSCmdlet.ShouldProcess("Exercises directory", "replace all solutions with corresponding examples")) {
Write-Output "Replacing concept exercise stubs with exemplar"
Set-ExampleImplementation $ConceptExercisesDir "Exemplar.cs"
function Prepare-Exercises($Exercises) {
Process-Exercises $Exercises {
param($Path)
Prepare-Exercise $Path
}
}

Write-Output "Replacing practice exercise stubs with example"
Set-ExampleImplementation $PracticeExercisesDir "Example.cs"
function Restore-Exercises($Exercises) {
Process-Exercises $Exercises {
param($Path)
Restore-Exercise $Path
}
}

function Test-ExerciseImplementation($Exercise, $BuildDir, $ConceptExercisesDir, $PracticeExercisesDir) {
Write-Output "Running tests"
function Run-Tests($Path) {
& dotnet test $Path
}

if (-Not $Exercise) {
Invoke-Tests -Path $BuildDir
function Find-Exercise-Path($Exercise, $Exercises) {
if ($Exercises.practice.Contains($Exercise)) {
Join-Path "exercises" "practice" $Exercise
}
elseif ($Exercises.concept.Contains($Exercise)) {
Join-Path "exercises" "concept" $Exercise
} else {
throw "Could not find exercise '${Exercise}'"
}
elseif (Test-Path "${ConceptExercisesDir}/${Exercise}") {
Invoke-Tests -Path "${ConceptExercisesDir}/${Exercise}"
}

function Test-Single-Exercise($Exercise, $Exercises) {
$path = Find-Exercise-Path $Exercise $Exercises

try {
Prepare-Exercise $path
Run-Tests $path
} finally {
Restore-Exercise $path
}
elseif (Test-Path "${PracticeExercisesDir}/${Exercise}") {
Invoke-Tests -Path "${PracticeExercisesDir}/${Exercise}"
}

function Test-All-Exercises($Exercises) {
try {
Prepare-Exercises $Exercises
Run-Tests "exercises/Exercises.sln"
} finally {
Restore-Exercises $Exercises
}
else {
throw "Could not find exercise '${Exercise}'"
}

function Parse-Exercises {
Get-Content .\config.json -Raw |
ConvertFrom-Json |
Select-Object -ExpandProperty exercises |
ForEach-Object {
@{
concept = $_.concept | Select-Object -ExpandProperty slug | Sort-Object
practice = $_.practice | Select-Object -ExpandProperty slug | Sort-Object
}
}
}

function Invoke-Tests($Path) {
& dotnet test $Path
function Build-Generators {
Write-Output "Build generators"
& dotnet build generators
}

function Test-Refactoring-Exercise-Default-Implementations {
Write-Output "Testing refactoring exercises"
& dotnet test (Join-Path "exercises" "Refactoring.sln")
}

function Test-Exercise-Example-Implementations($Exercise) {
Write-Output "Testing example implementations"
$exercises = Parse-Exercises

$buildDir = "${PSScriptRoot}/build"
$practiceExercisesDir = "${buildDir}/practice"
$conceptExercisesDir = "${buildDir}/concept"
$sourceDir = Resolve-Path "exercises"
if ($Exercise) {
Test-Single-Exercise $Exercise $Exercises
} else {
Test-All-Exercises $Exercises
}
}

Clean $buildDir
Copy-Exercise $sourceDir $buildDir
Enable-All-UnitTests $buildDir
Test-Exercise-Example-Implementations $Exercise

if (!$Exercise) {
Invoke-Build-Generators
Test-Refactoring-Projects $practiceExercisesDir
Build-Generators
Test-Refactoring-Exercise-Default-Implementations
}

Use-ExampleImplementation $conceptExercisesDir $practiceExercisesDir
Test-ExerciseImplementation -Exercise $Exercise -BuildDir $buildDir -ConceptExercisesDir $conceptExercisesDir -PracticeExercisesDir $practiceExercisesDir
41 changes: 41 additions & 0 deletions exercises/Refactoring.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "practice", "practice", "{9CE64A98-EA82-4784-93E4-2C14222C5FDD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeBuilding", "practice\tree-building\TreeBuilding.csproj", "{202A66E7-F0BB-4B0D-A7C0-AE92B3B48B7F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ledger", "practice\ledger\Ledger.csproj", "{11EBF5DF-CE22-40D8-B96E-687461A16C1E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Markdown", "practice\markdown\Markdown.csproj", "{CB0F19FE-C1B9-4EC6-B969-C0F74B70E134}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{202A66E7-F0BB-4B0D-A7C0-AE92B3B48B7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{202A66E7-F0BB-4B0D-A7C0-AE92B3B48B7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{202A66E7-F0BB-4B0D-A7C0-AE92B3B48B7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{202A66E7-F0BB-4B0D-A7C0-AE92B3B48B7F}.Release|Any CPU.Build.0 = Release|Any CPU
{11EBF5DF-CE22-40D8-B96E-687461A16C1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11EBF5DF-CE22-40D8-B96E-687461A16C1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11EBF5DF-CE22-40D8-B96E-687461A16C1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11EBF5DF-CE22-40D8-B96E-687461A16C1E}.Release|Any CPU.Build.0 = Release|Any CPU
{CB0F19FE-C1B9-4EC6-B969-C0F74B70E134}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB0F19FE-C1B9-4EC6-B969-C0F74B70E134}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB0F19FE-C1B9-4EC6-B969-C0F74B70E134}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB0F19FE-C1B9-4EC6-B969-C0F74B70E134}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{202A66E7-F0BB-4B0D-A7C0-AE92B3B48B7F} = {9CE64A98-EA82-4784-93E4-2C14222C5FDD}
{11EBF5DF-CE22-40D8-B96E-687461A16C1E} = {9CE64A98-EA82-4784-93E4-2C14222C5FDD}
{CB0F19FE-C1B9-4EC6-B969-C0F74B70E134} = {9CE64A98-EA82-4784-93E4-2C14222C5FDD}
EndGlobalSection
EndGlobal

0 comments on commit ac83aa5

Please sign in to comment.