protobuf upgrade

7e63f64 · gmorell · 2026-05-22 16:10

2 files +53 -16

Files changed

modified lib/git_gud_web/controllers/runner_controller.ex
+22 −11
@@ -163,14 +163,23 @@ defmodule GitGudWeb.RunnerController do
163 163 %TaskMsg{
164 164 id: job.id,
165 165 workflow_payload: GitGud.Workflows.RunnerPayload.encode(job),
166 context: build_context(job, run, repo, token),
166 + context: build_context_struct(job, run, repo, token),
167 167 secrets: secrets,
168 needs: job.needs || [],
168 + # Modern proto changed `needs` from `repeated string` to
169 + # `map<string, TaskNeed>`. We don't (yet) carry forward upstream
170 + # job results, so emit an empty map.
171 + needs: %{},
169 172 vars: vars
170 173 }
171 174 end
172 175
173 defp build_context(job, run, repo, token) do
176 + # Forgejo's runner proto switched `Task.context` from
177 + # `map<string,string>` to `google.protobuf.Struct` so values can carry
178 + # nested objects, numbers, and bools. Our context is still all
179 + # strings, but the wire format requires Struct{ fields: %{ key =>
180 + # Value{ kind: {:string_value, v} } } } — `kind` is a oneof, so we
181 + # pass the tuple form `{:string_value, v}`.
182 + defp build_context_struct(job, run, repo, token) do
174 183 base = GitGudWeb.Endpoint.url()
175 184
176 185 %{
@@ -191,6 +200,16 @@ defmodule GitGudWeb.RunnerController do
191 200 "ACTIONS_RUNTIME_TOKEN" => token,
192 201 "ACTIONS_CACHE_URL" => base <> "/api/actions/_apis/artifactcache/"
193 202 }
203 + |> wrap_as_struct()
204 + end
205 +
206 + defp wrap_as_struct(map) when is_map(map) do
207 + %Google.Protobuf.Struct{
208 + fields:
209 + Map.new(map, fn {k, v} ->
210 + {k, %Google.Protobuf.Value{kind: {:string_value, v}}}
211 + end)
212 + }
194 213 end
195 214
196 215 # ── update_task ──────────────────────────────────────────────────────
@@ -326,15 +345,7 @@ defmodule GitGudWeb.RunnerController do
326 345 {:protobuf, echoed_ct} ->
327 346 body = msg.__struct__.encode(msg) |> IO.iodata_to_binary()
328 347
329 require Logger
330
331 Logger.info(
332 "runner-respond struct=#{inspect(msg.__struct__)} body_bytes=#{byte_size(body)} " <>
333 "task_present=#{inspect(match?(%{task: t} when not is_nil(t), msg))}"
334 )
335
336 348 conn
337 |> put_resp_header("x-debug-body-size", Integer.to_string(byte_size(body)))
338 349 |> put_resp_content_type(echoed_ct, nil)
339 350 |> send_resp(200, body)
340 351
modified lib/git_gud_web/protos/runner/v1/messages.pb.ex
+31 −5
@@ -102,11 +102,11 @@ defmodule Runner.V1.DeclareResponse do
102 102 field :runner, 1, type: Runner.V1.Runner
103 103 end
104 104
105 defmodule Runner.V1.Task.ContextEntry do
105 +defmodule Runner.V1.TaskNeed.OutputsEntry do
106 106 @moduledoc false
107 107
108 108 use Protobuf,
109 full_name: "runner.v1.Task.ContextEntry",
109 + full_name: "runner.v1.TaskNeed.OutputsEntry",
110 110 map: true,
111 111 protoc_gen_elixir_version: "0.16.0",
112 112 syntax: :proto3
@@ -115,6 +115,18 @@ defmodule Runner.V1.Task.ContextEntry do
115 115 field :value, 2, type: :string
116 116 end
117 117
118 +defmodule Runner.V1.TaskNeed do
119 + @moduledoc false
120 +
121 + use Protobuf,
122 + full_name: "runner.v1.TaskNeed",
123 + protoc_gen_elixir_version: "0.16.0",
124 + syntax: :proto3
125 +
126 + field :result, 1, type: Runner.V1.Result, enum: true
127 + field :outputs, 2, repeated: true, type: Runner.V1.TaskNeed.OutputsEntry, map: true
128 +end
129 +
118 130 defmodule Runner.V1.Task.SecretsEntry do
119 131 @moduledoc false
120 132
@@ -128,6 +140,19 @@ defmodule Runner.V1.Task.SecretsEntry do
128 140 field :value, 2, type: :string
129 141 end
130 142
143 +defmodule Runner.V1.Task.NeedsEntry do
144 + @moduledoc false
145 +
146 + use Protobuf,
147 + full_name: "runner.v1.Task.NeedsEntry",
148 + map: true,
149 + protoc_gen_elixir_version: "0.16.0",
150 + syntax: :proto3
151 +
152 + field :key, 1, type: :string
153 + field :value, 2, type: Runner.V1.TaskNeed
154 +end
155 +
131 156 defmodule Runner.V1.Task.VarsEntry do
132 157 @moduledoc false
133 158
@@ -148,10 +173,11 @@ defmodule Runner.V1.Task do
148 173
149 174 field :id, 1, type: :int64
150 175 field :workflow_payload, 2, type: :bytes, json_name: "workflowPayload"
151 field :context, 3, repeated: true, type: Runner.V1.Task.ContextEntry, map: true
176 + field :context, 3, type: Google.Protobuf.Struct
152 177 field :secrets, 4, repeated: true, type: Runner.V1.Task.SecretsEntry, map: true
153 field :needs, 5, repeated: true, type: :string
154 field :vars, 6, repeated: true, type: Runner.V1.Task.VarsEntry, map: true
178 + field :machine, 5, type: :string
179 + field :needs, 6, repeated: true, type: Runner.V1.Task.NeedsEntry, map: true
180 + field :vars, 7, repeated: true, type: Runner.V1.Task.VarsEntry, map: true
155 181 end
156 182
157 183 defmodule Runner.V1.FetchTaskRequest do

Parents: 99d66f7