diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..d6028fd --- /dev/null +++ b/.drone.yml @@ -0,0 +1,170 @@ +kind: pipeline +name: default +type: docker + +steps: + - name: build ci + image: rustlang/rust:nightly + volumes: + - name: ci + path: /mnt/ci + environment: + PKG_CONFIG_SYSROOT_DIR: "/" + CI_PREFIX: "/mnt/ci" + commands: + - set -e + - apt update + - apt install musl-tools pkg-config libssl-dev openssl build-essential musl-dev -y + - rustup target add x86_64-unknown-linux-musl + - cargo build --target=x86_64-unknown-linux-musl -p ci + #- cargo build -p ci + - mv target/x86_64-unknown-linux-musl/debug/ci "$CI_PREFIX/ci" + #- mv target/debug/ci $CI_PREFIX/ci + + - name: load_secret + image: debian:buster-slim + volumes: + - name: ssh + path: /root/.ssh/ + environment: + SSH_KEY: + from_secret: gitea_id_ed25519 + commands: + - mkdir -p $HOME/.ssh/ + - echo "$SSH_KEY" | base64 -d > $HOME/.ssh/id_ed25519 + + - name: build pr + image: kasperhermansen/cuddle:latest + pull: always + volumes: + - name: ssh + path: /root/.ssh/ + - name: dockersock + path: /var/run + - name: ci + path: /mnt/ci + commands: + - eval `ssh-agent` + - chmod -R 600 ~/.ssh + - ssh-add + - echo "$DOCKER_PASSWORD" | docker login --password-stdin --username="$DOCKER_USERNAME" docker.io + - ldd $CI_PREFIX + - apk add git + - cuddle x ci:pr + environment: + DOCKER_BUILDKIT: 1 + DOCKER_PASSWORD: + from_secret: docker_password + DOCKER_USERNAME: + from_secret: docker_username + CUDDLE_SECRETS_PROVIDER: 1password + CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci" + CUDDLE_SSH_AGENT: "true" + CI_PREFIX: "/mnt/ci/ci" + CUDDLE_PLEASE_TOKEN: + from_secret: cuddle_please_token + OP_SERVICE_ACCOUNT_TOKEN: + from_secret: op_service_account_token + when: + event: + - pull_request + exclude: + - main + - master + depends_on: + - "load_secret" + - "build ci" + + - name: build main + image: kasperhermansen/cuddle:latest + pull: always + volumes: + - name: ssh + path: /root/.ssh/ + - name: dockersock + path: /var/run + - name: ci + path: /mnt/ci + commands: + - eval `ssh-agent` + - chmod -R 600 ~/.ssh + - ssh-add + - echo "$DOCKER_PASSWORD" | docker login --password-stdin --username="$DOCKER_USERNAME" docker.io + - ldd $CI_PREFIX + - apk add git + - cuddle x ci:main + environment: + DOCKER_BUILDKIT: 1 + DOCKER_PASSWORD: + from_secret: docker_password + DOCKER_USERNAME: + from_secret: docker_username + CUDDLE_SECRETS_PROVIDER: 1password + CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci" + CUDDLE_SSH_AGENT: "true" + CI_PREFIX: "/mnt/ci/ci" + CUDDLE_PLEASE_TOKEN: + from_secret: cuddle_please_token + OP_SERVICE_ACCOUNT_TOKEN: + from_secret: op_service_account_token + when: + event: + - push + branch: + - main + - master + exclude: + - pull_request + depends_on: + - "load_secret" + - "build ci" + + - name: deploy release + image: kasperhermansen/cuddle:latest + pull: always + volumes: + - name: ssh + path: /root/.ssh/ + - name: dockersock + path: /var/run + commands: + - eval `ssh-agent` + - chmod -R 600 ~/.ssh + - ssh-add + - cuddle x build:release:all + - cuddle x deploy:docs:preview + environment: + DOCKER_BUILDKIT: 1 + CUDDLE_SECRETS_PROVIDER: 1password + CUDDLE_ONE_PASSWORD_DOT_ENV: ".env.ci" + CUDDLE_SSH_AGENT: "true" + CUDDLE_CI: "true" + CUDDLE_PLEASE_TOKEN: + from_secret: cuddle_please_token + OP_SERVICE_ACCOUNT_TOKEN: + from_secret: op_service_account_token + when: + event: + - tag + ref: + include: + - refs/tags/v* + depends_on: + - "load_secret" + - "build ci" + +services: +- name: docker + image: docker:dind + privileged: true + volumes: + - name: dockersock + path: /var/run + +volumes: + - name: ssh + temp: {} + - name: dockersock + temp: {} + - name: ci + temp: {} \ No newline at end of file diff --git a/.gitignore b/.gitignore index ea8c4bf..9ac4405 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target +.env +.cuddle/ diff --git a/ci/src/main.rs b/ci/src/main.rs index 6d5f8d5..7c2e93e 100644 --- a/ci/src/main.rs +++ b/ci/src/main.rs @@ -7,10 +7,6 @@ use clap::Parser; use clap::Subcommand; use clap::ValueEnum; -use dagger_sdk::Platform; -use dagger_sdk::QueryContainerOpts; -use futures::StreamExt; - use crate::please_release::run_release_please; #[derive(Parser, Clone)] @@ -30,44 +26,15 @@ pub enum Commands { #[command(subcommand)] command: LocalCommands, }, - PullRequest { - #[arg(long)] - image: String, - #[arg(long)] - tag: String, - #[arg(long)] - bin_name: String, - }, - Main { - #[arg(long)] - image: String, - #[arg(long)] - tag: String, - #[arg(long)] - bin_name: String, - }, + PullRequest {}, + Main {}, Release, } #[derive(Subcommand, Clone)] pub enum LocalCommands { - Build { - #[arg(long, default_value = "debug")] - profile: BuildProfile, - #[arg(long)] - bin_name: String, - }, Test, - DockerImage { - #[arg(long)] - image: String, - #[arg(long)] - tag: String, - #[arg(long)] - bin_name: String, - }, PleaseRelease, - BuildDocs {}, } #[derive(Debug, Clone, ValueEnum)] @@ -84,23 +51,8 @@ pub struct GlobalArgs { #[arg(long, global = true, help_heading = "Global")] rust_builder_image: Option, - #[arg(long, global = true, help_heading = "Global")] - production_image: Option, - - #[arg(long, global = true, help_heading = "Global")] - mkdocs_image: Option, - - #[arg(long, global = true, help_heading = "Global")] - caddy_image: Option, - #[arg(long, global = true, help_heading = "Global")] source: Option, - - #[arg(long, global = true, help_heading = "Global")] - docs_image: Option, - - #[arg(long, global = true, help_heading = "Global")] - docs_image_tag: Option, } #[tokio::main] @@ -114,118 +66,35 @@ async fn main() -> eyre::Result<()> { match &cli.commands { Commands::Local { command } => match command { - LocalCommands::Build { - profile: _, - bin_name, - } => { - let base_image = base_rust_image( - client.clone(), - &cli.global, - &None, - &bin_name.clone(), - &"release".into(), - ) - .await?; - let prod_image = get_base_debian_image(client.clone(), &cli.global, None).await?; - build::execute( - client, - &cli.global, - &base_image, - &prod_image, - bin_name, - &None, - ) - .await?; - } LocalCommands::Test => { - let base_image = base_rust_image( - client.clone(), - &cli.global, - &None, - &"cuddle-please".into(), - &"debug".into(), - ) - .await?; + let base_image = + base_rust_image(client.clone(), &cli.global, &None, &"debug".into()).await?; test::execute(client, &cli.global, base_image).await?; } - LocalCommands::DockerImage { - tag, - image, - bin_name, - } => { - build::build_and_deploy(client, &cli.global, bin_name, image, tag).await?; - } LocalCommands::PleaseRelease => todo!(), - LocalCommands::BuildDocs {} => { - let _image = docs::execute( - client.clone(), - &cli.global, - &Some("linux/amd64".to_string()), - ) - .await?; - } }, - Commands::PullRequest { - image, - tag, - bin_name, - } => { - async fn test(client: Arc, cli: &Command, bin_name: &String) { + Commands::PullRequest {} => { + async fn test(client: Arc, cli: &Command) { let args = &cli.global; - let base_image = - base_rust_image(client.clone(), args, &None, bin_name, &"debug".into()) - .await - .unwrap(); + let base_image = base_rust_image(client.clone(), args, &None, &"debug".into()) + .await + .unwrap(); test::execute(client.clone(), args, base_image) .await .unwrap(); } - async fn build( - client: Arc, - cli: &Command, - bin_name: &String, - image: &String, - tag: &String, - ) { - let args = &cli.global; - build::build(client.clone(), args, bin_name, image, tag) - .await - .unwrap(); - } - - tokio::join!( - test(client.clone(), &cli, bin_name), - build(client.clone(), &cli, bin_name, image, tag), - ); + tokio::join!(test(client.clone(), &cli),); } - Commands::Main { - image, - tag, - bin_name, - } => { - async fn test(client: Arc, cli: &Command, bin_name: &String) { + Commands::Main {} => { + async fn test(client: Arc, cli: &Command) { let args = &cli.global; - let base_image = - base_rust_image(client.clone(), args, &None, bin_name, &"debug".into()) - .await - .unwrap(); - test::execute(client.clone(), args, base_image) + let base_image = base_rust_image(client.clone(), args, &None, &"debug".into()) .await .unwrap(); - } - async fn build( - client: Arc, - cli: &Command, - bin_name: &String, - image: &String, - tag: &String, - ) { - let args = &cli.global; - - build::build_and_deploy(client.clone(), args, bin_name, image, tag) + test::execute(client.clone(), args, base_image) .await .unwrap(); } @@ -237,8 +106,7 @@ async fn main() -> eyre::Result<()> { } tokio::join!( - test(client.clone(), &cli, bin_name), - build(client.clone(), &cli, bin_name, image, tag), + test(client.clone(), &cli), cuddle_please(client.clone(), &cli) ); } @@ -249,7 +117,6 @@ async fn main() -> eyre::Result<()> { } mod please_release { - use std::sync::Arc; use crate::{base_rust_image, GlobalArgs}; @@ -258,26 +125,13 @@ mod please_release { client: Arc, args: &GlobalArgs, ) -> eyre::Result<()> { - let base_image = base_rust_image( - client.clone(), - args, - &Some("linux/amd64".to_string()), - &"cuddle-please".to_string(), - &"release".into(), - ) - .await?; - - let build_image = base_image.with_exec(vec![ - "cargo", - "install", - "--target", - "x86_64-unknown-linux-gnu", - "--path=crates/cuddle-please", - ]); + let build_image = client + .container() + .from("kasperhermansen/cuddle-please:main-1691504183"); let src = client .git_opts( - "https://git.front.kjuulh.io/kjuulh/cuddle-please", + "https://git.front.kjuulh.io/kjuulh/dagger-components", dagger_sdk::QueryGitOpts { experimental_service_host: None, keep_git_dir: Some(true), @@ -302,7 +156,7 @@ mod please_release { "set-url", "origin", &format!( - "https://git:{}@git.front.kjuulh.io/kjuulh/cuddle-please.git", + "https://git:{}@git.front.kjuulh.io/kjuulh/dagger-components.git", std::env::var("CUDDLE_PLEASE_TOKEN")? ), ]) @@ -311,7 +165,7 @@ mod please_release { "release", "--engine=gitea", "--owner=kjuulh", - "--repo=cuddle-please", + "--repo=dagger-components", "--branch=main", "--api-url=https://git.front.kjuulh.io", "--log-level=debug", @@ -331,225 +185,6 @@ mod please_release { } } -mod docs { - use std::sync::Arc; - - use dagger_sdk::Container; - - use crate::GlobalArgs; - - pub fn get_docs_src(client: Arc) -> eyre::Result { - let docs_content = client.host().directory_opts( - ".", - dagger_sdk::HostDirectoryOpts { - exclude: None, - include: Some(vec!["mkdocs.yml", "docs/"]), - }, - ); - - Ok(docs_content) - } - - pub async fn execute( - client: Arc, - args: &GlobalArgs, - _platform: &Option, - ) -> eyre::Result { - let mkdocs_container = client.container().from( - args.mkdocs_image - .as_ref() - .expect("--mkdocs-image to be set"), - ); - - let built_mkdocs_container = mkdocs_container - .with_directory("/docs", get_docs_src(client.clone())?.id().await?) - .with_exec(vec!["build"]); - - let site_output = built_mkdocs_container.directory("/docs/site").id().await?; - - let caddy_file = client.host().directory("templates").file("Caddyfile"); - - let dep_image = client - .container() - .from(args.caddy_image.as_ref().expect("--caddy-image to be set")) - .with_directory("/usr/share/caddy", site_output) - .with_file("/etc/caddy/Caddyfile", caddy_file.id().await?) - .with_exec(vec!["echo", "caddy"]); - - Ok(dep_image) - } - - pub async fn publish( - client: Arc, - args: &GlobalArgs, - containers: &Vec, - ) -> eyre::Result<()> { - let container_ids = - futures::future::join_all(containers.iter().map(|c| c.id()).collect::>()).await; - - let container_ids = container_ids - .into_iter() - .collect::>>()?; - - client - .container() - .publish_opts( - format!( - "{}:{}", - args.docs_image.as_ref().expect("--docs-image to be set"), - args.docs_image_tag - .as_ref() - .expect("--docs-image-tag to be set") - ), - dagger_sdk::ContainerPublishOpts { - platform_variants: Some(container_ids), - }, - ) - .await?; - - Ok(()) - } -} - -mod build { - use std::sync::Arc; - - use dagger_sdk::Container; - - use crate::{base_rust_image, get_base_debian_image, GlobalArgs}; - - pub async fn build_and_deploy( - client: Arc, - args: &GlobalArgs, - bin_name: &String, - image: &String, - tag: &String, - ) -> eyre::Result<()> { - // let containers = vec!["linux/amd64", "linux/arm64"]; - - let base_image = get_base_debian_image( - client.clone(), - &args.clone(), - Some("linux/amd64".to_string()), - ) - .await?; - - let container = base_rust_image( - client.clone(), - args, - &Some("linux/amd64".to_string()), - &bin_name.clone(), - &"release".into(), - ) - .await?; - let build_image = execute( - client.clone(), - args, - &container, - &base_image, - bin_name, - &Some("linux/amd64".to_string()), - ) - .await?; - - let build_id = build_image.id().await?; - - let _container = client - .clone() - .container() - .publish_opts( - format!("{image}:{tag}"), - dagger_sdk::ContainerPublishOpts { - platform_variants: Some(vec![build_id]), - }, - ) - .await?; - Ok(()) - } - pub async fn build( - client: Arc, - args: &GlobalArgs, - bin_name: &String, - _image: &String, - _tag: &String, - ) -> eyre::Result<()> { - // let containers = vec!["linux/amd64", "linux/arm64"]; - - let base_image = get_base_debian_image( - client.clone(), - &args.clone(), - Some("linux/amd64".to_string()), - ) - .await?; - - let container = base_rust_image( - client.clone(), - args, - &Some("linux/amd64".to_string()), - &bin_name.clone(), - &"release".into(), - ) - .await?; - let build_image = execute( - client.clone(), - args, - &container, - &base_image, - bin_name, - &Some("linux/amd64".to_string()), - ) - .await?; - - build_image.exit_code().await?; - - Ok(()) - } - pub async fn execute( - _client: Arc, - _args: &GlobalArgs, - container: &dagger_sdk::Container, - base_image: &dagger_sdk::Container, - bin_name: &String, - platform: &Option, - ) -> eyre::Result { - let rust_target = match platform - .clone() - .unwrap_or("linux/amd64".to_string()) - .as_str() - { - "linux/amd64" => "x86_64-unknown-linux-gnu", - "linux/arm64" => "aarch64-unknown-linux-gnu", - _ => eyre::bail!("architecture not supported"), - }; - let build_image = container.with_exec(vec![ - "cargo", - "build", - "--target", - rust_target, - "--release", - "-p", - bin_name, - ]); - - let final_image = base_image - .with_file( - format!("/usr/local/bin/{}", &bin_name), - build_image - .file(format!("target/{}/release/{}", rust_target, &bin_name)) - .id() - .await?, - ) - .with_exec(vec![bin_name, "--help"]); - - let output = final_image.stdout().await?; - println!("{output}"); - - //.with_entrypoint(vec![&bin_name, "--log-level=debug"]); - - Ok(final_image) - } -} - mod test { use std::sync::Arc; @@ -566,45 +201,17 @@ mod test { .with_exec(vec!["apt", "install", "-y", "git"]) .with_exec(vec!["cargo", "test"]); + let please_out = test_image.stdout().await?; + println!("{please_out}"); + let please_out = test_image.stderr().await?; + println!("{please_out}"); + test_image.exit_code().await?; Ok(()) } } -pub async fn get_base_debian_image( - client: Arc, - args: &GlobalArgs, - platform: Option, -) -> eyre::Result { - let default_platform = client.default_platform().await?; - let platform = platform.map(Platform).unwrap_or(default_platform); - - let image = client - .container_opts(QueryContainerOpts { - id: None, - platform: Some(platform), - }) - .from( - args.production_image - .clone() - .unwrap_or("debian:bullseye".to_string()), - ); - - let base_image = image.with_exec(vec!["apt", "update"]).with_exec(vec![ - "apt", - "install", - "-y", - "libssl-dev", - "pkg-config", - "openssl", - "git", - "jq", - ]); - - Ok(base_image) -} - pub fn get_src( client: Arc, args: &GlobalArgs, @@ -695,7 +302,6 @@ pub async fn base_rust_image( client: Arc, args: &GlobalArgs, platform: &Option, - bin_name: &String, profile: &String, ) -> eyre::Result { let dep_src = get_rust_dep_src(client.clone(), args).await?; @@ -725,7 +331,7 @@ pub async fn base_rust_image( .with_exec(vec!["apt", "install", "-y", "jq"]); let target_cache = client.cache_volume(format!("rust_target_{}", profile)); - let mut build_options = vec!["cargo", "build", "--target", rust_target, "-p", bin_name]; + let mut build_options = vec!["cargo", "build", "--target", rust_target]; if profile == "release" { build_options.push("--release"); diff --git a/cuddle.yaml b/cuddle.yaml index 41d8983..baaaed2 100644 --- a/cuddle.yaml +++ b/cuddle.yaml @@ -13,3 +13,12 @@ please: branch: main settings: api_url: https://git.front.kjuulh.io + +scripts: + "ci:main": + type: shell + "ci:pr": + type: shell + "ci:release": + type: shell + diff --git a/scripts/ci:main.sh b/scripts/ci:main.sh new file mode 100755 index 0000000..927b48c --- /dev/null +++ b/scripts/ci:main.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +CMD_PREFIX="cargo run -p ci --" + +if [[ -n "$CI_PREFIX" ]]; then + CMD_PREFIX="$CI_PREFIX" +fi + + +$CMD_PREFIX main diff --git a/scripts/ci:pr.sh b/scripts/ci:pr.sh new file mode 100755 index 0000000..530bd01 --- /dev/null +++ b/scripts/ci:pr.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -e + +CMD_PREFIX="cargo run -p ci --" + +if [[ -n "$CI_PREFIX" ]]; then + CMD_PREFIX="$CI_PREFIX" +fi + + +$CMD_PREFIX pull-request \ + --mkdocs-image "$MKDOCS_IMAGE" \ + --caddy-image "$CADDY_IMAGE" \ + --image "$REGISTRY/$SERVICE" \ + --tag "main-$(date +%s)" \ + --bin-name "$SERVICE" \ No newline at end of file