[READ-ONLY] Mirror of https://github.com/mrgnw/migrate-github-to-codeberg. Rust TUI and shell script for migrating GitHub repositories to Codeberg while preserving GitHub remotes.
7.1 kB
207 lines
1#!/bin/bash
2#
3# GitHub to Codeberg Migration Script
4# ------------------------------------
5#
6# Author: Rahul Martim Juliato
7# Email: rahul.juliato@gmail.com
8# License: GPL-3.0
9# Version: 0.1.2
10#
11# This script migrates GitHub repositories to Codeberg.
12#
13# User Configuration:
14# --------------------
15# GitHub username and personal access token
16# GITHUB_USERNAME="YourGitHubUsername"
17# GITHUB_TOKEN="YourGitHubToken"
18#
19# Codeberg username and personal access token
20# CODEBERG_USERNAME="YourCodebergUsername"
21# CODEBERG_TOKEN="YourCodebergToken"
22#
23# Define the REPOSITORIES array with repository names you want to migrate
24# Leave it blank to migrate all repositories, or create a list of repositories
25# if you want to select specific ones.
26# REPOSITORIES=(
27# "repository1"
28# "repository2"
29# "repository3"
30# )
31#
32# Custom prefix for description
33# DESCRIPTION_PREFIX=""
34# or something like:
35# DESCRIPTION_PREFIX="[MIRROR] "
36#
37# Usage:
38# ------
39# 1. Configure the user settings at the beginning of the script.
40# 2. Run the script.
41# 3. Follow the on-screen instructions to proceed with the migration.
42#
43# Note: Make sure to have 'curl' and 'jq' installed.
44#
45# Press ENTER to continue, or C-c to abort.
46#
47# -----------------------------------------------------------
48
49# USER CONFIGURATION
50#---------------------------------------------------------------------------
51
52# GitHub username and personal access token
53GITHUB_USERNAME="YourGitHubUsername"
54GITHUB_TOKEN="YourGitHubToken"
55
56# Codeberg username and personal access token
57CODEBERG_USERNAME="YourCodebergUsername"
58CODEBERG_TOKEN="YourCodebergToken"
59
60# Define the REPOSITORIES array with repository names you want to migrate
61# Leave it blank so you migrate ALL repositories. Create a one per line list
62# if you want to select the repositories to migrate.
63
64REPOSITORIES=()
65# REPOSITORIES=(
66# "repository1"
67# "repository2"
68# "repository3"
69# )
70
71# Define the OWNERS array with specific user names whose repositories you want to migrate
72# Leave it blank so you migrate ALL repositories. Create a one per line list
73# if you want to select the repositories to migrate.
74
75OWNERS=()
76# OWNERS=(
77# "owner1"
78# "owner2"
79# )
80
81# Custom prefix for description
82DESCRIPTION_PREFIX=""
83# DESCRIPTION_PREFIX="[Secondary] - "
84# DESCRIPTION_PREFIX="Draft: "
85
86# UTILS FUNCTIONS
87#---------------------------------------------------------------------------
88array_contains() {
89 local array="$1[@]"
90 local seeking=$2
91 local in=1
92 for element in "${!array}"; do
93 if [[ $element == "$seeking" ]]; then
94 in=0
95 break
96 fi
97 done
98 return $in
99}
100
101# PROCESSING
102#---------------------------------------------------------------------------
103printf "\n ----------------------------------------------"
104printf "\n Welcome to Github to Codeberg Migration Script"
105printf "\n ----------------------------------------------\n"
106printf "\n User on Github : $GITHUB_USERNAME"
107printf "\n User on Codeberg : $CODEBERG_USERNAME"
108printf "\n Using description prefix: $DESCRIPTION_PREFIX"
109if [ ${#OWNERS[@]} -eq 0 ]; then
110 printf "\n Migrating repos owned by: all users"
111else
112 printf "\n Migrating repos owned by: %s" "${OWNERS[@]}"
113fi
114if [ ${#REPOSITORIES[@]} -eq 0 ]; then
115 printf "\n Migrating repo : all"
116else
117 printf "\n Migrating repos : %s" "${REPOSITORIES[@]}"
118fi
119printf "\n"
120printf "\n If you wish to change this, abort and change this script.\n\n"
121printf "\n\n Press ENTER to continue, C-c to abort.\n\n"
122read
123printf ">>> Working...\n"
124
125# NOTE: Github api paginates to max 100 repositories, this calculates how many
126# runs (pages) we're going to do to fetch all user data.
127GITHUB_PAGINATION=100
128github_total_repos=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/user" | jq '.public_repos + .total_private_repos')
129github_needed_pages=$((($github_total_repos + $GITHUB_PAGINATION - 1) / $GITHUB_PAGINATION))
130
131# Start Migration to Codeberg
132for ((github_page_counter = 1; github_page_counter <= github_needed_pages; github_page_counter++)); do
133
134 repos=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/user/repos?per_page=${GITHUB_PAGINATION}&page=${github_page_counter}")
135
136 echo "$repos" | jq -c '.[]' | while read -r row; do
137 repo_name=$(echo "$row" | jq -r '.name')
138
139 # Skips current processing repo if
140 # A) it is not on the wanted list
141 # or B) and you're migrating 'all'
142 if ! array_contains REPOSITORIES "$repo_name" && [ ${#REPOSITORIES[@]} -ne 0 ]; then
143 continue
144 fi
145
146 repo_owner=$(echo "$row" | jq -r '.owner.login')
147 # Skips current processing repo if
148 # A) it is not owned by a targeted user
149 # B) no specific users are targeted
150 if ! array_contains OWNERS "$repo_owner" && [ ${#OWNERS[@]} -ne 0 ]; then
151 continue
152 fi
153
154 repo_clone_url=$(echo "$row" | jq -r '.clone_url')
155 repo_description="$DESCRIPTION_PREFIX$(echo "$row" | jq -r '.description')"
156 repo_is_private=$(echo "$row" | jq -r '.private')
157
158 printf ">>> Migrating: $repo_name ($([ "$repo_is_private" = "true" ] && echo "private" || echo "public"))...\n"
159
160 json_payload=$(jq -n \
161 --arg auth_username "$GITHUB_USERNAME" \
162 --arg auth_token "$GITHUB_TOKEN" \
163 --arg clone_addr "$repo_clone_url" \
164 --argjson private "$repo_is_private" \
165 --arg repo_name "$repo_name" \
166 --arg repo_owner "$CODEBERG_USERNAME" \
167 --arg description "$repo_description" \
168 '{
169 auth_username: $auth_username,
170 auth_token: $auth_token,
171 clone_addr: $clone_addr,
172 private: $private,
173 repo_name: $repo_name,
174 repo_owner: $repo_owner,
175 service: "github",
176 description: $description
177 }')
178
179 response=$(curl -s -w "\n%{http_code}" -X POST -H "Content-Type: application/json" -H "Authorization: token $CODEBERG_TOKEN" -d "$json_payload" "https://codeberg.org/api/v1/repos/migrate")
180
181 response_body=$(echo "$response" | head -n -1)
182 http_status=$(echo "$response" | tail -n 1)
183
184 case $http_status in
185 201)
186 printf " Success!\n"
187 ;;
188 409)
189 printf " Error! Already exists on Codeberg.\n"
190 ;;
191 403)
192 printf "Error! Forbidden.\n"
193 ;;
194 *)
195 error_message=$(echo "$response_body" | jq -r '.message // empty' 2>/dev/null)
196 if [ -n "$error_message" ]; then
197 printf "Error: %s (HTTP %s)\n" "$error_message" "$http_status"
198 else
199 printf "Error: Unknown! %s\n" "$http_status"
200 fi
201 ;;
202 esac
203
204 done
205done
206
207echo ">>> Migration script completed!"