GitHub CI: How to build my manifest if I want to test on stable and LTS?

I am trying to set up a GitHub action that runs tests for my package on the latest LTS (1.6) and the latest stable (1.7, soon to be 1.8) release. Here is my .github/workflows/RunTests.yml file:

name: RunTests
on: [push, pull_request]

jobs:
  RunTests:
    name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        version: ['1.6', '1']  # Test against LTS and current minor release
        os: [ubuntu-latest, macOS-latest, windows-latest]
        arch: [x64]
    steps:
      - uses: actions/checkout@v2
      - uses: julia-actions/setup-julia@v1
        with:
          version: ${{ matrix.version }}
          arch: ${{ matrix.arch }}
      - uses: julia-actions/julia-buildpkg@v1
      - uses: julia-actions/julia-runtest@v1

I basically copied this yml from Ipopt.jl and cut out the things that I deemed unnecessary.

Upon pushing this commit, all of the 1.6 tests failed, while all the 1.7 tests passed. Here is the output of the CI job for 1.6 on ubuntu-latest (the Windows and Mac results are similar):

Run julia --color=yes "$GITHUB_ACTION_PATH"/add_general_registry.jl
[ Info: Attempting to clone the General registry
     Cloning registry from "https://github.com/JuliaRegistries/General.git"
       Added registry `General` to `~/.julia/registries/General`
[ Info: Successfully added the General registry
Run julia --color=yes --project=@. -e 'using Pkg; if VERSION >= v"1.1.0-rc1"; Pkg.build(verbose=true); else Pkg.build(); end'
┌ Warning: The active manifest file has dependencies that were resolved with a different julia version (1.8.0-rc1). Unexpected behavior may occur.
└ @ ~/work/OptimalApplication.jl/OptimalApplication.jl/Manifest.toml:0
ERROR: MethodError: no method matching joinpath(::Nothing)
Closest candidates are:
  joinpath(::AbstractString) at path.jl:251
  joinpath(::AbstractString, ::AbstractString...) at path.jl:296
Stacktrace:
  [1] stat(path::Nothing)
    @ Base.Filesystem./stat.jl:109
  [2] ispath(path::Nothing)
    @ Base.Filesystem./stat.jl:311
  [3] download_source(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}, urls::Dict{Base.UUID, Vector{String}}; readonly::Bool)
    @ Pkg.Operations/buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/Operations.jl:752
  [4] #download_source#57
    @ /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/Operations.jl:742 [inlined]
  [5] download_source
    @ /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/Operations.jl:740 [inlined]
  [6] instantiate(ctx::Pkg.Types.Context; manifest::Nothing, update_registry::Bool, verbose::Bool, platform::Base.BinaryPlatforms.Platform, allow_build::Bool, allow_autoprecomp::Bool, kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Pkg.API/buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/API.jl:1410
  [7] build(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}, verbose::Bool)
    @ Pkg.Operations/buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/Operations.jl:925
  [8] build(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}; verbose::Bool, kwargs::Base.Iterators.Pairs{Symbol, IOContext{Base.PipeEndpoint}, Tuple{Symbol}, NamedTuple{(:io,), Tuple{IOContext{Base.PipeEndpoint}}}})
    @ Pkg.API/buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/API.jl:900
  [9] build(pkgs::Vector{Pkg.Types.PackageSpec}; io::IOContext{Base.PipeEndpoint}, kwargs::Base.Iterators.Pairs{Symbol, Bool, Tuple{Symbol}, NamedTuple{(:verbose,), Tuple{Bool}}})
    @ Pkg.API/buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/API.jl:80
 [10] build(; name::Nothing, uuid::Nothing, version::Nothing, url::Nothing, rev::Nothing, path::Nothing, mode::Pkg.Types.PackageMode, subdir::Nothing, kwargs::Base.Iterators.Pairs{Symbol, Bool, Tuple{Symbol}, NamedTuple{(:verbose,), Tuple{Bool}}})
    @ Pkg.API/buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/API.jl:96
 [11] top-level scope
    @ none:1
Error: Process completed with exit code 1.

It appears that the issue is that I built my manifest using 1.8.0-rc1 instead of 1.6, right? But if this is the issue, then how come the tests pass in 1.7 but not in 1.6?

Will rebuilding my manifest in 1.6 (or 1.7) solve the issue?


