135 lines
3.7 KiB
Ruby
135 lines
3.7 KiB
Ruby
#!/usr/bin/env ruby
|
|
require 'net/http'
|
|
require 'json'
|
|
require 'uri'
|
|
require 'yaml'
|
|
require 'optparse'
|
|
|
|
# Configuration mapping
|
|
ENV_CONFIG = {
|
|
'stg' => {
|
|
url: "https://git.staging.jamkazam.com/api/v1",
|
|
token_var: "GITEA_TOKEN_STG"
|
|
},
|
|
'prd' => {
|
|
url: "https://git.jamkazam.com/api/v1",
|
|
token_var: "GITEA_TOKEN_PRD"
|
|
}
|
|
}
|
|
|
|
options = { env: 'stg' }
|
|
OptionParser.new do |opts|
|
|
opts.banner = "Usage: ruby sync-gitea-repos.rb [options] <bitbucket_user> <bitbucket_pass>"
|
|
opts.on("-e", "--env ENV", "Environment (stg or prd, default stg)") { |v| options[:env] = v }
|
|
end.parse!
|
|
|
|
if ARGV.length < 2
|
|
puts "❌ Error: Missing Bitbucket credentials."
|
|
puts "Usage: ruby sync-gitea-repos.rb --env [stg|prd] <bb_user> <bb_pass>"
|
|
exit 1
|
|
end
|
|
|
|
BB_USER = ARGV[0]
|
|
BB_PASS = ARGV[1]
|
|
|
|
# Select config
|
|
config = ENV_CONFIG[options[:env]]
|
|
if config.nil?
|
|
puts "❌ Error: Invalid environment '#{options[:env]}'. Use 'stg' or 'prd'."
|
|
exit 1
|
|
end
|
|
|
|
# Resolve Token
|
|
GITEA_TOKEN = ENV[config[:token_var]] || ENV['GITEA_TOKEN']
|
|
GITEA_URL = config[:url]
|
|
GITEA_OWNER = "seth"
|
|
MANIFEST_FILE = File.expand_path('gitea-repos.yaml', __dir__)
|
|
|
|
if GITEA_TOKEN.nil? || GITEA_TOKEN.empty?
|
|
puts "❌ Error: API Token environment variable '#{config[:token_var]}' is not set."
|
|
exit 1
|
|
end
|
|
|
|
def gitea_request(method, path, payload = nil)
|
|
uri = URI.parse("#{GITEA_URL}#{path}")
|
|
header = {
|
|
'Content-Type' => 'application/json',
|
|
'Authorization' => "token #{GITEA_TOKEN}"
|
|
}
|
|
http = Net::HTTP.new(uri.host, uri.port)
|
|
http.use_ssl = true
|
|
http.read_timeout = 300
|
|
|
|
case method
|
|
when :get then req = Net::HTTP::Get.new(uri.request_uri, header)
|
|
when :post then req = Net::HTTP::Post.new(uri.request_uri, header); req.body = payload.to_json if payload
|
|
when :delete then req = Net::HTTP::Delete.new(uri.request_uri, header)
|
|
end
|
|
http.request(req)
|
|
end
|
|
|
|
puts "🚀 Reconciling Gitea mirrors for #{options[:env].upcase}..."
|
|
puts "🔗 API: #{GITEA_URL}"
|
|
|
|
# 1. Load Manifest
|
|
manifest = YAML.load_file(MANIFEST_FILE)
|
|
desired_repos = manifest['repositories']
|
|
desired_names = desired_repos.map { |r| r['name'] }
|
|
|
|
# 2. Get Current State from Gitea
|
|
puts "🔍 Fetching current repositories..."
|
|
resp = gitea_request(:get, "/users/#{GITEA_OWNER}/repos")
|
|
if resp.code != "200"
|
|
puts "❌ Failed to fetch repos: #{resp.code} #{resp.body}"
|
|
exit 1
|
|
end
|
|
current_repos = JSON.parse(resp.body)
|
|
current_names = current_repos.map { |r| r['name'] }
|
|
|
|
# 3. Reconcile: Delete repos not in manifest
|
|
repos_to_delete = current_names - desired_names
|
|
repos_to_delete.each do |name|
|
|
puts "🗑️ Deleting repository '#{name}' (not in manifest)..."
|
|
gitea_request(:delete, "/repos/#{GITEA_OWNER}/#{name}")
|
|
end
|
|
|
|
# 4. Reconcile: Create/Update mirrors
|
|
desired_repos.each do |repo|
|
|
name = repo['name']
|
|
url = repo['url']
|
|
|
|
if current_names.include?(name)
|
|
repo_info = current_repos.find { |r| r['name'] == name }
|
|
if repo_info['empty']
|
|
puts "⚠️ Mirror '#{name}' exists but is EMPTY. Recreating..."
|
|
gitea_request(:delete, "/repos/#{GITEA_OWNER}/#{name}")
|
|
else
|
|
puts "✅ Mirror '#{name}' already exists. Skipping."
|
|
next
|
|
end
|
|
end
|
|
|
|
puts "🚀 Creating mirror for '#{name}'..."
|
|
payload = {
|
|
"clone_addr" => url,
|
|
"auth_username" => BB_USER,
|
|
"auth_password" => BB_PASS,
|
|
"repo_name" => name,
|
|
"mirror" => true,
|
|
"mirror_interval" => "10m",
|
|
"service" => "bitbucket",
|
|
"repo_owner" => GITEA_OWNER,
|
|
"lfs" => true,
|
|
"releases" => true
|
|
}
|
|
|
|
res = gitea_request(:post, "/repos/migrate", payload)
|
|
if res.code == "201"
|
|
puts "✨ Successfully created mirror for '#{name}'."
|
|
else
|
|
puts "❌ Failed to create mirror for '#{name}': #{res.code} #{res.body}"
|
|
end
|
|
end
|
|
|
|
puts "\n🎯 Reconcile complete for #{options[:env].upcase}."
|