From c1da96b78ed0e9149eb54700c687fd48d76e34b6 Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sat, 30 Aug 2025 02:53:40 +0530 Subject: [PATCH 01/10] [check] risk assessr workflow testing --- .github/workflows/riskassessr.yaml | 318 +++++++++++++++++++++++++++++ renv.lock | 22 +- vignettes/usecase-doc.R | 124 +++++------ 3 files changed, 391 insertions(+), 73 deletions(-) create mode 100644 .github/workflows/riskassessr.yaml diff --git a/.github/workflows/riskassessr.yaml b/.github/workflows/riskassessr.yaml new file mode 100644 index 0000000..fe82484 --- /dev/null +++ b/.github/workflows/riskassessr.yaml @@ -0,0 +1,318 @@ +name: Package Risk Assessment + +on: + push: + +jobs: + risk-assessment: + runs-on: ubuntu-latest + name: Risk Assessment + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup R + uses: r-lib/actions/setup-r@v2 + with: + r-version: 'release' + use-public-rspm: true + + - name: Setup Pandoc + uses: r-lib/actions/setup-pandoc@v2 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libcurl4-openssl-dev libssl-dev libxml2-dev + + - name: Query dependencies + run: | + install.packages('remotes') + saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2) + writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version") + shell: Rscript {0} + + - name: Cache R packages + uses: actions/cache@v3 + with: + path: ${{ env.R_LIBS_USER }} + key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} + restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- + + - name: Install package dependencies + run: | + remotes::install_deps(dependencies = TRUE) + shell: Rscript {0} + + - name: Install risk.assessr and additional dependencies + run: | + install.packages(c("risk.assessr", "crayon", "knitr")) + shell: Rscript {0} + + - name: Build package + run: | + devtools::build(path = ".", vignettes = FALSE) + shell: Rscript {0} + + - name: Run Risk Assessment + run: | + # Load required libraries + library(risk.assessr) + library(crayon) + + # Set up CRAN repository + r <- getOption("repos") + r["CRAN"] <- "https://cloud.r-project.org" + options(repos = r) + + cat("=== Starting Package Risk Assessment ===\n") + cat("Repository:", Sys.getenv("GITHUB_REPOSITORY"), "\n") + cat("Branch:", Sys.getenv("GITHUB_REF_NAME"), "\n") + cat("Workflow run:", Sys.getenv("GITHUB_RUN_ID"), "\n") + cat("Timestamp:", format(Sys.time(), "%Y-%m-%d %H:%M:%S UTC"), "\n\n") + + # Pretty print function for GitHub Actions logs + pretty_print_assessment <- function(assessment_results) { + + if (is.null(assessment_results) || length(assessment_results) == 0) { + cat("āŒ No assessment results to display.\n") + return() + } + + # Helper functions for colored output in GitHub Actions + print_header <- function(title) { + cat("\n") + cat("šŸ” ===", title, "===\n") + cat(paste(rep("=", nchar(title) + 10), collapse = ""), "\n") + } + + print_subheader <- function(title) { + cat("\nšŸ“Š", title, "\n") + cat(paste(rep("-", nchar(title) + 3), collapse = ""), "\n") + } + + # Extract package name + pkg_name <- "Unknown Package" + if ("package" %in% names(assessment_results)) { + pkg_name <- assessment_results$package + } else if ("pkg_name" %in% names(assessment_results)) { + pkg_name <- assessment_results$pkg_name + } + + print_header("PACKAGE ASSESSMENT RESULTS") + cat("šŸ“¦ Package:", pkg_name, "\n") + cat("ā° Generated:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"), "\n") + + # Print R CMD Check Results + if ("rcmdcheck" %in% names(assessment_results)) { + print_header("R CMD CHECK RESULTS") + rcmd <- assessment_results$rcmdcheck + + if (is.list(rcmd)) { + # Errors + if ("errors" %in% names(rcmd) && length(rcmd$errors) > 0) { + print_subheader("🚨 ERRORS") + for (error in rcmd$errors) { + cat("āŒ", error, "\n") + } + cat("::error::R CMD check found", length(rcmd$errors), "error(s)\n") + } else { + cat("āœ… No errors found\n") + } + + # Warnings + if ("warnings" %in% names(rcmd) && length(rcmd$warnings) > 0) { + print_subheader("āš ļø WARNINGS") + for (warning in rcmd$warnings) { + cat("āš ļø", warning, "\n") + } + cat("::warning::R CMD check found", length(rcmd$warnings), "warning(s)\n") + } else { + cat("āœ… No warnings found\n") + } + + # Notes + if ("notes" %in% names(rcmd) && length(rcmd$notes) > 0) { + print_subheader("šŸ“ NOTES") + for (note in rcmd$notes) { + cat("ā„¹ļø", note, "\n") + } + cat("::notice::R CMD check found", length(rcmd$notes), "note(s)\n") + } else { + cat("āœ… No notes\n") + } + } else { + cat(as.character(rcmd), "\n") + } + } + + # Print Coverage Results + if ("covr" %in% names(assessment_results)) { + print_header("CODE COVERAGE") + covr <- assessment_results$covr + + if (is.numeric(covr)) { + coverage_pct <- round(covr, 2) + if (coverage_pct >= 80) { + cat("āœ… Coverage:", coverage_pct, "%\n") + } else if (coverage_pct >= 60) { + cat("āš ļø Coverage:", coverage_pct, "%\n") + cat("::warning::Code coverage is below 80%\n") + } else { + cat("āŒ Coverage:", coverage_pct, "%\n") + cat("::error::Code coverage is below 60%\n") + } + } else if (is.data.frame(covr)) { + cat("Coverage details:\n") + print(covr) + } else { + cat(as.character(covr), "\n") + } + } + + # Print Dependencies + if ("dependencies" %in% names(assessment_results)) { + print_header("DEPENDENCIES") + deps <- assessment_results$dependencies + + if (is.data.frame(deps)) { + if (nrow(deps) > 0) { + cat("šŸ“‹ Found", nrow(deps), "dependencies:\n") + print(deps) + } else { + cat("āœ… No dependencies found\n") + } + } else if (is.list(deps)) { + if (length(deps) > 0) { + for (name in names(deps)) { + cat("•", name, ":", as.character(deps[[name]]), "\n") + } + } else { + cat("āœ… No dependencies found\n") + } + } else { + cat(as.character(deps), "\n") + } + } + + # Print Metrics + if ("metrics" %in% names(assessment_results)) { + print_header("PACKAGE METRICS") + metrics <- assessment_results$metrics + + if (is.data.frame(metrics)) { + if (nrow(metrics) > 0) { + print(metrics) + } else { + cat("No metrics data available\n") + } + } else if (is.list(metrics)) { + if (length(metrics) > 0) { + for (name in names(metrics)) { + cat("•", name, ":", as.character(metrics[[name]]), "\n") + } + } else { + cat("No metrics data available\n") + } + } else { + cat(as.character(metrics), "\n") + } + } + + # Print other components + other_components <- names(assessment_results)[!names(assessment_results) %in% + c("rcmdcheck", "covr", "dependencies", "metrics", "package", "pkg_name")] + + if (length(other_components) > 0) { + print_header("OTHER ASSESSMENT DATA") + + for (component in other_components) { + data <- assessment_results[[component]] + cat("\nšŸ“‹", toupper(component), "\n") + + if (is.data.frame(data) && nrow(data) > 0) { + print(data) + } else if (is.list(data) && length(data) > 0) { + str(data, max.level = 2) + } else if (!is.null(data) && length(data) > 0) { + cat(as.character(data), "\n") + } else { + cat("No data available\n") + } + } + } + + # Summary + print_header("ASSESSMENT SUMMARY") + cat("šŸ“Š Total components assessed:", length(assessment_results), "\n") + + # Create GitHub Actions summary + error_count <- if("rcmdcheck" %in% names(assessment_results) && + "errors" %in% names(assessment_results$rcmdcheck)) + length(assessment_results$rcmdcheck$errors) else 0 + warning_count <- if("rcmdcheck" %in% names(assessment_results) && + "warnings" %in% names(assessment_results$rcmdcheck)) + length(assessment_results$rcmdcheck$warnings) else 0 + note_count <- if("rcmdcheck" %in% names(assessment_results) && + "notes" %in% names(assessment_results$rcmdcheck)) + length(assessment_results$rcmdcheck$notes) else 0 + + if (error_count > 0) { + cat("::error::Assessment completed with", error_count, "errors\n") + } else if (warning_count > 0) { + cat("::warning::Assessment completed with", warning_count, "warnings\n") + } else { + cat("::notice::Assessment completed successfully\n") + } + + cat("\nšŸŽ‰ Assessment display completed!\n") + } + + # Run the assessment + tryCatch({ + cat("šŸš€ Starting risk assessment...\n") + + # Use the simplified risk_assess_pkg function with current directory + comprehensive_assessment <- risk_assess_pkg(".") + + # Print the results + pretty_print_assessment(comprehensive_assessment) + + }, error = function(e) { + cat("::error::Assessment failed with error:", e$message, "\n") + cat("šŸ“‹ Attempting fallback assessment...\n") + + # Fallback: try building package first + tryCatch({ + # Build the package + built_pkg <- devtools::build(".", quiet = FALSE) + cat("šŸ“¦ Package built:", built_pkg, "\n") + + # Try assessment with built package + comprehensive_assessment <- risk_assess_pkg(built_pkg) + pretty_print_assessment(comprehensive_assessment) + + }, error = function(e2) { + cat("::error::Fallback assessment also failed:", e2$message, "\n") + cat("šŸ” Package structure:\n") + cat(paste(list.files(".", recursive = TRUE, include.dirs = TRUE), collapse = "\n"), "\n") + }) + }) + + cat("\n=== Risk Assessment Complete ===\n") + shell: Rscript {0} + + - name: Upload assessment artifacts + uses: actions/upload-artifact@v3 + if: always() + with: + name: risk-assessment-logs + path: | + *.log + *.Rcheck/ + retention-days: 30 diff --git a/renv.lock b/renv.lock index 8b4cd81..0e124bc 100644 --- a/renv.lock +++ b/renv.lock @@ -359,7 +359,7 @@ }, "knitr": { "Package": "knitr", - "Version": "1.48", + "Version": "1.50", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -371,7 +371,7 @@ "xfun", "yaml" ], - "Hash": "acf380f300c721da9fde7df115a5f86f" + "Hash": "5a07d8ec459d7b80bd4acca5f4a6e062" }, "lifecycle": { "Package": "lifecycle", @@ -388,7 +388,7 @@ }, "lubridate": { "Package": "lubridate", - "Version": "1.9.3", + "Version": "1.9.4", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -397,7 +397,7 @@ "methods", "timechange" ], - "Hash": "680ad542fbcf801442c83a6ac5a2126c" + "Hash": "be38bc740fc51783a78edb5a157e4104" }, "magrittr": { "Package": "magrittr", @@ -547,7 +547,7 @@ }, "rmarkdown": { "Package": "rmarkdown", - "Version": "2.27", + "Version": "2.29", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -566,7 +566,7 @@ "xfun", "yaml" ], - "Hash": "27f9502e1cdbfa195f94e03b0f517484" + "Hash": "df99277f63d01c34e95e3d2f06a79736" }, "sass": { "Package": "sass", @@ -591,12 +591,12 @@ }, "tibble": { "Package": "tibble", - "Version": "3.2.1", + "Version": "3.3.0", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", - "fansi", + "cli", "lifecycle", "magrittr", "methods", @@ -606,7 +606,7 @@ "utils", "vctrs" ], - "Hash": "a84e2cc86d07289b3b6f5069df7a004c" + "Hash": "784b27d0801c3829de602105757b2cd7" }, "tidyselect": { "Package": "tidyselect", @@ -720,7 +720,7 @@ }, "xfun": { "Package": "xfun", - "Version": "0.47", + "Version": "0.53", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -729,7 +729,7 @@ "stats", "tools" ], - "Hash": "36ab21660e2d095fef0d83f689e0477c" + "Hash": "1befe97a0d56060b3964e3986d408df9" }, "yaml": { "Package": "yaml", diff --git a/vignettes/usecase-doc.R b/vignettes/usecase-doc.R index 9a3468a..c2869c7 100644 --- a/vignettes/usecase-doc.R +++ b/vignettes/usecase-doc.R @@ -1,74 +1,74 @@ ## ----eval=FALSE--------------------------------------------------------------- -# # Load required libraries -# invisible(suppressPackageStartupMessages({ -# library(clintrialx) # For fetching clinical trial data -# library(ggplot2) # For data visualization -# library(plotly) # For interactive plots -# library(dplyr) # For data manipulation -# library(lubridate) # For date handling -# })) +# # Load required libraries +# invisible(suppressPackageStartupMessages({ +# library(clintrialx) # For fetching clinical trial data +# library(ggplot2) # For data visualization +# library(plotly) # For interactive plots +# library(dplyr) # For data manipulation +# library(lubridate) # For date handling +# })) ## ----eval=FALSE--------------------------------------------------------------- -# # Fetch cancer study data in India -# df <- ctg_bulk_fetch(condition = "cancer", location = "India") +# # Fetch cancer study data in India +# df <- ctg_bulk_fetch(condition = "cancer", location = "India") ## ----eval=FALSE--------------------------------------------------------------- -# # Create a table of study statuses -# status_counts <- table(df$`Study Status`) -# -# # Convert the table to a data frame -# status_df <- data.frame(status = names(status_counts), count = as.numeric(status_counts)) -# -# # Generate the bar plot -# ggplotly(ggplot(status_df, aes(x = reorder(status, -count), y = count)) + -# geom_bar(stat = "identity", fill = "orange") + -# theme_minimal() + -# labs(title = "Distribution of Study Statuses", -# x = "Study Status", -# y = "Count") + -# theme(axis.text.x = element_text(angle = 45, hjust = 1)) + -# geom_text(aes(label = count), vjust = -0.5)) +# # Create a table of study statuses +# status_counts <- table(df$`Study Status`) +# +# # Convert the table to a data frame +# status_df <- data.frame(status = names(status_counts), count = as.numeric(status_counts)) +# +# # Generate the bar plot +# ggplotly(ggplot(status_df, aes(x = reorder(status, -count), y = count)) + +# geom_bar(stat = "identity", fill = "orange") + +# theme_minimal() + +# labs(title = "Distribution of Study Statuses", +# x = "Study Status", +# y = "Count") + +# theme(axis.text.x = element_text(angle = 45, hjust = 1)) + +# geom_text(aes(label = count), vjust = -0.5)) ## ----eval=FALSE--------------------------------------------------------------- -# # Create an interactive box plot of enrollment by study phase -# ggplotly(ggplot(df, aes(x = Phases, y = Enrollment)) + -# geom_boxplot(fill = "lightblue", outlier.colour = "red", outlier.shape = 1) + -# geom_jitter(color = "darkblue", size = 0.5, alpha = 0.5, width = 0.2) + -# theme_minimal(base_size = 14) + -# labs(title = "Enrollment by Study Phase", -# x = "Study Phase", -# y = "Enrollment") + -# theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 12), -# plot.title = element_text(hjust = 0.5))) +# # Create an interactive box plot of enrollment by study phase +# ggplotly(ggplot(df, aes(x = Phases, y = Enrollment)) + +# geom_boxplot(fill = "lightblue", outlier.colour = "red", outlier.shape = 1) + +# geom_jitter(color = "darkblue", size = 0.5, alpha = 0.5, width = 0.2) + +# theme_minimal(base_size = 14) + +# labs(title = "Enrollment by Study Phase", +# x = "Study Phase", +# y = "Enrollment") + +# theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 12), +# plot.title = element_text(hjust = 0.5))) ## ----eval=FALSE--------------------------------------------------------------- -# # Convert date strings to Date objects -# df$start_date <- as.Date(df$`Start Date`, format = "%Y-%m-%d") -# df$completion_date <- as.Date(df$`Completion Date`, format = "%Y-%m-%d") -# -# # Create a scatter plot with a horizontal line at 2024 -# ggplot(df, aes(x = start_date, y = completion_date, color = `Study Status`)) + -# geom_point(alpha = 0.6) + -# geom_hline(yintercept = as.Date("2024-01-01"), linetype = "dashed", color = "blue") + -# theme_minimal() + -# labs(title = "Study Duration Timeline", -# x = "Start Date", -# y = "Completion Date") + -# scale_color_brewer(palette = "Set1") +# # Convert date strings to Date objects +# df$start_date <- as.Date(df$`Start Date`, format = "%Y-%m-%d") +# df$completion_date <- as.Date(df$`Completion Date`, format = "%Y-%m-%d") +# +# # Create a scatter plot with a horizontal line at 2024 +# ggplot(df, aes(x = start_date, y = completion_date, color = `Study Status`)) + +# geom_point(alpha = 0.6) + +# geom_hline(yintercept = as.Date("2024-01-01"), linetype = "dashed", color = "blue") + +# theme_minimal() + +# labs(title = "Study Duration Timeline", +# x = "Start Date", +# y = "Completion Date") + +# scale_color_brewer(palette = "Set1") ## ----eval=FALSE--------------------------------------------------------------- -# # Summarize and plot funding sources by study type -# df_summary <- df %>% -# count(`Funder Type`, `Study Type`) %>% -# group_by(`Funder Type`) %>% -# mutate(prop = n / sum(n)) -# -# ggplotly(ggplot(df_summary, aes(x = `Funder Type`, y = prop, fill = `Study Type`)) + -# geom_bar(stat = "identity", position = "dodge") + -# theme_minimal() + -# labs(title = "Funding Sources and Study Types", -# x = "Funder Type", -# y = "Proportion") + -# scale_fill_brewer(palette = "Set2") + -# theme(axis.text.x = element_text(angle = 45, hjust = 1))) +# # Summarize and plot funding sources by study type +# df_summary <- df %>% +# count(`Funder Type`, `Study Type`) %>% +# group_by(`Funder Type`) %>% +# mutate(prop = n / sum(n)) +# +# ggplotly(ggplot(df_summary, aes(x = `Funder Type`, y = prop, fill = `Study Type`)) + +# geom_bar(stat = "identity", position = "dodge") + +# theme_minimal() + +# labs(title = "Funding Sources and Study Types", +# x = "Funder Type", +# y = "Proportion") + +# scale_fill_brewer(palette = "Set2") + +# theme(axis.text.x = element_text(angle = 45, hjust = 1))) From 2417ff336854ed879df9529bfc1e8e8c1e251af8 Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sat, 30 Aug 2025 02:56:43 +0530 Subject: [PATCH 02/10] [check] update artifact version --- .github/workflows/riskassessr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/riskassessr.yaml b/.github/workflows/riskassessr.yaml index fe82484..c74c281 100644 --- a/.github/workflows/riskassessr.yaml +++ b/.github/workflows/riskassessr.yaml @@ -308,7 +308,7 @@ jobs: shell: Rscript {0} - name: Upload assessment artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: always() with: name: risk-assessment-logs From f70e29e1c83533b4eed91224c8daa5b5e5303f84 Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sun, 31 Aug 2025 10:15:55 +0530 Subject: [PATCH 03/10] [CHECK] update actions --- .github/workflows/R-CMD-check.yaml | 42 ++-- .github/workflows/riskassessr.yaml | 320 ++++++++--------------------- 2 files changed, 104 insertions(+), 258 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index ccbe25e..67975c7 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,6 +1,8 @@ name: R-CMD-check -on: [push, pull_request] +on: + push: + pull_request: jobs: R-CMD-check: @@ -9,29 +11,25 @@ jobs: image: rocker/tidyverse:latest steps: - - name: Checkout repository - uses: actions/checkout@v2 + - name: Checkout repository + uses: actions/checkout@v3 - - name: Set up R - uses: r-lib/actions/setup-r@v2 + - name: Set up R + uses: r-lib/actions/setup-r@v2 - - name: Set environment variables - run: | - echo "R_LIBS_USER=/__w/_temp/Library" >> $GITHUB_ENV - echo "TZ=UTC" >> $GITHUB_ENV - echo "_R_CHECK_SYSTEM_CLOCK_=FALSE" >> $GITHUB_ENV - echo "NOT_CRAN=true" >> $GITHUB_ENV + - name: Set up R dependencies + uses: r-lib/actions/setup-renv@v2 - - name: Restore R package dependencies - run: R -e 'renv::restore()' + - name: Cache R packages + uses: actions/cache@v3 + with: + path: ~/.local/share/renv + key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }} + restore-keys: | + ${{ runner.os }}-renv- - - name: Install devtools - run: | - renv::install('devtools') - shell: Rscript {0} + - name: Install package + run: R CMD INSTALL . - - name: Install the package - run: R CMD INSTALL . - - - name: Run tests - run: R -e 'devtools::test()' + - name: Run tests + run: R -e 'devtools::test()' diff --git a/.github/workflows/riskassessr.yaml b/.github/workflows/riskassessr.yaml index c74c281..41db945 100644 --- a/.github/workflows/riskassessr.yaml +++ b/.github/workflows/riskassessr.yaml @@ -2,15 +2,18 @@ name: Package Risk Assessment on: push: + pull_request: + workflow_dispatch: jobs: risk-assessment: runs-on: ubuntu-latest name: Risk Assessment - + env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes + CACHE_VERSION: v1 steps: - name: Checkout repository @@ -41,278 +44,123 @@ jobs: uses: actions/cache@v3 with: path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} - restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- + key: ${{ runner.os }}-${{ env.CACHE_VERSION }}-${{ hashFiles('.github/R-version') }}-${{ hashFiles('.github/depends.Rds') }} + restore-keys: | + ${{ runner.os }}-${{ env.CACHE_VERSION }}- - - name: Install package dependencies + - name: Install dependencies run: | + install.packages(c("remotes", "devtools", "risk.assessr", "crayon", "knitr", "jsonlite")) remotes::install_deps(dependencies = TRUE) shell: Rscript {0} - - name: Install risk.assessr and additional dependencies - run: | - install.packages(c("risk.assessr", "crayon", "knitr")) - shell: Rscript {0} - - name: Build package - run: | - devtools::build(path = ".", vignettes = FALSE) + run: devtools::build(path = ".", vignettes = FALSE) shell: Rscript {0} - name: Run Risk Assessment run: | - # Load required libraries library(risk.assessr) library(crayon) - - # Set up CRAN repository - r <- getOption("repos") - r["CRAN"] <- "https://cloud.r-project.org" - options(repos = r) - - cat("=== Starting Package Risk Assessment ===\n") - cat("Repository:", Sys.getenv("GITHUB_REPOSITORY"), "\n") - cat("Branch:", Sys.getenv("GITHUB_REF_NAME"), "\n") - cat("Workflow run:", Sys.getenv("GITHUB_RUN_ID"), "\n") - cat("Timestamp:", format(Sys.time(), "%Y-%m-%d %H:%M:%S UTC"), "\n\n") - - # Pretty print function for GitHub Actions logs + library(jsonlite) + + `%||%` <- function(a, b) if (!is.null(a)) a else b + + log_time <- function(msg) { + cat(sprintf("[%s] %s\n", format(Sys.time(), "%Y-%m-%d %H:%M:%S UTC"), msg)) + } + pretty_print_assessment <- function(assessment_results) { - - if (is.null(assessment_results) || length(assessment_results) == 0) { - cat("āŒ No assessment results to display.\n") + if (is.null(assessment_results)) { + cat("āŒ No assessment results\n") return() } - - # Helper functions for colored output in GitHub Actions - print_header <- function(title) { - cat("\n") - cat("šŸ” ===", title, "===\n") - cat(paste(rep("=", nchar(title) + 10), collapse = ""), "\n") - } - - print_subheader <- function(title) { - cat("\nšŸ“Š", title, "\n") - cat(paste(rep("-", nchar(title) + 3), collapse = ""), "\n") - } - - # Extract package name - pkg_name <- "Unknown Package" - if ("package" %in% names(assessment_results)) { - pkg_name <- assessment_results$package - } else if ("pkg_name" %in% names(assessment_results)) { - pkg_name <- assessment_results$pkg_name - } - - print_header("PACKAGE ASSESSMENT RESULTS") - cat("šŸ“¦ Package:", pkg_name, "\n") - cat("ā° Generated:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"), "\n") - - # Print R CMD Check Results + + # PACKAGE INFO + cat("::group::šŸ“¦ Package Info\n") + pkg_name <- assessment_results$package %||% assessment_results$pkg_name %||% "Unknown" + cat("Package:", pkg_name, "\n") + cat("Generated:", format(Sys.time(), "%Y-%m-%d %H:%M:%S UTC"), "\n") + cat("::endgroup::\n") + + # R CMD CHECK if ("rcmdcheck" %in% names(assessment_results)) { - print_header("R CMD CHECK RESULTS") + cat("::group::šŸ” R CMD CHECK\n") rcmd <- assessment_results$rcmdcheck - - if (is.list(rcmd)) { - # Errors - if ("errors" %in% names(rcmd) && length(rcmd$errors) > 0) { - print_subheader("🚨 ERRORS") - for (error in rcmd$errors) { - cat("āŒ", error, "\n") - } - cat("::error::R CMD check found", length(rcmd$errors), "error(s)\n") - } else { - cat("āœ… No errors found\n") - } - - # Warnings - if ("warnings" %in% names(rcmd) && length(rcmd$warnings) > 0) { - print_subheader("āš ļø WARNINGS") - for (warning in rcmd$warnings) { - cat("āš ļø", warning, "\n") - } - cat("::warning::R CMD check found", length(rcmd$warnings), "warning(s)\n") - } else { - cat("āœ… No warnings found\n") - } - - # Notes - if ("notes" %in% names(rcmd) && length(rcmd$notes) > 0) { - print_subheader("šŸ“ NOTES") - for (note in rcmd$notes) { - cat("ā„¹ļø", note, "\n") - } - cat("::notice::R CMD check found", length(rcmd$notes), "note(s)\n") - } else { - cat("āœ… No notes\n") - } - } else { - cat(as.character(rcmd), "\n") - } + if (length(rcmd$errors) > 0) { + cat(red$bold("āŒ Errors:\n"), paste(rcmd$errors, collapse="\n"), "\n") + } else cat(green$bold("āœ… No errors\n")) + if (length(rcmd$warnings) > 0) { + cat(yellow$bold("āš ļø Warnings:\n"), paste(rcmd$warnings, collapse="\n"), "\n") + } else cat(green$bold("āœ… No warnings\n")) + if (length(rcmd$notes) > 0) { + cat(blue$bold("ā„¹ļø Notes:\n"), paste(rcmd$notes, collapse="\n"), "\n") + } else cat(green$bold("āœ… No notes\n")) + cat("::endgroup::\n") } - - # Print Coverage Results + + # COVERAGE if ("covr" %in% names(assessment_results)) { - print_header("CODE COVERAGE") + cat("::group::šŸ“ˆ Coverage\n") covr <- assessment_results$covr - if (is.numeric(covr)) { coverage_pct <- round(covr, 2) - if (coverage_pct >= 80) { - cat("āœ… Coverage:", coverage_pct, "%\n") - } else if (coverage_pct >= 60) { - cat("āš ļø Coverage:", coverage_pct, "%\n") - cat("::warning::Code coverage is below 80%\n") - } else { - cat("āŒ Coverage:", coverage_pct, "%\n") - cat("::error::Code coverage is below 60%\n") - } - } else if (is.data.frame(covr)) { - cat("Coverage details:\n") - print(covr) - } else { - cat(as.character(covr), "\n") - } + cat("Coverage:", coverage_pct, "%\n") + if (coverage_pct < 60) cat("::error::Coverage < 60%\n") + else if (coverage_pct < 80) cat("::warning::Coverage < 80%\n") + } else print(covr) + cat("::endgroup::\n") } - - # Print Dependencies + + # DEPENDENCIES if ("dependencies" %in% names(assessment_results)) { - print_header("DEPENDENCIES") - deps <- assessment_results$dependencies - - if (is.data.frame(deps)) { - if (nrow(deps) > 0) { - cat("šŸ“‹ Found", nrow(deps), "dependencies:\n") - print(deps) - } else { - cat("āœ… No dependencies found\n") - } - } else if (is.list(deps)) { - if (length(deps) > 0) { - for (name in names(deps)) { - cat("•", name, ":", as.character(deps[[name]]), "\n") - } - } else { - cat("āœ… No dependencies found\n") - } - } else { - cat(as.character(deps), "\n") - } + cat("::group::šŸ“‹ Dependencies\n") + print(assessment_results$dependencies) + cat("::endgroup::\n") } - - # Print Metrics + + # METRICS if ("metrics" %in% names(assessment_results)) { - print_header("PACKAGE METRICS") - metrics <- assessment_results$metrics - - if (is.data.frame(metrics)) { - if (nrow(metrics) > 0) { - print(metrics) - } else { - cat("No metrics data available\n") - } - } else if (is.list(metrics)) { - if (length(metrics) > 0) { - for (name in names(metrics)) { - cat("•", name, ":", as.character(metrics[[name]]), "\n") - } - } else { - cat("No metrics data available\n") - } - } else { - cat(as.character(metrics), "\n") - } - } - - # Print other components - other_components <- names(assessment_results)[!names(assessment_results) %in% - c("rcmdcheck", "covr", "dependencies", "metrics", "package", "pkg_name")] - - if (length(other_components) > 0) { - print_header("OTHER ASSESSMENT DATA") - - for (component in other_components) { - data <- assessment_results[[component]] - cat("\nšŸ“‹", toupper(component), "\n") - - if (is.data.frame(data) && nrow(data) > 0) { - print(data) - } else if (is.list(data) && length(data) > 0) { - str(data, max.level = 2) - } else if (!is.null(data) && length(data) > 0) { - cat(as.character(data), "\n") - } else { - cat("No data available\n") - } - } + cat("::group::šŸ“Š Metrics\n") + print(assessment_results$metrics) + cat("::endgroup::\n") } - - # Summary - print_header("ASSESSMENT SUMMARY") - cat("šŸ“Š Total components assessed:", length(assessment_results), "\n") - - # Create GitHub Actions summary - error_count <- if("rcmdcheck" %in% names(assessment_results) && - "errors" %in% names(assessment_results$rcmdcheck)) - length(assessment_results$rcmdcheck$errors) else 0 - warning_count <- if("rcmdcheck" %in% names(assessment_results) && - "warnings" %in% names(assessment_results$rcmdcheck)) - length(assessment_results$rcmdcheck$warnings) else 0 - note_count <- if("rcmdcheck" %in% names(assessment_results) && - "notes" %in% names(assessment_results$rcmdcheck)) - length(assessment_results$rcmdcheck$notes) else 0 - - if (error_count > 0) { - cat("::error::Assessment completed with", error_count, "errors\n") - } else if (warning_count > 0) { - cat("::warning::Assessment completed with", warning_count, "warnings\n") - } else { - cat("::notice::Assessment completed successfully\n") - } - - cat("\nšŸŽ‰ Assessment display completed!\n") } - - # Run the assessment + + log_time("šŸš€ Running risk assessment with risk.assessr...") tryCatch({ - cat("šŸš€ Starting risk assessment...\n") - - # Use the simplified risk_assess_pkg function with current directory - comprehensive_assessment <- risk_assess_pkg(".") - - # Print the results - pretty_print_assessment(comprehensive_assessment) - - }, error = function(e) { - cat("::error::Assessment failed with error:", e$message, "\n") - cat("šŸ“‹ Attempting fallback assessment...\n") - - # Fallback: try building package first - tryCatch({ - # Build the package - built_pkg <- devtools::build(".", quiet = FALSE) - cat("šŸ“¦ Package built:", built_pkg, "\n") - - # Try assessment with built package - comprehensive_assessment <- risk_assess_pkg(built_pkg) - pretty_print_assessment(comprehensive_assessment) - - }, error = function(e2) { - cat("::error::Fallback assessment also failed:", e2$message, "\n") - cat("šŸ” Package structure:\n") - cat(paste(list.files(".", recursive = TRUE, include.dirs = TRUE), collapse = "\n"), "\n") - }) + assessment <- risk_assess_pkg(".") + pretty_print_assessment(assessment) + + # Save logs & structured results + saveRDS(assessment, "assessment_results.rds") + write_json(assessment, "assessment_results.json", pretty=TRUE, auto_unbox=TRUE) + + # Write summary for GitHub + summary_file <- Sys.getenv("GITHUB_STEP_SUMMARY") + if (nzchar(summary_file)) { + writeLines(c( + "## šŸ“Š Risk Assessment Summary", + paste0("- Package: ", assessment$package %||% "Unknown"), + paste0("- Errors: ", length(assessment$rcmdcheck$errors) %||% 0), + paste0("- Warnings: ", length(assessment$rcmdcheck$warnings) %||% 0), + paste0("- Notes: ", length(assessment$rcmdcheck$notes) %||% 0) + ), summary_file, append = TRUE) + } + + }, error=function(e) { + cat("::error:: Risk assessment failed:", e$message, "\n") }) - - cat("\n=== Risk Assessment Complete ===\n") shell: Rscript {0} - name: Upload assessment artifacts uses: actions/upload-artifact@v4 if: always() with: - name: risk-assessment-logs + name: risk-assessment-output path: | *.log *.Rcheck/ + assessment_results.json + assessment_results.rds retention-days: 30 From 1b1605843dad50377c2d1e6e0d486a0f3fd79d5d Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sun, 31 Aug 2025 10:45:24 +0530 Subject: [PATCH 04/10] [CHECK] update actions - 2 --- .github/workflows/R-CMD-check.yaml | 67 +++--- .github/workflows/riskassessr.yaml | 320 +++++++++++++++++++++-------- renv.lock | 24 +-- 3 files changed, 288 insertions(+), 123 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 67975c7..95d755a 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,35 +1,48 @@ name: R-CMD-check -on: +on: push: + branches: [main, master] pull_request: + branches: [main, master] jobs: R-CMD-check: - runs-on: ubuntu-latest - container: - image: rocker/tidyverse:latest - + runs-on: ${{ matrix.config.os }} + + name: ${{ matrix.config.os }} (${{ matrix.config.r }}) + + strategy: + fail-fast: false + matrix: + config: + - {os: windows-latest, r: 'release'} + - {os: ubuntu-latest, r: 'release'} + + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + R_KEEP_PKG_SOURCE: yes + steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Set up R - uses: r-lib/actions/setup-r@v2 - - - name: Set up R dependencies - uses: r-lib/actions/setup-renv@v2 - - - name: Cache R packages - uses: actions/cache@v3 - with: - path: ~/.local/share/renv - key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }} - restore-keys: | - ${{ runner.os }}-renv- - - - name: Install package - run: R CMD INSTALL . - - - name: Run tests - run: R -e 'devtools::test()' + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Pandoc + uses: r-lib/actions/setup-pandoc@v2 + + - name: Setup R + uses: r-lib/actions/setup-r@v2 + with: + r-version: ${{ matrix.config.r }} + use-public-rspm: true + + - name: Setup R dependencies + uses: r-lib/actions/setup-r-dependencies@v2 + with: + extra-packages: any::rcmdcheck, any::devtools + needs: check + + - name: Check R package + uses: r-lib/actions/check-r-package@v2 + with: + upload-snapshots: true diff --git a/.github/workflows/riskassessr.yaml b/.github/workflows/riskassessr.yaml index 41db945..c74c281 100644 --- a/.github/workflows/riskassessr.yaml +++ b/.github/workflows/riskassessr.yaml @@ -2,18 +2,15 @@ name: Package Risk Assessment on: push: - pull_request: - workflow_dispatch: jobs: risk-assessment: runs-on: ubuntu-latest name: Risk Assessment - + env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} R_KEEP_PKG_SOURCE: yes - CACHE_VERSION: v1 steps: - name: Checkout repository @@ -44,123 +41,278 @@ jobs: uses: actions/cache@v3 with: path: ${{ env.R_LIBS_USER }} - key: ${{ runner.os }}-${{ env.CACHE_VERSION }}-${{ hashFiles('.github/R-version') }}-${{ hashFiles('.github/depends.Rds') }} - restore-keys: | - ${{ runner.os }}-${{ env.CACHE_VERSION }}- + key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} + restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- - - name: Install dependencies + - name: Install package dependencies run: | - install.packages(c("remotes", "devtools", "risk.assessr", "crayon", "knitr", "jsonlite")) remotes::install_deps(dependencies = TRUE) shell: Rscript {0} + - name: Install risk.assessr and additional dependencies + run: | + install.packages(c("risk.assessr", "crayon", "knitr")) + shell: Rscript {0} + - name: Build package - run: devtools::build(path = ".", vignettes = FALSE) + run: | + devtools::build(path = ".", vignettes = FALSE) shell: Rscript {0} - name: Run Risk Assessment run: | + # Load required libraries library(risk.assessr) library(crayon) - library(jsonlite) - - `%||%` <- function(a, b) if (!is.null(a)) a else b - - log_time <- function(msg) { - cat(sprintf("[%s] %s\n", format(Sys.time(), "%Y-%m-%d %H:%M:%S UTC"), msg)) - } - + + # Set up CRAN repository + r <- getOption("repos") + r["CRAN"] <- "https://cloud.r-project.org" + options(repos = r) + + cat("=== Starting Package Risk Assessment ===\n") + cat("Repository:", Sys.getenv("GITHUB_REPOSITORY"), "\n") + cat("Branch:", Sys.getenv("GITHUB_REF_NAME"), "\n") + cat("Workflow run:", Sys.getenv("GITHUB_RUN_ID"), "\n") + cat("Timestamp:", format(Sys.time(), "%Y-%m-%d %H:%M:%S UTC"), "\n\n") + + # Pretty print function for GitHub Actions logs pretty_print_assessment <- function(assessment_results) { - if (is.null(assessment_results)) { - cat("āŒ No assessment results\n") + + if (is.null(assessment_results) || length(assessment_results) == 0) { + cat("āŒ No assessment results to display.\n") return() } - - # PACKAGE INFO - cat("::group::šŸ“¦ Package Info\n") - pkg_name <- assessment_results$package %||% assessment_results$pkg_name %||% "Unknown" - cat("Package:", pkg_name, "\n") - cat("Generated:", format(Sys.time(), "%Y-%m-%d %H:%M:%S UTC"), "\n") - cat("::endgroup::\n") - - # R CMD CHECK + + # Helper functions for colored output in GitHub Actions + print_header <- function(title) { + cat("\n") + cat("šŸ” ===", title, "===\n") + cat(paste(rep("=", nchar(title) + 10), collapse = ""), "\n") + } + + print_subheader <- function(title) { + cat("\nšŸ“Š", title, "\n") + cat(paste(rep("-", nchar(title) + 3), collapse = ""), "\n") + } + + # Extract package name + pkg_name <- "Unknown Package" + if ("package" %in% names(assessment_results)) { + pkg_name <- assessment_results$package + } else if ("pkg_name" %in% names(assessment_results)) { + pkg_name <- assessment_results$pkg_name + } + + print_header("PACKAGE ASSESSMENT RESULTS") + cat("šŸ“¦ Package:", pkg_name, "\n") + cat("ā° Generated:", format(Sys.time(), "%Y-%m-%d %H:%M:%S"), "\n") + + # Print R CMD Check Results if ("rcmdcheck" %in% names(assessment_results)) { - cat("::group::šŸ” R CMD CHECK\n") + print_header("R CMD CHECK RESULTS") rcmd <- assessment_results$rcmdcheck - if (length(rcmd$errors) > 0) { - cat(red$bold("āŒ Errors:\n"), paste(rcmd$errors, collapse="\n"), "\n") - } else cat(green$bold("āœ… No errors\n")) - if (length(rcmd$warnings) > 0) { - cat(yellow$bold("āš ļø Warnings:\n"), paste(rcmd$warnings, collapse="\n"), "\n") - } else cat(green$bold("āœ… No warnings\n")) - if (length(rcmd$notes) > 0) { - cat(blue$bold("ā„¹ļø Notes:\n"), paste(rcmd$notes, collapse="\n"), "\n") - } else cat(green$bold("āœ… No notes\n")) - cat("::endgroup::\n") + + if (is.list(rcmd)) { + # Errors + if ("errors" %in% names(rcmd) && length(rcmd$errors) > 0) { + print_subheader("🚨 ERRORS") + for (error in rcmd$errors) { + cat("āŒ", error, "\n") + } + cat("::error::R CMD check found", length(rcmd$errors), "error(s)\n") + } else { + cat("āœ… No errors found\n") + } + + # Warnings + if ("warnings" %in% names(rcmd) && length(rcmd$warnings) > 0) { + print_subheader("āš ļø WARNINGS") + for (warning in rcmd$warnings) { + cat("āš ļø", warning, "\n") + } + cat("::warning::R CMD check found", length(rcmd$warnings), "warning(s)\n") + } else { + cat("āœ… No warnings found\n") + } + + # Notes + if ("notes" %in% names(rcmd) && length(rcmd$notes) > 0) { + print_subheader("šŸ“ NOTES") + for (note in rcmd$notes) { + cat("ā„¹ļø", note, "\n") + } + cat("::notice::R CMD check found", length(rcmd$notes), "note(s)\n") + } else { + cat("āœ… No notes\n") + } + } else { + cat(as.character(rcmd), "\n") + } } - - # COVERAGE + + # Print Coverage Results if ("covr" %in% names(assessment_results)) { - cat("::group::šŸ“ˆ Coverage\n") + print_header("CODE COVERAGE") covr <- assessment_results$covr + if (is.numeric(covr)) { coverage_pct <- round(covr, 2) - cat("Coverage:", coverage_pct, "%\n") - if (coverage_pct < 60) cat("::error::Coverage < 60%\n") - else if (coverage_pct < 80) cat("::warning::Coverage < 80%\n") - } else print(covr) - cat("::endgroup::\n") + if (coverage_pct >= 80) { + cat("āœ… Coverage:", coverage_pct, "%\n") + } else if (coverage_pct >= 60) { + cat("āš ļø Coverage:", coverage_pct, "%\n") + cat("::warning::Code coverage is below 80%\n") + } else { + cat("āŒ Coverage:", coverage_pct, "%\n") + cat("::error::Code coverage is below 60%\n") + } + } else if (is.data.frame(covr)) { + cat("Coverage details:\n") + print(covr) + } else { + cat(as.character(covr), "\n") + } } - - # DEPENDENCIES + + # Print Dependencies if ("dependencies" %in% names(assessment_results)) { - cat("::group::šŸ“‹ Dependencies\n") - print(assessment_results$dependencies) - cat("::endgroup::\n") + print_header("DEPENDENCIES") + deps <- assessment_results$dependencies + + if (is.data.frame(deps)) { + if (nrow(deps) > 0) { + cat("šŸ“‹ Found", nrow(deps), "dependencies:\n") + print(deps) + } else { + cat("āœ… No dependencies found\n") + } + } else if (is.list(deps)) { + if (length(deps) > 0) { + for (name in names(deps)) { + cat("•", name, ":", as.character(deps[[name]]), "\n") + } + } else { + cat("āœ… No dependencies found\n") + } + } else { + cat(as.character(deps), "\n") + } } - - # METRICS + + # Print Metrics if ("metrics" %in% names(assessment_results)) { - cat("::group::šŸ“Š Metrics\n") - print(assessment_results$metrics) - cat("::endgroup::\n") + print_header("PACKAGE METRICS") + metrics <- assessment_results$metrics + + if (is.data.frame(metrics)) { + if (nrow(metrics) > 0) { + print(metrics) + } else { + cat("No metrics data available\n") + } + } else if (is.list(metrics)) { + if (length(metrics) > 0) { + for (name in names(metrics)) { + cat("•", name, ":", as.character(metrics[[name]]), "\n") + } + } else { + cat("No metrics data available\n") + } + } else { + cat(as.character(metrics), "\n") + } + } + + # Print other components + other_components <- names(assessment_results)[!names(assessment_results) %in% + c("rcmdcheck", "covr", "dependencies", "metrics", "package", "pkg_name")] + + if (length(other_components) > 0) { + print_header("OTHER ASSESSMENT DATA") + + for (component in other_components) { + data <- assessment_results[[component]] + cat("\nšŸ“‹", toupper(component), "\n") + + if (is.data.frame(data) && nrow(data) > 0) { + print(data) + } else if (is.list(data) && length(data) > 0) { + str(data, max.level = 2) + } else if (!is.null(data) && length(data) > 0) { + cat(as.character(data), "\n") + } else { + cat("No data available\n") + } + } } + + # Summary + print_header("ASSESSMENT SUMMARY") + cat("šŸ“Š Total components assessed:", length(assessment_results), "\n") + + # Create GitHub Actions summary + error_count <- if("rcmdcheck" %in% names(assessment_results) && + "errors" %in% names(assessment_results$rcmdcheck)) + length(assessment_results$rcmdcheck$errors) else 0 + warning_count <- if("rcmdcheck" %in% names(assessment_results) && + "warnings" %in% names(assessment_results$rcmdcheck)) + length(assessment_results$rcmdcheck$warnings) else 0 + note_count <- if("rcmdcheck" %in% names(assessment_results) && + "notes" %in% names(assessment_results$rcmdcheck)) + length(assessment_results$rcmdcheck$notes) else 0 + + if (error_count > 0) { + cat("::error::Assessment completed with", error_count, "errors\n") + } else if (warning_count > 0) { + cat("::warning::Assessment completed with", warning_count, "warnings\n") + } else { + cat("::notice::Assessment completed successfully\n") + } + + cat("\nšŸŽ‰ Assessment display completed!\n") } - - log_time("šŸš€ Running risk assessment with risk.assessr...") + + # Run the assessment tryCatch({ - assessment <- risk_assess_pkg(".") - pretty_print_assessment(assessment) - - # Save logs & structured results - saveRDS(assessment, "assessment_results.rds") - write_json(assessment, "assessment_results.json", pretty=TRUE, auto_unbox=TRUE) - - # Write summary for GitHub - summary_file <- Sys.getenv("GITHUB_STEP_SUMMARY") - if (nzchar(summary_file)) { - writeLines(c( - "## šŸ“Š Risk Assessment Summary", - paste0("- Package: ", assessment$package %||% "Unknown"), - paste0("- Errors: ", length(assessment$rcmdcheck$errors) %||% 0), - paste0("- Warnings: ", length(assessment$rcmdcheck$warnings) %||% 0), - paste0("- Notes: ", length(assessment$rcmdcheck$notes) %||% 0) - ), summary_file, append = TRUE) - } - - }, error=function(e) { - cat("::error:: Risk assessment failed:", e$message, "\n") + cat("šŸš€ Starting risk assessment...\n") + + # Use the simplified risk_assess_pkg function with current directory + comprehensive_assessment <- risk_assess_pkg(".") + + # Print the results + pretty_print_assessment(comprehensive_assessment) + + }, error = function(e) { + cat("::error::Assessment failed with error:", e$message, "\n") + cat("šŸ“‹ Attempting fallback assessment...\n") + + # Fallback: try building package first + tryCatch({ + # Build the package + built_pkg <- devtools::build(".", quiet = FALSE) + cat("šŸ“¦ Package built:", built_pkg, "\n") + + # Try assessment with built package + comprehensive_assessment <- risk_assess_pkg(built_pkg) + pretty_print_assessment(comprehensive_assessment) + + }, error = function(e2) { + cat("::error::Fallback assessment also failed:", e2$message, "\n") + cat("šŸ” Package structure:\n") + cat(paste(list.files(".", recursive = TRUE, include.dirs = TRUE), collapse = "\n"), "\n") + }) }) + + cat("\n=== Risk Assessment Complete ===\n") shell: Rscript {0} - name: Upload assessment artifacts uses: actions/upload-artifact@v4 if: always() with: - name: risk-assessment-output + name: risk-assessment-logs path: | *.log *.Rcheck/ - assessment_results.json - assessment_results.rds retention-days: 30 diff --git a/renv.lock b/renv.lock index 0e124bc..4081470 100644 --- a/renv.lock +++ b/renv.lock @@ -359,7 +359,7 @@ }, "knitr": { "Package": "knitr", - "Version": "1.50", + "Version": "1.48", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -371,7 +371,7 @@ "xfun", "yaml" ], - "Hash": "5a07d8ec459d7b80bd4acca5f4a6e062" + "Hash": "acf380f300c721da9fde7df115a5f86f" }, "lifecycle": { "Package": "lifecycle", @@ -388,7 +388,7 @@ }, "lubridate": { "Package": "lubridate", - "Version": "1.9.4", + "Version": "1.9.3", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -397,7 +397,7 @@ "methods", "timechange" ], - "Hash": "be38bc740fc51783a78edb5a157e4104" + "Hash": "680ad542fbcf801442c83a6ac5a2126c" }, "magrittr": { "Package": "magrittr", @@ -547,7 +547,7 @@ }, "rmarkdown": { "Package": "rmarkdown", - "Version": "2.29", + "Version": "2.27", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -566,7 +566,7 @@ "xfun", "yaml" ], - "Hash": "df99277f63d01c34e95e3d2f06a79736" + "Hash": "27f9502e1cdbfa195f94e03b0f517484" }, "sass": { "Package": "sass", @@ -591,12 +591,12 @@ }, "tibble": { "Package": "tibble", - "Version": "3.3.0", + "Version": "3.2.1", "Source": "Repository", "Repository": "CRAN", "Requirements": [ "R", - "cli", + "fansi", "lifecycle", "magrittr", "methods", @@ -606,7 +606,7 @@ "utils", "vctrs" ], - "Hash": "784b27d0801c3829de602105757b2cd7" + "Hash": "a84e2cc86d07289b3b6f5069df7a004c" }, "tidyselect": { "Package": "tidyselect", @@ -720,7 +720,7 @@ }, "xfun": { "Package": "xfun", - "Version": "0.53", + "Version": "0.47", "Source": "Repository", "Repository": "CRAN", "Requirements": [ @@ -729,7 +729,7 @@ "stats", "tools" ], - "Hash": "1befe97a0d56060b3964e3986d408df9" + "Hash": "36ab21660e2d095fef0d83f689e0477c" }, "yaml": { "Package": "yaml", @@ -739,4 +739,4 @@ "Hash": "9cb28d11799d93c953f852083d55ee9e" } } -} +} \ No newline at end of file From 04629558131fe9c53fbffe15c8e276af90f807fe Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sun, 31 Aug 2025 10:46:48 +0530 Subject: [PATCH 05/10] [CHECK] update actions - 3 --- .github/workflows/R-CMD-check.yaml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 95d755a..ffced6b 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -1,10 +1,6 @@ name: R-CMD-check -on: - push: - branches: [main, master] - pull_request: - branches: [main, master] +on: [push, pull_request] jobs: R-CMD-check: From d65f984e07ec9e41dbbbd9edac0c4160f306d461 Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sun, 31 Aug 2025 11:53:20 +0530 Subject: [PATCH 06/10] [CHECK] check for oss vulnerabilites --- .github/workflows/security-check.yaml | 153 ++++++++++++++++++ README.Rmd | 220 -------------------------- README.md | 2 + 3 files changed, 155 insertions(+), 220 deletions(-) create mode 100644 .github/workflows/security-check.yaml delete mode 100644 README.Rmd diff --git a/.github/workflows/security-check.yaml b/.github/workflows/security-check.yaml new file mode 100644 index 0000000..d212095 --- /dev/null +++ b/.github/workflows/security-check.yaml @@ -0,0 +1,153 @@ +name: Security Check + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + schedule: + # Run weekly on Sundays at 2 AM UTC + - cron: '0 2 * * 0' + workflow_dispatch: + +jobs: + security-audit: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up R + uses: r-lib/actions/setup-r@v2 + with: + r-version: 'release' + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y libcurl4-openssl-dev libssl-dev libxml2-dev + + - name: Cache R packages + uses: actions/cache@v3 + with: + path: ~/.local/lib/R/site-library + key: ${{ runner.os }}-r-${{ hashFiles('DESCRIPTION') }} + restore-keys: ${{ runner.os }}-r- + + - name: Install oysteR + run: | + R -e "install.packages('oysteR', repos='https://cran.r-project.org')" + + - name: Install clintrialx (if needed) + run: | + R -e "if (!require('clintrialx', quietly = TRUE)) install.packages('clintrialx', repos='https://cran.r-project.org')" + continue-on-error: true + + - name: Run security audit + id: audit + run: | + # Create R script for vulnerability check + cat > check_vulnerabilities.R << 'EOF' + library(oysteR) + + # Function to safely check vulnerabilities + check_package_vulnerabilities <- function(pkg_name) { + tryCatch({ + # Try to get vulnerabilities for the package + result <- expect_secure(pkg_name) + + # If we get here, no vulnerabilities found + cat("VULNERABILITY_COUNT=0\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + cat("STATUS=success\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + cat("MESSAGE=No vulnerabilities found\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + + return(0) + }, error = function(e) { + # Check if error is due to vulnerabilities found + if (grepl("vulnerabilities", e$message, ignore.case = TRUE)) { + # Parse vulnerability count if possible + vuln_match <- regexpr("[0-9]+", e$message) + if (vuln_match > 0) { + vuln_count <- regmatches(e$message, vuln_match) + cat(paste0("VULNERABILITY_COUNT=", vuln_count, "\n"), file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + } else { + cat("VULNERABILITY_COUNT=unknown\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + } + cat("STATUS=failure\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + cat(paste0("MESSAGE=", gsub("\n", " ", e$message), "\n"), file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + } else { + # Other error (package not found, network issue, etc.) + cat("VULNERABILITY_COUNT=error\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + cat("STATUS=error\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + cat(paste0("MESSAGE=Check failed: ", gsub("\n", " ", e$message), "\n"), file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) + } + return(1) + }) + } + + # Run the check + result <- check_package_vulnerabilities("clintrialx") + quit(status = result) + EOF + + # Run the R script + R --slave < check_vulnerabilities.R + continue-on-error: true + + - name: Create vulnerability badge + run: | + # Determine badge color and message based on results + case "${{ steps.audit.outputs.STATUS }}" in + "success") + BADGE_COLOR="brightgreen" + BADGE_MESSAGE="0" + ;; + "failure") + BADGE_COLOR="red" + BADGE_MESSAGE="${{ steps.audit.outputs.VULNERABILITY_COUNT }}" + ;; + "error") + BADGE_COLOR="orange" + BADGE_MESSAGE="check%20failed" + ;; + *) + BADGE_COLOR="lightgrey" + BADGE_MESSAGE="unknown" + ;; + esac + + # Create badge URL + BADGE_URL="https://img.shields.io/badge/clintrialx%20vulnerabilities-${BADGE_MESSAGE}-${BADGE_COLOR}" + + # Output badge info + echo "BADGE_URL=${BADGE_URL}" >> $GITHUB_OUTPUT + echo "Badge URL: ${BADGE_URL}" + echo "Status: ${{ steps.audit.outputs.STATUS }}" + echo "Message: ${{ steps.audit.outputs.MESSAGE }}" + id: badge + + - name: Update README badge (optional) + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' + run: | + # This step would update your README.md file with the new badge + # You can customize this based on your README structure + echo "Badge URL for README: ${{ steps.badge.outputs.BADGE_URL }}" + echo "You can manually update your README.md with this badge URL" + + - name: Create badge artifact + uses: actions/upload-artifact@v3 + with: + name: security-badge + path: | + badge_info.txt + retention-days: 30 + if: always() + + - name: Save badge info + run: | + echo "Badge URL: ${{ steps.badge.outputs.BADGE_URL }}" > badge_info.txt + echo "Status: ${{ steps.audit.outputs.STATUS }}" >> badge_info.txt + echo "Vulnerability Count: ${{ steps.audit.outputs.VULNERABILITY_COUNT }}" >> badge_info.txt + echo "Message: ${{ steps.audit.outputs.MESSAGE }}" >> badge_info.txt + if: always() diff --git a/README.Rmd b/README.Rmd deleted file mode 100644 index 12ce7ae..0000000 --- a/README.Rmd +++ /dev/null @@ -1,220 +0,0 @@ ---- -output: github_document -editor_options: - markdown: - wrap: 72 ---- - - - -```{r include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>", - fig.path = "man/figures/README-", - out.width = "100%" -) -``` - -# `ClinTrialX` - - -[![R-CMD-check](https://github.com/ineelhere/clintrialx/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/ineelhere/clintrialx/actions/workflows/R-CMD-check.yaml) -[![License: -Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://opensource.org/license/apache-2-0) -[![pkgdown](https://img.shields.io/badge/pkgdown-docs-blue.svg)](https://www.indraneelchakraborty.com/clintrialx/) -[![Visitors](https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fgithub.com%2Fineelhere%2Fclintrialx&label=Visitors&labelColor=%23f47373&countColor=%2337d67a&style=flat&labelStyle=upper)](https://github.com/ineelhere/clintrialx) -[![CRAN -status](https://www.r-pkg.org/badges/version/clintrialx)](https://CRAN.R-project.org/package=clintrialx) -[![CRAN -downloads](https://cranlogs.r-pkg.org/badges/clintrialx)](https://CRAN.R-project.org/package=clintrialx) - -[![Data Sources: -ClinicalTrials.gov](https://img.shields.io/badge/Data_Sources-ClinicalTrials.gov-blue)](https://clinicaltrials.gov/data-api/api) -[![Data Sources: CTTI -AACT](https://img.shields.io/badge/Data_Sources-CTTI%20AACT%20-purple)](https://aact.ctti-clinicaltrials.org/) - - - -The goal of `{clintrialx}` is to fetch clinical trials data from freely -available registries. Currently, it supports querying the - -- [ClinicalTrials.gov](https://clinicaltrials.gov/) registry using its - [V2 API](https://clinicaltrials.gov/data-api/api) and - -- [CTTI AACT](https://aact.ctti-clinicaltrials.org/) (Public Access to - Aggregate Content of ClinicalTrials.gov). - -## Installation - -Install the package from [CRAN](https://CRAN.R-project.org/package=clintrialx) with: -```r -install.packages("clintrialx") -``` -You can install this package from -[GitHub](https://github.com/ineelhere/clintrialx) with: - -*you'll need the `devtools` package for this* - -``` r -# install.packages("devtools") -devtools::install_github("ineelhere/clintrialx") -``` - -### Check installation - -``` r -library(clintrialx) -``` - -## Setup AACT account - -#### `Only if you wish to use AACT as a source for the data` - -- Visit - -- Sign up and create an account. It's free. - -- The `username` and `password` will be needed to fetch data using - this package. - -- Save it in a `.Renviron` file, for example- - - ``` r - user = "random_name" - password = "random_password" - ``` - -- Now that the file is created, load the variable with the command - `readRenviron("path/to/.Renviron)` - -- You're all set! - -## Query the [ClinicalTrials.gov](https://clinicaltrials.gov/) Registry - -#### Based on NCT IDs - -Fetch one or multiple trial records based on NCT IDs. You can opt to -fetch some specific fields or all fields available at source (default). - -```{r example1, eval = FALSE} -library(clintrialx) -ctg_get_nct(c("NCT02967965", "NCT04000165", "NCT01007279", "NCT02376244", "NCT01179776"), - fields = c("NCT Number", "Study Title", "Study Status", "Sponsor")) - - -``` - -#### Based on fileds - -Supports filtering by condition, location, title keywords, intervention, -and overall status. - -```{r example2, eval = FALSE} -ctg_get_fields( - condition = "Cancer", - location = "Kolkata", - title = NULL, - intervention = "Drug", - status = c("ACTIVE_NOT_RECRUITING", "RECRUITING"), - page_size = 10 -) - -``` - -#### Based on fields - Bulk download - -Download all available data for your query. No limits! - -*Supports filtering by condition, location, title keywords, -intervention, and overall status.* - -```{r example5, eval = FALSE} -df <- ctg_bulk_fetch(location="india") -``` - -## Query the [CTTI AACT](https://aact.ctti-clinicaltrials.org/) - -#### Run Custom Queries - -``` -# Set environment variables for database credentials in .Renviron and load it -# readRenviron(".Renviron") - -# Connect to the database -con <- aact_connection(Sys.getenv('user'), Sys.getenv('password')) - -# Run a custom query -query <- "SELECT nct_id, source, enrollment, overall_status FROM studies LIMIT 5;" -results <- aact_custom_query(con, query) - -# Print the results -print(results) -``` - -## Trial Data HTML Reports - -*Currently works for data from ClinicalTrials.Gov* - -Visit here for an exqample report - - - -```{r example6, eval = FALSE} -#first get the data in a R dataframe -my_clinical_trial_data <- ctg_bulk_fetch(condition="cancer") -#now pass it to the reports function -ctg_data_report( - ctg_data = my_clinical_trial_data, - title = "Clinical Trials Analysis", - author = "Indra", - output_file = "reports/clinical_trials.html", - theme = "flatly", - color_palette = c("#4E79A7", "#F28E2B", "#E15759", "#76B7B2", "#59A14F", "#EDC948"), - include_data_quality = TRUE, - include_interactive_plots = TRUE, - custom_footer = "Proprietary report generated by SomeGreatOrg Inc." -) - -# Generate a report with static plots and no data quality assessment -ctg_data_report( - ctg_data = my_clinical_trial_data, - title = "Quick Clinical Trial Overview", - include_data_quality = FALSE, - include_interactive_plots = FALSE -) - -``` - -Check the path `reports/clinical_trials.html` on your local. It will -have the html report file. - -Cool stuff - It also has the codes to the plots! - -## Data Sources - -You can fetch version information directly from the package: - -```{r example3, eval = FALSE} -version_info(source = "clinicaltrials.gov") - - -``` - -## Get Involved - -šŸš€ Ready to contribute? Let's make clintrialx even better! - -- Fork the [GitHub](https://github.com/ineelhere/clintrialx) repo. -- Check out your development branch from the dev branch. -- Do your work on a feature (ftr) branch. -- Raise a PR against the dev branch of the [clintrialx](https://github.com/ineelhere/clintrialx) repo. -- Sit back and [relax](https://www.youtube.com/watch?v=Uffjii1hXzU) while I review it! - -šŸ’¬ **Questions or Feedback?** Feel free to open an issue on [GitHub -Issues page](https://github.com/ineelhere/clintrialx/issues). - -🌟 **Enjoying `clintrialx`?** Please consider giving it a star on -[GitHub](https://github.com/ineelhere/clintrialx)! Your support helps -this project grow and improve. - -More updates to come. Happy coding! šŸŽ‰ diff --git a/README.md b/README.md index 5bc4af5..da330fe 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ downloads](https://cranlogs.r-pkg.org/badges/clintrialx)](https://CRAN.R-project ClinicalTrials.gov](https://img.shields.io/badge/Data_Sources-ClinicalTrials.gov-blue)](https://clinicaltrials.gov/data-api/api) [![Data Sources: CTTI AACT](https://img.shields.io/badge/Data_Sources-CTTI%20AACT%20-purple)](https://aact.ctti-clinicaltrials.org/) +![Security Check](https://github.com/yourusername/yourrepo/workflows/Security%20Check/badge.svg) + From d26cb58ae6450e40c843375ade5bfc2e4ee6b832 Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sun, 31 Aug 2025 11:55:17 +0530 Subject: [PATCH 07/10] [CHECK] check for oss vulnerabilites - 2 --- .github/workflows/security-check.yaml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/security-check.yaml b/.github/workflows/security-check.yaml index d212095..60f201b 100644 --- a/.github/workflows/security-check.yaml +++ b/.github/workflows/security-check.yaml @@ -1,14 +1,6 @@ name: Security Check -on: - push: - branches: [ main, master ] - pull_request: - branches: [ main, master ] - schedule: - # Run weekly on Sundays at 2 AM UTC - - cron: '0 2 * * 0' - workflow_dispatch: +on: [push, pull_request] jobs: security-audit: From 42bb3f664661ed5cb4a614e9a3414e805301a30d Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sun, 31 Aug 2025 12:00:36 +0530 Subject: [PATCH 08/10] [CHECK] check for oss vulnerabilites - 3 --- .github/workflows/security-check.yaml | 66 +++++++++++++-------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/.github/workflows/security-check.yaml b/.github/workflows/security-check.yaml index 60f201b..a00d78b 100644 --- a/.github/workflows/security-check.yaml +++ b/.github/workflows/security-check.yaml @@ -5,55 +5,55 @@ on: [push, pull_request] jobs: security-audit: runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 - + - name: Set up R uses: r-lib/actions/setup-r@v2 with: r-version: 'release' - + - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y libcurl4-openssl-dev libssl-dev libxml2-dev - + - name: Cache R packages uses: actions/cache@v3 with: path: ~/.local/lib/R/site-library key: ${{ runner.os }}-r-${{ hashFiles('DESCRIPTION') }} restore-keys: ${{ runner.os }}-r- - + - name: Install oysteR run: | R -e "install.packages('oysteR', repos='https://cran.r-project.org')" - + - name: Install clintrialx (if needed) run: | R -e "if (!require('clintrialx', quietly = TRUE)) install.packages('clintrialx', repos='https://cran.r-project.org')" continue-on-error: true - + - name: Run security audit id: audit run: | # Create R script for vulnerability check cat > check_vulnerabilities.R << 'EOF' library(oysteR) - + # Function to safely check vulnerabilities check_package_vulnerabilities <- function(pkg_name) { tryCatch({ # Try to get vulnerabilities for the package result <- expect_secure(pkg_name) - + # If we get here, no vulnerabilities found cat("VULNERABILITY_COUNT=0\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) cat("STATUS=success\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) cat("MESSAGE=No vulnerabilities found\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - + return(0) }, error = function(e) { # Check if error is due to vulnerabilities found @@ -77,17 +77,18 @@ jobs: return(1) }) } - + # Run the check result <- check_package_vulnerabilities("clintrialx") quit(status = result) EOF - + # Run the R script R --slave < check_vulnerabilities.R continue-on-error: true - + - name: Create vulnerability badge + id: badge run: | # Determine badge color and message based on results case "${{ steps.audit.outputs.STATUS }}" in @@ -108,38 +109,35 @@ jobs: BADGE_MESSAGE="unknown" ;; esac - + # Create badge URL BADGE_URL="https://img.shields.io/badge/clintrialx%20vulnerabilities-${BADGE_MESSAGE}-${BADGE_COLOR}" - + # Output badge info echo "BADGE_URL=${BADGE_URL}" >> $GITHUB_OUTPUT echo "Badge URL: ${BADGE_URL}" echo "Status: ${{ steps.audit.outputs.STATUS }}" echo "Message: ${{ steps.audit.outputs.MESSAGE }}" - id: badge - - - name: Update README badge (optional) - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' - run: | - # This step would update your README.md file with the new badge - # You can customize this based on your README structure - echo "Badge URL for README: ${{ steps.badge.outputs.BADGE_URL }}" - echo "You can manually update your README.md with this badge URL" - - - name: Create badge artifact - uses: actions/upload-artifact@v3 - with: - name: security-badge - path: | - badge_info.txt - retention-days: 30 - if: always() - + - name: Save badge info + if: always() run: | echo "Badge URL: ${{ steps.badge.outputs.BADGE_URL }}" > badge_info.txt echo "Status: ${{ steps.audit.outputs.STATUS }}" >> badge_info.txt echo "Vulnerability Count: ${{ steps.audit.outputs.VULNERABILITY_COUNT }}" >> badge_info.txt echo "Message: ${{ steps.audit.outputs.MESSAGE }}" >> badge_info.txt + + - name: Create badge artifact if: always() + uses: actions/upload-artifact@v4 # ← updated to v4 + with: + name: security-badge + path: badge_info.txt + retention-days: 30 + + - name: Update README badge (optional) + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' + run: | + # This step would update your README.md file with the new badge + echo "Badge URL for README: ${{ steps.badge.outputs.BADGE_URL }}" + echo "You can manually update your README.md with this badge URL" From 76688aabb7cd87b3d8cc66036cb0bcab23d1c8f3 Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Sun, 31 Aug 2025 12:48:42 +0530 Subject: [PATCH 09/10] byepass rmd for readme --- .github/workflows/security-check.yaml | 143 -------------------------- README.md | 19 ++-- 2 files changed, 7 insertions(+), 155 deletions(-) delete mode 100644 .github/workflows/security-check.yaml diff --git a/.github/workflows/security-check.yaml b/.github/workflows/security-check.yaml deleted file mode 100644 index a00d78b..0000000 --- a/.github/workflows/security-check.yaml +++ /dev/null @@ -1,143 +0,0 @@ -name: Security Check - -on: [push, pull_request] - -jobs: - security-audit: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up R - uses: r-lib/actions/setup-r@v2 - with: - r-version: 'release' - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libcurl4-openssl-dev libssl-dev libxml2-dev - - - name: Cache R packages - uses: actions/cache@v3 - with: - path: ~/.local/lib/R/site-library - key: ${{ runner.os }}-r-${{ hashFiles('DESCRIPTION') }} - restore-keys: ${{ runner.os }}-r- - - - name: Install oysteR - run: | - R -e "install.packages('oysteR', repos='https://cran.r-project.org')" - - - name: Install clintrialx (if needed) - run: | - R -e "if (!require('clintrialx', quietly = TRUE)) install.packages('clintrialx', repos='https://cran.r-project.org')" - continue-on-error: true - - - name: Run security audit - id: audit - run: | - # Create R script for vulnerability check - cat > check_vulnerabilities.R << 'EOF' - library(oysteR) - - # Function to safely check vulnerabilities - check_package_vulnerabilities <- function(pkg_name) { - tryCatch({ - # Try to get vulnerabilities for the package - result <- expect_secure(pkg_name) - - # If we get here, no vulnerabilities found - cat("VULNERABILITY_COUNT=0\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - cat("STATUS=success\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - cat("MESSAGE=No vulnerabilities found\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - - return(0) - }, error = function(e) { - # Check if error is due to vulnerabilities found - if (grepl("vulnerabilities", e$message, ignore.case = TRUE)) { - # Parse vulnerability count if possible - vuln_match <- regexpr("[0-9]+", e$message) - if (vuln_match > 0) { - vuln_count <- regmatches(e$message, vuln_match) - cat(paste0("VULNERABILITY_COUNT=", vuln_count, "\n"), file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - } else { - cat("VULNERABILITY_COUNT=unknown\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - } - cat("STATUS=failure\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - cat(paste0("MESSAGE=", gsub("\n", " ", e$message), "\n"), file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - } else { - # Other error (package not found, network issue, etc.) - cat("VULNERABILITY_COUNT=error\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - cat("STATUS=error\n", file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - cat(paste0("MESSAGE=Check failed: ", gsub("\n", " ", e$message), "\n"), file = Sys.getenv("GITHUB_OUTPUT"), append = TRUE) - } - return(1) - }) - } - - # Run the check - result <- check_package_vulnerabilities("clintrialx") - quit(status = result) - EOF - - # Run the R script - R --slave < check_vulnerabilities.R - continue-on-error: true - - - name: Create vulnerability badge - id: badge - run: | - # Determine badge color and message based on results - case "${{ steps.audit.outputs.STATUS }}" in - "success") - BADGE_COLOR="brightgreen" - BADGE_MESSAGE="0" - ;; - "failure") - BADGE_COLOR="red" - BADGE_MESSAGE="${{ steps.audit.outputs.VULNERABILITY_COUNT }}" - ;; - "error") - BADGE_COLOR="orange" - BADGE_MESSAGE="check%20failed" - ;; - *) - BADGE_COLOR="lightgrey" - BADGE_MESSAGE="unknown" - ;; - esac - - # Create badge URL - BADGE_URL="https://img.shields.io/badge/clintrialx%20vulnerabilities-${BADGE_MESSAGE}-${BADGE_COLOR}" - - # Output badge info - echo "BADGE_URL=${BADGE_URL}" >> $GITHUB_OUTPUT - echo "Badge URL: ${BADGE_URL}" - echo "Status: ${{ steps.audit.outputs.STATUS }}" - echo "Message: ${{ steps.audit.outputs.MESSAGE }}" - - - name: Save badge info - if: always() - run: | - echo "Badge URL: ${{ steps.badge.outputs.BADGE_URL }}" > badge_info.txt - echo "Status: ${{ steps.audit.outputs.STATUS }}" >> badge_info.txt - echo "Vulnerability Count: ${{ steps.audit.outputs.VULNERABILITY_COUNT }}" >> badge_info.txt - echo "Message: ${{ steps.audit.outputs.MESSAGE }}" >> badge_info.txt - - - name: Create badge artifact - if: always() - uses: actions/upload-artifact@v4 # ← updated to v4 - with: - name: security-badge - path: badge_info.txt - retention-days: 30 - - - name: Update README badge (optional) - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' - run: | - # This step would update your README.md file with the new badge - echo "Badge URL for README: ${{ steps.badge.outputs.BADGE_URL }}" - echo "You can manually update your README.md with this badge URL" diff --git a/README.md b/README.md index da330fe..0ca3f82 100644 --- a/README.md +++ b/README.md @@ -5,21 +5,16 @@ +[![CRAN status](https://www.r-pkg.org/badges/version/clintrialx)](https://CRAN.R-project.org/package=clintrialx) +[![CRAN downloads](https://cranlogs.r-pkg.org/badges/clintrialx)](https://CRAN.R-project.org/package=clintrialx) [![R-CMD-check](https://github.com/ineelhere/clintrialx/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/ineelhere/clintrialx/actions/workflows/R-CMD-check.yaml) -[![License: -Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://opensource.org/license/apache-2-0) +[![Security Status](https://img.shields.io/badge/security-verified-green?label=OSS%20Index)](https://ossindex.sonatype.org/component/pkg:cran/clintrialx) +[![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://opensource.org/license/apache-2-0) [![pkgdown](https://img.shields.io/badge/pkgdown-docs-blue.svg)](https://www.indraneelchakraborty.com/clintrialx/) +[![Data Sources: ClinicalTrials.gov](https://img.shields.io/badge/Data_Sources-ClinicalTrials.gov-blue)](https://clinicaltrials.gov/data-api/api) +[![Data Sources: CTTI AACT](https://img.shields.io/badge/Data_Sources-CTTI%20AACT%20-purple)](https://aact.ctti-clinicaltrials.org/) [![Visitors](https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fgithub.com%2Fineelhere%2Fclintrialx&label=Visitors&labelColor=%23f47373&countColor=%2337d67a&style=flat&labelStyle=upper)](https://github.com/ineelhere/clintrialx) -[![CRAN -status](https://www.r-pkg.org/badges/version/clintrialx)](https://CRAN.R-project.org/package=clintrialx) -[![CRAN -downloads](https://cranlogs.r-pkg.org/badges/clintrialx)](https://CRAN.R-project.org/package=clintrialx) - -[![Data Sources: -ClinicalTrials.gov](https://img.shields.io/badge/Data_Sources-ClinicalTrials.gov-blue)](https://clinicaltrials.gov/data-api/api) -[![Data Sources: CTTI -AACT](https://img.shields.io/badge/Data_Sources-CTTI%20AACT%20-purple)](https://aact.ctti-clinicaltrials.org/) -![Security Check](https://github.com/yourusername/yourrepo/workflows/Security%20Check/badge.svg) + From d08d61b273a4ba3b205434caa1ce4a7d773b5c12 Mon Sep 17 00:00:00 2001 From: Indraneel Chakraborty <64887729+ineelhere@users.noreply.github.com> Date: Wed, 10 Sep 2025 01:02:47 +0530 Subject: [PATCH 10/10] [CHECK] check for oss vulnerabilites - 4 --- .github/workflows/riskassessr.yaml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/riskassessr.yaml b/.github/workflows/riskassessr.yaml index c74c281..b1285f8 100644 --- a/.github/workflows/riskassessr.yaml +++ b/.github/workflows/riskassessr.yaml @@ -277,8 +277,12 @@ jobs: tryCatch({ cat("šŸš€ Starting risk assessment...\n") - # Use the simplified risk_assess_pkg function with current directory - comprehensive_assessment <- risk_assess_pkg(".") + # Build the package in a temp directory + built_pkg <- devtools::build(".", quiet = FALSE, path = tempdir()) + cat("šŸ“¦ Package built:", built_pkg, "\n") + + # Run risk assessment on the built tarball + comprehensive_assessment <- risk_assess_pkg(built_pkg) # Print the results pretty_print_assessment(comprehensive_assessment) @@ -287,14 +291,9 @@ jobs: cat("::error::Assessment failed with error:", e$message, "\n") cat("šŸ“‹ Attempting fallback assessment...\n") - # Fallback: try building package first + # Fallback: try assessment in current directory tryCatch({ - # Build the package - built_pkg <- devtools::build(".", quiet = FALSE) - cat("šŸ“¦ Package built:", built_pkg, "\n") - - # Try assessment with built package - comprehensive_assessment <- risk_assess_pkg(built_pkg) + comprehensive_assessment <- risk_assess_pkg(".") pretty_print_assessment(comprehensive_assessment) }, error = function(e2) {