From 023e355124722efbce344343dfe86ed665ab8b7e Mon Sep 17 00:00:00 2001 From: Gabriele Bozzola Date: Mon, 2 Sep 2024 09:29:35 -0700 Subject: [PATCH] Add test for dependencies Adding new dependencies to a Julia project has downsides. First, every dependency increases the precompilation and import time of a package. For complex packages, such as CUDA, this translates in several minutes of precompilation time that every single user of ClimaAtmos (including our CI runners) always pays. Second, dependencies can increase the cost of maintaining ClimaAtmos and the surface area of things that can go wrong (a buggy update in a dependency can break ClimaAtmos). Third, dependencies increase the complexity of the project's environment, potentially causing compatibility issues and restricting the versions we can use. This new test follows the spirit of the regression tests and tries to capture the cost of adding a new dependency by having developers explicitly come here and --- test/Project.toml | 1 + test/dependencies.jl | 87 ++++++++++++++++++++++++++++++++++++++++++++ test/runtests.jl | 1 + 3 files changed, 89 insertions(+) create mode 100644 test/dependencies.jl diff --git a/test/Project.toml b/test/Project.toml index 7e879672ad..6ff05f4fd1 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -30,6 +30,7 @@ NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" NCRegressionTests = "1789bc09-29e6-4c93-9c75-fe2179693664" NVTX = "5da4648a-3479-48b8-97b9-01cb529c0a1f" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Profile = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79" diff --git a/test/dependencies.jl b/test/dependencies.jl new file mode 100644 index 0000000000..92e507ee52 --- /dev/null +++ b/test/dependencies.jl @@ -0,0 +1,87 @@ +import Pkg +import Test + +# Adding new dependencies to a Julia project has downsides. First, every +# dependency increases the precompilation and import time of a package. For +# complex packages, such as CUDA, this translates in several minutes of +# precompilation time that every single user of ClimaAtmos (including our CI +# runners) always pays. Second, dependencies can increase the cost of +# maintaining ClimaAtmos and the surface area of things that can go wrong (a +# buggy update in a dependency can break ClimaAtmos). Third, dependencies +# increase the complexity of the project's environment, potentially causing +# compatibility issues and restricting the versions we can use. + +# This test follows the spirit of the regression tests and tries to capture the +# cost of adding a new dependency by having developers explicitly come here and +# declare their intents. +# +# DO NOT ADD new dependencies if: + +# - the feature you need can be easily implemented (e.g., do you need the might +# of Distributions.jl to compute a guassian function?) +# - your dependency is heavy/has lots of dependencies (e.g., DataFrames, CUDA). +# Instead, ask around, someone will help you accomplish what you need +# - your dependency implements code that logically should be implemented elsewhere +# (e.g., if your importing CUDA, maybe we should extend ClimaComms instead). +# Instead, ask around, someone will help you accomplish what you need + +atmos_uuid = Pkg.project().dependencies["ClimaAtmos"] +direct_dependencies = + keys(Pkg.dependencies(identity, atmos_uuid).dependencies) |> Set + +known_dependencies = Set([ + # Adapt is used to generate the spline for Earth topography + "Adapt", + # ArgParse is used to read --config_file and --job_id from command line + "ArgParse", + # ArtifactWrappers is used to topography and gravity wave NetCDF data + "ArtifactWrappers", + "Artifacts", + "AtmosphericProfilesLibrary", + "ClimaComms", + "ClimaCore", + "ClimaDiagnostics", + "ClimaParams", + "ClimaTimeSteppers", + "ClimaUtilities", + "CloudMicrophysics", + "Dates", + "DiffEqBase", + "FastGaussQuadrature", + "Insolation", + "Interpolations", + "LazyArtifacts", + "LinearAlgebra", + "Logging", + # NCDatasets is used to read Earth topography, GCM driven initial conditions, orographic gravity wave data + "NCDatasets", + "NVTX", + "RRTMGP", + "SciMLBase", + "StaticArrays", + # Statistics is used to call 'mean' on ClimaCore Fields + "Statistics", + "SurfaceFluxes", + "Thermodynamics", + # UnrolledUtilities is used to make some loops and maps in the gravity-wave code type-stable + "UnrolledUtilities", + "YAML", +]) + +diff = setdiff(direct_dependencies, known_dependencies) + +if !isempty(diff) + println("Detected new dependencies: $diff") + println("Please, double check if you really need the new dependencies") + println( + "If you do, edit the dependencies.jl file adding a note about where the packages are used", + ) +end + +otherdiff = setdiff(known_dependencies, direct_dependencies) +if !isempty(otherdiff) + println("Detected stale dependencies: $otherdiff") + println("Please, edit the dependencies.jl file") +end + +Test.@test direct_dependencies == known_dependencies diff --git a/test/runtests.jl b/test/runtests.jl index db0c16c1c2..1781fd87ad 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,6 +9,7 @@ using Test #! format: off @safetestset "Aqua" begin @time include("aqua.jl") end +@safetestset "Dependencies" begin @time include("dependencies.jl") end @safetestset "Callbacks" begin @time include("callbacks.jl") end @safetestset "Utilities" begin @time include("utilities.jl") end @safetestset "Parameter tests" begin @time include("parameters/parameter_tests.jl") end