Other facts that may be relevant:

  • My package passes tests locally on 1.6.7, 1.7.3, and 1.8.0-rc1, as I can verify by ]adding my package from the general registry and doing ]test MyPackage.
  • However, if I instead use ~/julia-1.6.7/bin/julia --project in my local clone of the project repo and try ]test, I get a similar (but not identical) error:
 Warning: The active manifest file has dependencies that were resolved with a different julia version (1.8.0-rc1). Unexpected behavior may occur.
└ @ ~/OptimalApplication.jl/Manifest.toml:0
ERROR: AssertionError: sourcepath !== nothing
Stacktrace:
  [1] is_package_downloaded(ctx::Pkg.Types.Context, pkg::Pkg.Types.PackageSpec)
    @ Pkg.Operations /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/Operations.jl:1807
  [2] #13
    @ /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/Operations.jl:131 [inlined]
  [3] _all
    @ ./reduce.jl:923 [inlined]
  [4] #all#704
    @ ./reducedim.jl:886 [inlined]
  [5] all
    @ ./reducedim.jl:886 [inlined]
  [6] is_instantiated(ctx::Pkg.Types.Context)
    @ Pkg.Operations /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/Operations.jl:131
  [7] instantiate(ctx::Pkg.Types.Context; manifest::Nothing, update_registry::Bool, verbose::Bool, platform::Base.BinaryPlatforms.Platform, allow_build::Bool, allow_autoprecomp::Bool, kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Pkg.API /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/API.jl:1360
  [8] test(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}; coverage::Bool, julia_args::Cmd, test_args::Cmd, test_fn::Nothing)
    @ Pkg.Operations /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/Operations.jl:1646
  [9] test(ctx::Pkg.Types.Context, pkgs::Vector{Pkg.Types.PackageSpec}; coverage::Bool, test_fn::Nothing, julia_args::Cmd, test_args::Cmd, kwargs::Base.Iterators.Pairs{Symbol, Base.TTY, Tuple{Symbol}, NamedTuple{(:io,), Tuple{Base.TTY}}})
    @ Pkg.API /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/API.jl:343
 [10] test(pkgs::Vector{Pkg.Types.PackageSpec}; io::Base.TTY, kwargs::Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Pkg.API /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/API.jl:80
 [11] test(pkgs::Vector{Pkg.Types.PackageSpec})
    @ Pkg.API /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/API.jl:78
 [12] do_cmd!(command::Pkg.REPLMode.Command, repl::REPL.LineEditREPL)
    @ Pkg.REPLMode /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/REPLMode/REPLMode.jl:408
 [13] do_cmd(repl::REPL.LineEditREPL, input::String; do_rethrow::Bool)
    @ Pkg.REPLMode /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/REPLMode/REPLMode.jl:386
 [14] do_cmd
    @ /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/REPLMode/REPLMode.jl:377 [inlined]
 [15] (::Pkg.REPLMode.var"#24#27"{REPL.LineEditREPL, REPL.LineEdit.Prompt})(s::REPL.LineEdit.MIState, buf::IOBuffer, ok::Bool)
    @ Pkg.REPLMode /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/Pkg/src/REPLMode/REPLMode.jl:550
 [16] #invokelatest#2
    @ ./essentials.jl:708 [inlined]
 [17] invokelatest
    @ ./essentials.jl:706 [inlined]
 [18] run_interface(terminal::REPL.Terminals.TextTerminal, m::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
    @ REPL.LineEdit /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/LineEdit.jl:2441https://github.com/maxkapur/OptimalApplication.jl/blob/main/Project.toml
 [19] run_frontend(repl::REPL.LineEditREPL, backend::REPL.REPLBackendRef)
    @ REPL /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.6/REPL/src/REPL.jl:1126
 [20] (::REPL.var"#44#49"{REPL.LineEditREPL, REPL.REPLBackendRef})()
    @ REPL ./task.jl:417
  • The only differences between my local clone of the GitHub repo and the version of the package in the public registry are superficial: I added Aqua.jl tests and renamed some internal variables. Adding Aqua.jl, however, required rebuilding the manifest (on 1.8.0-rc1). Therefore, I expect my project to be compatible with 1.6.7, although I have not actually been able to test it because of this manifest conflict.
  • Link to the full CI run
  • Link to Project.toml

One option might be to not include a Manifest.toml in your git repository. Most Julia library packages do not include a Manifest.toml in the git repository, in part for this reason.

If you really want to test using a Manifest.toml, you could have a distinct Manifest.toml for each Julia minor version within separate project folders that include the main package that lacks the Manifest.toml. During different CI runs, you would use Pkg.activate to choose a different Manifest.toml based on the Julia minor version.

Thank you! It never occurred to me that the build steps would automatically generate Manifest.toml if it weren’t present already. This fixed my issue.