Credo: deep nesting out, into named private functions

591e34a · Gabe Morell · 2026-11-04 20:41

28 files +341 -324
Message
{commit_body(@commit)}

Files changed

modified lib/git_gud/accounts/user.ex
+11 −22
@@ -119,28 +119,17 @@ defmodule GitGud.Accounts.User do
119 119 # email local-part. Collisions are caught by the unique constraint;
120 120 # callers can retry with a suffix.
121 121 defp maybe_seed_handle(changeset) do
122 − case get_field(changeset, :handle) do
123 − nil ->
124 − email = get_field(changeset, :email)
125 −
126 − if is_binary(email) do
127 − base = email |> String.split("@") |> hd() |> String.downcase()
128 −
129 − if String.match?(base, @handle_format) do
130 − # The CI account's handle is the forge's even before that
131 − # account exists: someone registering as gg-security@… is
132 − # gg-security_1, as for a handle already taken.
133 − base = if base == GitGud.Accounts.ci_handle(), do: base <> "_1", else: base
134 − put_change(changeset, :handle, base)
135 − else
136 − changeset
137 − end
138 − else
139 − changeset
140 − end
141 −
142 − _existing ->
143 − changeset
122 + with nil <- get_field(changeset, :handle),
123 + email when is_binary(email) <- get_field(changeset, :email),
124 + base = email |> String.split("@") |> hd() |> String.downcase(),
125 + true <- String.match?(base, @handle_format) do
126 + # The CI account's handle is the forge's even before that
127 + # account exists: someone registering as gg-security@… is
128 + # gg-security_1, as for a handle already taken.
129 + base = if base == GitGud.Accounts.ci_handle(), do: base <> "_1", else: base
130 + put_change(changeset, :handle, base)
131 + else
132 + _ -> changeset
144 133 end
145 134 end
146 135
modified lib/git_gud/audit.ex
+44 −48
@@ -118,23 +118,7 @@ defmodule GitGud.Audit do
118 118 end
119 119
120 120 result =
121 − Repo.transact(fn ->
122 − case Keyword.get(opts, :record, :after) do
123 − :before ->
124 − entries = insert_all!.(:before)
125 − wrap(fun.(), entries)
126 −
127 − :after ->
128 − case fun.() do
129 − ok when ok == :ok or (is_tuple(ok) and elem(ok, 0) == :ok) ->
130 − value = if ok == :ok, do: :ok, else: elem(ok, 1)
131 − {:ok, {ok, insert_all!.(value)}}
132 −
133 − other ->
134 − {:error, {:returned, other}}
135 − end
136 − end
137 − end)
121 + Repo.transact(fn -> run_recorded(Keyword.get(opts, :record, :after), fun, insert_all!) end)
138 122
139 123 case result do
140 124 {:ok, {original, entries}} ->
@@ -146,6 +130,22 @@ defmodule GitGud.Audit do
146 130 end
147 131 end
148 132
133 + defp run_recorded(:before, fun, insert_all!) do
134 + entries = insert_all!.(:before)
135 + wrap(fun.(), entries)
136 + end
137 +
138 + defp run_recorded(:after, fun, insert_all!) do
139 + case fun.() do
140 + ok when ok == :ok or (is_tuple(ok) and elem(ok, 0) == :ok) ->
141 + value = if ok == :ok, do: :ok, else: elem(ok, 1)
142 + {:ok, {ok, insert_all!.(value)}}
143 +
144 + other ->
145 + {:error, {:returned, other}}
146 + end
147 + end
148 +
149 149 defp wrap(result, entries) do
150 150 if result == :ok or (is_tuple(result) and elem(result, 0) == :ok),
151 151 do: {:ok, {result, entries}},
@@ -386,47 +386,43 @@ defmodule GitGud.Audit do
386 386 |> scoped(scope)
387 387 |> filtered(filters)
388 388
389 − {rows, more?} =
390 − case cursor do
391 − {:after, id} ->
392 − rows =
393 − from(e in base, where: e.id > ^id, order_by: [asc: e.id], limit: ^(limit + 1))
394 − |> Repo.all()
389 + {rows, more?} = fetch_page(base, cursor, limit)
390 + rows = Repo.preload(rows, [:actor])
395 391
396 − {Enum.reverse(Enum.take(rows, limit)), length(rows) > limit}
392 + {rows, page_cursors(cursor, rows, more?)}
393 + end
397 394
398 − before ->
399 − query = from(e in base, order_by: [desc: e.id], limit: ^(limit + 1))
395 + defp fetch_page(base, {:after, id}, limit) do
396 + rows =
397 + from(e in base, where: e.id > ^id, order_by: [asc: e.id], limit: ^(limit + 1))
398 + |> Repo.all()
400 399
401 − query =
402 − case before do
403 − {:before, id} -> from(e in query, where: e.id < ^id)
404 − _ -> query
405 − end
400 + {Enum.reverse(Enum.take(rows, limit)), length(rows) > limit}
401 + end
406 402
407 − rows = Repo.all(query)
408 − {Enum.take(rows, limit), length(rows) > limit}
409 − end
403 + defp fetch_page(base, before, limit) do
404 + query = from(e in base, order_by: [desc: e.id], limit: ^(limit + 1))
410 405
411 − rows = Repo.preload(rows, [:actor])
406 + query =
407 + case before do
408 + {:before, id} -> from(e in query, where: e.id < ^id)
409 + _ -> query
410 + end
412 411
413 − cursors =
414 − case {cursor, rows} do
415 − {_, []} ->
416 − %{older: nil, newer: nil}
412 + rows = Repo.all(query)
413 + {Enum.take(rows, limit), length(rows) > limit}
414 + end
417 415
418 − {{:after, _}, rows} ->
419 − %{older: List.last(rows).id, newer: if(more?, do: hd(rows).id)}
416 + defp page_cursors(_cursor, [], _more?), do: %{older: nil, newer: nil}
420 417
421 − {{:before, _}, rows} ->
422 − %{older: if(more?, do: List.last(rows).id), newer: hd(rows).id}
418 + defp page_cursors({:after, _}, rows, more?),
419 + do: %{older: List.last(rows).id, newer: if(more?, do: hd(rows).id)}
423 420
424 − {nil, rows} ->
425 − %{older: if(more?, do: List.last(rows).id), newer: nil}
426 − end
421 + defp page_cursors({:before, _}, rows, more?),
422 + do: %{older: if(more?, do: List.last(rows).id), newer: hd(rows).id}
427 423
428 − {rows, cursors}
429 − end
424 + defp page_cursors(nil, rows, more?),
425 + do: %{older: if(more?, do: List.last(rows).id), newer: nil}
430 426
431 427 @doc """
432 428 The names of `org`'s repositories that are gone but still have
modified lib/git_gud/git/cli.ex
+15 −20
@@ -134,26 +134,21 @@ defmodule GitGud.Git.Cli do
134 134 defp fold_name_only(out, dir, wanted) do
135 135 out
136 136 |> String.split(<<1>>, trim: true)
137 − |> Enum.reduce(%{}, fn block, acc ->
138 − case String.split(block, "\n") do
139 − [header | files] ->
140 − case String.split(header, <<0>>, parts: 2) do
141 − [sha_hex, iso] ->
142 − touch = %{sha: hex_to_sha_or_nil(sha_hex), committed_at: parse_dt(iso)}
143 −
144 − files
145 − |> Enum.flat_map(&entry_name(&1, dir))
146 − |> Enum.filter(&MapSet.member?(wanted, &1))
147 − |> Enum.reduce(acc, fn name, acc -> Map.put_new(acc, name, touch) end)
148 −
149 − _ ->
150 − acc
151 − end
152 −
153 − _ ->
154 − acc
155 − end
156 − end)
137 + |> Enum.reduce(%{}, &fold_block(&1, &2, dir, wanted))
138 + end
139 +
140 + defp fold_block(block, acc, dir, wanted) do
141 + with [header | files] <- String.split(block, "\n"),
142 + [sha_hex, iso] <- String.split(header, <<0>>, parts: 2) do
143 + touch = %{sha: hex_to_sha_or_nil(sha_hex), committed_at: parse_dt(iso)}
144 +
145 + files
146 + |> Enum.flat_map(&entry_name(&1, dir))
147 + |> Enum.filter(&MapSet.member?(wanted, &1))
148 + |> Enum.reduce(acc, fn name, acc -> Map.put_new(acc, name, touch) end)
149 + else
150 + _ -> acc
151 + end
157 152 end
158 153
159 154 # `--name-only` reports full paths from the repo root; the listing
modified lib/git_gud/imports.ex
+12 −9
@@ -108,15 +108,7 @@ defmodule GitGud.Imports do
108 108 Repo.transaction(fn ->
109 109 import_row = Repo.insert!(base)
110 110
111 − items =
112 − repos
113 − |> Enum.uniq_by(& &1.full_name)
114 − |> Enum.map(fn repo ->
115 − case insert_item(import_row, repo) do
116 − {:ok, item} -> item
117 − {:error, changeset} -> Repo.rollback(changeset)
118 − end
119 − end)
111 + items = insert_items!(import_row, repos)
120 112
121 113 import_row =
122 114 import_row
@@ -143,6 +135,17 @@ defmodule GitGud.Imports do
143 135 end
144 136 end
145 137
138 + defp insert_items!(import_row, repos) do
139 + repos
140 + |> Enum.uniq_by(& &1.full_name)
141 + |> Enum.map(fn repo ->
142 + case insert_item(import_row, repo) do
143 + {:ok, item} -> item
144 + {:error, changeset} -> Repo.rollback(changeset)
145 + end
146 + end)
147 + end
148 +
146 149 defp build_import(%User{} = actor, destination, attrs, token) do
147 150 attrs = stringify(attrs)
148 151 provider = attrs["provider"]
modified lib/git_gud/organizations.ex
+19 −16
@@ -61,22 +61,7 @@ defmodule GitGud.Organizations do
61 61 |> Organization.visibility_changeset(%{visibility: new_visibility})
62 62 |> Repo.update() do
63 63 {:ok, updated} ->
64 − # Cascade: every repo with a lower visibility rank than the
65 − # org bubbles up to match.
66 − floor = floor_visibility(new_rank)
67 −
68 − if floor do
69 − ranks =
70 − for v <- Organization.valid_visibilities(),
71 − Organization.visibility_rank(v) < new_rank,
72 − do: v
73 −
74 − from(r in GitGud.Repositories.Repository,
75 − where: r.organization_id == ^updated.id and r.visibility in ^ranks
76 − )
77 − |> Repo.update_all(set: [visibility: floor, updated_at: DateTime.utc_now(:second)])
78 − end
79 −
64 + cascade_visibility(updated, new_rank)
80 65 updated
81 66
82 67 {:error, cs} ->
@@ -85,6 +70,24 @@ defmodule GitGud.Organizations do
85 70 end)
86 71 end
87 72
73 + # Cascade: every repo with a lower visibility rank than the org
74 + # bubbles up to match.
75 + defp cascade_visibility(%Organization{} = org, new_rank) do
76 + floor = floor_visibility(new_rank)
77 +
78 + if floor do
79 + ranks =
80 + for v <- Organization.valid_visibilities(),
81 + Organization.visibility_rank(v) < new_rank,
82 + do: v
83 +
84 + from(r in GitGud.Repositories.Repository,
85 + where: r.organization_id == ^org.id and r.visibility in ^ranks
86 + )
87 + |> Repo.update_all(set: [visibility: floor, updated_at: DateTime.utc_now(:second)])
88 + end
89 + end
90 +
88 91 defp floor_visibility(0), do: nil
89 92 defp floor_visibility(1), do: "internal"
90 93 defp floor_visibility(2), do: "private"
modified lib/git_gud/packages/formats/fdroid/arsc.ex
+14 −10

Click to load diff…

modified lib/git_gud/pull_requests.ex
+18 −14

Click to load diff…

modified lib/git_gud/repositories.ex
+24 −20

Click to load diff…

modified lib/git_gud/repositories/hook_receiver.ex
+15 −11

Click to load diff…

modified lib/git_gud/workflows.ex
+42 −39

Click to load diff…

modified lib/git_gud_web/controllers/api/mobile/pull_request_controller.ex
+16 −12

Click to load diff…

modified lib/git_gud_web/controllers/api/v1/workflow_controller.ex
+27 −18

Click to load diff…

modified lib/git_gud_web/controllers/runner_controller.ex
+67 −70

Click to load diff…

modified lib/git_gud_web/plugs/git_smart_http.ex
+17 −15

Click to load diff…

Parents: 4f41acc