diff --git a/i18n/en-GB/gitlab_project_doctor.ftl b/i18n/en-GB/gitlab_project_doctor.ftl index 13bbbf2e694581e309e812c60f502f8c4a873a9b..5ad36a7874e8b322aef101a23ef08b489696850a 100644 --- a/i18n/en-GB/gitlab_project_doctor.ftl +++ b/i18n/en-GB/gitlab_project_doctor.ftl @@ -32,7 +32,8 @@ package-deleting = Deleting obsolete packages files package-no-deletion = No package has been deleted package-report = {$nb_packages} packages. {$nb_files} files are obsolete ({$size}) pipeline-analysing = Analysis of pipelines -pipeline-clean-report = Deleted {$nb_pipelines} pipelines, {$size} saved. +pipeline-clean-report = Deleted {$nb_pipelines} pipelines. +pipeline-clean-report-size = Deleted {$nb_pipelines} pipelines, {$size} saved. pipeline-deleting = Deleting old pipelines pipeline-last-notdeleted = Latest pipeline is not deleted. pipeline-no-deletion = No pipeline has been deleted @@ -40,4 +41,7 @@ pipeline-report = {$total_pipelines} pipelines. {$old_pipelines} pipelines are o size-artifacts = Artifact jobs size: size-git-repo = Git repository size: size-packages = Package registry size: -size-storage = Storage size: \ No newline at end of file +size-storage = Storage size: +token-argument = Using the private token from the command argument +token-environment = Using the private token provided in GL_TOKEN variable +token-job = Using the job token from CI_JOB_TOKEN. Warning ! This token provides less permissions than private token ! diff --git a/i18n/fr-FR/gitlab_project_doctor.ftl b/i18n/fr-FR/gitlab_project_doctor.ftl index 62858d21ab1b72bfb1d0e782702b7b99e67613e3..de2a036710bcc94b4a5a00b09c1f7fc433505305 100644 --- a/i18n/fr-FR/gitlab_project_doctor.ftl +++ b/i18n/fr-FR/gitlab_project_doctor.ftl @@ -32,7 +32,8 @@ package-deleting = Suppression des fichiers de package obsolètes package-no-deletion = Aucun package n'a été supprimé package-report = {$nb_packages} packages. {$nb_files} fichiers sont obsolètes ({$size}) pipeline-analysing = Analyse des pipelines -pipeline-clean-report = {$nb_pipelines} pipelines supprimés, {$size} économisés. +pipeline-clean-report = {$nb_pipelines} pipelines supprimés. +pipeline-clean-report-size = {$nb_pipelines} pipelines supprimés, {$size} économisés. pipeline-deleting = Suppression des anciens pipelines pipeline-last-notdeleted = Le dernier pipeline n'est pas supprimé. pipeline-no-deletion = Aucun pipeline n'a été supprimé. @@ -41,4 +42,7 @@ size-artifacts = Taille des artefacts de jobs : size-git-repo = Taille du dépôt Git : size-packages = Package registry size: size-packages = Taille du package registry : -size-storage = Taille globale : \ No newline at end of file +size-storage = Taille globale : +token-argument = Utilisation du token privé fourni en argument de commande +token-environment = Utilisation du token privé founi par la variable GL_TOKEN +token-job = Utilisation du token de job CI_JOB_TOKEN. Attention ! Ce token offre moins de permissions qu'un token privé diff --git a/src/diagnosis/container_analysis.rs b/src/diagnosis/container_analysis.rs index d5155f010688af59a62cf7ab6f4e97a8a124c561..287ed9cc8d2dc14df1531110fb90b052d3a4af3b 100644 --- a/src/diagnosis/container_analysis.rs +++ b/src/diagnosis/container_analysis.rs @@ -1,12 +1,12 @@ -use chrono::{DateTime, Duration, Local}; +use chrono::{DateTime, Local, TimeDelta}; use gitlab::api::{Pagination, Query}; use gitlab::Gitlab; use human_bytes::human_bytes; use serde::Deserialize; +use crate::{api, fl, Reportable, ReportJob, ReportPending, ReportStatus}; +use crate::diagnosis::{CONTAINER_REGISTRY_LIMIT, warning_if}; use crate::diagnosis::gitlab_connection::{GitlabRepository, Project}; -use crate::diagnosis::{warning_if, CONTAINER_REGISTRY_LIMIT}; -use crate::{api, fl, ReportJob, ReportPending, ReportStatus, Reportable}; #[derive(Debug, Deserialize)] pub struct GitlabRawContainerRepository { @@ -126,7 +126,7 @@ impl ReportJob for ContainerAnalysisJob { Ok(containers) => { let container_repos = self.get_detailed_repo(&containers); let days = self.days; - let ref_date = Local::now() - Duration::days(days as i64); + let ref_date = Local::now() - TimeDelta::try_days(days as i64).unwrap(); let image_count: usize = container_repos.iter().map(|cr| cr.tags.len()).sum(); let registry_size: u64 = container_repos diff --git a/src/diagnosis/gitlab_connection.rs b/src/diagnosis/gitlab_connection.rs index 7adcf3e5716a66d10175154a735facc8830e13fc..0c1dfa88d26a283376f66f38e4158366ad4d85e8 100644 --- a/src/diagnosis/gitlab_connection.rs +++ b/src/diagnosis/gitlab_connection.rs @@ -9,8 +9,8 @@ use regex::Regex; use serde::{Deserialize, Serialize}; use crate::diagnosis::{ - warning_if, ReportJob, ReportPending, ReportStatus, Reportable, ARTIFACT_JOBS_LIMIT, - PACKAGE_REGISTRY_LIMIT, REPO_LIMIT, STORAGE_LIMIT, + ARTIFACT_JOBS_LIMIT, PACKAGE_REGISTRY_LIMIT, REPO_LIMIT, Reportable, ReportJob, ReportPending, + ReportStatus, STORAGE_LIMIT, warning_if, }; use crate::fl; @@ -19,7 +19,8 @@ type Result<T> = std::result::Result<T, Box<dyn error::Error>>; // An enum of a Gitlab token type : private or job token #[derive(Debug, Deserialize, Clone)] pub enum GitlabToken { - PrivateToken(String), + PrivateTokenFromArg(String), + PrivateTokenFromEnv(String), JobToken(String), } @@ -41,7 +42,7 @@ pub struct ContainerExpirationPolicy { pub struct Project { pub id: u64, pub name: String, - pub statistics: Statistics, + pub statistics: Option<Statistics>, pub jobs_enabled: bool, pub container_registry_enabled: bool, pub container_expiration_policy: Option<ContainerExpirationPolicy>, @@ -54,6 +55,7 @@ pub struct GitlabRepository { pub gitlab: Gitlab, pub project: Project, pub repo: Option<Repository>, + pub token: GitlabToken, } pub struct ConnectionReport { @@ -97,39 +99,46 @@ impl Reportable for ConnectionReport { impl ConnectionJob { fn _to_report_status(result: Result<GitlabRepository>) -> ConnectionReport { match result { - Ok(gitlab) => ConnectionReport { - report_status: vec![ - ReportStatus::OK(fl!("gitlab-repo", repo = gitlab.url.as_str())), - _report_global_storage(&gitlab.project), - _report_repo_storage(&gitlab.project), - _report_artifact_storage(&gitlab.project), - _report_package_storage(&gitlab.project), - ], - data: Some(gitlab), - }, + Ok(gitlab) => { + let token_status = match gitlab.token { + GitlabToken::PrivateTokenFromArg(_) => ReportStatus::OK(fl!("token-argument")), + GitlabToken::PrivateTokenFromEnv(_) => { + ReportStatus::OK(fl!("token-environment")) + } + GitlabToken::JobToken(_) => ReportStatus::WARNING(fl!("token-job")), + }; + let report_status = if let Some(stats) = &gitlab.project.statistics { + vec![ + token_status, + ReportStatus::OK(fl!("gitlab-repo", repo = gitlab.url.as_str())), + _report_global_storage(stats), + _report_repo_storage(stats), + _report_artifact_storage(stats), + _report_package_storage(stats), + ] + } else { + vec![ + token_status, + ReportStatus::OK(fl!("gitlab-repo", repo = gitlab.url.as_str())), + ] + }; + ConnectionReport { + report_status, + data: Some(gitlab), + } + } Err(e) => ConnectionReport { data: None, report_status: vec![ReportStatus::ERROR(format!("{}", e))], }, } } - fn _gitlab_project( + fn _gitlab_project_private_token( server: &str, path: &str, - token: Option<String>, + token: &str, ) -> Result<(Gitlab, Project)> { - println!("INFO: Project server : {server}"); - let client = match Self::_env_token(token)? { - GitlabToken::PrivateToken(token) => { - println!("INFO: Private token : {token:?}"); - Gitlab::new(server, token)? - } - GitlabToken::JobToken(token) => { - println!("INFO: Job token : {token:?}"); - Gitlab::new_job_token(server, token)? - } - }; - println!("INFO: Project path : {path}"); + let client = Gitlab::new(server, token)?; let endpoint = projects::Project::builder() .project(path) .statistics(true) @@ -140,86 +149,115 @@ impl ConnectionJob { Ok((client, project)) } + fn _gitlab_project_job_token( + server: &str, + token: &str, + ) -> Result<(Gitlab, Project)> { + let client = Gitlab::new_job_token(server, token)?; + let project = Project { + id: env::var("CI_PROJECT_ID")?.parse()?, + name: env::var("CI_PROJECT_NAME")?, + statistics: None, + jobs_enabled: true, + container_expiration_policy: None, + container_registry_enabled: false, // TODO is there a way to find it out with job token? + web_url: env::var("CI_PROJECT_URL")?, + path_with_namespace: env::var("CI_PROJECT_PATH")?, + }; + Ok((client, project)) + } fn _env_token(token: Option<String>) -> Result<GitlabToken> { - let private_token_option = token.or(env::var("GL_TOKEN").ok()); - if let Some(private_token) = private_token_option { - eprintln!("INFO : Using GL_TOKEN environment variable or -t option"); - Ok(GitlabToken::PrivateToken(private_token)) + if let Some(token_value) = token { + Ok(GitlabToken::PrivateTokenFromArg(token_value)) + } else if let Ok(token_value) = env::var("GL_TOKEN") { + Ok(GitlabToken::PrivateTokenFromEnv(token_value)) } else { - eprintln!("INFO : Using CI_JOB_TOKEN if it exists"); Ok(GitlabToken::JobToken( env::var("CI_JOB_TOKEN").map_err(|_| fl!("error-gl-token"))?, )) } } + fn _gitlab_project(server: &str, path: &str, token: &GitlabToken) -> Result<(Gitlab, Project)> { + match token { + GitlabToken::PrivateTokenFromArg(token) | GitlabToken::PrivateTokenFromEnv(token) => { + Self::_gitlab_project_private_token(server, path, token) + } + GitlabToken::JobToken(token) => Self::_gitlab_project_job_token(server, token), + } + } + fn _from_url(url: &str, token: Option<String>) -> Result<GitlabRepository> { let (server, path) = path_from_git_url(url).ok_or_else(|| fl!("error-not-gitlab-repo"))?; - let (gitlab, project) = ConnectionJob::_gitlab_project(server, path, token)?; + let used_token = Self::_env_token(token)?; + let (gitlab, project) = ConnectionJob::_gitlab_project(server, path, &used_token)?; Ok(GitlabRepository { url: String::from(path), gitlab, project, repo: None, + token: used_token, }) } fn _from_git_path(path: &str, token: Option<String>) -> Result<GitlabRepository> { let repo = Repository::open(path).map_err(|_| fl!("error-not-git-repo"))?; let (server, url_path) = gitlab_url(&repo).ok_or_else(|| fl!("error-no-gitlab-remote"))?; - let (gitlab, project) = ConnectionJob::_gitlab_project(&server, &url_path, token)?; + let used_token = Self::_env_token(token)?; + let (gitlab, project) = ConnectionJob::_gitlab_project(&server, &url_path, &used_token)?; Ok(GitlabRepository { url: url_path, gitlab, project, repo: Some(repo), + token: used_token, }) } } -fn _report_global_storage(project: &Project) -> ReportStatus { +fn _report_global_storage(stats: &Statistics) -> ReportStatus { let msg = format!( "{} {}", fl!("size-storage"), - human_bytes(project.statistics.storage_size as f64) + human_bytes(stats.storage_size as f64) ); - warning_if(project.statistics.storage_size > STORAGE_LIMIT, msg) + warning_if(stats.storage_size > STORAGE_LIMIT, msg) } -fn _report_repo_storage(project: &Project) -> ReportStatus { +fn _report_repo_storage(stats: &Statistics) -> ReportStatus { let msg = format!( "{} {} ({} %)", fl!("size-git-repo"), - human_bytes(project.statistics.repository_size as f64), - 100 * project.statistics.repository_size / project.statistics.storage_size + human_bytes(stats.repository_size as f64), + 100 * stats.repository_size / stats.storage_size ); - warning_if(project.statistics.repository_size > REPO_LIMIT, msg) + warning_if(stats.repository_size > REPO_LIMIT, msg) } -fn _report_artifact_storage(project: &Project) -> ReportStatus { +fn _report_artifact_storage(stats: &Statistics) -> ReportStatus { let msg = format!( "{} {} ({} %)", fl!("size-artifacts"), - human_bytes(project.statistics.job_artifacts_size as f64), - 100 * project.statistics.job_artifacts_size / project.statistics.storage_size + human_bytes(stats.job_artifacts_size as f64), + 100 * stats.job_artifacts_size / stats.storage_size ); warning_if( - project.statistics.job_artifacts_size > ARTIFACT_JOBS_LIMIT, + stats.job_artifacts_size > ARTIFACT_JOBS_LIMIT, msg, ) } -fn _report_package_storage(project: &Project) -> ReportStatus { +fn _report_package_storage(stats: &Statistics) -> ReportStatus { let msg = format!( "{} {} ({} %)", fl!("size-packages"), - human_bytes(project.statistics.packages_size as f64), - 100 * project.statistics.packages_size / project.statistics.storage_size + human_bytes(stats.packages_size as f64), + 100 * stats.packages_size / stats.storage_size ); warning_if( - project.statistics.packages_size > PACKAGE_REGISTRY_LIMIT, + stats.packages_size > PACKAGE_REGISTRY_LIMIT, msg, ) } diff --git a/src/diagnosis/job_analysis.rs b/src/diagnosis/job_analysis.rs index c5a7e2588131d236915ce9ac46a57147e0319ab2..2ffbcfa8a27382ffb9587865cbc5b54083a5c361 100644 --- a/src/diagnosis/job_analysis.rs +++ b/src/diagnosis/job_analysis.rs @@ -1,13 +1,13 @@ -use chrono::{DateTime, Duration, Local}; +use chrono::{DateTime, Local, TimeDelta}; +use gitlab::api::{Pagination, projects, Query}; use gitlab::api::paged; -use gitlab::api::{projects, Pagination, Query}; use gitlab::Gitlab; use human_bytes::human_bytes; use serde::Deserialize; +use crate::{Reportable, ReportJob, ReportPending}; use crate::diagnosis::gitlab_connection::{GitlabRepository, Project}; use crate::diagnosis::ReportStatus; -use crate::{ReportJob, ReportPending, Reportable}; #[derive(Debug, Deserialize)] pub struct Artifact { @@ -86,7 +86,7 @@ impl JobAnalysisJob { } fn _number_jobs(&self, jobs: &[GitlabJob]) -> (ReportStatus, u64) { - let ref_date = Local::now() - Duration::days(self.days as i64); + let ref_date = Local::now() - TimeDelta::try_days(self.days as i64).unwrap(); let mut old_count: usize = 0; let mut old_size: u64 = 0; for job in jobs.iter() { diff --git a/src/diagnosis/package_analysis.rs b/src/diagnosis/package_analysis.rs index f3faddb911a97b7097cf64e603a6a4ec07be88a4..035e2d9ed34df5f7be25ecb75b73341858c61edb 100644 --- a/src/diagnosis/package_analysis.rs +++ b/src/diagnosis/package_analysis.rs @@ -6,9 +6,9 @@ use lazy_static::lazy_static; use regex::Regex; use serde::Deserialize; +use crate::{fl, Reportable, ReportJob, ReportPending, ReportStatus}; use crate::api::packages::{PackageFiles, Packages}; use crate::diagnosis::gitlab_connection::{GitlabRepository, Project}; -use crate::{fl, ReportJob, ReportPending, ReportStatus, Reportable}; #[derive(Debug, Deserialize)] pub struct GitlabPackage { @@ -203,7 +203,7 @@ fn _get_extension(file_name: &str) -> &str { #[cfg(test)] mod tests { - use chrono::Duration; + use chrono::TimeDelta; use super::*; @@ -214,36 +214,36 @@ mod tests { id: 42, name: "generic".to_string(), package_type: "".to_string(), - created_at: Local::now() - Duration::days(30), + created_at: Local::now() - TimeDelta::try_days(30).unwrap(), }; let files = vec![ GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(4), + created_at: Local::now() - TimeDelta::try_days(4).unwrap(), file_name: "abc.txt".to_string(), size: 13, }, GitlabPackageFile { id: 54, - created_at: Local::now() - Duration::days(5), + created_at: Local::now() - TimeDelta::try_days(5).unwrap(), file_name: "abc.txt".to_string(), size: 13, }, GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(6), + created_at: Local::now() - TimeDelta::try_days(6).unwrap(), file_name: "zyx.txt".to_string(), size: 13, }, GitlabPackageFile { id: 56, - created_at: Local::now() - Duration::days(7), + created_at: Local::now() - TimeDelta::try_days(7).unwrap(), file_name: "abc.txt".to_string(), size: 13, }, GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(8), + created_at: Local::now() - TimeDelta::try_days(8).unwrap(), file_name: "zyx.txt".to_string(), size: 13, }, @@ -263,7 +263,7 @@ mod tests { id: 42, name: "my-generic".to_string(), package_type: "generic".to_string(), - created_at: Local::now() - Duration::days(30), + created_at: Local::now() - TimeDelta::try_days(30).unwrap(), }; let files = vec![]; @@ -281,42 +281,42 @@ mod tests { id: 42, name: "my-app".to_string(), package_type: "maven".to_string(), - created_at: Local::now() - Duration::days(30), + created_at: Local::now() - TimeDelta::try_days(30).unwrap(), }; let files = vec![ GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(4), + created_at: Local::now() - TimeDelta::try_days(4).unwrap(), file_name: "my-app-1.5-20181107.152550-1.jar".to_string(), size: 13, }, GitlabPackageFile { id: 54, - created_at: Local::now() - Duration::days(4), + created_at: Local::now() - TimeDelta::try_days(4).unwrap(), file_name: "my-app-1.5-20181107.152550-1.pom".to_string(), size: 13, }, GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(4), + created_at: Local::now() - TimeDelta::try_days(4).unwrap(), file_name: "maven-metadata.xml".to_string(), size: 13, }, GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(5), + created_at: Local::now() - TimeDelta::try_days(5).unwrap(), file_name: "my-app-1.5-20181007.142550-1.jar".to_string(), size: 13, }, GitlabPackageFile { id: 54, - created_at: Local::now() - Duration::days(5), + created_at: Local::now() - TimeDelta::try_days(5).unwrap(), file_name: "my-app-1.5-20181007.142550-1.pom".to_string(), size: 13, }, GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(5), + created_at: Local::now() - TimeDelta::try_days(5).unwrap(), file_name: "maven-metadata.xml".to_string(), size: 13, }, @@ -336,42 +336,42 @@ mod tests { id: 42, name: "my-app".to_string(), package_type: "generic".to_string(), - created_at: Local::now() - Duration::days(30), + created_at: Local::now() - TimeDelta::try_days(30).unwrap(), }; let files = vec![ GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(4), + created_at: Local::now() - TimeDelta::try_days(4).unwrap(), file_name: "my-app-1.5-20181107.152550-1.jar".to_string(), size: 13, }, GitlabPackageFile { id: 54, - created_at: Local::now() - Duration::days(4), + created_at: Local::now() - TimeDelta::try_days(4).unwrap(), file_name: "my-app-1.5-20181107.152550-1.pom".to_string(), size: 13, }, GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(4), + created_at: Local::now() - TimeDelta::try_days(4).unwrap(), file_name: "maven-metadata.xml".to_string(), size: 13, }, GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(5), + created_at: Local::now() - TimeDelta::try_days(5).unwrap(), file_name: "my-app-1.5-20181007.142550-1.jar".to_string(), size: 13, }, GitlabPackageFile { id: 54, - created_at: Local::now() - Duration::days(5), + created_at: Local::now() - TimeDelta::try_days(5).unwrap(), file_name: "my-app-1.5-20181007.142550-1.pom".to_string(), size: 13, }, GitlabPackageFile { id: 50, - created_at: Local::now() - Duration::days(5), + created_at: Local::now() - TimeDelta::try_days(5).unwrap(), file_name: "maven-metadata.xml".to_string(), size: 13, }, diff --git a/src/diagnosis/pipeline_analysis.rs b/src/diagnosis/pipeline_analysis.rs index 46ad7f819505e4ada752b5f0a1d87ddc7eb7da1d..61d23b00ac8b0bbf0205a554861d69520beae780 100644 --- a/src/diagnosis/pipeline_analysis.rs +++ b/src/diagnosis/pipeline_analysis.rs @@ -1,10 +1,10 @@ -use chrono::{DateTime, Duration, Local}; +use chrono::{DateTime, Local, TimeDelta}; use gitlab::api::{Pagination, Query}; use gitlab::Gitlab; use serde::Deserialize; +use crate::{fl, Reportable, ReportJob, ReportPending, ReportStatus}; use crate::diagnosis::gitlab_connection::{GitlabRepository, Project}; -use crate::{fl, ReportJob, ReportPending, ReportStatus, Reportable}; #[derive(Debug, Deserialize)] pub struct GitlabPipeline { @@ -70,7 +70,7 @@ impl ReportJob for PipelineAnalysisJob { ), Ok(mut pipelines) => { let days = self.days; - let ref_date = Local::now() - Duration::days(days as i64); + let ref_date = Local::now() - TimeDelta::try_days(days as i64).unwrap(); pipelines.sort_by(|a, b| a.created_at.partial_cmp(&b.created_at).unwrap()); self.into_report( vec![ReportStatus::NA(fl!( diff --git a/src/diagnosis/pipeline_clean.rs b/src/diagnosis/pipeline_clean.rs index af6e3cc13f329af38472eddfb0183f7ba8f20f3a..24b3873a990fe218aea1ca270e0ef19da4ceb918 100644 --- a/src/diagnosis/pipeline_clean.rs +++ b/src/diagnosis/pipeline_clean.rs @@ -1,15 +1,15 @@ use std::cmp::max; use std::sync::mpsc; -use chrono::{Duration, Local}; +use chrono::{Local, TimeDelta}; use gitlab::api::{ApiError, Query}; use gitlab::Gitlab; use human_bytes::human_bytes; -use crate::diagnosis::gitlab_connection::Project; +use crate::{fl, Reportable, ReportPending, ReportStatus}; +use crate::diagnosis::{GITLAB_SCOPE_ERROR, RemedyJob}; +use crate::diagnosis::gitlab_connection::{Project, Statistics}; use crate::diagnosis::pipeline_analysis::{GitlabPipeline, PipelineAnalysisReport}; -use crate::diagnosis::{RemedyJob, GITLAB_SCOPE_ERROR}; -use crate::{fl, ReportPending, ReportStatus, Reportable}; pub struct PipelineCleanJob { pub pipeline_report: PipelineAnalysisReport, @@ -17,7 +17,7 @@ pub struct PipelineCleanJob { } pub struct PipelineCleanReport { - pub saved_bytes: u64, + pub saved_bytes: Option<u64>, pub deleted_pipelines: Vec<GitlabPipeline>, pub report_status: Vec<ReportStatus>, } @@ -31,7 +31,7 @@ impl Reportable for PipelineCleanReport { impl PipelineCleanReport { fn fatal_error(id: u64, msg: &str) -> Self { Self { - saved_bytes: 0, + saved_bytes: None, deleted_pipelines: vec![], report_status: vec![ReportStatus::ERROR(format!( "Pipeline {} - Error : {}", @@ -46,7 +46,7 @@ impl RemedyJob for PipelineCleanJob { fn remedy(self) -> ReportPending<Self::Report> { let (tx, rx) = mpsc::channel(); - let ref_date = Local::now() - Duration::days(self.days as i64); + let ref_date = Local::now() - TimeDelta::try_days(self.days as i64).unwrap(); let count = self .pipeline_report .pipelines @@ -115,15 +115,29 @@ impl RemedyJob for PipelineCleanJob { } let _ = tx.send(i); } - let saved_bytes = PipelineCleanJob::_compute_saved_bytes( - &self.pipeline_report.gitlab, - &self.pipeline_report.project, - ); - let mut report_status = vec![ReportStatus::OK(fl!( - "pipeline-clean-report", + + let mut report_status = vec![]; + + let saved_bytes = if let Some(stats) = self.pipeline_report.project.statistics.as_ref() { + let saved_bytes_value = PipelineCleanJob::_compute_saved_bytes( + &self.pipeline_report.gitlab, + &self.pipeline_report.project, + stats, + ); + report_status.push(ReportStatus::OK(fl!( + "pipeline-clean-report-size", nb_pipelines = deleted_pipelines.len(), - size = human_bytes(saved_bytes as f64) - ))]; + size = human_bytes(saved_bytes_value as f64) + ))); + Some(saved_bytes_value) + } else { + report_status.push(ReportStatus::OK(fl!( + "pipeline-clean-report", + nb_pipelines = deleted_pipelines.len() + ))); + None + }; + if last_is_old { report_status.push(ReportStatus::NA(fl!("pipeline-last-notdeleted"))); } @@ -147,8 +161,8 @@ impl PipelineCleanJob { } } - fn _compute_saved_bytes(gitlab: &Gitlab, project: &Project) -> u64 { - let old_size = project.statistics.job_artifacts_size; + fn _compute_saved_bytes(gitlab: &Gitlab, project: &Project, stats: &Statistics) -> u64 { + let old_size = stats.job_artifacts_size; let endpoint = gitlab::api::projects::Project::builder() .project(project.id) .statistics(true) @@ -157,7 +171,7 @@ impl PipelineCleanJob { let new_size = endpoint .query(gitlab) - .map(|p: Project| p.statistics.job_artifacts_size) + .map(|p: Project| p.statistics.unwrap().job_artifacts_size) .unwrap_or(old_size); max(0, old_size - new_size) } diff --git a/src/main.rs b/src/main.rs index ace57092a5933f078d7245faf9580e5f322d6ed7..24ba522b7acb5d9eafb81e2e6a45ce68968dc511 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use i18n_embed::{ - fluent::{fluent_language_loader, FluentLanguageLoader}, DesktopLanguageRequester, + fluent::{fluent_language_loader, FluentLanguageLoader}, }; use lazy_static::lazy_static; use rust_embed::RustEmbed; @@ -9,6 +9,7 @@ use structopt::StructOpt; use cli::Args; +use crate::diagnosis::{RemedyJob, Reportable, ReportJob, ReportPending}; use crate::diagnosis::conf_analysis::{ConfAnalysisJob, ConfAnalysisReport}; use crate::diagnosis::container_analysis::{ContainerAnalysisJob, ContainerAnalysisReport}; use crate::diagnosis::gitlab_connection::{ConnectionJob, GitlabRepository, Statistics}; @@ -18,7 +19,6 @@ use crate::diagnosis::package_clean::PackageCleanJob; use crate::diagnosis::pipeline_analysis::{PipelineAnalysisJob, PipelineAnalysisReport}; use crate::diagnosis::pipeline_clean::PipelineCleanJob; use crate::diagnosis::ReportStatus; -use crate::diagnosis::{RemedyJob, ReportJob, ReportPending, Reportable}; pub mod api; pub mod cli; @@ -68,7 +68,7 @@ macro_rules! fl { #[derive(Serialize)] struct AnalysisReport { pub url: String, - pub stats: Statistics, + pub stats: Option<Statistics>, pub savable_bytes_jobs: u64, pub savable_bytes_packages: u64, pub savable_bytes_containers: u64, @@ -78,41 +78,43 @@ struct AnalysisReport { impl AnalysisReport { pub fn compute_values(&mut self) { - let rating_number = self._get_rating(); - self.rating = Some( - RATING_ACRONYM[RATING_RANGE - .iter() - .position(|&e| rating_number < e) - .unwrap_or(RATING_ACRONYM.len() - 1)], - ); - - let impact_number = self._get_impact(); - self.impact = Some( - IMPACT_ACRONYM[IMPACT_RANGE - .iter() - .position(|&e| impact_number < e) - .unwrap_or(IMPACT_ACRONYM.len() - 1)], - ); + if let Some(stats) = &self.stats { + let rating_number = self._get_rating(stats); + self.rating = Some( + RATING_ACRONYM[RATING_RANGE + .iter() + .position(|&e| rating_number < e) + .unwrap_or(RATING_ACRONYM.len() - 1)], + ); + + let impact_number = self._get_impact(stats); + self.impact = Some( + IMPACT_ACRONYM[IMPACT_RANGE + .iter() + .position(|&e| impact_number < e) + .unwrap_or(IMPACT_ACRONYM.len() - 1)], + ); + } } - pub fn _get_impact(&self) -> u64 { + pub fn _get_impact(&self, stats: &Statistics) -> u64 { // Impact == Disk impact. git repo is evaluated ten times - self.stats.repository_size * 9 + self.stats.storage_size + stats.repository_size * 9 + stats.storage_size } - pub fn _get_rating(&self) -> u64 { + pub fn _get_rating(&self, stats: &Statistics) -> u64 { // Rating == Margin of improvement (less is better) // Containers are ignored for now let repo_limit = 100 * 1024 * 1024; - let savable_repo = if self.stats.repository_size > repo_limit { - self.stats.repository_size - repo_limit + let savable_repo = if stats.repository_size > repo_limit { + stats.repository_size - repo_limit } else { 0 }; (savable_repo * 9 + self.savable_bytes_jobs + self.savable_bytes_packages) * 100 - / (self.stats.repository_size * 9 - + self.stats.job_artifacts_size - + self.stats.packages_size) + / (stats.repository_size * 9 + + stats.job_artifacts_size + + stats.packages_size) } }