[+] Docker
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
/target
|
||||
/.git
|
||||
/.github
|
||||
.env
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
FROM rust:1-slim-bookworm AS build
|
||||
|
||||
WORKDIR /app
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
COPY src ./src
|
||||
RUN cargo build --release --locked
|
||||
|
||||
FROM debian:bookworm-slim AS runtime
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates git nano openssh-client vim \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& useradd --uid 10001 --create-home --home-dir /home/refray --shell /usr/sbin/nologin refray \
|
||||
&& mkdir -p /data \
|
||||
&& chown -R refray:refray /data
|
||||
|
||||
COPY --from=build /app/target/release/refray /usr/local/bin/refray
|
||||
|
||||
USER refray
|
||||
WORKDIR /data
|
||||
ENV XDG_CONFIG_HOME=/data/config \
|
||||
XDG_CACHE_HOME=/data/cache
|
||||
|
||||
EXPOSE 8787
|
||||
ENTRYPOINT ["refray"]
|
||||
CMD ["serve", "--listen", "0.0.0.0:8787"]
|
||||
@@ -1,6 +1,6 @@
|
||||
# refray
|
||||
|
||||
A tool to keep ALL of your repos in sync across ALL git platforms, while being able to work from any one of them.
|
||||
A tool to keep your repos in sync across all git platforms, while being able to work from everywhere all at once.
|
||||
|
||||
Created becasue github is so unusable and unreliable and I want to leave, but I don't want to leave the community behind.
|
||||
|
||||
@@ -22,6 +22,26 @@ Supported platforms: GitHub, GitLab, Gitea, Forgejo
|
||||
|
||||
Go to the [releases page](https://github.com/MaigoLabs/refray/releases), find the latest release, and download the appropriate binary for your platform.
|
||||
|
||||
### Option 3. Docker Compose
|
||||
|
||||
Run config wizard:
|
||||
|
||||
```sh
|
||||
docker compose run --rm refray config
|
||||
```
|
||||
|
||||
Start the webhook receiver as a service:
|
||||
|
||||
```sh
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
To edit config manually:
|
||||
|
||||
```sh
|
||||
docker compose run --rm --entrypoint nano refray /data/config/refray/config.toml
|
||||
```
|
||||
|
||||
## Configure
|
||||
|
||||
Run the interactive configuration wizard:
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
services:
|
||||
refray:
|
||||
build: .
|
||||
image: refray:local
|
||||
command: ["serve", "--listen", "0.0.0.0:8787"]
|
||||
ports:
|
||||
- "8787:8787"
|
||||
volumes:
|
||||
- refray-data:/data
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
refray-data:
|
||||
name: refray-data
|
||||
+25
-2
@@ -37,7 +37,7 @@ struct ParsedProfileUrl {
|
||||
namespace: String,
|
||||
}
|
||||
|
||||
pub fn run_config_wizard(path: &Path) -> Result<()> {
|
||||
pub fn run_config_wizard(path: &Path) -> Result<ConfigWizardOutcome> {
|
||||
let existing_config = path.exists();
|
||||
let mut config = Config::load_or_default(path)?;
|
||||
let theme = ColorfulTheme::default();
|
||||
@@ -85,7 +85,17 @@ pub fn run_config_wizard(path: &Path) -> Result<()> {
|
||||
style("saved").green().bold(),
|
||||
style(path.display()).cyan()
|
||||
);
|
||||
Ok(())
|
||||
let run_full_sync_now = prompt_run_full_sync_now_styled(&config, &theme)?;
|
||||
Ok(ConfigWizardOutcome {
|
||||
config,
|
||||
run_full_sync_now,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConfigWizardOutcome {
|
||||
pub config: Config,
|
||||
pub run_full_sync_now: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -389,6 +399,19 @@ fn prompt_wizard_action_styled(theme: &ColorfulTheme) -> Result<WizardAction> {
|
||||
})
|
||||
}
|
||||
|
||||
fn prompt_run_full_sync_now_styled(config: &Config, theme: &ColorfulTheme) -> Result<bool> {
|
||||
if config.mirrors.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
println!();
|
||||
Confirm::with_theme(theme)
|
||||
.with_prompt("Run full sync now?")
|
||||
.default(false)
|
||||
.interact()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
fn edit_sync_group_styled(config: &mut Config, theme: &ColorfulTheme) -> Result<bool> {
|
||||
if config.mirrors.is_empty() {
|
||||
println!("{}", style("No sync groups to edit.").yellow());
|
||||
|
||||
+8
-1
@@ -146,7 +146,14 @@ fn main() -> Result<()> {
|
||||
let config_path = cli.config.unwrap_or_else(default_config_path);
|
||||
|
||||
match cli.command {
|
||||
Command::Config => interactive::run_config_wizard(&config_path),
|
||||
Command::Config => {
|
||||
let outcome = interactive::run_config_wizard(&config_path)?;
|
||||
if outcome.run_full_sync_now {
|
||||
sync_all(&outcome.config, SyncOptions::default())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Command::Sync(command) => {
|
||||
let config = load_config(&config_path)?;
|
||||
sync_all(
|
||||
|
||||
@@ -219,6 +219,43 @@ fn wizard_starts_existing_config_at_sync_group_menu() {
|
||||
assert!(!output.contains("Profile/org URL:"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wizard_can_ask_to_run_full_sync_after_config() {
|
||||
let config = Config {
|
||||
sites: Vec::new(),
|
||||
mirrors: vec![MirrorConfig {
|
||||
name: "sync-1".to_string(),
|
||||
endpoints: Vec::new(),
|
||||
create_missing: true,
|
||||
visibility: Visibility::Private,
|
||||
allow_force: false,
|
||||
conflict_resolution: ConflictResolutionStrategy::Fail,
|
||||
}],
|
||||
webhook: None,
|
||||
};
|
||||
let mut reader = Cursor::new(b"y\n".as_slice());
|
||||
let mut output = Vec::new();
|
||||
|
||||
let run_full_sync =
|
||||
prompt_run_full_sync_now_with_io(&config, &mut reader, &mut output).unwrap();
|
||||
|
||||
assert!(run_full_sync);
|
||||
let output = String::from_utf8(output).unwrap();
|
||||
assert!(output.contains("Run full sync now? [y/N]:"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wizard_skips_full_sync_prompt_without_sync_groups() {
|
||||
let mut reader = Cursor::new(b"".as_slice());
|
||||
let mut output = Vec::new();
|
||||
|
||||
let run_full_sync =
|
||||
prompt_run_full_sync_now_with_io(&Config::default(), &mut reader, &mut output).unwrap();
|
||||
|
||||
assert!(!run_full_sync);
|
||||
assert!(output.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wizard_edits_existing_sync_group_from_menu() {
|
||||
let config = Config {
|
||||
|
||||
@@ -41,6 +41,22 @@ where
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn prompt_run_full_sync_now_with_io<R, W>(
|
||||
config: &Config,
|
||||
reader: &mut R,
|
||||
writer: &mut W,
|
||||
) -> Result<bool>
|
||||
where
|
||||
R: BufRead,
|
||||
W: Write,
|
||||
{
|
||||
if config.mirrors.is_empty() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
prompt_bool(reader, writer, "Run full sync now?", false)
|
||||
}
|
||||
|
||||
fn add_sync_group<R, W>(reader: &mut R, writer: &mut W, config: &mut Config) -> Result<()>
|
||||
where
|
||||
R: BufRead,
|
||||
|
||||
Reference in New Issue
Block a user