use colored::Colorize;
use crate::entities::environment::RunEnvironment;
use crate::entities::gitlab_cicd_opts::GitLabOpts;
use crate::pipelines::DescribedPipeline;
use crate::project::DeployerProjectOptions;
const GL_CICD_TEMPLATE: &str = r#"# Generated by Deployer 2.X
variables:
TERM: xterm
{cache-rules}
{pipeline-title}:{base-image}{preflight-cmds}{artifacts}{trigger-rules}
stage: deployer
script:
- chmod +x .gitlab/workflows/{shell-script-path}
- sh ./.gitlab/workflows/{shell-script-path}
"#;
pub fn export(
config: &DeployerProjectOptions,
pipeline: &DescribedPipeline,
gl_opts: Option<&GitLabOpts>,
env: &RunEnvironment<'_>,
shell_script: &str,
output_dir: Option<&str>,
) -> anyhow::Result<()> {
let gl_dir = if let Some(output) = output_dir {
let dir = std::path::PathBuf::from(output);
let _ = std::fs::create_dir_all(dir.as_path());
dir
} else {
let dir = env
.project_dir
.ok_or(anyhow::anyhow!("Can't get project dir!"))?
.join(".gitlab")
.join("workflows");
let _ = std::fs::create_dir_all(dir.as_path());
dir
};
let pipe_filename = format!(".pipe.{}.sh", env.master_pipeline);
std::fs::write(gl_dir.join(pipe_filename.as_str()), shell_script)?;
let trigger_rules = if gl_opts.is_none_or(|gl_opts| gl_opts.rules.is_empty()) {
"\n rules:\n - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH".to_string()
} else if gl_opts.unwrap().rules.is_empty() {
"".to_string()
} else {
format!(
"\n rules:{}",
gl_opts
.unwrap()
.rules
.iter()
.map(|r| format!("\n - if: {r}"))
.collect::<Vec<_>>()
.join(""),
)
};
let artifacts_actions = if !pipeline.artifacts.is_empty() {
format!(
"\n artifacts:\n paths:{}",
pipeline
.artifacts
.iter()
.map(|a| format!("\n - {}", a.from))
.collect::<Vec<_>>()
.join("")
)
} else {
String::new()
};
let preflight_cmds = if let Some(gl_opts) = gl_opts
&& !gl_opts.preflight_cmds.is_empty()
{
format!(
"\n before_script:\n - |{}",
gl_opts
.preflight_cmds
.iter()
.map(|s| format!("\n {s}"))
.collect::<Vec<_>>()
.join("")
)
} else {
String::new()
};
let cache_rules = if gl_opts.is_none_or(|gl_opts| gl_opts.enable_cache) && !config.cache_files.is_empty() {
let mut cache_files: std::collections::BTreeSet<_> = config.cache_files.iter().collect();
cache_files.remove(&std::path::PathBuf::from(".git"));
let cache_files = cache_files
.iter()
.map(|cf| {
format!(
"\n - {}",
cf.to_str().expect("`cache_file` contains non-UTF8 symbols!")
)
})
.collect::<Vec<_>>()
.join("");
format!("\ncache:\n key: \"${{CI_COMMIT_REF_SLUG}}\"\n paths:{cache_files}\n")
} else {
String::new()
};
let cicd_script = GL_CICD_TEMPLATE
.replace("{pipeline-title}", env.master_pipeline)
.replace("{shell-script-path}", pipe_filename.as_str())
.replace("{trigger-rules}", trigger_rules.as_str())
.replace(
"{base-image}",
&format!(
"\n image: {}",
gl_opts
.map(|gl_opts| gl_opts.base_image.as_deref().unwrap_or("ubuntu:latest"))
.unwrap_or("ubuntu:latest")
),
)
.replace("{artifacts}", artifacts_actions.as_str())
.replace("{preflight-cmds}", preflight_cmds.as_str())
.replace("{cache-rules}", cache_rules.as_str());
let cicd_filename = format!("{}.yml", env.master_pipeline);
std::fs::write(gl_dir.join(cicd_filename.as_str()), cicd_script.as_str())?;
println!(
"{}",
"Don't forget to add the following lines to `.gitlab-ci.yml`:".red()
);
println!(
"{}",
format!("include:\n - local: '.gitlab/workflows/{cicd_filename}'\n\nstages:\n - deployer")
.as_str()
.blue()
);
Ok(())
}