From 6beefe4bdfe8f6ae7b501a2d254af5f4e73cb332 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Thu, 9 Oct 2025 12:59:37 +1300 Subject: [PATCH 1/7] Update Elixir and Erlang --- .tool-versions | 4 ++-- mix.exs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.tool-versions b/.tool-versions index ad5a9a9a5..6f437652e 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ nodejs 16.18.1 python 3.10.13 -elixir 1.18.3-otp-27 -erlang 27.3.3 +elixir 1.19.0-rc.2-otp-28 +erlang 28.1 diff --git a/mix.exs b/mix.exs index 0580974ed..0b0543afb 100644 --- a/mix.exs +++ b/mix.exs @@ -14,7 +14,7 @@ defmodule NervesHub.MixProject do "coveralls.html": :test ], elixirc_paths: elixirc_paths(Mix.env()), - elixir: "~> 1.18.0", + elixir: "~> 1.19.0-rc.2", listeners: listeners(Mix.env()), releases: [ nerves_hub: [ From 0f2ae559d3cff53b27fbcd1e38ced350a96b79c7 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Thu, 9 Oct 2025 13:00:09 +1300 Subject: [PATCH 2/7] Move `preferred_cli_env` to `def cli()` --- mix.exs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mix.exs b/mix.exs index 0b0543afb..37e646a9f 100644 --- a/mix.exs +++ b/mix.exs @@ -8,11 +8,6 @@ defmodule NervesHub.MixProject do start_permanent: Mix.env() == :prod, deps: deps(), aliases: aliases(), - preferred_cli_env: [ - docs: :docs, - coveralls: :test, - "coveralls.html": :test - ], elixirc_paths: elixirc_paths(Mix.env()), elixir: "~> 1.19.0-rc.2", listeners: listeners(Mix.env()), @@ -57,6 +52,10 @@ defmodule NervesHub.MixProject do ] end + def cli() do + [preferred_envs: [docs: :docs, coveralls: :test, "coveralls.html": :test]] + end + defp build() do cmd = "git rev-parse --short=8 HEAD" From c5ba139504a4bd8586dc797b11063077367fc56a Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Thu, 9 Oct 2025 13:01:23 +1300 Subject: [PATCH 3/7] Rename a test file that wasn't run due to its incorrect naming --- .../live/org/{signing_keys.exs => signing_keys_test.exs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename test/nerves_hub_web/live/org/{signing_keys.exs => signing_keys_test.exs} (97%) diff --git a/test/nerves_hub_web/live/org/signing_keys.exs b/test/nerves_hub_web/live/org/signing_keys_test.exs similarity index 97% rename from test/nerves_hub_web/live/org/signing_keys.exs rename to test/nerves_hub_web/live/org/signing_keys_test.exs index 9da56a94e..4e10985ff 100644 --- a/test/nerves_hub_web/live/org/signing_keys.exs +++ b/test/nerves_hub_web/live/org/signing_keys_test.exs @@ -34,7 +34,7 @@ defmodule NervesHubWeb.Live.Org.SigningKeysTest do |> assert_has("div", text: "Signing Key created successfully.") |> assert_has("h3", text: "my amazing key") |> assert_has(".key-value", text: "wouldn't you like to know!") - |> assert_has("div", text: "Created by: #{user.username}") + |> assert_has("div", text: "Created by: #{user.name}") end test "name is trimmed if there is extra space", %{conn: conn, org: org} do From 340de24e13baf33c8471d687a1e44f4d749054b4 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Thu, 9 Oct 2025 13:03:54 +1300 Subject: [PATCH 4/7] Remove the options argument for `Firmwares.create_firmware` This was only used for testing, and could instead be achieved with a stub. (Elixir 1.19 warning) --- lib/nerves_hub/firmwares.ex | 9 +++------ test/nerves_hub/firmwares_test.exs | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/nerves_hub/firmwares.ex b/lib/nerves_hub/firmwares.ex index aba715a63..89dddf96e 100644 --- a/lib/nerves_hub/firmwares.ex +++ b/lib/nerves_hub/firmwares.ex @@ -224,19 +224,16 @@ defmodule NervesHub.Firmwares do @spec create_firmware( org :: Org.t(), - filepath :: Path.t(), - opts :: [{:upload_file_2, upload_file_2()}] + filepath :: Path.t() ) :: {:ok, Firmware.t()} | {:error, Changeset.t() | :no_public_keys | :invalid_signature | any} - def create_firmware(org, filepath, opts \\ []) do - upload_file_2 = opts[:upload_file_2] || (&firmware_upload_config().upload_file/2) - + def create_firmware(org, filepath) do Repo.transaction( fn -> with {:ok, params} <- build_firmware_params(org, filepath), {:ok, firmware} <- insert_firmware(params), - :ok <- upload_file_2.(filepath, firmware.upload_metadata) do + :ok <- firmware_upload_config().upload_file(filepath, firmware.upload_metadata) do _ = NervesHubWeb.Endpoint.broadcast("firmware", "created", %{firmware: firmware}) firmware else diff --git a/test/nerves_hub/firmwares_test.exs b/test/nerves_hub/firmwares_test.exs index acac635e0..76268ba0f 100644 --- a/test/nerves_hub/firmwares_test.exs +++ b/test/nerves_hub/firmwares_test.exs @@ -36,24 +36,26 @@ defmodule NervesHub.FirmwaresTest do end describe "create_firmware/2" do + test "enforces uuid uniqueness within a product", + %{firmware: %{upload_metadata: %{local_path: filepath}}, org: org} do + assert {:error, %Ecto.Changeset{errors: [uuid: {"has already been taken", [_ | _]}]}} = + Firmwares.create_firmware(org, filepath) + end + test "remote creation failure triggers transaction rollback", %{ org: org, org_key: org_key, product: product } do firmwares = Firmwares.get_firmwares_by_product(product.id) - upload_file_2 = fn _, _ -> {:error, :nope} end + filepath = Fixtures.firmware_file_fixture(org_key, product) - assert {:error, _} = Firmwares.create_firmware(org, filepath, upload_file_2: upload_file_2) + stub(NervesHub.Firmwares.Upload.File, :upload_file, fn _, _ -> {:error, :nope} end) - assert ^firmwares = Firmwares.get_firmwares_by_product(product.id) - end + assert {:error, _} = Firmwares.create_firmware(org, filepath) - test "enforces uuid uniqueness within a product", - %{firmware: %{upload_metadata: %{local_path: filepath}}, org: org} do - assert {:error, %Ecto.Changeset{errors: [uuid: {"has already been taken", [_ | _]}]}} = - Firmwares.create_firmware(org, filepath) + assert ^firmwares = Firmwares.get_firmwares_by_product(product.id) end end From 6746567c8e5f3efc76695e1e5459426cfdc796fe Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Thu, 9 Oct 2025 13:04:19 +1300 Subject: [PATCH 5/7] Address a failing test in a slightly cleaner way --- .../live/devices/health_test.exs | 21 +++++++++++-------- .../live/new_ui/devices/health_tab_test.exs | 21 +++++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/test/nerves_hub_web/live/devices/health_test.exs b/test/nerves_hub_web/live/devices/health_test.exs index 0b66517e9..8bce474bb 100644 --- a/test/nerves_hub_web/live/devices/health_test.exs +++ b/test/nerves_hub_web/live/devices/health_test.exs @@ -166,15 +166,18 @@ defmodule NervesHubWeb.Devices.HealthTest do |> DeviceMetric.save_with_timestamp() |> Repo.insert() - {:ok, _view, html} = - live(conn, "/org/#{org.name}/#{product.name}/devices/#{device.identifier}/health") - - organized_metrics = - ~s([{"y":#{value},"x":"#{now}"}]) - |> html_escape() - |> safe_to_string() - - assert html =~ ~s(data-metrics="#{organized_metrics}") + {:ok, _view, html} = live(conn, "/org/#{org.name}/#{product.name}/devices/#{device.identifier}/health") + + metrics = + html + |> LazyHTML.from_document() + |> LazyHTML.query("canvas") + |> LazyHTML.attributes() + |> List.first() + |> Enum.find(fn {key, _} -> key == "data-metrics" end) + |> elem(1) + + assert metrics == ~s([{"x":"#{now}","y":#{value}}]) end defp save_metrics_with_timestamp(device_id, timestamp) do diff --git a/test/nerves_hub_web/live/new_ui/devices/health_tab_test.exs b/test/nerves_hub_web/live/new_ui/devices/health_tab_test.exs index ea6302e73..1cdcc1c4f 100644 --- a/test/nerves_hub_web/live/new_ui/devices/health_tab_test.exs +++ b/test/nerves_hub_web/live/new_ui/devices/health_tab_test.exs @@ -167,15 +167,18 @@ defmodule NervesHubWeb.Live.NewUi.Devices.HealthTabTest do |> DeviceMetric.save_with_timestamp() |> Repo.insert() - {:ok, _view, html} = - live(conn, "/org/#{org.name}/#{product.name}/devices/#{device.identifier}/health") - - organized_metrics = - ~s([{"y":#{value},"x":"#{now}"}]) - |> html_escape() - |> safe_to_string() - - assert html =~ ~s(data-metrics="#{organized_metrics}") + {:ok, _view, html} = live(conn, "/org/#{org.name}/#{product.name}/devices/#{device.identifier}/health") + + metrics = + html + |> LazyHTML.from_document() + |> LazyHTML.query("canvas") + |> LazyHTML.attributes() + |> List.first() + |> Enum.find(fn {key, _} -> key == "data-metrics" end) + |> elem(1) + + assert metrics == ~s([{"x":"#{now}","y":#{value}}]) end defp save_metrics_with_timestamp(device_id, timestamp) do From 725732cb8d7b8c23ad3cf51940f24ebda6881b81 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Thu, 9 Oct 2025 13:04:29 +1300 Subject: [PATCH 6/7] `mix format` --- lib/nerves_hub/managed_deployments.ex | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/nerves_hub/managed_deployments.ex b/lib/nerves_hub/managed_deployments.ex index 2a77d34dd..c3cb392f8 100644 --- a/lib/nerves_hub/managed_deployments.ex +++ b/lib/nerves_hub/managed_deployments.ex @@ -272,14 +272,12 @@ defmodule NervesHub.ManagedDeployments do defp maybe_trigger_delta_generation( %{delta_updatable: true} = deployment_group, %{changes: %{firmware_id: _}} = _changeset - ), - do: trigger_delta_generation_for_deployment_group(deployment_group) + ), do: trigger_delta_generation_for_deployment_group(deployment_group) defp maybe_trigger_delta_generation( %{delta_updatable: true} = deployment_group, %{changes: %{is_active: true}} = _changeset - ), - do: trigger_delta_generation_for_deployment_group(deployment_group) + ), do: trigger_delta_generation_for_deployment_group(deployment_group) defp maybe_trigger_delta_generation(deployment_group, %{changes: %{delta_updatable: true}} = _changeset), do: trigger_delta_generation_for_deployment_group(deployment_group) From 48e792cabb143bba75eb763c9a46b9cb04257ab7 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 17 Oct 2025 20:37:16 +1300 Subject: [PATCH 7/7] Bump to 1.19.0 --- .tool-versions | 2 +- Dockerfile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.tool-versions b/.tool-versions index 6f437652e..0c2921d40 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ nodejs 16.18.1 python 3.10.13 -elixir 1.19.0-rc.2-otp-28 +elixir 1.19.0 erlang 28.1 diff --git a/Dockerfile b/Dockerfile index d74363459..2195e2c7a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ -ARG ELIXIR_VERSION=1.18.3 -ARG OTP_VERSION=27.3.3 +ARG ELIXIR_VERSION=1.19.0 +ARG OTP_VERSION=28.1 ARG DISTRO=noble-20250404 ARG NODE_VERSION=16.20.2