diff --git a/ci/packages.Tests.ps1 b/ci/packages.Tests.ps1 index 77ecd47..2a2887d 100644 --- a/ci/packages.Tests.ps1 +++ b/ci/packages.Tests.ps1 @@ -285,6 +285,11 @@ Describe 'the real packages.json' { $ipi.Count | Should -Be 5 $ipi.FirstVersion | Select-Object -Unique | Should -Be '4.5.0' } + + It 'has every tox.ini install the packages its package depends on' { + Get-ToxGaps (Split-Path $PSScriptRoot) $script:Real | + Should -BeNullOrEmpty + } } } diff --git a/ci/packages.ps1 b/ci/packages.ps1 index 5043d0a..70e6af0 100644 --- a/ci/packages.ps1 +++ b/ci/packages.ps1 @@ -30,6 +30,51 @@ function Test-PathUnder([string]$Path, [string]$Folder) { return $Path -eq $Folder -or $Path.StartsWith("$Folder/") } +# Each tox.ini that does not install every package its package depends on, +# directly or through another, from this checkout, as a line naming what is +# missing. Taken from a package index instead, a dependency is tested at its +# last release rather than with the code it is released with. +function Get-ToxGaps([string]$RepoPath, $Packages = $null) { + if ($null -eq $Packages) { + $Packages = Get-Packages $RepoPath + } + $byName = @{} + foreach ($package in $Packages) { + $byName[$package.Name] = $package + } + $gaps = @() + foreach ($package in $Packages) { + $tox = Join-Path $RepoPath $package.Path 'tox.ini' + if ((Test-Path $tox) -eq $false) { + continue + } + $text = Get-Content -Raw $tox + $needed = [Collections.Generic.HashSet[string]]::new() + $queue = [Collections.Generic.Queue[string]]::new() + foreach ($name in $package.DependsOn) { + $queue.Enqueue($name) + } + while ($queue.Count -gt 0) { + $name = $queue.Dequeue() + if ($needed.Add($name) -eq $true) { + foreach ($next in $byName[$name].DependsOn) { + $queue.Enqueue($next) + } + } + } + foreach ($name in $needed) { + $relative = [IO.Path]::GetRelativePath( + (Join-Path $RepoPath $package.Path), + (Join-Path $RepoPath $byName[$name].Path)).Replace('\', '/') + $pattern = '(?m)^\s*-e\s*' + [regex]::Escape($relative) + '/?\s*$' + if ($text -notmatch $pattern) { + $gaps += "$($package.Path)/tox.ini does not install $name from $relative" + } + } + } + return $gaps +} + # The names of the given packages and of every package that depends on one of # them, directly or through another. function Get-DependentClosure($Packages, [string[]]$Names) { diff --git a/ci/run-unit-tests.ps1 b/ci/run-unit-tests.ps1 index 77ad8ca..e74a60f 100644 --- a/ci/run-unit-tests.ps1 +++ b/ci/run-unit-tests.ps1 @@ -3,5 +3,15 @@ param ( ) $ErrorActionPreference = "Stop" . (Join-Path $PSScriptRoot 'dispatch.ps1') +. (Join-Path $PSScriptRoot 'packages.ps1') + +# Each package's tests take the packages it depends on from this checkout, so +# they test the code those packages are released with. A tox.ini that takes +# one from PyPI instead stops the tests before they run. +$gaps = @(Get-ToxGaps (Split-Path $PSScriptRoot)) +if ($gaps.Count -gt 0) { + throw "A tox.ini takes a package from PyPI that this checkout has:`n" + + ($gaps -join "`n") +} Invoke-ProductStep 'run-unit-tests' $RepoName $PSBoundParameters diff --git a/device-detection/fiftyone_devicedetection_cloud/tox.ini b/device-detection/fiftyone_devicedetection_cloud/tox.ini index 14fad03..a0d62c6 100644 --- a/device-detection/fiftyone_devicedetection_cloud/tox.ini +++ b/device-detection/fiftyone_devicedetection_cloud/tox.ini @@ -12,7 +12,13 @@ package = wheel wheel_build_env = .pkg deps = {[common]deps} + # The packages it depends on come from this checkout rather than a + # package index, so the tests run with the code they are released with. -e../fiftyone_devicedetection_shared/ + -e../../pipeline/fiftyone_pipeline_core/ + -e../../pipeline/fiftyone_pipeline_engines/ + -e../../pipeline/fiftyone_pipeline_engines_fiftyone/ + -e../../pipeline/fiftyone_pipeline_cloudrequestengine/ commands = pytest --cov={envsitepackagesdir}/fiftyone_devicedetection_cloud {tty:--color=yes} {posargs} pass_env = diff --git a/ip-intelligence/fiftyone_ipintelligence_cloud/tox.ini b/ip-intelligence/fiftyone_ipintelligence_cloud/tox.ini index 4aa6341..668932c 100644 --- a/ip-intelligence/fiftyone_ipintelligence_cloud/tox.ini +++ b/ip-intelligence/fiftyone_ipintelligence_cloud/tox.ini @@ -12,7 +12,13 @@ package = wheel wheel_build_env = .pkg deps = {[common]deps} + # The packages it depends on come from this checkout rather than a + # package index, so the tests run with the code they are released with. -e../fiftyone_ipintelligence_shared/ + -e../../pipeline/fiftyone_pipeline_core/ + -e../../pipeline/fiftyone_pipeline_engines/ + -e../../pipeline/fiftyone_pipeline_engines_fiftyone/ + -e../../pipeline/fiftyone_pipeline_cloudrequestengine/ commands = pytest --cov={envsitepackagesdir}/fiftyone_ipintelligence_cloud {tty:--color=yes} {posargs} pass_env = diff --git a/ip-intelligence/fiftyone_ipintelligence_shared/tox.ini b/ip-intelligence/fiftyone_ipintelligence_shared/tox.ini index 2bf335a..98972fd 100644 --- a/ip-intelligence/fiftyone_ipintelligence_shared/tox.ini +++ b/ip-intelligence/fiftyone_ipintelligence_shared/tox.ini @@ -12,6 +12,12 @@ package = wheel wheel_build_env = .pkg deps = {[common]deps} + # The packages it depends on come from this checkout rather than a + # package index, so the tests run with the code they are released with. + -e../../pipeline/fiftyone_pipeline_core/ + -e../../pipeline/fiftyone_pipeline_engines/ + -e../../pipeline/fiftyone_pipeline_engines_fiftyone/ + -e../../pipeline/fiftyone_pipeline_cloudrequestengine/ commands = pytest --cov={envsitepackagesdir}/fiftyone_ipintelligence_shared {tty:--color=yes} {posargs} pass_env = diff --git a/ip-intelligence/fiftyone_ipintelligence_translation/tox.ini b/ip-intelligence/fiftyone_ipintelligence_translation/tox.ini index 11283b9..b055ee0 100644 --- a/ip-intelligence/fiftyone_ipintelligence_translation/tox.ini +++ b/ip-intelligence/fiftyone_ipintelligence_translation/tox.ini @@ -12,6 +12,10 @@ package = wheel wheel_build_env = .pkg deps = {[common]deps} + # The packages it depends on come from this checkout rather than a + # package index, so the tests run with the code they are released with. + -e../../pipeline/fiftyone_pipeline_core/ + -e../../pipeline/fiftyone_pipeline_translation/ commands = pytest --cov={envsitepackagesdir}/fiftyone_ipintelligence_translation {tty:--color=yes} {posargs} pass_env = diff --git a/location/tox.ini b/location/tox.ini index 3cd28ff..504de88 100644 --- a/location/tox.ini +++ b/location/tox.ini @@ -8,6 +8,11 @@ wheel_build_env = .pkg deps = pytest>=6 pytest-cov + # The packages it depends on come from this checkout rather than a + # package index, so the tests run with the code they are released with. + -e../pipeline/fiftyone_pipeline_core/ + -e../pipeline/fiftyone_pipeline_engines/ + -e../pipeline/fiftyone_pipeline_cloudrequestengine/ commands = pytest --cov={envsitepackagesdir}/fiftyone_location {tty:--color=yes} {posargs} pass_env =