feat: add base dir to server

This commit is contained in:
2026-08-23 08:33:39 +05:00
parent 31bbeca941
commit 5126e10e9d
2 changed files with 68 additions and 1 deletions
+3 -1
View File
@@ -52,6 +52,7 @@ host = "195.0.2.10" # алиас из ~/.ssh/config или IP
port = 2222
user = "deploy"
key_path = "~/.ssh/id_ed25519"
base_dir = "/var/www/pages" # корень для относительных sync target
[projects.my-node-app]
server = "my-vps" # ссылка на профиль
@@ -65,7 +66,8 @@ commands = ["npm ci", "npm run build"]
[[projects.my-node-app.sync]] # что заливать на сервер
source = "dist" # файл или папка (относительно workdir)
target = "/var/www/pages"
target = "my-node-app" # относительный -> base_dir сервера;
# абсолютный "/path" используется как есть
[projects.my-node-app.remote] # команды управления на сервере
commands = ["pm2 restart pages"]
+65
View File
@@ -20,6 +20,7 @@ pub struct Config {
#[serde(deny_unknown_fields)]
pub struct Server {
pub host: String,
pub base_dir: Option<String>,
pub user: Option<String>,
pub port: Option<u16>,
pub key_path: Option<PathBuf>,
@@ -115,6 +116,30 @@ impl Config {
for rule in &mut project.sync {
rule.source = expand_tilde(&rule.source)
.with_context(|| format!("project '{name}': invalid sync source"))?;
rule.target = expand_tilde(&rule.target)
.with_context(|| format!("project '{name}': invalid sync target"))?;
}
let base_dir = project
.server
.as_ref()
.and_then(|s| servers.get(s))
.and_then(|s| s.base_dir.as_deref());
for rule in &mut project.sync {
if rule.target.to_string_lossy().starts_with('/') {
continue;
}
let Some(base) = base_dir else {
bail!(
"project '{name}': sync target '{}' is relative, but the referenced server has no 'base_dir'",
rule.target.display()
);
};
let rel = rule.target.to_string_lossy().replace('\\', "/");
rule.target = PathBuf::from(format!(
"{}/{}",
base.trim_end_matches('/'),
rel.trim_start_matches('/')
));
}
for key in project.env.keys() {
let valid = !key.is_empty()
@@ -292,6 +317,46 @@ workdir = "."
assert!(err.to_string().contains("no host"), "{err:#}");
}
#[test]
fn relative_sync_target_resolves_against_server_base_dir() {
let s = r#"
[servers.main]
host = "10.0.0.9"
base_dir = "/var/www/pages/"
[projects.web]
workdir = "."
server = "main"
[[projects.web.sync]]
source = "dist"
target = "web-app"
[[projects.web.sync]]
source = "dist/favicon.ico"
target = "/opt/static/favicon.ico"
"#;
let cfg = parse(s).unwrap();
let sync = &cfg.projects.get("web").unwrap().sync;
assert_eq!(sync[0].target.to_string_lossy(), "/var/www/pages/web-app");
assert_eq!(sync[1].target.to_string_lossy(), "/opt/static/favicon.ico");
}
#[test]
fn relative_sync_target_without_base_dir_is_error() {
let s = r#"
[projects.web]
workdir = "."
host = "10.0.0.9"
[[projects.web.sync]]
source = "dist"
target = "web-app"
"#;
let err = parse(s).unwrap_err();
assert!(err.to_string().contains("base_dir"), "{err:#}");
}
#[test]
fn empty_commands_section_is_rejected() {
let s = r#"