feat: add base dir to server
This commit is contained in:
@@ -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"]
|
||||
|
||||
@@ -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#"
|
||||
|
||||
Reference in New Issue
Block a user