Deployment and lifecycle management for Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

server: init deployments

+235 -6
+2 -2
cmd/client/services.go
··· 18 18 var nixpkgsref = "refs/heads/nixos-unstable" 19 19 20 20 type ServicesManifest struct { 21 - Paths []string `json:"paths"` 21 + Inputs []client.StorePath `json:"inputs"` 22 22 } 23 23 24 24 // https://github.com/NixOS/nixpkgs/archive/refs/heads/master.zip ··· 52 52 return "", fmt.Errorf("failed to copy path %s to profile %s: %v", path.Path, profileDir, err) 53 53 } 54 54 55 - manifest.Paths = append(manifest.Paths, path.Path) 55 + manifest.Inputs = append(manifest.Inputs, path) 56 56 } 57 57 58 58 data, err := json.MarshalIndent(manifest, "", " ")
+106
lib/sower/distribution.ex
··· 1 + defmodule Sower.Distribution do 2 + @moduledoc """ 3 + The Distribution context. 4 + """ 5 + 6 + import Ecto.Query, warn: false 7 + alias Sower.Repo 8 + 9 + alias Sower.Distribution.Deployment 10 + 11 + @doc """ 12 + Returns the list of deployments. 13 + 14 + ## Examples 15 + 16 + iex> list_deployments() 17 + [%Deployment{}, ...] 18 + 19 + """ 20 + def list_deployments do 21 + Repo.all(Deployment) 22 + end 23 + 24 + @doc """ 25 + Gets a single deployment. 26 + 27 + Raises `Ecto.NoResultsError` if the Deployment does not exist. 28 + 29 + ## Examples 30 + 31 + iex> get_deployment!(123) 32 + %Deployment{} 33 + 34 + iex> get_deployment!(456) 35 + ** (Ecto.NoResultsError) 36 + 37 + """ 38 + def get_deployment!(id), do: Repo.get!(Deployment, id) 39 + 40 + @doc """ 41 + Creates a deployment. 42 + 43 + ## Examples 44 + 45 + iex> create_deployment(%{field: value}) 46 + {:ok, %Deployment{}} 47 + 48 + iex> create_deployment(%{field: bad_value}) 49 + {:error, %Ecto.Changeset{}} 50 + 51 + """ 52 + def create_deployment(attrs \\ %{}) do 53 + %Deployment{ 54 + org_id: Sower.Repo.get_org_id() 55 + } 56 + |> Deployment.changeset(attrs) 57 + |> Repo.insert() 58 + end 59 + 60 + @doc """ 61 + Updates a deployment. 62 + 63 + ## Examples 64 + 65 + iex> update_deployment(deployment, %{field: new_value}) 66 + {:ok, %Deployment{}} 67 + 68 + iex> update_deployment(deployment, %{field: bad_value}) 69 + {:error, %Ecto.Changeset{}} 70 + 71 + """ 72 + def update_deployment(%Deployment{} = deployment, attrs) do 73 + deployment 74 + |> Deployment.changeset(attrs) 75 + |> Repo.update() 76 + end 77 + 78 + @doc """ 79 + Deletes a deployment. 80 + 81 + ## Examples 82 + 83 + iex> delete_deployment(deployment) 84 + {:ok, %Deployment{}} 85 + 86 + iex> delete_deployment(deployment) 87 + {:error, %Ecto.Changeset{}} 88 + 89 + """ 90 + def delete_deployment(%Deployment{} = deployment) do 91 + Repo.delete(deployment) 92 + end 93 + 94 + @doc """ 95 + Returns an `%Ecto.Changeset{}` for tracking deployment changes. 96 + 97 + ## Examples 98 + 99 + iex> change_deployment(deployment) 100 + %Ecto.Changeset{data: %Deployment{}} 101 + 102 + """ 103 + def change_deployment(%Deployment{} = deployment, attrs \\ %{}) do 104 + Deployment.changeset(deployment, attrs) 105 + end 106 + end
+28
lib/sower/distribution/deployment.ex
··· 1 + defmodule Sower.Distribution.Deployment do 2 + use Sower.Schema 3 + import Ecto.Changeset 4 + 5 + alias Sower.Distribution 6 + 7 + @derive {Jason.Encoder, only: [:sid]} 8 + @derive {Phoenix.Param, key: :sid} 9 + 10 + schema "deployments" do 11 + field :sid, Sower.Schema.Sid, autogenerate: true 12 + field :org_id, Ecto.UUID 13 + 14 + many_to_many :seeds, Sower.Seed, join_through: Distribution.SeedDeployment 15 + many_to_many :store_paths, Sower.Nix.StorePath, join_through: Distribution.StorePathDeployment 16 + 17 + field :deployed_at, :utc_datetime 18 + 19 + timestamps() 20 + end 21 + 22 + @doc false 23 + def changeset(deployment, attrs) do 24 + deployment 25 + |> cast(attrs, []) 26 + |> validate_required([]) 27 + end 28 + end
+19
lib/sower/distribution/seed_deployment.ex
··· 1 + defmodule Sower.Distribution.SeedDeployment do 2 + use Sower.Schema 3 + import Ecto.Changeset 4 + 5 + schema "seeds_deployments" do 6 + field :seed_id, :id 7 + field :deployment_id, :id 8 + field :org_id, Ecto.UUID 9 + 10 + timestamps() 11 + end 12 + 13 + @doc false 14 + def changeset(seed_deployment, attrs) do 15 + seed_deployment 16 + |> cast(attrs, []) 17 + |> validate_required([]) 18 + end 19 + end
+19
lib/sower/distribution/store_path_deployment.ex
··· 1 + defmodule Sower.Distribution.StorePathDeployment do 2 + use Sower.Schema 3 + import Ecto.Changeset 4 + 5 + schema "store_paths_deployments" do 6 + field :store_path_id, :id 7 + field :deployment_id, :id 8 + field :org_id, Ecto.UUID 9 + 10 + timestamps() 11 + end 12 + 13 + @doc false 14 + def changeset(store_path_deployment, attrs) do 15 + store_path_deployment 16 + |> cast(attrs, []) 17 + |> validate_required([]) 18 + end 19 + end
+3
lib/sower/nix/store_path.ex
··· 14 14 15 15 many_to_many :seeds, Sower.Seed, join_through: Sower.SeedStorePath 16 16 17 + many_to_many :deployments, Sower.Distribution.Deployment, 18 + join_through: Sower.Distribution.StorePathDeployment 19 + 17 20 timestamps() 18 21 end 19 22
+3 -3
lib/sower/repo.ex
··· 7 7 8 8 @tenant_key {__MODULE__, :org_id} 9 9 10 - @impl true 10 + @impl Ecto.Repo 11 11 def init(_context, config) do 12 12 {:ok, Keyword.merge(config, Application.get_env(:sower, :database, []))} 13 13 end ··· 15 15 @doc """ 16 16 Enable foreign key multitenancy and require :org_id unless :skip_org_id is passed 17 17 """ 18 - @impl true 18 + @impl Ecto.Repo 19 19 def prepare_query(_operation, query, opts) do 20 20 cond do 21 21 opts[:skip_org_id] || opts[:ecto_query] in [:schema_migration, :preload] || ··· 41 41 @doc """ 42 42 Read the org id by default on operations 43 43 """ 44 - @impl true 44 + @impl Ecto.Repo 45 45 def default_options(_operation) do 46 46 [org_id: get_org_id()] 47 47 end
+2 -1
lib/sower/seed.ex
··· 4 4 import Ecto.Changeset 5 5 import Ecto.Query, only: [from: 2] 6 6 7 - alias Sower.{Nix, Repo, Seed, SeedStorePath} 7 + alias Sower.{Distribution, Nix, Repo, Seed, SeedStorePath} 8 8 9 9 @derive {Jason.Encoder, only: [:sid, :name, :seed_type]} 10 10 ··· 19 19 field :org_id, Ecto.UUID 20 20 21 21 many_to_many :store_paths, Nix.StorePath, join_through: Sower.SeedStorePath 22 + many_to_many :deployments, Distribution.Deployments, join_through: Distribution.SeedDeployment 22 23 23 24 timestamps() 24 25 end
+17
priv/repo/migrations/20250531133248_create_deployments.exs
··· 1 + defmodule Sower.Repo.Migrations.CreateDeployments do 2 + use Ecto.Migration 3 + 4 + def change do 5 + create table(:deployments) do 6 + add :sid, :string, null: false 7 + add :org_id, references(:organizations, column: :org_id, type: :uuid), null: false 8 + 9 + add :deployed_at, :utc_datetime 10 + 11 + timestamps() 12 + end 13 + 14 + create index(:deployments, [:org_id]) 15 + create unique_index(:deployments, :sid) 16 + end 17 + end
+18
priv/repo/migrations/20250531134025_create_seeds_deployments.exs
··· 1 + defmodule Sower.Repo.Migrations.CreateSeedsDeployments do 2 + use Ecto.Migration 3 + 4 + def change do 5 + create table(:seeds_deployments) do 6 + add :seed_id, references(:seeds, on_delete: :nothing) 7 + add :deployment_id, references(:deployments, on_delete: :nothing) 8 + add :org_id, references(:organizations, column: :org_id, type: :uuid), null: false 9 + 10 + timestamps() 11 + end 12 + 13 + create index(:seeds_deployments, [:seed_id]) 14 + create index(:seeds_deployments, [:deployment_id]) 15 + create index(:seeds_deployments, [:org_id]) 16 + create unique_index(:seeds_deployments, [:seed_id, :deployment_id]) 17 + end 18 + end
+18
priv/repo/migrations/20250531134253_create_store_paths_deployments.exs
··· 1 + defmodule Sower.Repo.Migrations.CreateStorePathsDeployments do 2 + use Ecto.Migration 3 + 4 + def change do 5 + create table(:store_paths_deployments) do 6 + add :store_path_id, references(:store_paths, on_delete: :nothing), null: false 7 + add :deployment_id, references(:deployments, on_delete: :nothing), null: false 8 + add :org_id, references(:organizations, column: :org_id, type: :uuid), null: false 9 + 10 + timestamps() 11 + end 12 + 13 + create index(:store_paths_deployments, [:store_path_id]) 14 + create index(:store_paths_deployments, [:deployment_id]) 15 + create index(:store_paths_deployments, [:org_id]) 16 + create unique_index(:store_paths_deployments, [:store_path_id, :deployment_id]) 17 + end 18 + end