Enable uploadpack allow-SHA1-in-want for CI checkout
e60ba65 · gmorell · 2026-06-25 15:34
Message
{commit_body(@commit)}
Files changed
modified
lib/git_gud/release.ex
+36
−0
@@ -44,6 +44,42 @@ defmodule GitGud.Release do
| 44 | 44 | IO.write(pub_pem) |
| 45 | 45 | end |
| 46 | 46 | |
| 47 | + @doc """ | |
| 48 | + Backfill the per-repo git config that CI clients need — `actions/checkout` | |
| 49 | + (and any `git fetch --depth=1 <sha>`) asks the server to `want` a | |
| 50 | + specific commit SHA, which git refuses ("Server does not allow request | |
| 51 | + for unadvertised object") unless `uploadpack.allow*SHA1InWant` is set. | |
| 52 | + New repos get this at creation; this fixes ones created before it. | |
| 53 | + | |
| 54 | + Run in a deployed pod (no Mix in a release): | |
| 55 | + | |
| 56 | + kubectl -n git-gud exec deployment/git-gud -- \\ | |
| 57 | + bin/git_gud eval 'GitGud.Release.configure_repos()' | |
| 58 | + | |
| 59 | + Idempotent. | |
| 60 | + """ | |
| 61 | + def configure_repos do | |
| 62 | + load_app() | |
| 63 | + | |
| 64 | + {:ok, {ok, skipped}, _} = | |
| 65 | + Ecto.Migrator.with_repo(GitGud.Repo, fn _repo -> | |
| 66 | + import Ecto.Query, warn: false | |
| 67 | + | |
| 68 | + GitGud.Repo.all(from(r in GitGud.Repositories.Repository, select: r.disk_path)) | |
| 69 | + |> Enum.reduce({0, 0}, fn disk_path, {ok, skipped} -> | |
| 70 | + if is_binary(disk_path) and File.dir?(disk_path) do | |
| 71 | + GitGud.Repositories.configure_git(disk_path) | |
| 72 | + {ok + 1, skipped} | |
| 73 | + else | |
| 74 | + {ok, skipped + 1} | |
| 75 | + end | |
| 76 | + end) | |
| 77 | + end) | |
| 78 | + | |
| 79 | + IO.puts("configured #{ok} repo(s); #{skipped} skipped (missing disk_path/dir)") | |
| 80 | + :ok | |
| 81 | + end | |
| 82 | + | |
| 47 | 83 | defp repos do |
| 48 | 84 | Application.fetch_env!(@app, :ecto_repos) |
| 49 | 85 | end |
modified
lib/git_gud/repositories.ex
+24
−0
@@ -558,6 +558,7 @@ defmodule GitGud.Repositories do
| 558 | 558 | case init_function(fk).(disk_path) do |
| 559 | 559 | :ok -> |
| 560 | 560 | install_hooks(disk_path) |
| 561 | + configure_git(disk_path) | |
| 561 | 562 | repo |
| 562 | 563 | |
| 563 | 564 | {:error, reason} -> |
@@ -857,6 +858,29 @@ defmodule GitGud.Repositories do
| 857 | 858 | install_hook(disk_path, "pre-receive", "gitgud-prereceive") |
| 858 | 859 | end |
| 859 | 860 | |
| 861 | + @doc """ | |
| 862 | + Per-repo git config required for CI. `actions/checkout` (and any | |
| 863 | + `git fetch --depth=1 <sha>`) asks the server to `want` a specific | |
| 864 | + commit SHA; vanilla git refuses unadvertised objects with "Server does | |
| 865 | + not allow request for unadvertised object". Enabling | |
| 866 | + `uploadpack.allowReachableSHA1InWant` (+ `allowAnySHA1InWant`) permits | |
| 867 | + it, matching what Gitea/Forgejo set on Actions-enabled repos. | |
| 868 | + | |
| 869 | + Idempotent — safe to call on existing repos (see the | |
| 870 | + `gitgud.repos.configure` mix task for backfilling). | |
| 871 | + """ | |
| 872 | + def configure_git(disk_path) do | |
| 873 | + for {k, v} <- [ | |
| 874 | + {"uploadpack.allowAnySHA1InWant", "true"}, | |
| 875 | + {"uploadpack.allowReachableSHA1InWant", "true"}, | |
| 876 | + {"uploadpack.allowTipSHA1InWant", "true"} | |
| 877 | + ] do | |
| 878 | + System.cmd("git", ["-C", disk_path, "config", k, v], stderr_to_stdout: true) | |
| 879 | + end | |
| 880 | + | |
| 881 | + :ok | |
| 882 | + end | |
| 883 | + | |
| 860 | 884 | defp install_hook(disk_path, name, default_bin) do |
| 861 | 885 | hook_path = Path.join([disk_path, "hooks", name]) |
| 862 | 886 | bridge = script_path(default_bin) |
Parents: 5e67fc0