Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
ae347d7506
|
@@ -4,6 +4,10 @@ gitea_url = "https://gitmirror.hak8or.com"
|
|||||||
# Your Gitea API key (generate one from User Settings -> Applications)
|
# Your Gitea API key (generate one from User Settings -> Applications)
|
||||||
api_key = "API_KEY_GOES_HERE"
|
api_key = "API_KEY_GOES_HERE"
|
||||||
|
|
||||||
|
# Optional: specify the owner username for all migrated repos
|
||||||
|
# If not specified, uses the user who owns the API key
|
||||||
|
repo_owner = "mirror_org"
|
||||||
|
|
||||||
# A list of remote git repositories to mirror.
|
# A list of remote git repositories to mirror.
|
||||||
repos = [
|
repos = [
|
||||||
{ url = "https://gitea.hak8or.com/hak8or/gitea_mirror.git" },
|
{ url = "https://gitea.hak8or.com/hak8or/gitea_mirror.git" },
|
||||||
|
40
src/main.rs
40
src/main.rs
@@ -43,6 +43,7 @@ struct Config {
|
|||||||
api_key: String,
|
api_key: String,
|
||||||
repos: Option<Vec<RepoConfig>>,
|
repos: Option<Vec<RepoConfig>>,
|
||||||
organizations: Option<Vec<OrgConfig>>,
|
organizations: Option<Vec<OrgConfig>>,
|
||||||
|
repo_owner: Option<String>, // Optional owner username/org for all migrated repos
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents the payload for creating a migration in Gitea.
|
// Represents the payload for creating a migration in Gitea.
|
||||||
@@ -50,16 +51,16 @@ struct Config {
|
|||||||
struct MigrateRepoPayload<'a> {
|
struct MigrateRepoPayload<'a> {
|
||||||
clone_addr: &'a str,
|
clone_addr: &'a str,
|
||||||
repo_name: &'a str,
|
repo_name: &'a str,
|
||||||
|
repo_owner: &'a str, // Username or organization name
|
||||||
mirror: bool,
|
mirror: bool,
|
||||||
private: bool,
|
private: bool,
|
||||||
description: &'a str,
|
description: &'a str,
|
||||||
uid: i64, // The user ID of the owner. We'll fetch this.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents a user as returned by the Gitea API.
|
// Represents a user as returned by the Gitea API.
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
struct GiteaUser {
|
struct GiteaUser {
|
||||||
id: i64,
|
login: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Entry point of the application.
|
/// Entry point of the application.
|
||||||
@@ -77,12 +78,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let config = load_config(&args.config)?;
|
let config = load_config(&args.config)?;
|
||||||
let http_client = reqwest::Client::new();
|
let http_client = reqwest::Client::new();
|
||||||
|
|
||||||
// Fetch the Gitea user ID for the authenticated user.
|
// Determine the owner (either from repo_owner or authenticated user)
|
||||||
let user_id = get_gitea_user_id(&http_client, &config.gitea_url, &config.api_key).await?;
|
let owner_name = if let Some(owner) = &config.repo_owner {
|
||||||
info!(
|
info!("Using specified repo_owner: {}", owner);
|
||||||
"Successfully authenticated and retrieved user ID: {}",
|
owner.clone()
|
||||||
user_id
|
} else {
|
||||||
);
|
info!("No repo_owner specified, fetching authenticated user");
|
||||||
|
get_authenticated_username(&http_client, &config.gitea_url, &config.api_key).await?
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("Using owner '{}' for all migrated repositories", owner_name);
|
||||||
|
|
||||||
// Process repositories from the static list.
|
// Process repositories from the static list.
|
||||||
if let Some(repos) = &config.repos {
|
if let Some(repos) = &config.repos {
|
||||||
@@ -90,7 +95,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
process_repo(
|
process_repo(
|
||||||
&repo_config.url,
|
&repo_config.url,
|
||||||
repo_config.rename.as_deref(),
|
repo_config.rename.as_deref(),
|
||||||
user_id,
|
&owner_name,
|
||||||
&http_client,
|
&http_client,
|
||||||
&config,
|
&config,
|
||||||
args.dry_run,
|
args.dry_run,
|
||||||
@@ -119,7 +124,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
process_repo(
|
process_repo(
|
||||||
&url,
|
&url,
|
||||||
None, // No rename support for orgs
|
None, // No rename support for orgs
|
||||||
user_id,
|
&owner_name,
|
||||||
&http_client,
|
&http_client,
|
||||||
&config,
|
&config,
|
||||||
args.dry_run,
|
args.dry_run,
|
||||||
@@ -145,13 +150,13 @@ fn load_config(path: &Path) -> Result<Config, Box<dyn std::error::Error>> {
|
|||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches the authenticated user's ID from Gitea.
|
/// Fetches the authenticated user's login name from Gitea.
|
||||||
#[instrument(skip(http_client, gitea_url, api_key))]
|
#[instrument(skip(http_client, gitea_url, api_key))]
|
||||||
async fn get_gitea_user_id(
|
async fn get_authenticated_username(
|
||||||
http_client: &reqwest::Client,
|
http_client: &reqwest::Client,
|
||||||
gitea_url: &str,
|
gitea_url: &str,
|
||||||
api_key: &str,
|
api_key: &str,
|
||||||
) -> Result<i64, reqwest::Error> {
|
) -> Result<String, reqwest::Error> {
|
||||||
let url = format!("{}/api/v1/user", gitea_url);
|
let url = format!("{}/api/v1/user", gitea_url);
|
||||||
let user: GiteaUser = http_client
|
let user: GiteaUser = http_client
|
||||||
.get(&url)
|
.get(&url)
|
||||||
@@ -161,7 +166,8 @@ async fn get_gitea_user_id(
|
|||||||
.error_for_status()?
|
.error_for_status()?
|
||||||
.json()
|
.json()
|
||||||
.await?;
|
.await?;
|
||||||
Ok(user.id)
|
info!("Authenticated as user: {}", user.login);
|
||||||
|
Ok(user.login)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if a repository already exists in Gitea for the user.
|
/// Checks if a repository already exists in Gitea for the user.
|
||||||
@@ -276,11 +282,11 @@ async fn fetch_org_repos(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Core logic to process a single repository.
|
/// Core logic to process a single repository.
|
||||||
#[instrument(skip(user_id, http_client, config, dry_run))]
|
#[instrument(skip(owner_name, http_client, config, dry_run))]
|
||||||
async fn process_repo(
|
async fn process_repo(
|
||||||
repo_url: &str,
|
repo_url: &str,
|
||||||
rename: Option<&str>,
|
rename: Option<&str>,
|
||||||
user_id: i64,
|
owner_name: &str,
|
||||||
http_client: &reqwest::Client,
|
http_client: &reqwest::Client,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
@@ -301,10 +307,10 @@ async fn process_repo(
|
|||||||
let payload = MigrateRepoPayload {
|
let payload = MigrateRepoPayload {
|
||||||
clone_addr: repo_url,
|
clone_addr: repo_url,
|
||||||
repo_name,
|
repo_name,
|
||||||
|
repo_owner: owner_name,
|
||||||
mirror: true,
|
mirror: true,
|
||||||
private: false, // Defaulting to public, change if needed
|
private: false, // Defaulting to public, change if needed
|
||||||
description: "",
|
description: "",
|
||||||
uid: user_id,
|
|
||||||
};
|
};
|
||||||
if let Err(e) = create_migration(http_client, config, &payload).await {
|
if let Err(e) = create_migration(http_client, config, &payload).await {
|
||||||
error!("Failed to create migration for '{}': {}", repo_name, e);
|
error!("Failed to create migration for '{}': {}", repo_name, e);
|
||||||
|
Reference in New Issue
Block a user