From 38375dcebb64f3c2fbe4ecb8800c4721bbd8987b Mon Sep 17 00:00:00 2001
From: Graham McIntire
Date: Thu, 7 May 2026 07:44:48 -0500
Subject: [PATCH] chore: migrate agent repo references from GitHub to Codeberg
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Updates all docs, UI copy, release checker, proto go_package,
container image refs, and tests to point at
codeberg.org/towerops-agent/towerops-agent. Also deletes stray
empty package.json/package-lock.json (Phoenix uses esbuild — no
npm) and an unused test_encode_decode.exs scratch file.
---
lib/towerops/agents.ex | 2 +-
lib/towerops/agents/release_checker.ex | 19 ++++++-------
.../controllers/page_html/home.html.heex | 2 +-
lib/towerops_web/live/agent_live/index.ex | 7 ++++-
lib/towerops_web/live/help_live/index.ex | 4 +--
.../live/onboarding_live.html.heex | 2 +-
package-lock.json | 6 -----
package.json | 1 -
priv/proto/agent.proto | 2 +-
test/towerops/agents/release_checker_test.exs | 8 +++---
test/towerops/agents_test.exs | 8 +++---
test_encode_decode.exs | 27 -------------------
12 files changed, 31 insertions(+), 57 deletions(-)
delete mode 100644 package-lock.json
delete mode 100644 package.json
delete mode 100644 test_encode_decode.exs
diff --git a/lib/towerops/agents.ex b/lib/towerops/agents.ex
index 701885a6..431da0ec 100644
--- a/lib/towerops/agents.ex
+++ b/lib/towerops/agents.ex
@@ -354,7 +354,7 @@ defmodule Towerops.Agents do
Broadcasts an update command to all connected agents.
1. Invalidates the release cache
- 2. Fetches the latest release from GitHub
+ 2. Fetches the latest release from Codeberg
3. Finds all updatable agents
4. Sends update command to each agent matching their architecture
diff --git a/lib/towerops/agents/release_checker.ex b/lib/towerops/agents/release_checker.ex
index c840ffd5..b10de77a 100644
--- a/lib/towerops/agents/release_checker.ex
+++ b/lib/towerops/agents/release_checker.ex
@@ -1,13 +1,14 @@
defmodule Towerops.Agents.ReleaseChecker do
@moduledoc """
- Fetches latest release info from GitHub Releases API for the towerops-agent repo.
+ Fetches latest release info from the Codeberg (Forgejo) Releases API for the
+ towerops-agent repo.
Caches results for 5 minutes to avoid excessive API calls.
"""
require Logger
- @github_repo "towerops-app/towerops-agent"
+ @codeberg_repo "towerops-agent/towerops-agent"
@cache_ttl_ms to_timeout(minute: 5)
@arch_map %{
@@ -17,7 +18,7 @@ defmodule Towerops.Agents.ReleaseChecker do
@doc """
Clears the cached release info so the next call to `get_latest_release/0`
- fetches fresh data from GitHub.
+ fetches fresh data from Codeberg.
"""
@spec invalidate_cache() :: :ok
def invalidate_cache do
@@ -28,7 +29,7 @@ defmodule Towerops.Agents.ReleaseChecker do
end
@doc """
- Returns the latest release info from GitHub.
+ Returns the latest release info from Codeberg.
Returns `{:ok, %{version: String.t(), assets: [asset]}}` where each asset
has `name`, `url`, and `checksum` fields.
@@ -76,20 +77,20 @@ defmodule Towerops.Agents.ReleaseChecker do
end
defp fetch_and_cache do
- url = "https://api.github.com/repos/#{@github_repo}/releases/latest"
+ url = "https://codeberg.org/api/v1/repos/#{@codeberg_repo}/releases/latest"
- case req_get(url, headers: [{"accept", "application/vnd.github+json"}], retry: false) do
+ case req_get(url, headers: [{"accept", "application/json"}], retry: false) do
{:ok, %Req.Response{status: 200, body: body}} ->
release = parse_release(body)
:persistent_term.put({__MODULE__, :release}, {release, System.monotonic_time(:millisecond)})
{:ok, release}
{:ok, %Req.Response{status: status}} ->
- Logger.warning("GitHub API returned status #{status} for latest release")
- {:error, {:github_api, status}}
+ Logger.warning("Codeberg API returned status #{status} for latest release")
+ {:error, {:codeberg_api, status}}
{:error, reason} ->
- Logger.warning("Failed to fetch latest release from GitHub: #{inspect(reason)}")
+ Logger.warning("Failed to fetch latest release from Codeberg: #{inspect(reason)}")
{:error, reason}
end
end
diff --git a/lib/towerops_web/controllers/page_html/home.html.heex b/lib/towerops_web/controllers/page_html/home.html.heex
index ab1345be..7f7d4a66 100644
--- a/lib/towerops_web/controllers/page_html/home.html.heex
+++ b/lib/towerops_web/controllers/page_html/home.html.heex
@@ -199,7 +199,7 @@
and starts collecting metrics. No firewall changes, no VPN, no open ports.
- $ docker run -d towerops/agent
+ $ docker run -d codeberg.org/towerops-agent/towerops-agent
diff --git a/lib/towerops_web/live/agent_live/index.ex b/lib/towerops_web/live/agent_live/index.ex
index 85013bef..4b9e585f 100644
--- a/lib/towerops_web/live/agent_live/index.ex
+++ b/lib/towerops_web/live/agent_live/index.ex
@@ -51,7 +51,12 @@ defmodule ToweropsWeb.AgentLive.Index do
offline_agents = Stats.get_offline_agents(organization.id)
# Get agent image URL from config or use default
- agent_image = Application.get_env(:towerops, :agent_docker_image, "towerops/agent:latest")
+ agent_image =
+ Application.get_env(
+ :towerops,
+ :agent_docker_image,
+ "codeberg.org/towerops-agent/towerops-agent:latest"
+ )
{:ok,
socket
diff --git a/lib/towerops_web/live/help_live/index.ex b/lib/towerops_web/live/help_live/index.ex
index 91ef47cc..3f226347 100644
--- a/lib/towerops_web/live/help_live/index.ex
+++ b/lib/towerops_web/live/help_live/index.ex
@@ -392,7 +392,7 @@ defmodule ToweropsWeb.HelpLive.Index do
No data collection or sharing.
Our remote agent is
-
+
fully open source
and ONLY collects monitoring jobs from the server and WILL NEVER allow us to access any part of your internal network.
@@ -977,7 +977,7 @@ defmodule ToweropsWeb.HelpLive.Index do
<%= raw(~S[services:
towerops-agent:
- image: ghcr.io/towerops-app/towerops-agent:latest
+ image: codeberg.org/towerops-agent/towerops-agent:latest
container_name: towerops-agent
restart: unless-stopped
environment:
diff --git a/lib/towerops_web/live/onboarding_live.html.heex b/lib/towerops_web/live/onboarding_live.html.heex
index c9bc8340..bbe3d48b 100644
--- a/lib/towerops_web/live/onboarding_live.html.heex
+++ b/lib/towerops_web/live/onboarding_live.html.heex
@@ -345,7 +345,7 @@
-e TOWEROPS_TOKEN=<%= if @agent_token_value, do: @agent_token_value, else: "" %> \
-e TOWEROPS_SERVER=<%= ToweropsWeb.Endpoint.url() %> \
--network host \
- ghcr.io/towerops/agent:latest
+ codeberg.org/towerops-agent/towerops-agent:latest
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 5a81c707..00000000
--- a/package-lock.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "towerops-web",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {}
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index 0967ef42..00000000
--- a/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/priv/proto/agent.proto b/priv/proto/agent.proto
index d5b8574d..c7cb68eb 100644
--- a/priv/proto/agent.proto
+++ b/priv/proto/agent.proto
@@ -2,7 +2,7 @@ syntax = "proto3";
package towerops.agent;
-option go_package = "github.com/towerops-app/towerops-agent/pb";
+option go_package = "codeberg.org/towerops-agent/towerops-agent/pb";
// Configuration received from the API
message AgentConfig {
diff --git a/test/towerops/agents/release_checker_test.exs b/test/towerops/agents/release_checker_test.exs
index ef7e3ef7..9b0b6b4e 100644
--- a/test/towerops/agents/release_checker_test.exs
+++ b/test/towerops/agents/release_checker_test.exs
@@ -14,7 +14,7 @@ defmodule Towerops.Agents.ReleaseCheckerTest do
describe "get_latest_release/0" do
test "returns release info from the configured test stub" do
Req.Test.stub(ReleaseChecker, fn conn ->
- if conn.request_path == "/repos/towerops-app/towerops-agent/releases/latest" do
+ if conn.request_path == "/api/v1/repos/towerops-agent/towerops-agent/releases/latest" do
conn
|> Plug.Conn.put_resp_content_type("application/json")
|> Plug.Conn.send_resp(
@@ -55,7 +55,7 @@ defmodule Towerops.Agents.ReleaseCheckerTest do
Plug.Conn.send_resp(conn, 503, "")
end)
- assert {:error, {:github_api, 503}} = ReleaseChecker.get_latest_release()
+ assert {:error, {:codeberg_api, 503}} = ReleaseChecker.get_latest_release()
end
test "uses cached release info until invalidated" do
@@ -80,8 +80,8 @@ defmodule Towerops.Agents.ReleaseCheckerTest do
assert release.version == "9.9.9"
assert cached_release == release
- assert_receive {:release_request, "/repos/towerops-app/towerops-agent/releases/latest"}
- refute_receive {:release_request, "/repos/towerops-app/towerops-agent/releases/latest"}
+ assert_receive {:release_request, "/api/v1/repos/towerops-agent/towerops-agent/releases/latest"}
+ refute_receive {:release_request, "/api/v1/repos/towerops-agent/towerops-agent/releases/latest"}
end
end
diff --git a/test/towerops/agents_test.exs b/test/towerops/agents_test.exs
index ea7d95ce..7e395f1a 100644
--- a/test/towerops/agents_test.exs
+++ b/test/towerops/agents_test.exs
@@ -1981,7 +1981,9 @@ defmodule Towerops.AgentsTest do
{:ok, agent_token, _token} = Agents.create_agent_token(org.id, "Test Agent")
Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:lifecycle")
- url = "https://github.com/towerops-app/towerops-agent/releases/download/v0.2.0/towerops-agent-linux-amd64"
+ url =
+ "https://codeberg.org/towerops-agent/towerops-agent/releases/download/v0.2.0/towerops-agent-linux-amd64"
+
checksum = "abc123def456"
assert :ok = Agents.update_agent(agent_token.id, url, checksum)
@@ -1991,8 +1993,8 @@ defmodule Towerops.AgentsTest do
end
describe "broadcast_mass_update/0" do
- test "returns error when GitHub API is unavailable" do
- # In test environment, GitHub returns 404 for the private repo
+ test "returns error when Codeberg API is unavailable" do
+ # In test environment, Codeberg returns 404 for the private repo
assert {:error, _reason} = Agents.broadcast_mass_update()
end
end
diff --git a/test_encode_decode.exs b/test_encode_decode.exs
deleted file mode 100644
index 366d7bf7..00000000
--- a/test_encode_decode.exs
+++ /dev/null
@@ -1,27 +0,0 @@
-alias Towerops.Agent.SnmpResult
-
-result = %SnmpResult{
- device_id: "550e8400-e29b-41d4-a716-446655440000",
- job_type: :POLL,
- job_id: "test",
- timestamp: 1_234_567_890,
- oid_values: %{"1.2.3" => "test"}
-}
-
-IO.puts("Original: #{inspect(result)}")
-
-binary = SnmpResult.encode(result)
-IO.puts("Encoded to #{byte_size(binary)} bytes")
-
-case SnmpResult.decode(binary) do
- {:ok, decoded} ->
- IO.puts("Decoded successfully!")
- IO.puts(" device_id: #{decoded.device_id}")
- IO.puts(" job_type: #{inspect(decoded.job_type)}")
- IO.puts(" job_id: #{decoded.job_id}")
- IO.puts(" timestamp: #{decoded.timestamp}")
- IO.puts(" oid_values: #{inspect(decoded.oid_values)}")
-
- {:error, reason} ->
- IO.puts("Decode failed: #{inspect(reason)}")
-end