- Coming Soon...
+
+
+
+
+
+
+
No releases yet
+
+ Release history will appear here when you change the firmware version in settings.
+
+
+
+
+
+
+
+ | Released |
+ Firmware Version |
+ UUID |
+ Archive |
+ Released By |
+
+
+
+
+ |
+
+ {Calendar.strftime(release.inserted_at, "%B %d, %Y")}
+ {Calendar.strftime(release.inserted_at, "%I:%M %p")} UTC
+
+ |
+
+ {release.firmware.version}
+ |
+
+ {release.firmware.uuid}
+ |
+
+
+ {release.archive.version} ({String.slice(release.archive.uuid, 0..7)})
+
+
+ None
+
+ |
+
+ {release.user.name}
+ |
+
+
+
+
+
"""
diff --git a/lib/nerves_hub_web/components/deployment_group_page/settings.ex b/lib/nerves_hub_web/components/deployment_group_page/settings.ex
index d577f27a8..99b53e2db 100644
--- a/lib/nerves_hub_web/components/deployment_group_page/settings.ex
+++ b/lib/nerves_hub_web/components/deployment_group_page/settings.ex
@@ -286,7 +286,7 @@ defmodule NervesHubWeb.Components.DeploymentGroupPage.Settings do
authorized!(:"deployment_group:update", org_user)
- case ManagedDeployments.update_deployment_group(deployment_group, params) do
+ case ManagedDeployments.update_deployment_group(deployment_group, params, user) do
{:ok, updated} ->
# Use original deployment so changes will get
# marked in audit log
diff --git a/lib/nerves_hub_web/controllers/api/deployment_group_controller.ex b/lib/nerves_hub_web/controllers/api/deployment_group_controller.ex
index 5d78e5dcd..5d9247a6a 100644
--- a/lib/nerves_hub_web/controllers/api/deployment_group_controller.ex
+++ b/lib/nerves_hub_web/controllers/api/deployment_group_controller.ex
@@ -29,7 +29,7 @@ defmodule NervesHubWeb.API.DeploymentGroupController do
uuid ->
with {:ok, firmware} <- Firmwares.get_firmware_by_product_and_uuid(product, uuid),
params = Map.put(params, "firmware_id", firmware.id),
- {:ok, deployment_group} <- ManagedDeployments.create_deployment_group(params, product) do
+ {:ok, deployment_group} <- ManagedDeployments.create_deployment_group(params, product, user) do
DeploymentGroupTemplates.audit_deployment_created(user, deployment_group)
conn
@@ -67,7 +67,7 @@ defmodule NervesHubWeb.API.DeploymentGroupController do
ManagedDeployments.get_deployment_group_by_name(product, name),
params = update_params(product, deployment_group_params),
{:ok, updated_deployment_group} <-
- ManagedDeployments.update_deployment_group(deployment_group, params) do
+ ManagedDeployments.update_deployment_group(deployment_group, params, user) do
DeploymentGroupTemplates.audit_deployment_updated(user, deployment_group)
render(conn, :show, deployment_group: updated_deployment_group)
diff --git a/lib/nerves_hub_web/live/deployment_groups/new.ex b/lib/nerves_hub_web/live/deployment_groups/new.ex
index 919eb05d0..3497583a4 100644
--- a/lib/nerves_hub_web/live/deployment_groups/new.ex
+++ b/lib/nerves_hub_web/live/deployment_groups/new.ex
@@ -143,7 +143,7 @@ defmodule NervesHubWeb.Live.DeploymentGroups.New do
%{user: user, org: org, product: product} = socket.assigns
- ManagedDeployments.create_deployment_group(params, product)
+ ManagedDeployments.create_deployment_group(params, product, user)
|> case do
{:ok, deployment_group} ->
_ = DeploymentGroupTemplates.audit_deployment_created(user, deployment_group)
diff --git a/lib/nerves_hub_web/live/deployment_groups/show.ex b/lib/nerves_hub_web/live/deployment_groups/show.ex
index 6689005d0..eb0c03b2f 100644
--- a/lib/nerves_hub_web/live/deployment_groups/show.ex
+++ b/lib/nerves_hub_web/live/deployment_groups/show.ex
@@ -38,6 +38,7 @@ defmodule NervesHubWeb.Live.DeploymentGroups.Show do
inflight_updates = Devices.inflight_updates_for(deployment_group)
updating_count = Devices.updating_count(deployment_group)
+ releases = ManagedDeployments.list_deployment_releases(deployment_group)
:ok = socket.endpoint.subscribe("deployment:#{deployment_group.id}:internal")
@@ -55,6 +56,7 @@ defmodule NervesHubWeb.Live.DeploymentGroups.Show do
|> assign(:firmware, deployment_group.firmware)
|> assign(:deltas, Firmwares.get_deltas_by_target_firmware(deployment_group.firmware))
|> assign(:update_stats, UpdateStats.stats_by_deployment(deployment_group))
+ |> assign(:releases, releases)
|> assign_matched_devices_count()
|> schedule_inflight_updates_updater()
|> ok()
@@ -85,7 +87,7 @@ defmodule NervesHubWeb.Live.DeploymentGroups.Show do
value = !deployment_group.is_active
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{is_active: value})
+ ManagedDeployments.update_deployment_group(deployment_group, %{is_active: value}, user)
active_str = if value, do: "active", else: "inactive"
DeploymentGroupTemplates.audit_deployment_toggle_active(user, deployment_group, active_str)
diff --git a/lib/nerves_hub_web/live/deployment_groups/show.html.heex b/lib/nerves_hub_web/live/deployment_groups/show.html.heex
index 0a44489da..c08609349 100644
--- a/lib/nerves_hub_web/live/deployment_groups/show.html.heex
+++ b/lib/nerves_hub_web/live/deployment_groups/show.html.heex
@@ -101,7 +101,7 @@
update_stats={@update_stats}
/>
- <.live_component :if={@tab == :release_history} module={ReleaseHistoryTab} id="deployment_group_release_history" />
+ <.live_component :if={@tab == :release_history} module={ReleaseHistoryTab} id="deployment_group_release_history" releases={@releases} />
<.live_component :if={@tab == :activity} module={ActivityTab} id="deployment_group_activity" deployment_group={@deployment_group} org={@org} product={@product} user={@user} />
diff --git a/priv/repo/migrations/20251206184125_add_cascade_delete_to_deployment_releases.exs b/priv/repo/migrations/20251206184125_add_cascade_delete_to_deployment_releases.exs
new file mode 100644
index 000000000..d01a24fcf
--- /dev/null
+++ b/priv/repo/migrations/20251206184125_add_cascade_delete_to_deployment_releases.exs
@@ -0,0 +1,23 @@
+defmodule NervesHub.Repo.Migrations.AddCascadeDeleteToDeploymentReleases do
+ use Ecto.Migration
+
+ def up do
+ # Drop the existing foreign key constraint
+ drop constraint(:deployment_releases, "deployment_releases_deployment_group_id_fkey")
+
+ # Add it back with cascade delete
+ alter table(:deployment_releases) do
+ modify :deployment_group_id, references(:deployments, on_delete: :delete_all), null: false
+ end
+ end
+
+ def down do
+ # Drop the cascade delete foreign key constraint
+ drop constraint(:deployment_releases, "deployment_releases_deployment_group_id_fkey")
+
+ # Add it back without cascade delete (original state)
+ alter table(:deployment_releases) do
+ modify :deployment_group_id, references(:deployments), null: false
+ end
+ end
+end
diff --git a/test/nerves_hub/devices/update_stats_test.exs b/test/nerves_hub/devices/update_stats_test.exs
index d1584aa5f..dab497699 100644
--- a/test/nerves_hub/devices/update_stats_test.exs
+++ b/test/nerves_hub/devices/update_stats_test.exs
@@ -183,7 +183,8 @@ defmodule NervesHub.Devices.UpdateStatsTest do
source_firmware: source_firmware,
target_firmware: target_firmware,
other_firmware: other_firmware,
- source_firmware_metadata: source_firmware_metadata
+ source_firmware_metadata: source_firmware_metadata,
+ user: user
} do
device = Devices.update_deployment_group(device, deployment_group)
device2 = Devices.update_deployment_group(device2, deployment_group)
@@ -193,9 +194,13 @@ defmodule NervesHub.Devices.UpdateStatsTest do
:ok = UpdateStats.log_update(device, source_firmware_metadata)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- firmware_id: other_firmware.id
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ firmware_id: other_firmware.id
+ },
+ user
+ )
# deployment group needs to be explicitly passed in because association
# is already preloaded from fixtures, causing the preload in log_update/2
diff --git a/test/nerves_hub/devices_test.exs b/test/nerves_hub/devices_test.exs
index 7ff2c1bd2..8a18fb8aa 100644
--- a/test/nerves_hub/devices_test.exs
+++ b/test/nerves_hub/devices_test.exs
@@ -805,12 +805,17 @@ defmodule NervesHub.DevicesTest do
deployment_group: deployment_group,
device: device1 = %{id: device1_id},
org: org,
- product: product
+ product: product,
+ user: user
} do
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- enable_priority_updates: true
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ enable_priority_updates: true
+ },
+ user
+ )
{:ok, device1} = Devices.update_device(device1, %{first_seen_at: DateTime.utc_now()})
diff --git a/test/nerves_hub/managed_deployments/distributed/orchestrator_test.exs b/test/nerves_hub/managed_deployments/distributed/orchestrator_test.exs
index e120c2153..f6b62b93a 100644
--- a/test/nerves_hub/managed_deployments/distributed/orchestrator_test.exs
+++ b/test/nerves_hub/managed_deployments/distributed/orchestrator_test.exs
@@ -51,16 +51,21 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
org_key: org_key,
device: device1,
device2: device2,
- device3: device3
+ device3: device3,
+ user: user
} do
# setup deployment group, listen for broadcasts, and start the orchestrator
firmware = Fixtures.firmware_fixture(org_key, product)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- concurrent_updates: 2,
- firmware_id: firmware.id
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ concurrent_updates: 2,
+ firmware_id: firmware.id
+ },
+ user
+ )
{:ok, _pid} =
start_supervised(%{
@@ -114,11 +119,12 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
deployment_group: deployment_group,
org_key: org_key,
device: device,
- device2: device2
+ device2: device2,
+ user: user
} do
# only allow for 1 update at a time
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{concurrent_updates: 1})
+ ManagedDeployments.update_deployment_group(deployment_group, %{concurrent_updates: 1}, user)
device = Devices.update_deployment_group(device, deployment_group)
{:ok, connection} = Connections.device_connecting(device, device.product_id)
@@ -148,7 +154,7 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
firmware = Fixtures.firmware_fixture(org_key, product)
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware.id})
+ ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware.id}, user)
# check that the first device was told to update
assert_receive %Broadcast{topic: ^topic1, event: "update"}, 500
@@ -183,11 +189,12 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
product: product,
deployment_group: deployment_group,
org_key: org_key,
- device: device
+ device: device,
+ user: user
} do
# only allow for 1 update at a time
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{concurrent_updates: 1})
+ ManagedDeployments.update_deployment_group(deployment_group, %{concurrent_updates: 1}, user)
device = Devices.update_deployment_group(device, deployment_group)
{:ok, device} = Devices.update_device(device, %{firmware_validation_status: "not_validated"})
@@ -211,7 +218,7 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
firmware = Fixtures.firmware_fixture(org_key, product)
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware.id})
+ ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware.id}, user)
# check that the device is not told to update
refute_receive %Broadcast{topic: ^topic1, event: "update"}, 1_000
@@ -222,7 +229,8 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
org_key: org_key,
product: product,
device: device1,
- device2: device2
+ device2: device2,
+ user: user
} do
# An ugly set of expectations
# `Devices.available_for_update` should be called:
@@ -241,10 +249,14 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
firmware = Fixtures.firmware_fixture(org_key, product)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- concurrent_updates: 2,
- firmware_id: firmware.id
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ concurrent_updates: 2,
+ firmware_id: firmware.id
+ },
+ user
+ )
deployment_group_topic = "orchestrator:deployment:#{deployment_group.id}"
Phoenix.PubSub.subscribe(NervesHub.PubSub, deployment_group_topic)
@@ -316,10 +328,14 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
firmware = Fixtures.firmware_fixture(org_key, product)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- concurrent_updates: 2,
- firmware_id: firmware.id
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ concurrent_updates: 2,
+ firmware_id: firmware.id
+ },
+ user
+ )
deployment_topic = "orchestrator:deployment:#{deployment_group.id}"
Phoenix.PubSub.subscribe(NervesHub.PubSub, deployment_topic)
@@ -441,7 +457,8 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
test "handles delta subscriptions when firmware changes", %{
deployment_group: deployment_group,
org_key: org_key,
- product: product
+ product: product,
+ user: user
} do
new_firmware = %{id: new_firmware_id} = Fixtures.firmware_fixture(org_key, product)
%{firmware_id: old_firmware_id} = deployment_group
@@ -458,7 +475,7 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
expect(Firmwares, :unsubscribe_firmware_delta_target, fn ^old_firmware_id -> :ok end)
expect(Firmwares, :subscribe_firmware_delta_target, fn ^new_firmware_id -> :ok end)
- {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id})
+ {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}, user)
_ = :sys.get_state(pid)
end
@@ -466,7 +483,8 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
deployment_group: deployment_group,
org_key: org_key,
product: product,
- org: org
+ org: org,
+ user: user
} do
other_firmware = Fixtures.firmware_fixture(org_key, product)
@@ -491,7 +509,7 @@ defmodule NervesHub.ManagedDeployments.Distributed.OrchestratorTest do
allow(Devices, self(), pid)
- {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true})
+ {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user)
_ = :sys.get_state(pid)
end
diff --git a/test/nerves_hub/managed_deployments_test.exs b/test/nerves_hub/managed_deployments_test.exs
index 1b33ca76d..7286b53be 100644
--- a/test/nerves_hub/managed_deployments_test.exs
+++ b/test/nerves_hub/managed_deployments_test.exs
@@ -33,6 +33,7 @@ defmodule NervesHub.ManagedDeploymentsTest do
{:ok,
%{
+ user: user,
org: org,
org_key: org_key,
firmware: firmware,
@@ -48,7 +49,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
describe "create deployment" do
test "create_deployment_group with valid parameters", %{
product: product,
- firmware: firmware
+ firmware: firmware,
+ user: user
} do
params = %{
name: "a different name",
@@ -60,7 +62,7 @@ defmodule NervesHub.ManagedDeploymentsTest do
}
{:ok, %DeploymentGroup{} = deployment_group} =
- ManagedDeployments.create_deployment_group(params, product)
+ ManagedDeployments.create_deployment_group(params, product, user)
for key <- Map.keys(params) do
case Map.get(deployment_group, key) do
@@ -76,7 +78,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
test "deployments have unique names wrt product", %{
firmware: firmware,
product: product,
- deployment_group: existing_deployment_group
+ deployment_group: existing_deployment_group,
+ user: user
} do
params = %{
name: existing_deployment_group.name,
@@ -88,10 +91,10 @@ defmodule NervesHub.ManagedDeploymentsTest do
}
assert {:error, %Ecto.Changeset{errors: [name: {"has already been taken", _}]}} =
- ManagedDeployments.create_deployment_group(params, product)
+ ManagedDeployments.create_deployment_group(params, product, user)
end
- test "create_deployment_group with invalid parameters", %{product: product, firmware: firmware} do
+ test "create_deployment_group with invalid parameters fails", %{product: product, firmware: firmware, user: user} do
params = %{
name: "",
conditions: %{
@@ -101,10 +104,10 @@ defmodule NervesHub.ManagedDeploymentsTest do
firmware_id: firmware.id
}
- assert {:error, %Changeset{}} = ManagedDeployments.create_deployment_group(params, product)
+ assert {:error, %Changeset{}} = ManagedDeployments.create_deployment_group(params, product, user)
end
- test "create_deployment_group with non existant firmware", %{product: product} do
+ test "create_deployment_group with non existant firmware fails", %{product: product, user: user} do
params = %{
name: "Boop",
conditions: %{
@@ -115,10 +118,10 @@ defmodule NervesHub.ManagedDeploymentsTest do
}
assert {:error, %Changeset{errors: [firmware_id: {"does not exist", _}]}} =
- ManagedDeployments.create_deployment_group(params, product)
+ ManagedDeployments.create_deployment_group(params, product, user)
end
- test "create_deployment_group with non existant (empty) firmware", %{product: product} do
+ test "create_deployment_group with non existant (empty) firmware fails", %{product: product, user: user} do
params = %{
name: "Boop",
conditions: %{
@@ -134,12 +137,42 @@ defmodule NervesHub.ManagedDeploymentsTest do
{:firmware_id, {"can't be blank", [validation: :required]}}
]
}} =
- ManagedDeployments.create_deployment_group(params, product)
+ ManagedDeployments.create_deployment_group(params, product, user)
+ end
+
+ test "creates release history when deployment group is created with firmware", %{
+ product: product,
+ firmware: firmware,
+ user: user
+ } do
+ params = %{
+ name: "new deployment with release",
+ conditions: %{
+ version: "< 1.0.0",
+ tags: ["beta"]
+ },
+ firmware_id: firmware.id
+ }
+
+ {:ok, deployment_group} = ManagedDeployments.create_deployment_group(params, product, user)
+
+ releases = ManagedDeployments.list_deployment_releases(deployment_group)
+
+ assert length(releases) == 1
+ [release] = releases
+
+ assert release.deployment_group_id == deployment_group.id
+ assert release.firmware_id == firmware.id
+ refute release.archive_id
+ assert release.created_by_id == user.id
+ assert release.firmware.id == firmware.id
+ assert release.user.id == user.id
end
end
- describe "update_deployment_group/2" do
+ describe "update_deployment_group/3" do
test "updating firmware sends an update message", %{
+ user: user,
org_key: org_key,
firmware: firmware,
product: product
@@ -157,18 +190,19 @@ defmodule NervesHub.ManagedDeploymentsTest do
firmware_id: firmware.id
}
- {:ok, deployment_group} = ManagedDeployments.create_deployment_group(params, product)
+ {:ok, deployment_group} = ManagedDeployments.create_deployment_group(params, product, user)
Phoenix.PubSub.subscribe(NervesHub.PubSub, "deployment:#{deployment_group.id}")
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user)
assert_broadcast("deployments/update", %{}, 500)
end
test "starts distributed orchestrator if deployment updates to active from inactive",
%{
+ user: user,
deployment_group: deployment_group
} do
refute deployment_group.is_active
@@ -186,10 +220,10 @@ defmodule NervesHub.ManagedDeploymentsTest do
)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user)
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{is_active: false})
+ ManagedDeployments.update_deployment_group(deployment_group, %{is_active: false}, user)
topic = "orchestrator:deployment:#{deployment_group.id}"
assert_receive %Broadcast{topic: ^topic, event: "deactivated"}, 500
@@ -197,6 +231,7 @@ defmodule NervesHub.ManagedDeploymentsTest do
test "triggers delta generation when firmware is updated and delta updates are enabled",
%{
+ user: user,
deployment_group: deployment_group,
firmware: firmware,
org: org,
@@ -204,7 +239,7 @@ defmodule NervesHub.ManagedDeploymentsTest do
product: product
} do
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user)
assert deployment_group.delta_updatable
assert deployment_group.firmware_id == firmware.id
@@ -218,13 +253,14 @@ defmodule NervesHub.ManagedDeploymentsTest do
new_firmware = Fixtures.firmware_fixture(org_key, product)
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id})
+ ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}, user)
assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware.id, target_id: new_firmware.id})
end
test "triggers delta generation when delta updates are enabled",
%{
+ user: user,
deployment_group: deployment_group,
firmware: firmware,
org: org,
@@ -237,7 +273,7 @@ defmodule NervesHub.ManagedDeploymentsTest do
new_firmware = Fixtures.firmware_fixture(org_key, product)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id})
+ ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: new_firmware.id}, user)
device =
Fixtures.device_fixture(org, product, firmware, %{tags: ["beta", "rpi"]})
@@ -246,13 +282,14 @@ defmodule NervesHub.ManagedDeploymentsTest do
assert device.deployment_id == deployment_group.id
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user)
assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware.id, target_id: new_firmware.id})
end
test "does not trigger delta generation if firmware has not changed",
%{
+ user: user,
deployment_group: deployment_group,
firmware: firmware,
org: org,
@@ -268,13 +305,14 @@ defmodule NervesHub.ManagedDeploymentsTest do
assert device.deployment_id == deployment_group.id
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user)
reject(FirmwareDeltaBuilder, :new, 1)
end
test "triggers delta generation for every unique device firmware + deployment firmware combination",
%{
+ user: user,
deployment_group: deployment_group,
firmware: firmware,
org: org,
@@ -306,31 +344,142 @@ defmodule NervesHub.ManagedDeploymentsTest do
|> Devices.update_deployment_group(deployment_group)
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user)
assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware2.id, target_id: firmware.id})
assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware3.id, target_id: firmware.id})
assert_enqueued(worker: FirmwareDeltaBuilder, args: %{source_id: firmware4.id, target_id: firmware.id})
end
- test "sets status to :preparing when turning on deltas", %{deployment_group: deployment_group} do
+ test "sets status to :preparing when turning on deltas", %{user: user, deployment_group: deployment_group} do
assert deployment_group.status == :ready
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user)
assert deployment_group.status == :preparing
end
- test "sets status to :ready when turning off deltas", %{deployment_group: deployment_group} do
+ test "sets status to :ready when turning off deltas", %{user: user, deployment_group: deployment_group} do
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: true}, user)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: false})
+ ManagedDeployments.update_deployment_group(deployment_group, %{delta_updatable: false}, user)
assert deployment_group.status == :ready
end
+
+ test "creates release record when either firmware or archive change", %{
+ user: user,
+ deployment_group: deployment_group,
+ org_key: org_key,
+ product: product
+ } do
+ # One from the initial creation
+ assert length(ManagedDeployments.list_deployment_releases(deployment_group)) == 1
+
+ new_firmware = Fixtures.firmware_fixture(org_key, product, %{version: "3.0.0"})
+ archive = Fixtures.archive_fixture(org_key, product, %{version: "1.0.0"})
+
+ {:ok, updated_deployment_group} =
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{firmware_id: new_firmware.id, archive_id: archive.id},
+ user
+ )
+
+ releases = ManagedDeployments.list_deployment_releases(updated_deployment_group)
+ assert length(releases) == 2
+
+ [release | _rest] = releases
+ assert release.firmware_id == new_firmware.id
+ assert release.archive_id == archive.id
+ assert release.archive.version == "1.0.0"
+
+ {:ok, updated_deployment_group} =
+ ManagedDeployments.update_deployment_group(
+ updated_deployment_group,
+ %{archive_id: nil},
+ user
+ )
+
+ releases = ManagedDeployments.list_deployment_releases(updated_deployment_group)
+ assert length(releases) == 3
+ [latest_release | _rest] = releases
+ assert latest_release.archive_id == nil
+ end
+
+ test "does not create release record when firmware is not changed", %{
+ user: user,
+ deployment_group: deployment_group
+ } do
+ releases = ManagedDeployments.list_deployment_releases(deployment_group)
+ assert length(releases) == 1
+ # Update something other than firmware
+ {:ok, _updated_deployment_group} =
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{is_active: true},
+ user
+ )
+
+ # Should have no new releases
+ assert ManagedDeployments.list_deployment_releases(deployment_group) == releases
+ end
+
+ test "list_deployment_releases returns releases ordered by most recent first", %{
+ user: user,
+ deployment_group: deployment_group,
+ org_key: org_key,
+ product: product
+ } do
+ # Create several new releases
+ Enum.each(["2.0.0", "2.1.0", "2.2.0"], fn version ->
+ firmware = Fixtures.firmware_fixture(org_key, product, %{version: version})
+
+ {:ok, updated_dg} =
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{firmware_id: firmware.id},
+ user
+ )
+
+ updated_dg
+ end)
+
+ releases = ManagedDeployments.list_deployment_releases(deployment_group)
+ # 4 because one is created when the deployment group is created
+ assert length(releases) == 4
+
+ assert Enum.map(releases, & &1.firmware.version) == ["2.2.0", "2.1.0", "2.0.0", deployment_group.firmware.version]
+ end
+
+ test "deployment releases are cascade deleted when deployment group is deleted", %{
+ user: user,
+ deployment_group: deployment_group,
+ org_key: org_key,
+ product: product
+ } do
+ # Create some releases
+ firmware1 = Fixtures.firmware_fixture(org_key, product, %{version: "2.0.0"})
+ firmware2 = Fixtures.firmware_fixture(org_key, product, %{version: "2.1.0"})
+
+ {:ok, deployment_group} =
+ ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware1.id}, user)
+
+ {:ok, deployment_group} =
+ ManagedDeployments.update_deployment_group(deployment_group, %{firmware_id: firmware2.id}, user)
+
+ releases = ManagedDeployments.list_deployment_releases(deployment_group)
+ assert length(releases) == 3
+
+ # Delete the deployment group
+ {:ok, _deleted} = ManagedDeployments.delete_deployment_group(deployment_group)
+
+ # Verify releases are deleted
+ assert ManagedDeployments.list_deployment_releases(deployment_group) == []
+ end
end
describe "devices matching deployments" do
@@ -661,7 +810,7 @@ defmodule NervesHub.ManagedDeploymentsTest do
end
describe "matched_devices_count/2" do
- setup %{org: org, product: product, firmware: firmware} =
+ setup %{org: org, product: product, firmware: firmware, user: user} =
context do
{:ok, deployment_group} =
ManagedDeployments.create_deployment_group(
@@ -673,7 +822,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
},
firmware_id: firmware.id
},
- product
+ product,
+ user
)
Fixtures.device_fixture(org, product, firmware, %{
@@ -701,28 +851,39 @@ defmodule NervesHub.ManagedDeploymentsTest do
end
test "counts devices for deployment group with tags but no version", %{
+ user: user,
deployment_group: deployment_group
} do
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- conditions: %{"tags" => ["beta", "rpi"], "version" => ""}
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ conditions: %{"tags" => ["beta", "rpi"], "version" => ""}
+ },
+ user
+ )
assert ManagedDeployments.matched_devices_count(deployment_group, in_deployment: true) == 2
end
test "counts devices for deployment group with tags and version", %{
+ user: user,
deployment_group: deployment_group
} do
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- conditions: %{"tags" => ["beta", "rpi"], "version" => "> 1.1.0"}
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ conditions: %{"tags" => ["beta", "rpi"], "version" => "> 1.1.0"}
+ },
+ user
+ )
assert ManagedDeployments.matched_devices_count(deployment_group, in_deployment: true) == 1
end
test "accounts for devices outside of deployment group", %{
+ user: user,
deployment_group: deployment_group,
org: org,
product: product,
@@ -736,14 +897,19 @@ defmodule NervesHub.ManagedDeploymentsTest do
refute device.deployment_id
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- conditions: %{"tags" => ["beta", "rpi"], "version" => ""}
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ conditions: %{"tags" => ["beta", "rpi"], "version" => ""}
+ },
+ user
+ )
assert ManagedDeployments.matched_devices_count(deployment_group, in_deployment: false) == 1
end
test "devices outside deployment group account for platform and architecture", %{
+ user: user,
deployment_group: deployment_group,
org: org,
product: product,
@@ -757,9 +923,13 @@ defmodule NervesHub.ManagedDeploymentsTest do
refute device.deployment_id
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- conditions: %{"tags" => ["beta", "rpi"], "version" => ""}
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ conditions: %{"tags" => ["beta", "rpi"], "version" => ""}
+ },
+ user
+ )
assert ManagedDeployments.matched_devices_count(deployment_group, in_deployment: false) == 1
end
@@ -769,7 +939,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
test "takes platform and architecture into account", %{
org: org,
product: product,
- firmware: firmware
+ firmware: firmware,
+ user: user
} do
{:ok, deployment_group} =
ManagedDeployments.create_deployment_group(
@@ -781,7 +952,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
},
firmware_id: firmware.id
},
- product
+ product,
+ user
)
_device1 =
@@ -807,7 +979,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
test "matches against tags and version", %{
org: org,
product: product,
- firmware: firmware
+ firmware: firmware,
+ user: user
} do
{:ok, deployment_group} =
ManagedDeployments.create_deployment_group(
@@ -819,7 +992,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
},
firmware_id: firmware.id
},
- product
+ product,
+ user
)
_device1 =
@@ -850,7 +1024,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
test "matches against only tags if deployment group has no version", %{
org: org,
product: product,
- firmware: firmware
+ firmware: firmware,
+ user: user
} do
{:ok, deployment_group} =
ManagedDeployments.create_deployment_group(
@@ -862,7 +1037,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
},
firmware_id: firmware.id
},
- product
+ product,
+ user
)
device1 =
@@ -889,7 +1065,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
test "matches against only version if deployment group has no tags", %{
org: org,
product: product,
- firmware: firmware
+ firmware: firmware,
+ user: user
} do
{:ok, deployment_group} =
ManagedDeployments.create_deployment_group(
@@ -901,7 +1078,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
},
firmware_id: firmware.id
},
- product
+ product,
+ user
)
_device1 =
@@ -928,7 +1106,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
%{
org: org,
product: product,
- firmware: firmware
+ firmware: firmware,
+ user: user
} do
{:ok, deployment_group} =
ManagedDeployments.create_deployment_group(
@@ -940,7 +1119,8 @@ defmodule NervesHub.ManagedDeploymentsTest do
},
firmware_id: firmware.id
},
- product
+ product,
+ user
)
device1 =
@@ -985,9 +1165,9 @@ defmodule NervesHub.ManagedDeploymentsTest do
end
end
- test "should_run_orchestrator/0", %{deployment_group: deployment_group} do
+ test "should_run_orchestrator/0", %{user: user, deployment_group: deployment_group} do
assert [] == ManagedDeployments.should_run_orchestrator()
- {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true})
+ {:ok, _} = ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user)
assert length(ManagedDeployments.should_run_orchestrator()) == 1
end
diff --git a/test/nerves_hub_web/channels/device_channel_test.exs b/test/nerves_hub_web/channels/device_channel_test.exs
index 2ca4b1036..d9e50f2a3 100644
--- a/test/nerves_hub_web/channels/device_channel_test.exs
+++ b/test/nerves_hub_web/channels/device_channel_test.exs
@@ -484,7 +484,7 @@ defmodule NervesHubWeb.DeviceChannelTest do
refute device.deployment_id
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, user)
%{db_cert: certificate, cert: _cert} = Fixtures.device_certificate_fixture(device)
@@ -505,9 +505,13 @@ defmodule NervesHubWeb.DeviceChannelTest do
Devices.update_deployment_group(device, deployment_group)
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- conditions: %{"version" => "< 0.0.1"}
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ conditions: %{"version" => "< 0.0.1"}
+ },
+ user
+ )
%{db_cert: certificate, cert: _cert} = Fixtures.device_certificate_fixture(device)
@@ -614,7 +618,7 @@ defmodule NervesHubWeb.DeviceChannelTest do
firmware = Fixtures.firmware_fixture(org_key, product, %{dir: System.tmp_dir()})
deployment_group = Fixtures.deployment_group_fixture(firmware)
- ManagedDeployments.update_deployment_group(deployment_group, %{archive_id: archive.id})
+ ManagedDeployments.update_deployment_group(deployment_group, %{archive_id: archive.id}, user)
{device, _firmware, _deployment_group} =
device_fixture(user, %{identifier: "123", deployment_id: deployment_group.id})
diff --git a/test/nerves_hub_web/channels/websocket_test.exs b/test/nerves_hub_web/channels/websocket_test.exs
index e0fc00e4f..ada51a6da 100644
--- a/test/nerves_hub_web/channels/websocket_test.exs
+++ b/test/nerves_hub_web/channels/websocket_test.exs
@@ -673,7 +673,7 @@ defmodule NervesHubWeb.WebsocketTest do
"tags" => ["beta"]
}
})
- |> ManagedDeployments.update_deployment_group(%{is_active: true})
+ |> ManagedDeployments.update_deployment_group(%{is_active: true}, user)
deployment_group = Repo.preload(deployment_group, :org)
@@ -702,9 +702,13 @@ defmodule NervesHubWeb.WebsocketTest do
Fixtures.firmware_fixture(org_key, firmware.product, %{version: "0.0.2", dir: tmp_dir})
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- firmware_id: new_firmware.id
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ firmware_id: new_firmware.id
+ },
+ user
+ )
# This is what the orchestrator process will do
Orchestrator.trigger_update(deployment_group)
@@ -776,7 +780,7 @@ defmodule NervesHubWeb.WebsocketTest do
"tags" => ["beta", "beta-edge"]
}
})
- |> ManagedDeployments.update_deployment_group(%{is_active: true})
+ |> ManagedDeployments.update_deployment_group(%{is_active: true}, user)
device =
Fixtures.device_fixture(
@@ -843,7 +847,7 @@ defmodule NervesHubWeb.WebsocketTest do
"tags" => ["beta", "beta-edge"]
}
})
- |> ManagedDeployments.update_deployment_group(%{is_active: true})
+ |> ManagedDeployments.update_deployment_group(%{is_active: true}, user)
device =
Fixtures.device_fixture(
@@ -909,7 +913,7 @@ defmodule NervesHubWeb.WebsocketTest do
"tags" => ["beta", "beta-edge"]
}
})
- |> ManagedDeployments.update_deployment_group(%{is_active: true})
+ |> ManagedDeployments.update_deployment_group(%{is_active: true}, user)
device =
Fixtures.device_fixture(
@@ -1141,7 +1145,7 @@ defmodule NervesHubWeb.WebsocketTest do
"tags" => ["beta"]
}
})
- |> ManagedDeployments.update_deployment_group(%{is_active: true, archive_id: archive.id})
+ |> ManagedDeployments.update_deployment_group(%{is_active: true, archive_id: archive.id}, user)
device =
Fixtures.device_fixture(
@@ -1194,7 +1198,7 @@ defmodule NervesHubWeb.WebsocketTest do
"tags" => ["beta"]
}
})
- |> ManagedDeployments.update_deployment_group(%{is_active: true, archive_id: archive.id})
+ |> ManagedDeployments.update_deployment_group(%{is_active: true, archive_id: archive.id}, user)
device =
Fixtures.device_fixture(
@@ -1251,7 +1255,7 @@ defmodule NervesHubWeb.WebsocketTest do
"tags" => ["beta"]
}
})
- |> ManagedDeployments.update_deployment_group(%{is_active: true})
+ |> ManagedDeployments.update_deployment_group(%{is_active: true}, user)
device =
Fixtures.device_fixture(
@@ -1278,7 +1282,7 @@ defmodule NervesHubWeb.WebsocketTest do
assert_online_and_available(device)
{:ok, _deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{archive_id: archive.id})
+ ManagedDeployments.update_deployment_group(deployment_group, %{archive_id: archive.id}, user)
archive = SocketClient.wait_archive(socket)
assert %{"url" => _, "version" => _} = archive
diff --git a/test/nerves_hub_web/live/devices/show_test.exs b/test/nerves_hub_web/live/devices/show_test.exs
index 7f45b6e0e..40a4c71d6 100644
--- a/test/nerves_hub_web/live/devices/show_test.exs
+++ b/test/nerves_hub_web/live/devices/show_test.exs
@@ -100,7 +100,7 @@ defmodule NervesHubWeb.Live.Devices.ShowTest do
deployment_group: deployment_group
} do
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true})
+ ManagedDeployments.update_deployment_group(deployment_group, %{is_active: true}, fixture.user)
# Set device status to :provisioned for deployment group eligibility
%{status: :provisioned} = device = Devices.set_as_provisioned!(device)
diff --git a/test/nerves_hub_web/live/new_ui/deployment_groups/show_test.exs b/test/nerves_hub_web/live/new_ui/deployment_groups/show_test.exs
index c09890d40..0f1a733b7 100644
--- a/test/nerves_hub_web/live/new_ui/deployment_groups/show_test.exs
+++ b/test/nerves_hub_web/live/new_ui/deployment_groups/show_test.exs
@@ -46,14 +46,14 @@ defmodule NervesHubWeb.Live.NewUI.DeploymentGroups.ShowTest do
context.conn
|> visit("/org/#{org.name}/#{product.name}/deployment_groups/#{deployment_group.name}")
- [
+ %{
conn: conn,
device: device,
deployment_group: deployment_group,
source_firmware: source_firmware,
target_firmware: target_firmware,
source_firmware_metadata: source_firmware_metadata
- ]
+ }
end
test "empty state and displaying update stats", %{
@@ -114,7 +114,8 @@ defmodule NervesHubWeb.Live.NewUI.DeploymentGroups.ShowTest do
org_key: org_key,
product: product,
deployment_group: deployment_group,
- tmp_dir: tmp_dir
+ tmp_dir: tmp_dir,
+ user: user
} do
:ok = UpdateStats.log_update(device, source_firmware_metadata)
@@ -124,9 +125,13 @@ defmodule NervesHubWeb.Live.NewUI.DeploymentGroups.ShowTest do
{:ok, other_firmware_metadata} = Firmwares.metadata_from_firmware(other_firmware)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{
- firmware_id: other_firmware.id
- })
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{
+ firmware_id: other_firmware.id
+ },
+ user
+ )
# deployment group needs to be explicitly passed in because association
# is already preloaded from fixtures, causing the preload in log_update/2
diff --git a/test/support/fixtures.ex b/test/support/fixtures.ex
index 986001eae..71ed6abd9 100644
--- a/test/support/fixtures.ex
+++ b/test/support/fixtures.ex
@@ -224,15 +224,20 @@ defmodule NervesHub.Fixtures do
def deployment_group_fixture(%Firmwares.Firmware{} = firmware, params \\ %{}) do
{is_active, params} = Map.pop(params, :is_active, false)
+ user = Map.get_lazy(params, :user, &user_fixture/0)
{:ok, deployment_group} =
params
|> Map.put(:firmware_id, firmware.id)
|> Enum.into(@deployment_group_params)
- |> ManagedDeployments.create_deployment_group(%Product{id: firmware.product_id})
+ |> ManagedDeployments.create_deployment_group(%Product{id: firmware.product_id}, user)
{:ok, deployment_group} =
- ManagedDeployments.update_deployment_group(deployment_group, %{is_active: is_active})
+ ManagedDeployments.update_deployment_group(
+ deployment_group,
+ %{is_active: is_active},
+ user
+ )
deployment_group
end