initial
This commit is contained in:
144
src/main.rs
Normal file
144
src/main.rs
Normal file
@@ -0,0 +1,144 @@
|
||||
use git2::build::{CheckoutBuilder, RepoBuilder};
|
||||
use git2::{Cred, FetchOptions, PushOptions, RemoteCallbacks};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml::Value;
|
||||
use tempdir::TempDir;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> eyre::Result<()> {
|
||||
dotenv::dotenv()?;
|
||||
color_eyre::install().unwrap();
|
||||
tracing_subscriber::fmt().pretty().init();
|
||||
|
||||
let matches = clap::Command::new("update-deployment")
|
||||
.arg(clap::Arg::new("repo").long("repo").required(true))
|
||||
.arg(clap::Arg::new("service").long("service").required(true))
|
||||
.arg(clap::Arg::new("image").long("image").required(true))
|
||||
.arg(clap::Arg::new("path").long("path"))
|
||||
.get_matches();
|
||||
|
||||
let repo = matches.get_one::<String>("repo").unwrap();
|
||||
let service = matches.get_one::<String>("service").unwrap();
|
||||
let image = matches.get_one::<String>("image").unwrap();
|
||||
let docker_compose_path = matches.get_one::<String>("path");
|
||||
|
||||
tracing::info!(
|
||||
repo = repo,
|
||||
service = service,
|
||||
image = image,
|
||||
path = docker_compose_path,
|
||||
"updating deployment"
|
||||
);
|
||||
|
||||
let tmpdir = TempDir::new("update-deployment")?;
|
||||
let tmpdir = tmpdir.path();
|
||||
|
||||
tracing::info!(
|
||||
repo = repo,
|
||||
dest_dir = tmpdir.display().to_string(),
|
||||
"clone repo"
|
||||
);
|
||||
|
||||
let mut cb = RemoteCallbacks::new();
|
||||
cb.credentials(|_, _, _| {
|
||||
let username = std::env::var("GIT_USERNAME").expect("GIT_USERNAME to be set");
|
||||
let password = std::env::var("GIT_PASSWORD").expect("GIT_PASSWORD to be set");
|
||||
Cred::userpass_plaintext(&username, &password)
|
||||
});
|
||||
let co = CheckoutBuilder::new();
|
||||
let mut fo = FetchOptions::new();
|
||||
fo.remote_callbacks(cb);
|
||||
RepoBuilder::new()
|
||||
.fetch_options(fo)
|
||||
.with_checkout(co)
|
||||
.clone(repo, tmpdir)?;
|
||||
|
||||
let mut repo_dir = tmpdir.to_path_buf();
|
||||
repo_dir.push("repo");
|
||||
|
||||
let repo = git2::Repository::clone(repo, &repo_dir)?;
|
||||
|
||||
let dir = std::fs::read_dir(&repo_dir)?;
|
||||
for file in dir {
|
||||
println!("file: {}", file?.file_name().to_str().unwrap());
|
||||
}
|
||||
|
||||
let (docker_compose_raw, docker_compose_path) =
|
||||
if let Some(docker_compose_path) = docker_compose_path {
|
||||
let mut path = repo_dir.clone();
|
||||
path.push(docker_compose_path);
|
||||
(tokio::fs::read(&path).await?, path)
|
||||
} else {
|
||||
let mut path = repo_dir.clone();
|
||||
path.push("docker-compose.yml");
|
||||
(tokio::fs::read(&path).await?, path)
|
||||
};
|
||||
|
||||
let mut docker_compose: DockerCompose = serde_yaml::from_slice(docker_compose_raw.as_slice())?;
|
||||
|
||||
tracing::info!(
|
||||
docker_compose = serde_json::to_string(&docker_compose)?,
|
||||
"found docker-compose.yml"
|
||||
);
|
||||
|
||||
let service = docker_compose.services.get_mut(service);
|
||||
if let Some(service) = service {
|
||||
if let Some(img) = service.image.as_mut() {
|
||||
*img = image.clone();
|
||||
}
|
||||
}
|
||||
|
||||
let dest_docker_compose = serde_yaml::to_string(&docker_compose)?;
|
||||
tokio::fs::write(docker_compose_path, dest_docker_compose).await?;
|
||||
|
||||
let tree_id = {
|
||||
let mut index = repo.index()?;
|
||||
index.add_all(&["."], git2::IndexAddOption::DEFAULT, None)?;
|
||||
index.write()?;
|
||||
index.write_tree()?
|
||||
};
|
||||
|
||||
let sig = repo.signature()?;
|
||||
let tree = repo.find_tree(tree_id)?;
|
||||
|
||||
let head = repo.head()?;
|
||||
let commit = head.peel_to_commit()?;
|
||||
|
||||
let _ = repo.commit(
|
||||
Some("HEAD"),
|
||||
&sig,
|
||||
&sig,
|
||||
"update: docker-compose",
|
||||
&tree,
|
||||
&[&commit],
|
||||
)?;
|
||||
|
||||
let mut remote = repo.find_remote("origin")?;
|
||||
let mut cb = RemoteCallbacks::new();
|
||||
cb.credentials(|_, _, _| {
|
||||
let username = std::env::var("GIT_USERNAME").expect("GIT_USERNAME to be set");
|
||||
let password = std::env::var("GIT_PASSWORD").expect("GIT_PASSWORD to be set");
|
||||
Cred::userpass_plaintext(&username, &password)
|
||||
});
|
||||
remote.push(
|
||||
&["HEAD:refs/heads/main"],
|
||||
Some(PushOptions::new().remote_callbacks(cb)),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
use std::collections::BTreeMap as Map;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
struct DockerCompose {
|
||||
#[serde(flatten)]
|
||||
pub other: Map<String, Value>,
|
||||
pub services: Map<String, Service>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
struct Service {
|
||||
pub image: Option<String>,
|
||||
#[serde(flatten)]
|
||||
pub other: Map<String, Value>,
|
||||
}
|
Reference in New Issue
Block a user