diff --git a/server-modules/gitea.nix b/server-modules/gitea.nix index 411e82fa..971d0ea1 100644 --- a/server-modules/gitea.nix +++ b/server-modules/gitea.nix @@ -1,5 +1,6 @@ { config, + pkgs, pkgs-unstable, lib, ... @@ -11,6 +12,60 @@ sha256 = "sha256-rZHLORwLUfIFcB6K9yhrzr+UwdPNQVSadsw6rg8Q7gs="; stripRoot = false; }; + + giteaUrl = "http://10.233.11.2:3002"; + githubUsername = "anotherhadi"; + + giteaGithubMirror = pkgs.writeShellApplication { + name = "gitea-github-mirror"; + runtimeInputs = [pkgs.curl pkgs.jq]; + text = '' + github_token="$(cat "$GITHUB_TOKEN_FILE")" + gitea_token="$(cat "$GITEA_TOKEN_FILE")" + + tmp_github="$(mktemp)" + tmp_gitea="$(mktemp)" + trap 'rm -f "$tmp_github" "$tmp_gitea"' EXIT + + page=1 + while :; do + resp="$(curl -sf -H "Authorization: Bearer $github_token" \ + "https://api.github.com/user/repos?affiliation=owner&per_page=100&page=$page")" + echo "$resp" >> "$tmp_github" + count="$(echo "$resp" | jq 'length')" + [ "$count" -lt 100 ] && break + page=$((page + 1)) + done + + page=1 + while :; do + resp="$(curl -sf -H "Authorization: token $gitea_token" \ + "$GITEA_URL/api/v1/users/$GITEA_OWNER/repos?limit=50&page=$page")" + echo "$resp" >> "$tmp_gitea" + count="$(echo "$resp" | jq 'length')" + [ "$count" -lt 50 ] && break + page=$((page + 1)) + done + + existing="$(jq -s '[.[][].name]' "$tmp_gitea")" + github_repos="$(jq -s 'add | map(select(.archived | not)) | map({name, private, clone_url, description: (.description // "")})' "$tmp_github")" + + echo "$github_repos" | jq -c '.[]' | while IFS= read -r repo; do + name="$(echo "$repo" | jq -r '.name')" + if echo "$existing" | jq -e --arg n "$name" 'index($n)' > /dev/null; then + continue + fi + echo "Mirroring new repo: $name" + body="$(echo "$repo" | jq \ + --arg owner "$GITEA_OWNER" \ + --arg token "$github_token" \ + '{clone_addr: .clone_url, service: "github", repo_name: .name, repo_owner: $owner, mirror: true, private: .private, auth_token: $token, description: .description, mirror_interval: "8h0m0s"}')" + curl -sf -X POST -H "Authorization: token $gitea_token" -H "Content-Type: application/json" \ + "$GITEA_URL/api/v1/repos/migrate" -d "$body" > /dev/null \ + || echo "Failed to mirror $name" >&2 + done + ''; + }; in { imports = [ (mkContainer { @@ -80,5 +135,36 @@ in { }) ]; - services.cloudflared.tunnels."${config.var.tunnelId}".ingress."git.${domain}" = "http://10.233.11.2:3002"; + services.cloudflared.tunnels."${config.var.tunnelId}".ingress."git.${domain}" = giteaUrl; + + sops.secrets = { + github-mirror-token = {}; + gitea-mirror-token = {}; + }; + + systemd.services.gitea-github-mirror = { + description = "Mirror all GitHub repos of ${githubUsername} into Gitea"; + after = ["network-online.target" "container@gitea.service"]; + wants = ["network-online.target"]; + environment = { + GITHUB_TOKEN_FILE = config.sops.secrets.github-mirror-token.path; + GITEA_TOKEN_FILE = config.sops.secrets.gitea-mirror-token.path; + GITEA_URL = giteaUrl; + GITEA_OWNER = githubUsername; + }; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${giteaGithubMirror}/bin/gitea-github-mirror"; + }; + }; + + systemd.timers.gitea-github-mirror = { + description = "Periodically mirror all GitHub repos into Gitea"; + wantedBy = ["timers.target"]; + timerConfig = { + OnBootSec = "5m"; + OnUnitActiveSec = "30m"; + Persistent = true; + }; + }; }