gitea mirrors
This commit is contained in:
@@ -2,4 +2,4 @@
|
|||||||
# Do not delete.
|
# Do not delete.
|
||||||
|
|
||||||
folderID: nix
|
folderID: nix
|
||||||
created: 2026-01-29T23:06:32-06:00
|
created: 2026-01-29T23:05:44-06:00
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
catppuccin
|
catppuccin
|
||||||
#librewolf
|
#librewolf
|
||||||
nixcord
|
nixcord
|
||||||
organize
|
|
||||||
];
|
];
|
||||||
|
|
||||||
nixos = {
|
nixos = {
|
||||||
|
|||||||
201
modules/services/gitea-mirrors.nix
Normal file
201
modules/services/gitea-mirrors.nix
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
{ den, ... }: {
|
||||||
|
den.aspects.gitea-mirrors = {
|
||||||
|
nixos = { pkgs, lib, config, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.gitea;
|
||||||
|
mcfg = cfg.mirrors;
|
||||||
|
|
||||||
|
uniqueOwners = lib.unique (
|
||||||
|
(map (m: m.owner) mcfg.repos) ++
|
||||||
|
(map (m: m.owner) mcfg.users)
|
||||||
|
);
|
||||||
|
|
||||||
|
giteaUrl = "http://localhost:${toString cfg.settings.server.HTTP_PORT}";
|
||||||
|
tokenFile = "${cfg.stateDir}/mirror-setup-token";
|
||||||
|
|
||||||
|
setupScript = pkgs.writeShellScript "gitea-mirror-setup" ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
GITEA_URL="${giteaUrl}"
|
||||||
|
TOKEN_FILE="${tokenFile}"
|
||||||
|
GITEA_CMD="${lib.getExe cfg.package}"
|
||||||
|
|
||||||
|
# wait for gitea to be ready
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
if ${pkgs.curl}/bin/curl -sf "$GITEA_URL/api/v1/version" >/dev/null 2>&1; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
$GITEA_CMD admin user create \
|
||||||
|
--username "${mcfg.adminUser}" \
|
||||||
|
--email "${mcfg.adminEmail}" \
|
||||||
|
--random-password \
|
||||||
|
--admin \
|
||||||
|
--must-change-password=false 2>/dev/null || true
|
||||||
|
|
||||||
|
if [ ! -f "$TOKEN_FILE" ]; then
|
||||||
|
TOKEN=$($GITEA_CMD admin user generate-access-token \
|
||||||
|
--username "${mcfg.adminUser}" \
|
||||||
|
--token-name "mirror-setup" \
|
||||||
|
--scopes "all" \
|
||||||
|
--raw)
|
||||||
|
echo "$TOKEN" > "$TOKEN_FILE"
|
||||||
|
chmod 600 "$TOKEN_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TOKEN=$(cat "$TOKEN_FILE")
|
||||||
|
AUTH="Authorization: token $TOKEN"
|
||||||
|
|
||||||
|
${lib.concatMapStringsSep "\n" (owner: ''
|
||||||
|
RAND_PASS=$(${pkgs.openssl}/bin/openssl rand -base64 32)
|
||||||
|
${pkgs.curl}/bin/curl -sf -X POST "$GITEA_URL/api/v1/admin/users" \
|
||||||
|
-H "$AUTH" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"username\": \"${owner}\",
|
||||||
|
\"email\": \"${owner}@mirror.localhost\",
|
||||||
|
\"password\": \"$RAND_PASS\",
|
||||||
|
\"must_change_password\": false,
|
||||||
|
\"visibility\": \"public\"
|
||||||
|
}" >/dev/null 2>&1 || true
|
||||||
|
'') uniqueOwners}
|
||||||
|
|
||||||
|
${lib.concatMapStringsSep "\n" (m: ''
|
||||||
|
${pkgs.curl}/bin/curl -sf -X POST "$GITEA_URL/api/v1/repos/migrate" \
|
||||||
|
-H "$AUTH" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"clone_addr": "${m.source}",
|
||||||
|
"repo_name": "${m.repo}",
|
||||||
|
"repo_owner": "${m.owner}",
|
||||||
|
"mirror": true,
|
||||||
|
"private": false,
|
||||||
|
"service": "${m.service or "git"}"
|
||||||
|
}' >/dev/null 2>&1 || true
|
||||||
|
'') mcfg.repos}
|
||||||
|
|
||||||
|
${lib.concatMapStringsSep "\n" (u:
|
||||||
|
let
|
||||||
|
platform = u.platform;
|
||||||
|
owner = u.owner;
|
||||||
|
baseUrl = u.baseUrl or (if platform == "github" then "https://api.github.com"
|
||||||
|
else if platform == "gitlab" then "https://gitlab.com"
|
||||||
|
else if platform == "gitea" then u.baseUrl
|
||||||
|
else throw "mirrors.users: unsupported platform '${platform}', provide baseUrl");
|
||||||
|
cloneBase = if platform == "github" then "https://github.com/${owner}"
|
||||||
|
else if platform == "gitlab" then "${u.baseUrl or "https://gitlab.com"}/${owner}"
|
||||||
|
else if platform == "gitea" then "${u.baseUrl}/${owner}"
|
||||||
|
else throw "mirrors.users: unsupported platform '${platform}'";
|
||||||
|
service = if platform == "github" then "github"
|
||||||
|
else if platform == "gitlab" then "gitlab"
|
||||||
|
else if platform == "gitea" then "gitea"
|
||||||
|
else "git";
|
||||||
|
jqExpr = if platform == "gitlab" then ".[].path" else ".[].name";
|
||||||
|
pageSize = if platform == "gitea" then 50 else 100;
|
||||||
|
pageSizeStr = toString pageSize;
|
||||||
|
listUrl = if platform == "github" then "${baseUrl}/users/${owner}/repos?per_page=${pageSizeStr}&type=owner"
|
||||||
|
else if platform == "gitlab" then "${baseUrl}/api/v4/users/${owner}/projects?per_page=${pageSizeStr}"
|
||||||
|
else "${baseUrl}/api/v1/users/${owner}/repos?limit=${pageSizeStr}";
|
||||||
|
in ''
|
||||||
|
echo "Fetching repos for ${owner} from ${platform}..."
|
||||||
|
PAGE=1
|
||||||
|
while true; do
|
||||||
|
REPOS=$(${pkgs.curl}/bin/curl -sf "${listUrl}&page=$PAGE" || echo "[]")
|
||||||
|
|
||||||
|
NAMES=$(echo "$REPOS" | ${pkgs.jq}/bin/jq -r '${jqExpr}')
|
||||||
|
if [ -z "$NAMES" ] || [ "$NAMES" = "null" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
for REPO_NAME in $NAMES; do
|
||||||
|
${pkgs.curl}/bin/curl -sf -X POST "$GITEA_URL/api/v1/repos/migrate" \
|
||||||
|
-H "$AUTH" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"clone_addr\": \"${cloneBase}/$REPO_NAME.git\",
|
||||||
|
\"repo_name\": \"$REPO_NAME\",
|
||||||
|
\"repo_owner\": \"${owner}\",
|
||||||
|
\"mirror\": true,
|
||||||
|
\"private\": false,
|
||||||
|
\"service\": \"${service}\"
|
||||||
|
}" >/dev/null 2>&1 || true
|
||||||
|
done
|
||||||
|
|
||||||
|
COUNT=$(echo "$REPOS" | ${pkgs.jq}/bin/jq 'length')
|
||||||
|
if [ "$COUNT" -lt ${pageSizeStr} ]; then break; fi
|
||||||
|
PAGE=$((PAGE + 1))
|
||||||
|
done
|
||||||
|
'') mcfg.users}
|
||||||
|
|
||||||
|
echo "Mirror setup complete."
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.gitea.mirrors = {
|
||||||
|
adminUser = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "admin";
|
||||||
|
description = "Gitea admin username for mirror management.";
|
||||||
|
};
|
||||||
|
|
||||||
|
adminEmail = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "admin@localhost";
|
||||||
|
description = "Gitea admin email.";
|
||||||
|
};
|
||||||
|
|
||||||
|
repos = lib.mkOption {
|
||||||
|
type = lib.types.listOf (lib.types.attrsOf lib.types.str);
|
||||||
|
default = [];
|
||||||
|
description = "Individual repositories to mirror. Each entry: { owner, repo, source, service? }.";
|
||||||
|
example = [
|
||||||
|
{ owner = "nixos"; repo = "nixpkgs"; source = "https://github.com/NixOS/nixpkgs.git"; service = "github"; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
users = lib.mkOption {
|
||||||
|
type = lib.types.listOf (lib.types.attrsOf lib.types.str);
|
||||||
|
default = [];
|
||||||
|
description = "Mirror all public repos of a user/org. Each entry: { owner, platform, baseUrl? }.";
|
||||||
|
example = [
|
||||||
|
{ owner = "catppuccin"; platform = "github"; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf (mcfg.repos != [] || mcfg.users != []) {
|
||||||
|
services.gitea.settings.mirror = {
|
||||||
|
DEFAULT_INTERVAL = "6h";
|
||||||
|
MIN_INTERVAL = "10m";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gitea.settings."cron.update_mirrors" = {
|
||||||
|
SCHEDULE = "@every 10m";
|
||||||
|
RUN_AT_START = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.gitea-mirror-setup = {
|
||||||
|
description = "Setup Gitea mirror repositories";
|
||||||
|
after = [ "gitea.service" ];
|
||||||
|
requires = [ "gitea.service" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
User = cfg.user;
|
||||||
|
Group = cfg.group;
|
||||||
|
ExecStart = setupScript;
|
||||||
|
WorkingDirectory = cfg.stateDir;
|
||||||
|
Environment = [
|
||||||
|
"GITEA_WORK_DIR=${cfg.stateDir}"
|
||||||
|
"GITEA_CUSTOM=${cfg.customDir}"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
{
|
{ den, ... }: {
|
||||||
den.aspects.gitea = {
|
den.aspects.gitea = {
|
||||||
|
includes = [ den.aspects.gitea-mirrors ];
|
||||||
|
|
||||||
nixos = {
|
nixos = {
|
||||||
services.gitea = {
|
services.gitea = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -11,6 +13,23 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
settings.server.HTTP_PORT = 3002;
|
settings.server.HTTP_PORT = 3002;
|
||||||
|
|
||||||
|
mirrors = {
|
||||||
|
adminUser = "admin";
|
||||||
|
adminEmail = "admin@bug.tools";
|
||||||
|
|
||||||
|
repos = [
|
||||||
|
{ owner = "gmodena"; repo = "nix-flatpak"; source = "https://github.com/gmodena/nix-flatpak.git"; service = "github"; }
|
||||||
|
{ owner = "FlameFlag"; repo = "nixcord"; source = "https://github.com/FlameFlag/nixcord.git"; service = "github"; }
|
||||||
|
{ owner = "jacob.eva"; repo = "opencom-lte"; source = "https://git.liberatedsystems.co.uk/jacob.eva/opencom-lte.git"; }
|
||||||
|
];
|
||||||
|
|
||||||
|
users = [
|
||||||
|
{ owner = "catppuccin"; platform = "github"; }
|
||||||
|
{ owner = "picosh"; platform = "github"; }
|
||||||
|
{ owner = "vic"; platform = "github"; }
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user