initial
This commit is contained in:
commit
79ef3ecc43
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
.env
|
||||||
|
target/
|
1067
Cargo.lock
generated
Normal file
1067
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
23
Cargo.toml
Normal file
23
Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "update-deployment"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = "4.2.1"
|
||||||
|
color-eyre = "0.6.2"
|
||||||
|
dotenv = "0.15.0"
|
||||||
|
eyre = "0.6.8"
|
||||||
|
git2 = { version = "0.16.1", features = [
|
||||||
|
"vendored-libgit2",
|
||||||
|
"vendored-openssl",
|
||||||
|
] }
|
||||||
|
serde = { version = "1.0.159", features = ["derive"] }
|
||||||
|
serde_json = "1.0.95"
|
||||||
|
serde_yaml = "0.9.19"
|
||||||
|
tempdir = "0.3.7"
|
||||||
|
tokio = { version = "1.27.0", features = ["full"] }
|
||||||
|
tracing = { version = "0.1.37", features = ["log"] }
|
||||||
|
tracing-subscriber = "0.3.16"
|
9
build.sh
Executable file
9
build.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
pushd ci || exit
|
||||||
|
|
||||||
|
cargo build
|
||||||
|
|
||||||
|
popd || exit
|
||||||
|
|
||||||
|
./ci/target/debug/ci
|
2157
ci/Cargo.lock
generated
Normal file
2157
ci/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
ci/Cargo.toml
Normal file
14
ci/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "ci"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
chrono = "0.4.24"
|
||||||
|
color-eyre = "0.6.2"
|
||||||
|
dagger-sdk = "0.2.19"
|
||||||
|
eyre = "0.6.8"
|
||||||
|
tokio = { version = "1.27.0", features = ["full"] }
|
||||||
|
tokio-scoped = "0.2.0"
|
84
ci/src/main.rs
Normal file
84
ci/src/main.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use dagger_sdk::{HostDirectoryOptsBuilder, QueryContainerOptsBuilder};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> eyre::Result<()> {
|
||||||
|
color_eyre::install().unwrap();
|
||||||
|
|
||||||
|
let client = dagger_sdk::connect().await?;
|
||||||
|
|
||||||
|
let src = client.host().directory_opts(
|
||||||
|
".",
|
||||||
|
HostDirectoryOptsBuilder::default()
|
||||||
|
.exclude(vec!["target/", ".git/"])
|
||||||
|
.build()?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let variants = vec!["linux/amd64", "linux/arm64"];
|
||||||
|
let platform_variants = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
|
||||||
|
tokio_scoped::scope(|s| {
|
||||||
|
for platform in variants {
|
||||||
|
let client = client.clone();
|
||||||
|
let platform_variants = platform_variants.clone();
|
||||||
|
let src = src.clone();
|
||||||
|
|
||||||
|
s.spawn(async move {
|
||||||
|
let rust_dep_image = client
|
||||||
|
.container_opts(
|
||||||
|
QueryContainerOptsBuilder::default()
|
||||||
|
.platform(platform)
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.from("rustlang/rust:nightly")
|
||||||
|
.with_workdir("/app")
|
||||||
|
.with_directory(".", src.id().await.unwrap())
|
||||||
|
.with_exec(vec!["cargo", "build", "--release"]);
|
||||||
|
|
||||||
|
let dep_image = client
|
||||||
|
.container_opts(
|
||||||
|
QueryContainerOptsBuilder::default()
|
||||||
|
.platform(platform)
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.from("debian:bullseye")
|
||||||
|
.with_file(
|
||||||
|
"/usr/bin/update-deployment",
|
||||||
|
rust_dep_image
|
||||||
|
.file("target/release/update-deployment")
|
||||||
|
.id()
|
||||||
|
.await
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut platform_variants = platform_variants.lock().await;
|
||||||
|
platform_variants.push(dep_image.id().await.unwrap())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let variants = platform_variants
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.iter()
|
||||||
|
.map(|c| c.clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let tag = chrono::Utc::now().timestamp();
|
||||||
|
|
||||||
|
let _ = client
|
||||||
|
.container()
|
||||||
|
.publish_opts(
|
||||||
|
format!("kasperhermansen/update-deployment:{tag}"),
|
||||||
|
dagger_sdk::ContainerPublishOptsBuilder::default()
|
||||||
|
.platform_variants(variants)
|
||||||
|
.build()?,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
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>,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user