[M] Rebrand

This commit is contained in:
2026-05-08 05:34:08 +00:00
parent ebeb045c51
commit 9a9cbba767
14 changed files with 102 additions and 99 deletions
Generated
+21 -21
View File
@@ -420,27 +420,6 @@ dependencies = [
"wasip3", "wasip3",
] ]
[[package]]
name = "git-sync"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"console",
"dialoguer",
"directories",
"hmac",
"regex",
"reqwest",
"serde",
"serde_json",
"sha2",
"tempfile",
"tiny_http",
"toml",
"url",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.5" version = "0.15.5"
@@ -981,6 +960,27 @@ dependencies = [
"thiserror 1.0.69", "thiserror 1.0.69",
] ]
[[package]]
name = "refray"
version = "0.1.0"
dependencies = [
"anyhow",
"clap",
"console",
"dialoguer",
"directories",
"hmac",
"regex",
"reqwest",
"serde",
"serde_json",
"sha2",
"tempfile",
"tiny_http",
"toml",
"url",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.12.3" version = "1.12.3"
+1 -1
View File
@@ -1,5 +1,5 @@
[package] [package]
name = "git-sync" name = "refray"
version = "0.1.0" version = "0.1.0"
edition = "2024" edition = "2024"
+33 -33
View File
@@ -1,6 +1,6 @@
# git-sync # refray
`git-sync` mirrors repositories between Git hosting providers when you run it. It can run as a one-shot sync command, or as a webhook receiver that triggers one-repo syncs after push events. `refray` mirrors repositories between Git hosting providers when you run it. It can run as a one-shot sync command, or as a webhook receiver that triggers one-repo syncs after push events.
Supported providers: Supported providers:
@@ -18,14 +18,14 @@ Forgejo uses the same API shape as Gitea.
cargo build --release cargo build --release
``` ```
The binary will be at `target/release/git-sync`. The binary will be at `target/release/refray`.
## Configure ## Configure
Run the interactive configuration wizard: Run the interactive configuration wizard:
```sh ```sh
git-sync config refray config
``` ```
The wizard creates or updates the config file. It asks for profile or organization URLs, reuses existing credentials when it can, asks for a PAT only when needed, then offers webhook setup. Webhooks are strongly recommended because they sync soon after pushes and greatly reduce the chance of divergent histories. The wizard creates or updates the config file. It asks for profile or organization URLs, reuses existing credentials when it can, asks for a PAT only when needed, then offers webhook setup. Webhooks are strongly recommended because they sync soon after pushes and greatly reduce the chance of divergent histories.
@@ -43,7 +43,7 @@ Example wizard flow:
PAT quick setup: PAT quick setup:
- GitHub: open `https://github.com/settings/tokens`, create a classic PAT with `repo` permissions, then copy the token. - GitHub: open `https://github.com/settings/tokens`, create a classic PAT with `repo` permissions, then copy the token.
- GitLab: open `<base-url>/-/user_settings/personal_access_tokens?name=git-sync&scopes=api,write_repository`, select `api` and `write_repository`, create the token, then copy it. - GitLab: open `<base-url>/-/user_settings/personal_access_tokens?name=refray&scopes=api,write_repository`, select `api` and `write_repository`, create the token, then copy it.
- Gitea: open `<base-url>/user/settings/applications`, create a token with repository access, then copy it. - Gitea: open `<base-url>/user/settings/applications`, create a token with repository access, then copy it.
- Forgejo: open `<base-url>/user/settings/applications`, create a token with repository access, then copy it. - Forgejo: open `<base-url>/user/settings/applications`, create a token with repository access, then copy it.
@@ -62,54 +62,54 @@ Set `api_url` in the TOML if your instance is different.
Run all configured mirror groups: Run all configured mirror groups:
```sh ```sh
git-sync sync refray sync
``` ```
Run one group: Run one group:
```sh ```sh
git-sync sync --group personal refray sync --group personal
``` ```
Preview commands without writing to Git remotes: Preview commands without writing to Git remotes:
```sh ```sh
git-sync sync --dry-run refray sync --dry-run
``` ```
Sync only repositories whose names match a regex: Sync only repositories whose names match a regex:
```sh ```sh
git-sync sync --repo-pattern '^(foo|bar)-' refray sync --repo-pattern '^(foo|bar)-'
``` ```
Retry only repositories that failed during the previous non-dry-run sync: Retry only repositories that failed during the previous non-dry-run sync:
```sh ```sh
git-sync sync --retry-failed refray sync --retry-failed
``` ```
Control repo-level parallelism: Control repo-level parallelism:
```sh ```sh
git-sync sync --jobs 8 refray sync --jobs 8
``` ```
While jobs run, the bottom of the terminal shows one live status line per worker. When a repository finishes, its detailed log is printed as one complete block above those status lines. The default is 4 workers; use `--jobs 1` for serial sync. While jobs run, the bottom of the terminal shows one live status line per worker. When a repository finishes, its detailed log is printed as one complete block above those status lines. The default is 4 workers; use `--jobs 1` for serial sync.
`git-sync` stores a small ref cache in the work directory. On later runs it first checks each repository with `git ls-remote --heads --tags`; when all endpoints report the same refs as the last successful sync, or the existing local bare mirror cache already has those refs, it skips the full fetch/push pass for that repository. `refray` stores a small ref cache in the work directory. On later runs it first checks each repository with `git ls-remote --heads --tags`; when all endpoints report the same refs as the last successful sync, or the existing local bare mirror cache already has those refs, it skips the full fetch/push pass for that repository.
Use cron or another scheduler for automatic execution: Use cron or another scheduler for automatic execution:
```cron ```cron
*/15 * * * * GITHUB_TOKEN=... GITEA_TOKEN=... /path/to/git-sync sync */15 * * * * GITHUB_TOKEN=... GITEA_TOKEN=... /path/to/refray sync
``` ```
## Webhooks ## Webhooks
Webhook mode reduces the window for divergent commits by syncing a repository immediately after a provider sends a push event. It is still conservative: if two endpoints receive independent commits before webhook sync catches up, the normal divergence rules still apply. Webhook mode reduces the window for divergent commits by syncing a repository immediately after a provider sends a push event. It is still conservative: if two endpoints receive independent commits before webhook sync catches up, the normal divergence rules still apply.
The interactive wizard can configure webhooks for you. During setup it starts a temporary test listener on `127.0.0.1:8787`, asks for the public URL, checks that the URL is reachable from the current machine, creates a webhook secret, and can enable periodic full syncs while `git-sync serve` is running. The interactive wizard can configure webhooks for you. During setup it starts a temporary test listener on `127.0.0.1:8787`, asks for the public URL, checks that the URL is reachable from the current machine, creates a webhook secret, and can enable periodic full syncs while `refray serve` is running.
Example config: Example config:
@@ -125,66 +125,66 @@ reachability_check_interval_minutes = 15
Start the receiver: Start the receiver:
```sh ```sh
git-sync serve \ refray serve \
--listen 127.0.0.1:8787 --listen 127.0.0.1:8787
``` ```
Expose that listener with your reverse proxy or tunnel, then install repository webhooks. If `[webhook]` is configured, the URL and secret can come from config: Expose that listener with your reverse proxy or tunnel, then install repository webhooks. If `[webhook]` is configured, the URL and secret can come from config:
```sh ```sh
git-sync webhook install refray webhook install
``` ```
Manual `webhook install` always checks the selected repositories on the provider and repairs or records the hook state. To install or repair one repository exactly: Manual `webhook install` always checks the selected repositories on the provider and repairs or records the hook state. To install or repair one repository exactly:
```sh ```sh
git-sync webhook install important-repo refray webhook install important-repo
``` ```
You can also pass them explicitly: You can also pass them explicitly:
```sh ```sh
git-sync webhook install \ refray webhook install \
--url https://mirror.example.com/webhook \ --url https://mirror.example.com/webhook \
--secret-env GIT_SYNC_WEBHOOK_SECRET --secret-env REFRAY_WEBHOOK_SECRET
``` ```
Useful install filters: Useful install filters:
```sh ```sh
git-sync webhook install \ refray webhook install \
--url https://mirror.example.com/webhook \ --url https://mirror.example.com/webhook \
--secret-env GIT_SYNC_WEBHOOK_SECRET \ --secret-env REFRAY_WEBHOOK_SECRET \
--group personal \ --group personal \
--repo-pattern '^important-' --repo-pattern '^important-'
``` ```
The receiver accepts `POST /` and `POST /webhook`. It verifies GitHub/Gitea HMAC SHA-256 signatures and GitLab webhook tokens, then queues `git-sync sync --group <group> --repo-pattern '^<repo>$'` internally. Duplicate events for the same group/repo are coalesced while a job is queued or running. Sync jobs are serialized inside the receiver so the local ref and failure caches stay consistent. The receiver accepts `POST /` and `POST /webhook`. It verifies GitHub/Gitea HMAC SHA-256 signatures and GitLab webhook tokens, then queues `refray sync --group <group> --repo-pattern '^<repo>$'` internally. Duplicate events for the same group/repo are coalesced while a job is queued or running. Sync jobs are serialized inside the receiver so the local ref and failure caches stay consistent.
When `[webhook].install = true`, normal `git-sync sync` also checks webhook installation status and installs missing webhooks for repositories that have not been recorded yet. Installation status is stored in `webhook-state.toml` under the work directory. When `[webhook].install = true`, normal `refray sync` also checks webhook installation status and installs missing webhooks for repositories that have not been recorded yet. Installation status is stored in `webhook-state.toml` under the work directory.
To uninstall webhooks previously installed by `git-sync`: To uninstall webhooks previously installed by `refray`:
```sh ```sh
git-sync webhook uninstall refray webhook uninstall
``` ```
Manual `webhook uninstall` checks repositories on the provider instead of trusting only local state. To uninstall one repository exactly: Manual `webhook uninstall` checks repositories on the provider instead of trusting only local state. To uninstall one repository exactly:
```sh ```sh
git-sync webhook uninstall important-repo refray webhook uninstall important-repo
``` ```
To move installed hooks to a new public URL, use `webhook update`. It removes hooks matching the current configured `[webhook].url`, installs the new URL, updates `[webhook].url` in the config, and refreshes local webhook state: To move installed hooks to a new public URL, use `webhook update`. It removes hooks matching the current configured `[webhook].url`, installs the new URL, updates `[webhook].url` in the config, and refreshes local webhook state:
```sh ```sh
git-sync webhook update --url https://new.example.com/webhook refray webhook update --url https://new.example.com/webhook
``` ```
Serve can also run periodic full syncs. The interval can be configured in `[webhook].full_sync_interval_minutes` or overridden at startup: Serve can also run periodic full syncs. The interval can be configured in `[webhook].full_sync_interval_minutes` or overridden at startup:
```sh ```sh
git-sync serve --full-sync-interval-minutes 30 refray serve --full-sync-interval-minutes 30
``` ```
If `[webhook].reachability_check_interval_minutes` is configured, `serve` periodically checks that the public webhook URL is still reachable and logs a warning when it is not. If `[webhook].reachability_check_interval_minutes` is configured, `serve` periodically checks that the public webhook URL is still reachable and logs a warning when it is not.
@@ -193,7 +193,7 @@ If `[webhook].reachability_check_interval_minutes` is configured, `serve` period
Each mirror group is treated as a set of equivalent namespaces. Repositories are matched by repository name across all endpoints. Each mirror group is treated as a set of equivalent namespaces. Repositories are matched by repository name across all endpoints.
For every repository name found in any endpoint, `git-sync` will: For every repository name found in any endpoint, `refray` will:
1. Create missing repositories on the other endpoints when `create_missing = true`. 1. Create missing repositories on the other endpoints when `create_missing = true`.
2. Fetch all branches and tags from each existing endpoint into a local bare mirror cache. 2. Fetch all branches and tags from each existing endpoint into a local bare mirror cache.
@@ -205,18 +205,18 @@ Branch conflict handling is intentionally conservative:
- If all endpoints agree on a branch tip, that tip is pushed everywhere. - If all endpoints agree on a branch tip, that tip is pushed everywhere.
- If one branch tip is a descendant of the others, the descendant wins and is pushed everywhere. - If one branch tip is a descendant of the others, the descendant wins and is pushed everywhere.
- If branch tips diverged, `conflict_resolution` controls what happens. - If branch tips diverged, `conflict_resolution` controls what happens.
- If `allow_force = true` or `git-sync sync --force` is used, a diverged branch chooses the newest commit timestamp and force-pushes it. - If `allow_force = true` or `refray sync --force` is used, a diverged branch chooses the newest commit timestamp and force-pushes it.
Conflict resolution strategies are configured per mirror group: Conflict resolution strategies are configured per mirror group:
- `fail`: fail the repository sync when branch tips diverge. - `fail`: fail the repository sync when branch tips diverge.
- `auto_rebase`: rebase divergent commits in endpoint order into one branch history, push fast-forward updates normally, and force-push only endpoints whose original tip was rewritten. If rebase hits a file conflict, fail. - `auto_rebase`: rebase divergent commits in endpoint order into one branch history, push fast-forward updates normally, and force-push only endpoints whose original tip was rewritten. If rebase hits a file conflict, fail.
- `pull_request`: push temporary `git-sync/conflicts/...` branches and open provider pull requests/merge requests so a person can resolve the divergence. - `pull_request`: push temporary `refray/conflicts/...` branches and open provider pull requests/merge requests so a person can resolve the divergence.
- `auto_rebase_pull_request`: try `auto_rebase` first, then fall back to pull requests if rebase hits a conflict. - `auto_rebase_pull_request`: try `auto_rebase` first, then fall back to pull requests if rebase hits a conflict.
When a previously opened conflict pull request is merged, the next sync sees the merged branch as the winning tip, pushes it to the other endpoints, and closes stale `git-sync/conflicts/...` pull requests for that branch. When a previously opened conflict pull request is merged, the next sync sees the merged branch as the winning tip, pushes it to the other endpoints, and closes stale `refray/conflicts/...` pull requests for that branch.
Branch deletion is propagated only when it is safe to infer intent. If a branch existed on every endpoint in the previous successful sync, then disappears from one endpoint while the remaining endpoints still have the previous tip, `git-sync` deletes it from the remaining endpoints instead of recreating it. If the branch was deleted on one endpoint but changed elsewhere, it is treated as a conflict and skipped. Branch deletion is propagated only when it is safe to infer intent. If a branch existed on every endpoint in the previous successful sync, then disappears from one endpoint while the remaining endpoints still have the previous tip, `refray` deletes it from the remaining endpoints instead of recreating it. If the branch was deleted on one endpoint but changed elsewhere, it is treated as a conflict and skipped.
Tags are fetched into provider-specific cache refs and pushed only when the tag object agrees across providers or exists on one side. Divergent tags are skipped and reported. Tag deletion is not propagated. Tags are fetched into provider-specific cache refs and pushed only when the tag object agrees across providers or exists on one side. Divergent tags are skipped and reported. Tag deletion is not propagated.
+6 -4
View File
@@ -7,6 +7,8 @@ use anyhow::{Context, Result, anyhow, bail};
use directories::ProjectDirs; use directories::ProjectDirs;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
const APP_NAME: &str = "refray";
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Config { pub struct Config {
#[serde(default)] #[serde(default)]
@@ -223,15 +225,15 @@ impl EndpointConfig {
} }
pub fn default_config_path() -> PathBuf { pub fn default_config_path() -> PathBuf {
ProjectDirs::from("dev", "git-sync", "git-sync") ProjectDirs::from("dev", APP_NAME, APP_NAME)
.map(|dirs| dirs.config_dir().join("config.toml")) .map(|dirs| dirs.config_dir().join("config.toml"))
.unwrap_or_else(|| PathBuf::from("git-sync.toml")) .unwrap_or_else(|| PathBuf::from("refray.toml"))
} }
pub fn default_work_dir() -> PathBuf { pub fn default_work_dir() -> PathBuf {
ProjectDirs::from("dev", "git-sync", "git-sync") ProjectDirs::from("dev", APP_NAME, APP_NAME)
.map(|dirs| dirs.cache_dir().join("mirrors")) .map(|dirs| dirs.cache_dir().join("mirrors"))
.unwrap_or_else(|| PathBuf::from(".git-sync-cache")) .unwrap_or_else(|| PathBuf::from(".refray-cache"))
} }
fn trim_end(value: &str) -> &str { fn trim_end(value: &str) -> &str {
+2 -2
View File
@@ -649,9 +649,9 @@ impl GitMirror {
"-C", "-C",
worktree.to_str().unwrap(), worktree.to_str().unwrap(),
"-c", "-c",
"user.name=git-sync", "user.name=refray",
"-c", "-c",
"user.email=git-sync@example.invalid", "user.email=refray@example.invalid",
] ]
.into_iter() .into_iter()
.chain(args), .chain(args),
+7 -7
View File
@@ -43,11 +43,11 @@ pub fn run_config_wizard(path: &Path) -> Result<()> {
let theme = ColorfulTheme::default(); let theme = ColorfulTheme::default();
println!(); println!();
println!("{}", style("git-sync configuration wizard").cyan().bold()); println!("{}", style("refray configuration wizard").cyan().bold());
let description = if existing_config { let description = if existing_config {
"Review, add, edit, or delete sync groups." "Review, add, edit, or delete sync groups."
} else { } else {
"Enter profile or organization URLs, then git-sync will build the mirror group." "Enter profile or organization URLs, then refray will build the mirror group."
}; };
println!("{}", style(description).dim()); println!("{}", style(description).dim());
println!(); println!();
@@ -214,7 +214,7 @@ fn prompt_webhook_setup_styled(config: &mut Config, theme: &ColorfulTheme) -> Re
style(DEFAULT_WEBHOOK_LISTEN).bold() style(DEFAULT_WEBHOOK_LISTEN).bold()
); );
println!( println!(
" {} If git-sync serve is already running there, you can continue.", " {} If refray serve is already running there, you can continue.",
style("-").yellow() style("-").yellow()
); );
None None
@@ -280,7 +280,7 @@ fn print_webhook_url_instructions() {
println!( println!(
" {} Start the receiver with: {}", " {} Start the receiver with: {}",
style("-").cyan(), style("-").cyan(),
style(format!("git-sync serve --listen {DEFAULT_WEBHOOK_LISTEN}")).bold() style(format!("refray serve --listen {DEFAULT_WEBHOOK_LISTEN}")).bold()
); );
println!( println!(
" {} The receiver accepts: {} and {}", " {} The receiver accepts: {} and {}",
@@ -360,7 +360,7 @@ fn respond_demo_webhook_request(request: Request) {
let (status, body) = if path == "/" || path == "/webhook" { let (status, body) = if path == "/" || path == "/webhook" {
( (
StatusCode(200), StatusCode(200),
"git-sync webhook setup listener\nThis temporary server only confirms that your public URL reaches this machine.\nAfter saving config, run git-sync serve for real webhooks.\n", "refray webhook setup listener\nThis temporary server only confirms that your public URL reaches this machine.\nAfter saving config, run refray serve for real webhooks.\n",
) )
} else { } else {
(StatusCode(404), "not found\n") (StatusCode(404), "not found\n")
@@ -706,7 +706,7 @@ fn prompt_conflict_resolution_styled(
]; ];
let default = existing.map(conflict_resolution_index).unwrap_or(3); let default = existing.map(conflict_resolution_index).unwrap_or(3);
let index = Select::with_theme(theme) let index = Select::with_theme(theme)
.with_prompt("How should git-sync resolve branch conflicts?") .with_prompt("How should refray resolve branch conflicts?")
.items(options) .items(options)
.default(default) .default(default)
.interact()?; .interact()?;
@@ -1136,7 +1136,7 @@ fn token_creation_url(provider: &ProviderKind, base_url: &str) -> String {
ProviderKind::Github => format!("{base}/settings/tokens"), ProviderKind::Github => format!("{base}/settings/tokens"),
ProviderKind::Gitlab => { ProviderKind::Gitlab => {
format!( format!(
"{base}/-/user_settings/personal_access_tokens?name=git-sync&scopes=api,write_repository" "{base}/-/user_settings/personal_access_tokens?name=refray&scopes=api,write_repository"
) )
} }
ProviderKind::Gitea => format!("{base}/user/settings/applications"), ProviderKind::Gitea => format!("{base}/user/settings/applications"),
+1 -1
View File
@@ -21,7 +21,7 @@ use crate::webhook::{
}; };
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(name = "git-sync")] #[command(name = "refray")]
#[command(about = "Mirror repositories between Git hosting providers")] #[command(about = "Mirror repositories between Git hosting providers")]
struct Cli { struct Cli {
#[arg(long, global = true, value_name = "PATH")] #[arg(long, global = true, value_name = "PATH")]
+1 -1
View File
@@ -848,7 +848,7 @@ impl<'a> ProviderClient<'a> {
request: reqwest::blocking::RequestBuilder, request: reqwest::blocking::RequestBuilder,
) -> Result<reqwest::blocking::RequestBuilder> { ) -> Result<reqwest::blocking::RequestBuilder> {
let mut headers = HeaderMap::new(); let mut headers = HeaderMap::new();
headers.insert(USER_AGENT, HeaderValue::from_static("git-sync/0.1")); headers.insert(USER_AGENT, HeaderValue::from_static("refray/0.1"));
headers.insert(ACCEPT, HeaderValue::from_static("application/json")); headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
match self.site.provider { match self.site.provider {
ProviderKind::Github => { ProviderKind::Github => {
+3 -3
View File
@@ -35,7 +35,7 @@ use self::state::{
}; };
pub const DEFAULT_JOBS: usize = 4; pub const DEFAULT_JOBS: usize = 4;
const CONFLICT_BRANCH_ROOT: &str = "git-sync/conflicts/"; const CONFLICT_BRANCH_ROOT: &str = "refray/conflicts/";
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SyncOptions { pub struct SyncOptions {
@@ -1018,11 +1018,11 @@ fn open_conflict_pull_requests(
}; };
mirror_repo.push_branch_updates(remotes, &[update])?; mirror_repo.push_branch_updates(remotes, &[update])?;
let title = format!( let title = format!(
"Resolve git-sync conflict: {} from {}", "Resolve refray conflict: {} from {}",
conflict.branch, source_remote conflict.branch, source_remote
); );
let body = format!( let body = format!(
"git-sync detected divergent branch tips and opened this pull request to merge {}@{} into {}@{}.", "refray detected divergent branch tips and opened this pull request to merge {}@{} into {}@{}.",
source_remote, source_remote,
short_sha(source_sha), short_sha(source_sha),
target_remote, target_remote,
+15 -15
View File
@@ -2,7 +2,7 @@ use super::*;
#[test] #[test]
fn cli_config_opens_wizard() { fn cli_config_opens_wizard() {
let cli = Cli::try_parse_from(["git-sync", "config"]).unwrap(); let cli = Cli::try_parse_from(["refray", "config"]).unwrap();
assert!(matches!(cli.command, Command::Config)); assert!(matches!(cli.command, Command::Config));
} }
@@ -10,11 +10,11 @@ fn cli_config_opens_wizard() {
#[test] #[test]
fn cli_rejects_removed_config_subcommands() { fn cli_rejects_removed_config_subcommands() {
for args in [ for args in [
["git-sync", "config", "wizard"].as_slice(), ["refray", "config", "wizard"].as_slice(),
["git-sync", "config", "init"].as_slice(), ["refray", "config", "init"].as_slice(),
["git-sync", "config", "show"].as_slice(), ["refray", "config", "show"].as_slice(),
["git-sync", "config", "site", "list"].as_slice(), ["refray", "config", "site", "list"].as_slice(),
["git-sync", "config", "mirror", "list"].as_slice(), ["refray", "config", "mirror", "list"].as_slice(),
] { ] {
assert!(Cli::try_parse_from(args).is_err()); assert!(Cli::try_parse_from(args).is_err());
} }
@@ -23,7 +23,7 @@ fn cli_rejects_removed_config_subcommands() {
#[test] #[test]
fn cli_accepts_sync_repo_pattern() { fn cli_accepts_sync_repo_pattern() {
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"git-sync", "refray",
"sync", "sync",
"--repo-pattern", "--repo-pattern",
"^(foo|bar)-", "^(foo|bar)-",
@@ -40,7 +40,7 @@ fn cli_accepts_sync_repo_pattern() {
#[test] #[test]
fn cli_accepts_sync_retry_failed() { fn cli_accepts_sync_retry_failed() {
let cli = Cli::try_parse_from(["git-sync", "sync", "--retry-failed"]).unwrap(); let cli = Cli::try_parse_from(["refray", "sync", "--retry-failed"]).unwrap();
let Command::Sync(args) = cli.command else { let Command::Sync(args) = cli.command else {
panic!("parsed unexpected command"); panic!("parsed unexpected command");
@@ -50,7 +50,7 @@ fn cli_accepts_sync_retry_failed() {
#[test] #[test]
fn cli_accepts_sync_jobs() { fn cli_accepts_sync_jobs() {
let cli = Cli::try_parse_from(["git-sync", "sync", "--jobs", "8"]).unwrap(); let cli = Cli::try_parse_from(["refray", "sync", "--jobs", "8"]).unwrap();
let Command::Sync(args) = cli.command else { let Command::Sync(args) = cli.command else {
panic!("parsed unexpected command"); panic!("parsed unexpected command");
@@ -61,7 +61,7 @@ fn cli_accepts_sync_jobs() {
#[test] #[test]
fn cli_accepts_webhook_serve() { fn cli_accepts_webhook_serve() {
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"git-sync", "refray",
"serve", "serve",
"--listen", "--listen",
"127.0.0.1:9000", "127.0.0.1:9000",
@@ -86,7 +86,7 @@ fn cli_accepts_webhook_serve() {
#[test] #[test]
fn cli_accepts_webhook_install() { fn cli_accepts_webhook_install() {
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"git-sync", "refray",
"webhook", "webhook",
"install", "install",
"repo-one", "repo-one",
@@ -118,7 +118,7 @@ fn cli_accepts_webhook_install() {
#[test] #[test]
fn cli_accepts_webhook_install_repo_pattern() { fn cli_accepts_webhook_install_repo_pattern() {
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"git-sync", "refray",
"webhook", "webhook",
"install", "install",
"--url", "--url",
@@ -140,7 +140,7 @@ fn cli_accepts_webhook_install_repo_pattern() {
#[test] #[test]
fn cli_accepts_webhook_uninstall() { fn cli_accepts_webhook_uninstall() {
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"git-sync", "refray",
"webhook", "webhook",
"uninstall", "uninstall",
"repo-one", "repo-one",
@@ -170,7 +170,7 @@ fn cli_accepts_webhook_uninstall() {
#[test] #[test]
fn cli_accepts_webhook_update() { fn cli_accepts_webhook_update() {
let cli = Cli::try_parse_from([ let cli = Cli::try_parse_from([
"git-sync", "refray",
"webhook", "webhook",
"update", "update",
"--url", "--url",
@@ -193,7 +193,7 @@ fn cli_accepts_webhook_update() {
#[test] #[test]
fn cli_rejects_scoped_webhook_update() { fn cli_rejects_scoped_webhook_update() {
let result = Cli::try_parse_from([ let result = Cli::try_parse_from([
"git-sync", "refray",
"webhook", "webhook",
"update", "update",
"repo-one", "repo-one",
+3 -3
View File
@@ -123,7 +123,7 @@ fn wizard_can_enable_webhooks() {
); );
let output = String::from_utf8(output).unwrap(); let output = String::from_utf8(output).unwrap();
assert!(output.contains("git-sync serve --listen 127.0.0.1:8787")); assert!(output.contains("refray serve --listen 127.0.0.1:8787"));
assert!(output.contains("cloudflared tunnel --url http://127.0.0.1:8787")); assert!(output.contains("cloudflared tunnel --url http://127.0.0.1:8787"));
assert!(output.contains("POST / and POST /webhook")); assert!(output.contains("POST / and POST /webhook"));
assert!(output.contains("temporary listener on 127.0.0.1:8787")); assert!(output.contains("temporary listener on 127.0.0.1:8787"));
@@ -539,7 +539,7 @@ fn token_creation_urls_are_provider_specific() {
); );
assert_eq!( assert_eq!(
token_creation_url(&ProviderKind::Gitlab, "https://gitlab.example.test"), token_creation_url(&ProviderKind::Gitlab, "https://gitlab.example.test"),
"https://gitlab.example.test/-/user_settings/personal_access_tokens?name=git-sync&scopes=api,write_repository" "https://gitlab.example.test/-/user_settings/personal_access_tokens?name=refray&scopes=api,write_repository"
); );
assert_eq!( assert_eq!(
token_creation_url(&ProviderKind::Gitea, "gitea.example.test"), token_creation_url(&ProviderKind::Gitea, "gitea.example.test"),
@@ -561,6 +561,6 @@ fn demo_webhook_server_answers_reachability_checks() {
response response
.text() .text()
.unwrap() .unwrap()
.contains("git-sync webhook setup listener") .contains("refray webhook setup listener")
); );
} }
+4 -4
View File
@@ -11,7 +11,7 @@ where
R: BufRead, R: BufRead,
W: Write, W: Write,
{ {
writeln!(writer, "git-sync configuration wizard")?; writeln!(writer, "refray configuration wizard")?;
if config.mirrors.is_empty() { if config.mirrors.is_empty() {
add_sync_group(reader, writer, &mut config)?; add_sync_group(reader, writer, &mut config)?;
write_sync_groups(&config, writer)?; write_sync_groups(&config, writer)?;
@@ -182,7 +182,7 @@ where
)?; )?;
writeln!( writeln!(
writer, writer,
"Start the receiver with: git-sync serve --listen 127.0.0.1:8787" "Start the receiver with: refray serve --listen 127.0.0.1:8787"
)?; )?;
writeln!(writer, "The receiver accepts: POST / and POST /webhook")?; writeln!(writer, "The receiver accepts: POST / and POST /webhook")?;
writeln!( writeln!(
@@ -195,7 +195,7 @@ where
)?; )?;
writeln!( writeln!(
writer, writer,
"During the real wizard, git-sync starts a temporary listener on 127.0.0.1:8787 so you can test the tunnel now." "During the real wizard, refray starts a temporary listener on 127.0.0.1:8787 so you can test the tunnel now."
)?; )?;
Ok(()) Ok(())
} }
@@ -431,7 +431,7 @@ where
.map(conflict_resolution_value) .map(conflict_resolution_value)
.unwrap_or("auto-rebase + pull-request"); .unwrap_or("auto-rebase + pull-request");
loop { loop {
writeln!(writer, "How should git-sync resolve branch conflicts?")?; writeln!(writer, "How should refray resolve branch conflicts?")?;
writeln!(writer, " 1. fail")?; writeln!(writer, " 1. fail")?;
writeln!(writer, " 2. auto-rebase and fail on file conflict")?; writeln!(writer, " 2. auto-rebase and fail on file conflict")?;
writeln!(writer, " 3. pull-request")?; writeln!(writer, " 3. pull-request")?;
+4 -4
View File
@@ -277,7 +277,7 @@ fn open_pull_request_posts_github_pull_when_missing() {
"request was {request}" "request was {request}"
); );
assert!(request.contains("Resolve conflict")); assert!(request.contains("Resolve conflict"));
assert!(request.contains("git-sync/conflicts/main/from-b-abc123")); assert!(request.contains("refray/conflicts/main/from-b-abc123"));
assert!(request.contains("main")); assert!(request.contains("main"));
} }
_ => unreachable!(), _ => unreachable!(),
@@ -305,7 +305,7 @@ fn open_pull_request_posts_github_pull_when_missing() {
&PullRequestRequest { &PullRequestRequest {
title: "Resolve conflict".to_string(), title: "Resolve conflict".to_string(),
body: "Body".to_string(), body: "Body".to_string(),
head_branch: "git-sync/conflicts/main/from-b-abc123".to_string(), head_branch: "refray/conflicts/main/from-b-abc123".to_string(),
base_branch: "main".to_string(), base_branch: "main".to_string(),
}, },
) )
@@ -321,7 +321,7 @@ fn close_pull_requests_by_head_prefix_closes_matching_github_pulls() {
vec![ vec![
( (
"200 OK", "200 OK",
r#"[{"number":7,"head":{"ref":"git-sync/conflicts/main/from-b-abc123"}},{"number":8,"head":{"ref":"feature"}}]"#, r#"[{"number":7,"head":{"ref":"refray/conflicts/main/from-b-abc123"}},{"number":8,"head":{"ref":"feature"}}]"#,
), ),
("200 OK", r#"{"number":7}"#), ("200 OK", r#"{"number":7}"#),
], ],
@@ -361,7 +361,7 @@ fn close_pull_requests_by_head_prefix_closes_matching_github_pulls() {
description: None, description: None,
}, },
"main", "main",
"git-sync/conflicts/main/", "refray/conflicts/main/",
) )
.unwrap(); .unwrap();
+1
View File
@@ -182,6 +182,7 @@ fn conflict_branch_prefixes_are_reversible_not_slug_collisions() {
assert_ne!(slash_branch, dash_branch); assert_ne!(slash_branch, dash_branch);
assert!(slash_branch.starts_with(CONFLICT_BRANCH_ROOT)); assert!(slash_branch.starts_with(CONFLICT_BRANCH_ROOT));
assert!(dash_branch.starts_with(CONFLICT_BRANCH_ROOT)); assert!(dash_branch.starts_with(CONFLICT_BRANCH_ROOT));
assert!(conflict_pr_branch("main", "gitea", "abc123").starts_with(CONFLICT_BRANCH_ROOT));
assert_eq!( assert_eq!(
conflict_pr_base_branch(&format!("{slash_branch}from-gitea-abc123")), conflict_pr_base_branch(&format!("{slash_branch}from-gitea-abc123")),
Some("release/foo".to_string()) Some("release/foo".to_string())