Skip to content

update test matrix to include newer major and minor versions#1166

Open
Ch4s3 wants to merge 5 commits into
hexpm:mainfrom
Ch4s3:update-gha-matrix
Open

update test matrix to include newer major and minor versions#1166
Ch4s3 wants to merge 5 commits into
hexpm:mainfrom
Ch4s3:update-gha-matrix

Conversation

@Ch4s3
Copy link
Copy Markdown

@Ch4s3 Ch4s3 commented May 19, 2026

I'm not sure if it's desirable to test against the latest RC of elixir like this, but I've seen other ecosystems do something like this and in any case it might be good to move the main versions up to the latest Elixir 1.19 and OTP28.5.

@ericmj
Copy link
Copy Markdown
Member

ericmj commented May 19, 2026

@Ch4s3 Looks like there is a failing test even after retrying. Can you investigate?

@Ch4s3
Copy link
Copy Markdown
Author

Ch4s3 commented May 19, 2026

@Ch4s3 Looks like there is a failing test even after retrying. Can you investigate?

I sure can. This is the exact sort of thing I thought running against the latest versions might uncover.

@Ch4s3
Copy link
Copy Markdown
Author

Ch4s3 commented May 19, 2026

Interesting, this is a fixture issue. The data is wrong and new versions of mix now catch it. I'll have a fix later.

Ch4s3 added 3 commits May 19, 2026 23:15
ecto_3_3_2/mix.exs declared version "3.3.1" instead of "3.3.2", causing
Mix 1.20 to raise a nomatchvsn error when updating ecto_sql (which pulls
in ecto ~> 3.3.2). Also fix the copy-paste module name in ecto_sql_3_3_3.
Elixir 1.20 removed the `recently_fetched?` guard from
Mix.Dep.Loader.validate_app. Previously, when a dep was just fetched,
validate_app would short-circuit to :compile status instead of reading
the (potentially stale) .app file from the build directory.

Without that guard, when a dep like ecto is updated from 3.3.1 → 3.3.2
during `deps.update ecto_sql`, Mix reads the old compiled ecto.app
(version 3.3.1) and marks ecto as {:ok, "3.3.1"}. When ecto_sql 3.3.3
then requires ecto ~> 3.3.2, req_mismatch triggers :divergedreq — a
false positive since ecto is already being updated to 3.3.2.

Fix: delete the stale .app file from the build directory in
Hex.SCM.update/1 after extracting the new tarball. This causes
validate_app to see {:noappfile, ...} (not {:ok, "3.3.1"}), so
req_mismatch is not triggered.
The existing ":divergedreq" integration test only fails on Elixir >= 1.20
(older versions mask the bug via Mix.Dep.Loader's recently_fetched? guard),
so it cannot guard the fix when the suite runs on 1.19 and earlier.

This test asserts the concrete behavior of the fix directly: after a
transitive dependency is updated (ecto 3.3.1 -> 3.3.2), its stale compiled
.app file must be gone. It fails without the SCM fix on every Elixir
version and passes with it.

Verified:
  - 1.19.5 without fix: existing test passes (masked), this test fails
  - 1.19.5 with fix:    both pass
  - 1.20.0-rc.5 without fix: both fail
  - 1.20.0-rc.5 with fix:    both pass
Comment thread lib/hex/scm.ex
Comment on lines +204 to +206
if build = opts[:build] do
Path.join([build, "ebin", "#{name}.app"]) |> File.rm()
end
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ericmj you probably understand mix way better than I do. Can you think of an approach that doesn't require a call to File.rm/0?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like an Elixir bug to me. Opened a PR with a proposed fix here: elixir-lang/elixir#15406

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's even better. I can point this to the next rc, main, or the eventual 1.20 when that's ready.

ericmj added a commit to elixir-lang/elixir that referenced this pull request May 20, 2026
Covers the full chain seen in hexpm/hex#1166: a fetchable dep's stale
.app is read by `validate_app`, produces an `{:ok, vsn}` that matches
the top-level requirement, then a transitive parent with a stricter
requirement causes the converger's `req_mismatch` to mark the dep as
`:divergedreq` — even though the only thing actually wrong is that
`_build` hasn't been recompiled yet.

With the loader bypass, `validate_app` returns `:compile` for a
fetchable dep whose SCM manifest's stored lock differs from
`opts[:lock]`, so the dep never enters the converger with `{:ok, _}`
and `req_mismatch` doesn't fire.

The previous test exercised the loader short-circuit in isolation;
this one exercises the same path through the full converge step and
asserts `Mix.Dep.diverged?/1` returns false.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants