From efe37f020a949de2b5258593641dcc4b22273a66 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sat, 28 Sep 2024 21:50:50 -0400 Subject: [PATCH] Generate names for pipeline runs. --- docker/webhook_bridge_development/Dockerfile | 6 +- example_webhook_payload.json | 66 ++++++++++++++------ src/kubernetes.rs | 55 +++++++++++++++- src/main.rs | 7 ++- 4 files changed, 108 insertions(+), 26 deletions(-) diff --git a/docker/webhook_bridge_development/Dockerfile b/docker/webhook_bridge_development/Dockerfile index d430052..7f6a62d 100644 --- a/docker/webhook_bridge_development/Dockerfile +++ b/docker/webhook_bridge_development/Dockerfile @@ -1,6 +1,6 @@ -FROM rustlang/rust:nightly-alpine3.19 AS builder - -RUN apk add --no-cache musl-dev pkgconfig +FROM rustlang/rust:nightly-alpine3.20 AS builder +#openssl-dev +RUN apk add --no-cache musl-dev pkgconfig libressl3.8-libssl libressl-dev RUN cargo install --locked --no-default-features --features ci-autoclean cargo-cache RUN rustup component add rustfmt RUN rustup component add clippy diff --git a/example_webhook_payload.json b/example_webhook_payload.json index 4079cd1..9530633 100644 --- a/example_webhook_payload.json +++ b/example_webhook_payload.json @@ -1,13 +1,13 @@ { "ref": "refs/heads/main", - "before": "d5902e3e7f62cbd86e095437ccc33e945fcb0791", - "after": "b8444344c4821e87a894cd195f8bec39cd501f68", - "compare_url": "https://code.fizz.buzz/talexander/webhook_bridge/compare/d5902e3e7f62cbd86e095437ccc33e945fcb0791...b8444344c4821e87a894cd195f8bec39cd501f68", + "before": "b8444344c4821e87a894cd195f8bec39cd501f68", + "after": "470031251cc4f7d70227140f7edde09b53c372c4", + "compare_url": "https://code.fizz.buzz/talexander/webhook_bridge/compare/b8444344c4821e87a894cd195f8bec39cd501f68...470031251cc4f7d70227140f7edde09b53c372c4", "commits": [ { - "id": "b8444344c4821e87a894cd195f8bec39cd501f68", - "message": "Update PipelineRun to tekton v1 from v1beta.\n", - "url": "https://code.fizz.buzz/talexander/webhook_bridge/commit/b8444344c4821e87a894cd195f8bec39cd501f68", + "id": "470031251cc4f7d70227140f7edde09b53c372c4", + "message": "Remove prettier.\n", + "url": "https://code.fizz.buzz/talexander/webhook_bridge/commit/470031251cc4f7d70227140f7edde09b53c372c4", "author": { "name": "Tom Alexander", "email": "tom@fizz.buzz", @@ -19,21 +19,52 @@ "username": "" }, "verification": null, - "timestamp": "2024-09-28T20:33:35-04:00", + "timestamp": "2024-09-28T21:46:25-04:00", "added": [], "removed": [], "modified": [ ".webhook_bridge/pipeline-format.yaml", - ".webhook_bridge/pipeline-rust-clippy.yaml", - ".webhook_bridge/pipeline-rust-test.yaml" + "docker/webhook_bridge_development/Dockerfile" + ] + }, + { + "id": "ed1e1c08d08eb271fa7af35c22b4c9bfbc0d6224", + "message": "Create PipelineRun in response to webhook triggers.\n", + "url": "https://code.fizz.buzz/talexander/webhook_bridge/commit/ed1e1c08d08eb271fa7af35c22b4c9bfbc0d6224", + "author": { + "name": "Tom Alexander", + "email": "tom@fizz.buzz", + "username": "" + }, + "committer": { + "name": "Tom Alexander", + "email": "tom@fizz.buzz", + "username": "" + }, + "verification": null, + "timestamp": "2024-09-28T19:43:26-04:00", + "added": [ + "example_webhook_payload.json", + "src/kubernetes.rs" + ], + "removed": [ + "example_pipeline_run.json", + "example_pipeline_run.yaml" + ], + "modified": [ + "src/crd_pipeline_run.rs", + "src/gitea_client/mod.rs", + "src/hook_push.rs", + "src/in_repo_config.rs", + "src/main.rs" ] } ], - "total_commits": 1, + "total_commits": 2, "head_commit": { - "id": "b8444344c4821e87a894cd195f8bec39cd501f68", - "message": "Update PipelineRun to tekton v1 from v1beta.\n", - "url": "https://code.fizz.buzz/talexander/webhook_bridge/commit/b8444344c4821e87a894cd195f8bec39cd501f68", + "id": "470031251cc4f7d70227140f7edde09b53c372c4", + "message": "Remove prettier.\n", + "url": "https://code.fizz.buzz/talexander/webhook_bridge/commit/470031251cc4f7d70227140f7edde09b53c372c4", "author": { "name": "Tom Alexander", "email": "tom@fizz.buzz", @@ -45,13 +76,12 @@ "username": "" }, "verification": null, - "timestamp": "2024-09-28T20:33:35-04:00", + "timestamp": "2024-09-28T21:46:25-04:00", "added": [], "removed": [], "modified": [ ".webhook_bridge/pipeline-format.yaml", - ".webhook_bridge/pipeline-rust-clippy.yaml", - ".webhook_bridge/pipeline-rust-test.yaml" + "docker/webhook_bridge_development/Dockerfile" ] }, "repository": { @@ -88,7 +118,7 @@ "template": false, "parent": null, "mirror": false, - "size": 286, + "size": 293, "language": "", "languages_url": "https://code.fizz.buzz/api/v1/repos/talexander/webhook_bridge/languages", "html_url": "https://code.fizz.buzz/talexander/webhook_bridge", @@ -107,7 +137,7 @@ "default_branch": "main", "archived": false, "created_at": "2024-07-14T18:48:52Z", - "updated_at": "2024-09-28T23:43:53Z", + "updated_at": "2024-09-29T00:34:06Z", "archived_at": "1970-01-01T00:00:00Z", "permissions": { "admin": true, diff --git a/src/kubernetes.rs b/src/kubernetes.rs index 3de7b6f..415c3f0 100644 --- a/src/kubernetes.rs +++ b/src/kubernetes.rs @@ -1,7 +1,12 @@ +use std::borrow::Borrow; +use std::borrow::Cow; + use kube::api::PostParams; use kube::Api; use kube::CustomResourceExt; +use regex::Regex; use tracing::debug; +use tracing::info; use crate::crd_pipeline_run::PipelineParam; use crate::crd_pipeline_run::PipelineRun; @@ -16,7 +21,7 @@ pub(crate) async fn run_pipelines( ) -> Result<(), Box> { let jobs: Api = Api::namespaced(kubernetes_client, "lighthouse"); // let jobs: Api = Api::default_namespaced(kubernetes_client); - tracing::info!("Using crd: {}", serde_json::to_string(&PipelineRun::crd())?); + tracing::debug!("Using crd: {}", serde_json::to_string(&PipelineRun::crd())?); for mut pipeline in pipelines { debug!("Kicking off {}", pipeline.name); @@ -26,7 +31,7 @@ pub(crate) async fn run_pipelines( if let Some(param_list) = pipeline.pipeline.spec.params.as_mut() { param_list.push(PipelineParam { name: Some("JOB_NAME".to_owned()), - value: Some(serde_json::Value::String(pipeline.name)), + value: Some(serde_json::Value::String(pipeline.name.clone())), }); param_list.push(PipelineParam { name: Some("REPO_OWNER".to_owned()), @@ -61,9 +66,55 @@ pub(crate) async fn run_pipelines( )), }); } + if pipeline.pipeline.metadata.generate_name.is_none() + && pipeline.pipeline.metadata.name.is_some() + { + std::mem::swap( + &mut pipeline.pipeline.metadata.generate_name, + &mut pipeline.pipeline.metadata.name, + ); + if let Some(ref mut name) = pipeline.pipeline.metadata.generate_name { + let mut new_name_stub = sanitize_kubernetes_identifier(format!( + "{}-{}-{}", + name, + hook.get_repo_name()?, + hook.get_repo_owner()? + ))? + .into_owned(); + new_name_stub.truncate(63); + (*name) = new_name_stub + "-"; + debug!("Using generate name: {}", name); + } + } let pp = PostParams::default(); let created_run = jobs.create(&pp, &pipeline.pipeline).await?; + info!("Created PipelineRun {:?}", created_run.metadata.name); } Ok(()) } + +fn sanitize_kubernetes_identifier<'a, O: Into>>( + original: O, +) -> Result, Box> { + let validate_identifier_regex = + Regex::new(r"[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*")?; + let original = original.into(); + if !validate_identifier_regex.is_match(original.borrow()) { + return Ok(original); + } + + let mut clean_identifier = String::with_capacity(original.len()); + for c in original.chars() { + match c { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '.' | '-' => { + clean_identifier.push(c); + } + _ => { + clean_identifier.push('-'); + } + }; + } + + Ok(Cow::Owned(clean_identifier)) +} diff --git a/src/main.rs b/src/main.rs index 2cea010..da8ed04 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![forbid(unsafe_code)] +use std::borrow::Borrow; use std::sync::Arc; use std::time::Duration; @@ -23,6 +24,7 @@ use self::discovery::discover_matching_push_triggers; use self::discovery::discover_webhook_bridge_config; use self::gitea_client::GiteaClient; use self::hook_push::HookPush; +use self::hook_push::PipelineParamters; use self::in_repo_config::InRepoConfig; use self::kubernetes::run_pipelines; use self::webhook::hook; @@ -58,11 +60,12 @@ async fn main() -> Result<(), Box> { let gitea_api_token = std::env::var("WEBHOOK_BRIDGE_OAUTH_TOKEN")?; let gitea = GiteaClient::new(gitea_api_root, gitea_api_token); + let webhook_payload: HookPush = serde_json::from_str(EXAMPLE_WEBHOOK_PAYLOAD)?; let repo_tree = gitea .get_tree( "talexander", "webhook_bridge", - "b8444344c4821e87a894cd195f8bec39cd501f68", + webhook_payload.get_pull_base_sha()?, ) .await?; let in_repo_config = discover_webhook_bridge_config(&gitea, &repo_tree).await?; @@ -70,8 +73,6 @@ async fn main() -> Result<(), Box> { discover_matching_push_triggers(&gitea, &repo_tree, "refs/heads/main", &in_repo_config) .await?; - let webhook_payload: HookPush = serde_json::from_str(EXAMPLE_WEBHOOK_PAYLOAD)?; - run_pipelines(webhook_payload, pipelines, kubernetes_client).await?; // let app = Router::new()