use crate::platform::design::Design;
pub fn app_slug(design: &Design) -> String {
let mut s = String::with_capacity(design.name.len());
let mut prev_dash = false;
for c in design.name.to_ascii_lowercase().chars() {
if c.is_ascii_alphanumeric() {
s.push(c);
prev_dash = false;
} else if !prev_dash && !s.is_empty() {
s.push('-');
prev_dash = true;
}
}
let slug = s.trim_matches('-');
if slug.is_empty() {
"app".to_string()
} else {
slug.to_string()
}
}
const DEPLOY_SH: &str = include_str!("templates/render-deploy.sh");
const TEARDOWN_SH: &str = include_str!("templates/render-teardown.sh");
const RENDER_YAML: &str = include_str!("templates/render.yaml");
const README_MD: &str = include_str!("templates/render-README.md");
pub fn artifacts(design: &Design) -> Vec<(String, String)> {
let slug = app_slug(design);
let fill = |t: &str| t.replace("{{APP_SLUG}}", &slug);
vec![
("deploy/render/deploy.sh".into(), fill(DEPLOY_SH)),
("deploy/render/teardown.sh".into(), fill(TEARDOWN_SH)),
("deploy/render/render.yaml".into(), fill(RENDER_YAML)),
("deploy/render/README.md".into(), fill(README_MD)),
(
"deploy/render/Dockerfile".into(),
crate::platform::package::dockerfile(design),
),
]
}
#[cfg(test)]
mod tests {
use super::*;
fn design_named(name: &str) -> Design {
serde_json::from_value(serde_json::json!({
"name": name, "contract_version": 1, "modules": []
}))
.expect("minimal design")
}
#[test]
fn app_slug_slugifies_and_collapses() {
assert_eq!(app_slug(&design_named("Acme API")), "acme-api");
assert_eq!(app_slug(&design_named(" My__Cool App!! ")), "my-cool-app");
assert_eq!(app_slug(&design_named("already-slug")), "already-slug");
}
#[test]
fn app_slug_falls_back_to_app_when_no_alphanumerics() {
assert_eq!(app_slug(&design_named("!!! ___ ---")), "app");
assert_eq!(app_slug(&design_named("")), "app");
}
}