3.7 KiB · text 5af55d9
defmodule Mix.Tasks.Gitgud.Runner.Create do
@shortdoc "Offline-mint a runner: prints the server.connections snippet for config.yml."
@moduledoc """
mix gitgud.runner.create --scope SCOPE --name NAME [--labels A,B,C]
Modern (v6+) `forgejo-runner` no longer calls `RunnerService/Register`;
the operator mints the runner server-side and pastes a YAML snippet
into `config.yml`'s `server.connections.<name>` block. This task is
the server-side mint.
`SCOPE`:
* `global` — admin-only, picks up jobs from anywhere
* `<org_handle>` — org-scoped
* `<owner>/<repo>` — repo-scoped
`LABELS` is a comma-separated list (default: `ubuntu-latest`).
## Examples
mix gitgud.runner.create --scope acme --name builder-1
mix gitgud.runner.create --scope acme/web --name fast --labels ubuntu-latest,docker
mix gitgud.runner.create --scope global --name house
Prints the YAML snippet ready to paste under `server.connections.gitgud`
in the runner's `config.yml`. The hex token is shown once — record it.
"""
use Mix.Task
@switches [scope: :string, name: :string, labels: :string]
@impl Mix.Task
def run(argv) do
{opts, _, _} = OptionParser.parse(argv, switches: @switches)
Mix.Task.run("app.start")
name = opts[:name] || Mix.raise("--name is required")
scope_str = opts[:scope] || Mix.raise("--scope is required")
labels =
(opts[:labels] || "ubuntu-latest")
|> String.split(",", trim: true)
|> Enum.map(&String.trim/1)
|> Enum.reject(&(&1 == ""))
|> case do
[] -> ["ubuntu-latest"]
list -> list
end
scope = resolve_scope(scope_str)
case GitGud.Workflows.Runners.create_offline(
%{name: name, labels: %{"labels" => labels}},
scope
) do
{:ok, _runner, uuid, hex_token} ->
url = GitGudWeb.Endpoint.url()
config =
GitGud.Workflows.Runners.config_yaml(%{
url: url,
uuid: uuid,
token: hex_token,
labels: labels
})
Mix.shell().info("""
── Runner minted ──────────────────────────────────────────────
Save the following as your runner's `config.yml` (preconfigured
to run jobs in rootless Podman):
#{config}
Then start the daemon:
forgejo-runner daemon --config config.yml
Notes
* The token is shown once. If you lose it, mint a new runner
and delete this one from the settings UI.
* The runner identifies itself with the UUID above; rotating
tokens means re-minting (the server has no way to update
an existing runner's secret).
* Podman: bring up the socket first —
`systemctl --user enable --now podman.socket` — and set the
UID in `container.docker_host` to your `id -u`.
""")
{:error, cs} ->
Mix.shell().error("""
Failed to mint runner: #{inspect(cs.errors)}
""")
System.halt(1)
end
end
defp resolve_scope("global"), do: :global
defp resolve_scope(scope) do
case String.split(scope, "/", parts: 2) do
[owner, name] ->
try do
GitGud.Repositories.get_repository_by_path!(owner, name)
rescue
Ecto.NoResultsError ->
Mix.raise("repo not found: #{scope}")
end
[handle] ->
try do
GitGud.Organizations.get_organization_by_handle!(handle)
rescue
Ecto.NoResultsError ->
Mix.raise("org not found: #{handle}")
end
end
end
end