From 31f70b3da4201e6b343b0d30f783b1617d0112a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Tue, 21 Apr 2026 23:00:22 +0200 Subject: [PATCH] Handle latest version fallback --- lib/diff_web/live/diff_live_view.ex | 32 ++++++++++++++++++++++------- test/diff_web/integration_test.exs | 28 +++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/lib/diff_web/live/diff_live_view.ex b/lib/diff_web/live/diff_live_view.ex index cf2cccb..9ffebe9 100644 --- a/lib/diff_web/live/diff_live_view.ex +++ b/lib/diff_web/live/diff_live_view.ex @@ -16,7 +16,7 @@ defmodule DiffWeb.DiffLiveView do mount_single_diff(socket, package, resolved_from, resolved_to) {:error, reason} -> - {:ok, assign(socket, error: "Package not found: #{reason}")} + {:ok, assign(socket, error: latest_version_error(package, reason))} end :error -> @@ -117,13 +117,15 @@ defmodule DiffWeb.DiffLiveView do defp resolve_latest_version(package, from, to) when to == :latest or to == "latest" do case Diff.Package.Store.get_versions(package) do {:ok, versions} -> - to = - versions - |> Enum.map(&Version.parse!/1) - |> Enum.filter(&(&1.pre == [])) - |> Enum.max(Version) + versions = Enum.map(versions, &Version.parse!/1) - {:ok, from, to_string(to)} + case latest_version(versions) do + nil -> + {:error, :no_versions} + + to -> + {:ok, from, to_string(to)} + end {:error, :not_found} -> {:error, :not_found} @@ -132,6 +134,22 @@ defmodule DiffWeb.DiffLiveView do defp resolve_latest_version(_package, from, to), do: {:ok, from, to} + defp latest_version([]), do: nil + + defp latest_version(versions) do + stable_versions = Enum.filter(versions, &(&1.pre == [])) + + case stable_versions do + [] -> Enum.max(versions, Version) + stable_versions -> Enum.max(stable_versions, Version) + end + end + + defp latest_version_error(package, :not_found), do: "Package not found: #{package}" + + defp latest_version_error(package, :no_versions), + do: "No versions found for package: #{package}" + def handle_event("load-more", _params, socket) do batch_size = 5 {next_batch, _remaining} = Enum.split(socket.assigns.remaining_diffs, batch_size) diff --git a/test/diff_web/integration_test.exs b/test/diff_web/integration_test.exs index 2a36b8c..0bd265d 100644 --- a/test/diff_web/integration_test.exs +++ b/test/diff_web/integration_test.exs @@ -40,6 +40,34 @@ defmodule DiffWeb.IntegrationTest do assert html =~ "Generating diffs" end + test "/diff with implicit latest handles packages without stable versions", %{conn: conn} do + Diff.Package.StoreMock + |> stub(:get_versions, fn "prerelease_only" -> + {:ok, ["1.0.0-alpha.1", "1.0.0-rc.1", "1.0.0-rc.2"]} + end) + + Diff.StorageMock + |> stub(:get_metadata, fn "prerelease_only", "0.1.0", "1.0.0-rc.2" -> + {:error, :not_found} + end) + + Diff.HexMock + |> stub(:diff, fn "prerelease_only", "0.1.0", "1.0.0-rc.2" -> :error end) + + {:ok, _view, html} = live(conn, "/diff/prerelease_only/0.1.0..") + + assert html =~ "Generating diffs" + end + + test "/diff with implicit latest handles packages with an empty version list", %{conn: conn} do + Diff.Package.StoreMock + |> stub(:get_versions, fn "empty" -> {:ok, []} end) + + {:ok, _view, html} = live(conn, "/diff/empty/0.1.0..") + + assert html =~ "No versions found for package: empty" + end + test "/diff handles package not found", %{conn: conn} do Diff.Package.StoreMock |> stub(:get_versions, fn "nonexistent" -> {:error, :not_found} end)