diff --git a/README.md b/README.md index 22f887a..877664d 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,4 @@ The plan forward, roughly in falling priority: - [ ] lock state so that many kitops instances can collaborate - [ ] support Amazon S3 as state store - [ ] support Azure Blob storage as state store -- [ ] GitHub app for checking out private repo +- [x] GitHub app for checking out private repo diff --git a/src/opts.rs b/src/opts.rs index 3844f53..6651fc8 100644 --- a/src/opts.rs +++ b/src/opts.rs @@ -40,16 +40,13 @@ pub struct CliOptions { /// Environment variable for action #[clap(long)] pub environment: Vec, - /// GitHub App ID + /// GitHub App ID for authentication with private repos and commit status updates #[clap(long)] pub github_app_id: Option, /// GitHub App private key file #[clap(long)] pub github_private_key_file: Option, - /// Update GitHub commit status on this repo - #[clap(long)] - pub github_repo_slug: Option, - /// Use this context when updating GitHub commit status + /// Turn on updating GitHub commit status with this context (requires auth flags) #[clap(long)] pub github_context: Option, /// Check repo for changes at this interval (e.g. 1h, 30m, 10s) @@ -101,13 +98,17 @@ struct ConfigFile { fn into_task(mut config: GitTaskConfig, opts: &CliOptions) -> ScheduledTask { let github = config.github.take(); + let mut slug = None; // TODO Yuck! if let Some(ref github) = github { - config - .upgrade_url_provider(|current| GithubUrlProvider::new(current.url().clone(), github)); + let provider = GithubUrlProvider::new(config.git.url.url().clone(), github); + slug = Some(provider.repo_slug()); + config.upgrade_url_provider(|_| provider); } let mut work = GitWorkload::from_config(config, opts); - if let Some(ref github) = github { - work.watch(github_watcher(github.clone())); + if let Some(github) = github { + if github.notify_context.is_some() { + work.watch(github_watcher(slug.unwrap(), github)); + } } let (tx, rx) = channel(); work.watch(move |event| { diff --git a/src/task/github.rs b/src/task/github.rs index 4b6ad6d..7526136 100644 --- a/src/task/github.rs +++ b/src/task/github.rs @@ -20,9 +20,8 @@ use crate::{errors::GitOpsError, git::UrlProvider, opts::CliOptions, receiver::W pub struct GithubConfig { app_id: String, private_key_file: PathBuf, - notify_slug: Option, #[serde(default = "GithubConfig::default_context")] - notify_context: Option, + pub notify_context: Option, } impl GithubConfig { @@ -40,7 +39,6 @@ impl TryFrom<&CliOptions> for Option { (Some(app_id), Some(private_key_file)) => Ok(Some(GithubConfig { app_id: app_id.clone(), private_key_file: private_key_file.clone(), - notify_slug: opts.github_repo_slug.clone(), notify_context: opts.github_context.clone(), })), _ => Err(GitOpsError::InvalidNotifyConfig), @@ -63,6 +61,10 @@ impl GithubUrlProvider { private_key_file: config.private_key_file.clone(), } } + + pub fn repo_slug(&self) -> String { + self.url.path.to_string().replace(".git", "")[1..].to_owned() + } } impl UrlProvider for GithubUrlProvider { @@ -71,10 +73,9 @@ impl UrlProvider for GithubUrlProvider { } fn auth_url(&self) -> Result { - let repo_slug = self.url.path.to_string().replace(".git", "")[1..].to_owned(); let client = http_client(); let jwt_token = generate_jwt(&self.app_id, &self.private_key_file)?; - let installation_id = get_installation_id(&repo_slug, &client, &jwt_token)?; + let installation_id = get_installation_id(&self.repo_slug(), &client, &jwt_token)?; let access_token = get_access_token(installation_id, &client, &jwt_token)?; // TODO Newer version of gix-url has set_username/set_password Ok(Url::from_parts( @@ -183,6 +184,7 @@ fn get_access_token( } pub fn update_commit_status( + repo_slug: &str, config: &GithubConfig, sha: &ObjectId, status: GitHubStatus, @@ -191,14 +193,12 @@ pub fn update_commit_status( let config = config.clone(); let client = http_client(); let jwt_token = generate_jwt(&config.app_id, &config.private_key_file)?; - let installation_id = - get_installation_id(config.notify_slug.as_ref().unwrap(), &client, &jwt_token)?; + let installation_id = get_installation_id(repo_slug, &client, &jwt_token)?; let access_token = get_access_token(installation_id, &client, &jwt_token)?; let url = format!( "https://api.github.com/repos/{}/statuses/{}", - config.notify_slug.unwrap(), - sha + repo_slug, sha ); let body = serde_json::json!({ "state": status, @@ -225,12 +225,14 @@ pub fn update_commit_status( } pub fn github_watcher( + repo_slug: String, config: GithubConfig, ) -> impl Fn(WorkloadEvent) -> Result<(), GitOpsError> + Send + 'static { move |event| { match event { WorkloadEvent::Changes(name, prev_sha, new_sha) => { update_commit_status( + &repo_slug, &config, &new_sha, GitHubStatus::Pending, @@ -239,6 +241,7 @@ pub fn github_watcher( } WorkloadEvent::Success(name, new_sha) => { update_commit_status( + &repo_slug, &config, &new_sha, GitHubStatus::Success, @@ -247,6 +250,7 @@ pub fn github_watcher( } WorkloadEvent::Failure(task, action, new_sha) => { update_commit_status( + &repo_slug, &config, &new_sha, GitHubStatus::Failure, @@ -255,6 +259,7 @@ pub fn github_watcher( } WorkloadEvent::Error(task, action, new_sha) => { update_commit_status( + &repo_slug, &config, &new_sha, GitHubStatus::Error, diff --git a/src/task/mod.rs b/src/task/mod.rs index 8d53481..e7ba226 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -51,7 +51,7 @@ where pub struct GitTaskConfig { name: String, pub github: Option, - git: GitConfig, + pub git: GitConfig, actions: Vec, #[serde( default = "GitTaskConfig::default_interval",