api: default_branch on repo create (DB + HEAD) + delete endpoint
10b7f9d · gmorell · 2026-06-25 23:05
Message
{commit_body(@commit)}
Files changed
modified
lib/git_gud/repositories.ex
+18
−0
@@ -568,6 +568,11 @@ defmodule GitGud.Repositories do
| 568 | 568 | {:ok, repo} -> |
| 569 | 569 | case init_function(fk).(disk_path) do |
| 570 | 570 | :ok -> |
| 571 | + # A freshly `git init`'d bare repo HEADs at `main`; point it | |
| 572 | + # at the repo's actual default branch so the first push of | |
| 573 | + # that branch isn't orphaned (UI/clone follow HEAD). Skip | |
| 574 | + # for clones/forks — they inherit the source HEAD. | |
| 575 | + if init_empty?(fk), do: set_default_head(disk_path, repo.default_branch) | |
| 571 | 576 | install_hooks(disk_path) |
| 572 | 577 | configure_git(disk_path) |
| 573 | 578 | repo |
@@ -582,6 +587,19 @@ defmodule GitGud.Repositories do
| 582 | 587 | end) |
| 583 | 588 | end |
| 584 | 589 | |
| 590 | + defp init_empty?(fk), | |
| 591 | + do: not Map.has_key?(fk, :clone_from) and not Map.has_key?(fk, :clone_from_url) | |
| 592 | + | |
| 593 | + defp set_default_head(_path, nil), do: :ok | |
| 594 | + | |
| 595 | + defp set_default_head(path, branch) when is_binary(branch) do | |
| 596 | + System.cmd("git", ["-C", path, "symbolic-ref", "HEAD", "refs/heads/" <> branch], | |
| 597 | + stderr_to_stdout: true | |
| 598 | + ) | |
| 599 | + | |
| 600 | + :ok | |
| 601 | + end | |
| 602 | + | |
| 585 | 603 | defp init_function(%{clone_from_url: url}) when is_binary(url) do |
| 586 | 604 | fn dest -> clone_mirror(url, dest) end |
| 587 | 605 | end |
modified
lib/git_gud_web/controllers/api/v1/org_controller.ex
+21
−0
@@ -27,6 +27,7 @@ defmodule GitGudWeb.Api.V1.OrgController do
| 27 | 27 | "name" => params["name"], |
| 28 | 28 | "description" => params["description"], |
| 29 | 29 | "visibility" => params["visibility"] || "private", |
| 30 | + "default_branch" => params["default_branch"], | |
| 30 | 31 | "clone_addr" => params["clone_addr"] |
| 31 | 32 | } |
| 32 | 33 |
@@ -52,6 +53,26 @@ defmodule GitGudWeb.Api.V1.OrgController do
| 52 | 53 | end |
| 53 | 54 | end |
| 54 | 55 | |
| 56 | + def delete_repo(conn, %{"org" => handle, "name" => name}) do | |
| 57 | + with {:ok, user} <- authenticate(conn, "repo"), | |
| 58 | + %_{} = org <- Organizations.get_organization_by_handle(handle), | |
| 59 | + %_{} = repo <- get_repo(handle, name), | |
| 60 | + true <- Organizations.org_admin?(org, user) do | |
| 61 | + _ = Repositories.delete_repository(repo) | |
| 62 | + send_resp(conn, 204, "") | |
| 63 | + else | |
| 64 | + :error -> send_error(conn, 401, "invalid token or missing 'repo' scope") | |
| 65 | + false -> send_error(conn, 403, "must be an admin of #{handle}") | |
| 66 | + nil -> send_error(conn, 404, "organization or repository not found") | |
| 67 | + end | |
| 68 | + end | |
| 69 | + | |
| 70 | + defp get_repo(handle, name) do | |
| 71 | + Repositories.get_repository_by_path!(handle, name) | |
| 72 | + rescue | |
| 73 | + Ecto.NoResultsError -> nil | |
| 74 | + end | |
| 75 | + | |
| 55 | 76 | defp authenticate(conn, scope) do |
| 56 | 77 | with token when is_binary(token) <- bearer(conn), |
| 57 | 78 | {:ok, user, scopes} <- Accounts.verify_personal_access_token(token), |
modified
lib/git_gud_web/router.ex
+1
−0
@@ -235,6 +235,7 @@ defmodule GitGudWeb.Router do
| 235 | 235 | |
| 236 | 236 | # Write endpoints — Personal Access Token auth (handled in-controller). |
| 237 | 237 | post "/orgs/:org/repos", OrgController, :create_repo |
| 238 | + delete "/orgs/:org/repos/:name", OrgController, :delete_repo | |
| 238 | 239 | end |
| 239 | 240 | |
| 240 | 241 | # Enable LiveDashboard and Swoosh mailbox preview in development |
Parents: aa56cab