Repository navigation
add logging to debug #91
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ################################################################################ | |
| # trigger CI | |
| # DataSHIELD GHA test suite - dsBaseClient | |
| # Replaces azure-pipelines.yml / opal_azure-pipelines.yml / armadillo_azure-pipelines.yml. | |
| # | |
| # Structure (all jobs below run in parallel except where "needs" says otherwise): | |
| # r-checks - devtools::document()/check() sync checks. No backend needed. | |
| # opal-dsbase (matrix: smk/arg/perf/misc) - dsBase suite against Opal, | |
| # one category per job. | |
| # opal-dsdanger - dsDanger suite against Opal (small, not sharded). | |
| # opal-report - needs the two Opal jobs above; merges + publishes report. | |
| # armadillo-dsbase (matrix: smk/arg/perf/misc) - dsBase suite against Armadillo. | |
| # armadillo-dsdanger - dsDanger suite against Armadillo. | |
| # armadillo-report - needs the two Armadillo jobs above; merges + publishes report. | |
| # | |
| # The dsBase suite (matching TEST_FILTER_DSBASE - same 292 files the Azure | |
| # pipelines run) is split by matrix into 4 fixed categories - smk (116 files), | |
| # arg (96), perf (51), and misc (the smaller categories: datachk, disc, expt, | |
| # smk_expt, math, and the "_-" catch-all - 29 combined) - each with its own | |
| # testthat filter substring, no file-list partitioning logic. Categories | |
| # aren't evenly sized, so job durations differ, but a category can be added, | |
| # removed, or temporarily skipped just by editing the matrix list. | |
| # | |
| # Each dsbase/dsdanger job spins up its OWN backend instance (isolated - no | |
| # shared server state / concurrency risk between categories running at once). | |
| # | |
| # Opal runs via docker-compose (docker-compose_opal.yml). | |
| # Armadillo runs as a plain `java -jar` process (not docker-compose): Armadillo | |
| # self-manages its Rock container over the host Docker socket | |
| # (docker-management-enabled: true / docker-run-in-container: false), which skips | |
| # building/pulling the old custom armadillo_citest image. See | |
| # molgenis-service-armadillo's application.template.yml for that flag pairing. | |
| # | |
| # Every job starts its backend as the very first step so it boots in the | |
| # background while R dependencies install, instead of paying for both serially. | |
| # | |
| # As of Sept. 2025 the single-backend, dsBase-only, unsharded version of this | |
| # took ~ 95 mins; the full (Opal+Armadillo, dsBase+dsDanger) unsharded run is | |
| # well over an hour. | |
| ################################################################################ | |
| name: dsBaseClient tests' suite | |
| on: | |
| push: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: '0 0 * * 0' # Weekly | |
| - cron: '0 1 * * *' # Nightly | |
| permissions: | |
| contents: read | |
| env: | |
| _r_check_system_clock_: 0 | |
| WORKFLOW_ID: ${{ github.run_id }}-${{ github.run_attempt }} | |
| PROJECT_NAME: dsBaseClient | |
| BRANCH_NAME: ${{ github.head_ref || github.ref_name }} | |
| REPO_OWNER: ${{ github.repository_owner }} | |
| R_KEEP_PKG_SOURCE: yes | |
| GITHUB_TOKEN: ${{ github.token || 'placeholder-token' }} | |
| # These should all be constant, except the two TEST_FILTER_* values. These can | |
| # be used to test subsets of test files in the testthat directory. Options are | |
| # like: '*' <- run all tests, '*_smk_*' <- run all the smoke tests. | |
| TEST_FILTER_DSBASE: '_-|datachk-|smk-|arg-|disc-|perf-|smk_expt-|expt-|math-' | |
| TEST_FILTER_DSDANGER: '__dgr-|datachk_dgr-|smk_dgr-|arg_dgr-|disc_dgr-|smk_expt_dgr-|expt_dgr-|math_dgr-' | |
| jobs: | |
| ################################################################################ | |
| # Doc-sync / R CMD check - no backend needed, so this runs once, not per | |
| # backend or per shard. | |
| ################################################################################ | |
| r-checks: | |
| name: Package checks (doc sync, R CMD check) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: r-lib/actions/setup-pandoc@v2 | |
| - uses: r-lib/actions/setup-r@v2 | |
| with: | |
| r-version: release | |
| http-user-agent: release | |
| use-public-rspm: true | |
| - name: Install system libraries | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y | |
| sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y | |
| - uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| dependencies: 'c("Imports")' | |
| extra-packages: | | |
| any::rcmdcheck | |
| cran::devtools | |
| cran::usethis | |
| needs: check | |
| - name: Check manual updated | |
| run: | | |
| orig_sum=$(find man -type f | sort -u | xargs cat | md5sum) | |
| R -q -e "devtools::document()" | |
| new_sum=$(find man -type f | sort -u | xargs cat | md5sum) | |
| if [ "$orig_sum" != "$new_sum" ]; then | |
| echo "Your committed man/*.Rd files are out of sync with the R headers." | |
| exit 1 | |
| fi | |
| continue-on-error: true | |
| - name: Devtools checks | |
| run: | | |
| R -q -e "devtools::check(args = c('--no-examples', '--no-tests'))" | tee azure-pipelines_check.Rout | |
| grep --quiet "^0 errors" azure-pipelines_check.Rout && grep --quiet " 0 warnings" azure-pipelines_check.Rout && grep --quiet " 0 notes" azure-pipelines_check.Rout | |
| continue-on-error: true | |
| ################################################################################ | |
| # Opal - dsBase suite, sharded 4 ways. Each shard is a fully isolated job | |
| # with its own Opal instance. | |
| ################################################################################ | |
| opal-dsbase: | |
| name: Opal dsBase tests (${{ matrix.category }}) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| # One matrix entry per test-file category, each with its own testthat | |
| # filter substring - not evenly sized (smk/arg are much bigger than | |
| # perf/misc), so job durations differ. Traded for the ability to add, | |
| # remove, or temporarily skip a whole category by editing this list | |
| # alone, with no shell-side partitioning logic to keep in sync. | |
| matrix: | |
| include: | |
| - category: smk | |
| filter: 'smk-' | |
| - category: arg | |
| filter: 'arg-' | |
| - category: perf | |
| filter: 'perf-' | |
| - category: misc | |
| filter: 'datachk-|disc-|expt-|smk_expt-|math-|_-' | |
| env: | |
| DS_DRIVER: OpalDriver | |
| DSBASE_REF: v7.0-dev | |
| steps: | |
| - name: Checkout dsBaseClient | |
| uses: actions/checkout@v4 | |
| with: | |
| path: dsBaseClient | |
| - name: Start Opal docker-compose | |
| run: docker compose -f docker-compose_opal.yml up -d --build | |
| working-directory: dsBaseClient | |
| - name: Uninstall default MySQL | |
| run: | | |
| sudo service mysql stop || true | |
| sudo apt-get update | |
| sudo apt-get remove --purge mysql-client mysql-server mysql-common -y | |
| sudo apt-get autoremove -y | |
| sudo apt-get autoclean -y | |
| sudo rm -rf /var/lib/mysql/ | |
| - uses: r-lib/actions/setup-pandoc@v2 | |
| - uses: r-lib/actions/setup-r@v2 | |
| with: | |
| r-version: release | |
| http-user-agent: release | |
| use-public-rspm: true | |
| - name: Install system libraries | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y | |
| sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y | |
| - uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| dependencies: 'c("Imports")' | |
| extra-packages: | | |
| cran::devtools | |
| cran::usethis | |
| cran::covr | |
| cran::fields | |
| cran::meta | |
| cran::metafor | |
| cran::ggplot2 | |
| cran::gridExtra | |
| cran::data.table | |
| cran::DSI | |
| cran::opalr | |
| cran::DSOpal | |
| cran::DSLite | |
| cran::MolgenisAuth | |
| cran::MolgenisArmadillo | |
| cran::DSMolgenisArmadillo | |
| cran::DescTools | |
| cran::e1071 | |
| needs: check | |
| - name: Install test datasets to Opal | |
| run: | | |
| sleep 60 | |
| R -q -f "obiba_opal-upload_testing_datasets.R" | |
| working-directory: dsBaseClient/tests/testthat/data_files | |
| - name: Install dsBase to Opal, set disclosure test options | |
| run: | | |
| R -q -e "library(opalr); opal <- opal.login(username = 'administrator', password = 'datashield_test&', url = 'http://localhost:8080/'); opal.put(opal, 'system', 'conf', 'general', '_rPackage'); opal.logout(opal)" | |
| R -q -e "library(opalr); opal <- opal.login('administrator','datashield_test&', url='http://localhost:8080/'); dsadmin.install_github_package(opal, 'dsBase', username = 'datashield', ref = '${{ env.DSBASE_REF }}'); opal.logout(opal)" | |
| sleep 60 | |
| expected_version=$(curl -sf "https://raw.githubusercontent.com/datashield/dsBase/${{ env.DSBASE_REF }}/DESCRIPTION" | sed -n 's/^Version: //p' | tr -d '\r') | |
| if [ -z "$expected_version" ]; then | |
| echo "Could not determine expected dsBase version from GitHub" | |
| exit 1 | |
| fi | |
| echo "Expected dsBase version: $expected_version" | |
| R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); desc <- dsadmin.package_description(opal, 'dsBase'); opal.logout(opal); installed_version <- desc[['Version']]; cat('Installed dsBase version:', installed_version, '\n'); if (is.null(installed_version) || installed_version != '$expected_version') stop('dsBase version mismatch: expected $expected_version, found ', installed_version)" | |
| R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); dsadmin.profile_init(opal, name = 'default', packages = c('dsBase', 'dsTidyverse', 'resourcer')); opal.logout(opal)" | |
| R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); dsadmin.set_option(opal, 'default.datashield.privacyControlLevel', 'permissive'); opal.logout(opal)" | |
| working-directory: dsBaseClient/tests/testthat/data_files | |
| - name: Run dsBase tests with coverage & JUnit report | |
| run: | | |
| R -q -e "devtools::reload();" | |
| R -q -e ' | |
| write.csv( | |
| covr::coverage_to_list( | |
| covr::package_coverage( | |
| type = c("none"), | |
| code = c('"'"' | |
| output_file <- file("test_console_output_dsbase.txt"); | |
| sink(output_file); | |
| sink(output_file, type = "message"); | |
| junit_rep <- testthat::JunitReporter$new(file = file.path(getwd(), "test_results_dsbase.xml")); | |
| progress_rep <- testthat::ProgressReporter$new(max_failures = 999999); | |
| multi_rep <- testthat::MultiReporter$new(reporters = list(progress_rep, junit_rep)); | |
| options("datashield.return_errors" = FALSE, "default_driver" = "${{ env.DS_DRIVER }}"); | |
| testthat::test_package("${{ env.PROJECT_NAME }}", filter = "${{ matrix.filter }}", reporter = multi_rep, stop_on_failure = FALSE)'"'"' | |
| ) | |
| ) | |
| ), | |
| "coveragelist.csv" | |
| )' | |
| cat test_console_output_dsbase.txt | |
| working-directory: dsBaseClient | |
| - name: Upload shard results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: opal-dsbase-${{ matrix.category }} | |
| path: | | |
| dsBaseClient/test_results_dsbase.xml | |
| dsBaseClient/test_console_output_dsbase.txt | |
| dsBaseClient/coveragelist.csv | |
| ################################################################################ | |
| # Opal - dsDanger suite. Small (~15 files), so it stays a single job rather | |
| # than sharding further. | |
| ################################################################################ | |
| opal-dsdanger: | |
| name: Opal dsDanger tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| env: | |
| DS_DRIVER: OpalDriver | |
| DSBASE_REF: v7.0-dev | |
| DSDANGER_REF: '6.3.4' | |
| steps: | |
| - name: Checkout dsBaseClient | |
| uses: actions/checkout@v4 | |
| with: | |
| path: dsBaseClient | |
| - name: Start Opal docker-compose | |
| run: docker compose -f docker-compose_opal.yml up -d --build | |
| working-directory: dsBaseClient | |
| - name: Uninstall default MySQL | |
| run: | | |
| sudo service mysql stop || true | |
| sudo apt-get update | |
| sudo apt-get remove --purge mysql-client mysql-server mysql-common -y | |
| sudo apt-get autoremove -y | |
| sudo apt-get autoclean -y | |
| sudo rm -rf /var/lib/mysql/ | |
| - uses: r-lib/actions/setup-pandoc@v2 | |
| - uses: r-lib/actions/setup-r@v2 | |
| with: | |
| r-version: release | |
| http-user-agent: release | |
| use-public-rspm: true | |
| - name: Install system libraries | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y | |
| sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y | |
| - uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| dependencies: 'c("Imports")' | |
| extra-packages: | | |
| cran::devtools | |
| cran::usethis | |
| cran::git2r | |
| cran::covr | |
| cran::fields | |
| cran::meta | |
| cran::metafor | |
| cran::ggplot2 | |
| cran::gridExtra | |
| cran::data.table | |
| cran::DSI | |
| cran::opalr | |
| cran::DSOpal | |
| cran::DSLite | |
| cran::MolgenisAuth | |
| cran::MolgenisArmadillo | |
| cran::DSMolgenisArmadillo | |
| cran::DescTools | |
| cran::e1071 | |
| needs: check | |
| - name: Install dsDangerClient | |
| run: R -q -e "devtools::install_github(repo='datashield/dsDangerClient', ref=Sys.getenv('BRANCH_NAME'))" | |
| - name: Install test datasets to Opal | |
| run: | | |
| sleep 60 | |
| R -q -f "obiba_opal-upload_testing_datasets.R" | |
| working-directory: dsBaseClient/tests/testthat/data_files | |
| - name: Install dsBase to Opal, set disclosure test options | |
| run: | | |
| R -q -e "library(opalr); opal <- opal.login(username = 'administrator', password = 'datashield_test&', url = 'http://localhost:8080/'); opal.put(opal, 'system', 'conf', 'general', '_rPackage'); opal.logout(opal)" | |
| R -q -e "library(opalr); opal <- opal.login('administrator','datashield_test&', url='http://localhost:8080/'); dsadmin.install_github_package(opal, 'dsBase', username = 'datashield', ref = '${{ env.DSBASE_REF }}'); opal.logout(opal)" | |
| sleep 60 | |
| expected_version=$(curl -sf "https://raw.githubusercontent.com/datashield/dsBase/${{ env.DSBASE_REF }}/DESCRIPTION" | sed -n 's/^Version: //p' | tr -d '\r') | |
| if [ -z "$expected_version" ]; then | |
| echo "Could not determine expected dsBase version from GitHub" | |
| exit 1 | |
| fi | |
| echo "Expected dsBase version: $expected_version" | |
| R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); desc <- dsadmin.package_description(opal, 'dsBase'); opal.logout(opal); installed_version <- desc[['Version']]; cat('Installed dsBase version:', installed_version, '\n'); if (is.null(installed_version) || installed_version != '$expected_version') stop('dsBase version mismatch: expected $expected_version, found ', installed_version)" | |
| R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); dsadmin.profile_init(opal, name = 'default', packages = c('dsBase', 'dsTidyverse', 'resourcer')); opal.logout(opal)" | |
| R -q -e "library(opalr); opal <- opal.login('administrator', 'datashield_test&', url='http://localhost:8080/'); dsadmin.set_option(opal, 'default.datashield.privacyControlLevel', 'permissive'); opal.logout(opal)" | |
| working-directory: dsBaseClient/tests/testthat/data_files | |
| - name: Install dsDanger package on Opal server | |
| run: | | |
| R -q -e "library(opalr); opal <- opal.login(username = 'administrator', password = 'datashield_test&', url = 'http://localhost:8080'); opal.put(opal, 'system', 'conf', 'general', '_rPackage'); opal.logout(opal)" | |
| R -q -e "library(opalr); opal <- opal.login('administrator','datashield_test&', url='http://localhost:8080/'); dsadmin.install_github_package(opal, 'dsDanger', username = 'datashield', ref = '${{ env.DSDANGER_REF }}'); opal.logout(opal)" | |
| working-directory: dsBaseClient | |
| - name: Run dsDanger tests with JUnit report | |
| run: | | |
| R -q -e ' | |
| library(testthat); | |
| output_file <- file("test_console_output_dsdanger.txt"); | |
| sink(output_file); | |
| sink(output_file, type = "message"); | |
| junit_rep <- JunitReporter$new(file = "test_results_dsdanger.xml"); | |
| progress_rep <- ProgressReporter$new(max_failures = 999999); | |
| multi_rep <- MultiReporter$new(reporters = list(progress_rep, junit_rep)); | |
| options("datashield.return_errors" = FALSE, "default_driver" = "${{ env.DS_DRIVER }}"); | |
| testthat::test_package("${{ env.PROJECT_NAME }}", filter = "${{ env.TEST_FILTER_DSDANGER }}", reporter = multi_rep, stop_on_failure = FALSE)' | |
| cat test_console_output_dsdanger.txt | |
| working-directory: dsBaseClient | |
| - name: Upload dsDanger results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: opal-dsdanger | |
| path: | | |
| dsBaseClient/test_results_dsdanger.xml | |
| dsBaseClient/test_console_output_dsdanger.txt | |
| ################################################################################ | |
| # Opal - merge all shard + dsDanger results and publish the report. | |
| ################################################################################ | |
| opal-report: | |
| name: Opal report | |
| needs: [opal-dsbase, opal-dsdanger] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout dsBaseClient | |
| uses: actions/checkout@v4 | |
| with: | |
| path: dsBaseClient | |
| - name: Checkout testStatus | |
| if: ${{ github.actor != 'nektos/act' }} # for local deployment only | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.REPO_OWNER }}/testStatus | |
| ref: master | |
| path: testStatus | |
| persist-credentials: false | |
| token: ${{ env.GITHUB_TOKEN }} | |
| - uses: r-lib/actions/setup-pandoc@v2 | |
| - uses: r-lib/actions/setup-r@v2 | |
| with: | |
| r-version: release | |
| use-public-rspm: true | |
| - name: Install xml-twig-tools | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -qq xml-twig-tools -y | |
| - uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| dependencies: 'NA' | |
| extra-packages: | | |
| cran::quarto | |
| cran::knitr | |
| cran::kableExtra | |
| cran::rmarkdown | |
| cran::downlit | |
| cran::xml2 | |
| cran::purrr | |
| cran::dplyr | |
| cran::stringr | |
| cran::tidyr | |
| cran::readr | |
| cran::magrittr | |
| - name: Download shard/dsdanger results | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: 'opal-*' | |
| path: dsBaseClient/artifacts | |
| - name: Merge results | |
| run: | | |
| mkdir -p logs | |
| xml_grep --pretty_print indented --wrap "testsuites" --descr "" --cond "testsuite" artifacts/*/test_results_*.xml > logs/test_results.xml | |
| cat artifacts/*/test_console_output_*.txt > logs/test_console_output.txt | |
| first=1 | |
| for f in artifacts/opal-dsbase-*/coveragelist.csv; do | |
| if [ $first -eq 1 ]; then | |
| cat "$f" > logs/coveragelist.csv | |
| first=0 | |
| else | |
| tail -n +2 "$f" >> logs/coveragelist.csv | |
| fi | |
| done | |
| working-directory: dsBaseClient | |
| - name: Check for JUnit errors | |
| run: | | |
| issue_count=$(sed 's/failures="0" errors="0"//' test_results.xml | grep -c errors= || true) | |
| echo "Number of testsuites with issues: $issue_count" | |
| sed 's/failures="0" errors="0"//' test_results.xml | grep errors= > issues.log || true | |
| cat issues.log || true | |
| # continue with workflow even when some tests fail | |
| exit 0 | |
| working-directory: dsBaseClient/logs | |
| - name: Write versions to file | |
| run: | | |
| echo "branch:${{ env.BRANCH_NAME }}" > ${{ env.WORKFLOW_ID }}.txt | |
| echo "os:$(lsb_release -ds)" >> ${{ env.WORKFLOW_ID }}.txt | |
| echo "R:$(R --version | head -n1)" >> ${{ env.WORKFLOW_ID }}.txt | |
| working-directory: dsBaseClient/logs | |
| - name: Parse results from testthat and covr | |
| run: Rscript --verbose --vanilla ../testStatus/source/parse_test_report.R logs/ | |
| working-directory: dsBaseClient | |
| - name: Render report | |
| run: | | |
| cd testStatus | |
| mkdir -p new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/ | |
| mkdir -p new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/ | |
| mkdir -p new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/latest/ | |
| cp -rv ../dsBaseClient/logs/* new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/ | |
| cp -rv ../dsBaseClient/logs/${{ env.WORKFLOW_ID }}.txt new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/ | |
| R -e 'input_dir <- file.path("../new/logs", Sys.getenv("PROJECT_NAME"), Sys.getenv("BRANCH_NAME"), Sys.getenv("WORKFLOW_ID")); quarto::quarto_render("source/test_report.qmd", execute_params = list(input_dir = input_dir))' | |
| mv source/test_report.html new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/index.html | |
| cp -r new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/* new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/latest | |
| env: | |
| PROJECT_NAME: ${{ env.PROJECT_NAME }} | |
| BRANCH_NAME: ${{ env.BRANCH_NAME }} | |
| WORKFLOW_ID: ${{ env.WORKFLOW_ID }} | |
| - name: Upload test logs | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dsbaseclient-logs-opal | |
| path: testStatus/new | |
| ################################################################################ | |
| # Armadillo - dsBase suite, sharded 4 ways. Each shard downloads and runs its | |
| # own Armadillo jar instance. | |
| # | |
| # Runs as a plain `java -jar` process instead of docker-compose: Armadillo | |
| # self-manages its own Rock container over the host Docker socket | |
| # (docker-management-enabled: true / docker-run-in-container: false), which | |
| # avoids building/pulling the old custom armadillo_citest image and its | |
| # dockerised Armadillo layer. The latest GitHub release jar is downloaded at | |
| # run time. No process is restarted after installing dsBase - install then | |
| # whitelist directly. | |
| ################################################################################ | |
| armadillo-dsbase: | |
| name: Armadillo dsBase tests (${{ matrix.category }}) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| strategy: | |
| fail-fast: false | |
| # One matrix entry per test-file category, each with its own testthat | |
| # filter substring - not evenly sized (smk/arg are much bigger than | |
| # perf/misc), so job durations differ. Traded for the ability to add, | |
| # remove, or temporarily skip a whole category by editing this list | |
| # alone, with no shell-side partitioning logic to keep in sync. | |
| matrix: | |
| include: | |
| - category: smk | |
| filter: 'smk-' | |
| - category: arg | |
| filter: 'arg-' | |
| - category: perf | |
| filter: 'perf-' | |
| - category: misc | |
| filter: 'datachk-|disc-|expt-|smk_expt-|math-|_-' | |
| env: | |
| DS_DRIVER: ArmadilloDriver | |
| DSBASE_TARBALL: dsBase_7.0.0-permissive.tar.gz | |
| steps: | |
| - name: Checkout dsBaseClient | |
| uses: actions/checkout@v4 | |
| with: | |
| path: dsBaseClient | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '21' | |
| - name: Download and start Armadillo (jar) | |
| run: | | |
| mkdir -p armadillo_home/config armadillo_home/storage armadillo_home/logs | |
| cat > armadillo_home/config/application.yml <<EOF | |
| armadillo: | |
| docker-management-enabled: true | |
| docker-run-in-container: false | |
| profiles: | |
| - name: default | |
| image: datashield/rock_citest-permissive:latest | |
| port: 8085 | |
| package-whitelist: | |
| - dsBase | |
| - dsTidyverse | |
| - resourcer | |
| function-blacklist: [ ] | |
| options: | |
| datashield: | |
| seed: 342325352 | |
| spring: | |
| security: | |
| user: | |
| name: admin | |
| password: admin | |
| servlet: | |
| multipart: | |
| max-file-size: 1000MB | |
| max-request-size: 1000MB | |
| storage: | |
| root-dir: $(pwd)/armadillo_home/storage | |
| audit.log.path: '$(pwd)/armadillo_home/logs/audit.log' | |
| stdout.log.path: '$(pwd)/armadillo_home/logs/armadillo.log' | |
| logging: | |
| level: | |
| root: "warn" | |
| org.molgenis: "warn" | |
| EOF | |
| release_json=$(curl -sf https://api.github.com/repos/molgenis/molgenis-service-armadillo/releases/latest) | |
| jar_url=$(echo "$release_json" | jq -r '.assets[] | select(.name | endswith(".jar")) | .browser_download_url') | |
| echo "Installing Armadillo $(echo "$release_json" | jq -r '.tag_name')" | |
| curl -fSL -o armadillo_home/armadillo.jar "$jar_url" | |
| JAVA_TOOL_OPTIONS="-Xms1G -Xmx2G -XX:+UseG1GC" \ | |
| nohup java -jar armadillo_home/armadillo.jar \ | |
| --server.port=8080 \ | |
| --spring.config.additional-location=file:$(pwd)/armadillo_home/config/application.yml \ | |
| > armadillo_home/logs/stdout.log 2>&1 & | |
| echo $! > armadillo_home/armadillo.pid | |
| docker pull datashield/rock_citest-permissive:latest | |
| working-directory: dsBaseClient | |
| - name: Uninstall default MySQL | |
| run: | | |
| sudo service mysql stop || true | |
| sudo apt-get update | |
| sudo apt-get remove --purge mysql-client mysql-server mysql-common -y | |
| sudo apt-get autoremove -y | |
| sudo apt-get autoclean -y | |
| sudo rm -rf /var/lib/mysql/ | |
| - uses: r-lib/actions/setup-pandoc@v2 | |
| - uses: r-lib/actions/setup-r@v2 | |
| with: | |
| r-version: release | |
| http-user-agent: release | |
| use-public-rspm: true | |
| - name: Install system libraries | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y | |
| sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y | |
| - uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| dependencies: 'c("Imports")' | |
| extra-packages: | | |
| cran::devtools | |
| cran::usethis | |
| cran::covr | |
| cran::fields | |
| cran::meta | |
| cran::metafor | |
| cran::ggplot2 | |
| cran::gridExtra | |
| cran::data.table | |
| cran::DSI | |
| cran::opalr | |
| cran::DSOpal | |
| cran::DSLite | |
| cran::MolgenisAuth | |
| cran::MolgenisArmadillo | |
| cran::DSMolgenisArmadillo | |
| cran::DescTools | |
| cran::e1071 | |
| needs: check | |
| - name: Wait for Armadillo to be ready | |
| run: | | |
| for i in $(seq 1 60); do | |
| if curl -fsS http://localhost:8080/actuator/health 2>/dev/null | grep -q '"status":"UP"'; then | |
| echo "Armadillo is ready" | |
| exit 0 | |
| fi | |
| sleep 5 | |
| done | |
| echo "Armadillo did not become ready in time" | |
| cat armadillo_home/logs/stdout.log || true | |
| exit 1 | |
| working-directory: dsBaseClient | |
| - name: Install test datasets to Armadillo | |
| run: R -q -f "molgenis_armadillo-upload_testing_datasets.R" | |
| working-directory: dsBaseClient/tests/testthat/data_files | |
| - name: Install dsBase to Armadillo | |
| run: | | |
| curl -u admin:admin -X GET http://localhost:8080/packages | |
| install_status=$(curl -u admin:admin -H 'Content-Type: multipart/form-data' -F "file=@${{ env.DSBASE_TARBALL }}" -o /dev/null -w '%{http_code}' -X POST http://localhost:8080/install-package) | |
| if [ "$install_status" != "200" ]; then | |
| echo "dsBase install request failed with HTTP status $install_status" | |
| exit 1 | |
| fi | |
| expected_version=$(tar -xOzf ${{ env.DSBASE_TARBALL }} dsBase/DESCRIPTION | sed -n 's/^Version: //p' | tr -d '\r') | |
| if [ -z "$expected_version" ]; then | |
| echo "Could not determine expected dsBase version from ${{ env.DSBASE_TARBALL }}" | |
| exit 1 | |
| fi | |
| echo "Expected dsBase version: $expected_version" | |
| actual_version="" | |
| for i in $(seq 1 30); do | |
| packages_json=$(curl -sf -u admin:admin -X GET http://localhost:8080/packages || true) | |
| actual_version=$(echo "$packages_json" | jq -r '.[] | select(.name == "dsBase") | .version' 2>/dev/null || true) | |
| if [ "$actual_version" == "$expected_version" ]; then | |
| break | |
| fi | |
| sleep 10 | |
| done | |
| echo "Installed dsBase version: $actual_version" | |
| if [ "$actual_version" != "$expected_version" ]; then | |
| echo "dsBase version mismatch: expected $expected_version, found '$actual_version'" | |
| exit 1 | |
| fi | |
| curl -u admin:admin -X POST http://localhost:8080/whitelist/dsBase | |
| working-directory: dsBaseClient | |
| - name: Dump Armadillo server log | |
| if: failure() | |
| run: tail -c 20000 armadillo_home/logs/stdout.log | |
| working-directory: dsBaseClient | |
| - name: Run dsBase tests with coverage & JUnit report | |
| run: | | |
| R -q -e "devtools::reload();" | |
| R -q -e ' | |
| write.csv( | |
| covr::coverage_to_list( | |
| covr::package_coverage( | |
| type = c("none"), | |
| code = c('"'"' | |
| output_file <- file("test_console_output_dsbase.txt"); | |
| sink(output_file); | |
| sink(output_file, type = "message"); | |
| junit_rep <- testthat::JunitReporter$new(file = file.path(getwd(), "test_results_dsbase.xml")); | |
| progress_rep <- testthat::ProgressReporter$new(max_failures = 999999); | |
| multi_rep <- testthat::MultiReporter$new(reporters = list(progress_rep, junit_rep)); | |
| options("datashield.return_errors" = FALSE, "default_driver" = "${{ env.DS_DRIVER }}"); | |
| testthat::test_package("${{ env.PROJECT_NAME }}", filter = "${{ matrix.filter }}", reporter = multi_rep, stop_on_failure = FALSE)'"'"' | |
| ) | |
| ) | |
| ), | |
| "coveragelist.csv" | |
| )' | |
| cat test_console_output_dsbase.txt | |
| working-directory: dsBaseClient | |
| - name: Upload shard results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: armadillo-dsbase-${{ matrix.category }} | |
| path: | | |
| dsBaseClient/test_results_dsbase.xml | |
| dsBaseClient/test_console_output_dsbase.txt | |
| dsBaseClient/coveragelist.csv | |
| ################################################################################ | |
| # Armadillo - dsDanger suite. Small, so it stays a single job. | |
| ################################################################################ | |
| armadillo-dsdanger: | |
| name: Armadillo dsDanger tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| env: | |
| DS_DRIVER: ArmadilloDriver | |
| DSBASE_TARBALL: dsBase_7.0.0-permissive.tar.gz | |
| DSDANGER_TARBALL: dsDanger_6.3.4.tar.gz | |
| steps: | |
| - name: Checkout dsBaseClient | |
| uses: actions/checkout@v4 | |
| with: | |
| path: dsBaseClient | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '21' | |
| - name: Download and start Armadillo (jar) | |
| run: | | |
| mkdir -p armadillo_home/config armadillo_home/storage armadillo_home/logs | |
| cat > armadillo_home/config/application.yml <<EOF | |
| armadillo: | |
| docker-management-enabled: true | |
| docker-run-in-container: false | |
| profiles: | |
| - name: default | |
| image: datashield/rock_citest-permissive:latest | |
| port: 8085 | |
| package-whitelist: | |
| - dsBase | |
| - dsTidyverse | |
| - resourcer | |
| function-blacklist: [ ] | |
| options: | |
| datashield: | |
| seed: 342325352 | |
| spring: | |
| security: | |
| user: | |
| name: admin | |
| password: admin | |
| servlet: | |
| multipart: | |
| max-file-size: 1000MB | |
| max-request-size: 1000MB | |
| storage: | |
| root-dir: $(pwd)/armadillo_home/storage | |
| audit.log.path: '$(pwd)/armadillo_home/logs/audit.log' | |
| stdout.log.path: '$(pwd)/armadillo_home/logs/armadillo.log' | |
| logging: | |
| level: | |
| root: "warn" | |
| org.molgenis: "warn" | |
| EOF | |
| release_json=$(curl -sf https://api.github.com/repos/molgenis/molgenis-service-armadillo/releases/latest) | |
| jar_url=$(echo "$release_json" | jq -r '.assets[] | select(.name | endswith(".jar")) | .browser_download_url') | |
| echo "Installing Armadillo $(echo "$release_json" | jq -r '.tag_name')" | |
| curl -fSL -o armadillo_home/armadillo.jar "$jar_url" | |
| JAVA_TOOL_OPTIONS="-Xms1G -Xmx2G -XX:+UseG1GC" \ | |
| nohup java -jar armadillo_home/armadillo.jar \ | |
| --server.port=8080 \ | |
| --spring.config.additional-location=file:$(pwd)/armadillo_home/config/application.yml \ | |
| > armadillo_home/logs/stdout.log 2>&1 & | |
| echo $! > armadillo_home/armadillo.pid | |
| docker pull datashield/rock_citest-permissive:latest | |
| working-directory: dsBaseClient | |
| - name: Uninstall default MySQL | |
| run: | | |
| sudo service mysql stop || true | |
| sudo apt-get update | |
| sudo apt-get remove --purge mysql-client mysql-server mysql-common -y | |
| sudo apt-get autoremove -y | |
| sudo apt-get autoclean -y | |
| sudo rm -rf /var/lib/mysql/ | |
| - uses: r-lib/actions/setup-pandoc@v2 | |
| - uses: r-lib/actions/setup-r@v2 | |
| with: | |
| r-version: release | |
| http-user-agent: release | |
| use-public-rspm: true | |
| - name: Install system libraries | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -qq libxml2-dev libcurl4-openssl-dev libssl-dev libgsl-dev libgit2-dev -y | |
| sudo apt-get install -qq libharfbuzz-dev libfribidi-dev libmagick++-dev libudunits2-dev libuv1-dev -y | |
| - uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| dependencies: 'c("Imports")' | |
| extra-packages: | | |
| cran::devtools | |
| cran::usethis | |
| cran::git2r | |
| cran::covr | |
| cran::fields | |
| cran::meta | |
| cran::metafor | |
| cran::ggplot2 | |
| cran::gridExtra | |
| cran::data.table | |
| cran::DSI | |
| cran::opalr | |
| cran::DSOpal | |
| cran::DSLite | |
| cran::MolgenisAuth | |
| cran::MolgenisArmadillo | |
| cran::DSMolgenisArmadillo | |
| cran::DescTools | |
| cran::e1071 | |
| needs: check | |
| - name: Install dsDangerClient | |
| run: R -q -e "devtools::install_github(repo='datashield/dsDangerClient', ref=Sys.getenv('BRANCH_NAME'))" | |
| - name: Wait for Armadillo to be ready | |
| run: | | |
| for i in $(seq 1 60); do | |
| if curl -fsS http://localhost:8080/actuator/health 2>/dev/null | grep -q '"status":"UP"'; then | |
| echo "Armadillo is ready" | |
| exit 0 | |
| fi | |
| sleep 5 | |
| done | |
| echo "Armadillo did not become ready in time" | |
| cat armadillo_home/logs/stdout.log || true | |
| exit 1 | |
| working-directory: dsBaseClient | |
| - name: Install test datasets to Armadillo | |
| run: R -q -f "molgenis_armadillo-upload_testing_datasets.R" | |
| working-directory: dsBaseClient/tests/testthat/data_files | |
| - name: Install dsBase to Armadillo | |
| run: | | |
| curl -u admin:admin -X GET http://localhost:8080/packages | |
| install_status=$(curl -u admin:admin -H 'Content-Type: multipart/form-data' -F "file=@${{ env.DSBASE_TARBALL }}" -o /dev/null -w '%{http_code}' -X POST http://localhost:8080/install-package) | |
| if [ "$install_status" != "200" ]; then | |
| echo "dsBase install request failed with HTTP status $install_status" | |
| exit 1 | |
| fi | |
| expected_version=$(tar -xOzf ${{ env.DSBASE_TARBALL }} dsBase/DESCRIPTION | sed -n 's/^Version: //p' | tr -d '\r') | |
| if [ -z "$expected_version" ]; then | |
| echo "Could not determine expected dsBase version from ${{ env.DSBASE_TARBALL }}" | |
| exit 1 | |
| fi | |
| echo "Expected dsBase version: $expected_version" | |
| actual_version="" | |
| for i in $(seq 1 30); do | |
| packages_json=$(curl -sf -u admin:admin -X GET http://localhost:8080/packages || true) | |
| actual_version=$(echo "$packages_json" | jq -r '.[] | select(.name == "dsBase") | .version' 2>/dev/null || true) | |
| if [ "$actual_version" == "$expected_version" ]; then | |
| break | |
| fi | |
| sleep 10 | |
| done | |
| echo "Installed dsBase version: $actual_version" | |
| if [ "$actual_version" != "$expected_version" ]; then | |
| echo "dsBase version mismatch: expected $expected_version, found '$actual_version'" | |
| exit 1 | |
| fi | |
| curl -u admin:admin -X POST http://localhost:8080/whitelist/dsBase | |
| working-directory: dsBaseClient | |
| - name: Dump Armadillo server log | |
| if: failure() | |
| run: tail -c 20000 armadillo_home/logs/stdout.log | |
| working-directory: dsBaseClient | |
| - name: Install dsDanger package on Armadillo server | |
| run: | | |
| curl -u admin:admin http://localhost:8080/whitelist | |
| install_status=$(curl -u admin:admin -H 'Content-Type: multipart/form-data' -F "file=@${{ env.DSDANGER_TARBALL }}" -o /dev/null -w '%{http_code}' -X POST http://localhost:8080/install-package) | |
| if [ "$install_status" != "200" ]; then | |
| echo "dsDanger install request failed with HTTP status $install_status" | |
| exit 1 | |
| fi | |
| for i in $(seq 1 30); do | |
| packages_json=$(curl -sf -u admin:admin -X GET http://localhost:8080/packages || true) | |
| if echo "$packages_json" | jq -e '.[] | select(.name == "dsDanger")' >/dev/null 2>&1; then | |
| break | |
| fi | |
| sleep 10 | |
| done | |
| curl -u admin:admin -X POST http://localhost:8080/whitelist/dsDanger | |
| curl -u admin:admin http://localhost:8080/whitelist | |
| working-directory: dsBaseClient | |
| - name: Run dsDanger tests with JUnit report | |
| run: | | |
| R -q -e ' | |
| library(testthat); | |
| output_file <- file("test_console_output_dsdanger.txt"); | |
| sink(output_file); | |
| sink(output_file, type = "message"); | |
| junit_rep <- JunitReporter$new(file = "test_results_dsdanger.xml"); | |
| progress_rep <- ProgressReporter$new(max_failures = 999999); | |
| multi_rep <- MultiReporter$new(reporters = list(progress_rep, junit_rep)); | |
| options("datashield.return_errors" = FALSE, "default_driver" = "${{ env.DS_DRIVER }}"); | |
| testthat::test_package("${{ env.PROJECT_NAME }}", filter = "${{ env.TEST_FILTER_DSDANGER }}", reporter = multi_rep, stop_on_failure = FALSE)' | |
| cat test_console_output_dsdanger.txt | |
| working-directory: dsBaseClient | |
| - name: Upload dsDanger results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: armadillo-dsdanger | |
| path: | | |
| dsBaseClient/test_results_dsdanger.xml | |
| dsBaseClient/test_console_output_dsdanger.txt | |
| ################################################################################ | |
| # Armadillo - merge all shard + dsDanger results and publish the report. | |
| ################################################################################ | |
| armadillo-report: | |
| name: Armadillo report | |
| needs: [armadillo-dsbase, armadillo-dsdanger] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout dsBaseClient | |
| uses: actions/checkout@v4 | |
| with: | |
| path: dsBaseClient | |
| - name: Checkout testStatus | |
| if: ${{ github.actor != 'nektos/act' }} # for local deployment only | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.REPO_OWNER }}/testStatus | |
| ref: master | |
| path: testStatus | |
| persist-credentials: false | |
| token: ${{ env.GITHUB_TOKEN }} | |
| - uses: r-lib/actions/setup-pandoc@v2 | |
| - uses: r-lib/actions/setup-r@v2 | |
| with: | |
| r-version: release | |
| use-public-rspm: true | |
| - name: Install xml-twig-tools | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -qq xml-twig-tools -y | |
| - uses: r-lib/actions/setup-r-dependencies@v2 | |
| with: | |
| dependencies: 'NA' | |
| extra-packages: | | |
| cran::quarto | |
| cran::knitr | |
| cran::kableExtra | |
| cran::rmarkdown | |
| cran::downlit | |
| cran::xml2 | |
| cran::purrr | |
| cran::dplyr | |
| cran::stringr | |
| cran::tidyr | |
| cran::readr | |
| cran::magrittr | |
| - name: Download shard/dsdanger results | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: 'armadillo-*' | |
| path: dsBaseClient/artifacts | |
| - name: Merge results | |
| run: | | |
| mkdir -p logs | |
| xml_grep --pretty_print indented --wrap "testsuites" --descr "" --cond "testsuite" artifacts/*/test_results_*.xml > logs/test_results.xml | |
| cat artifacts/*/test_console_output_*.txt > logs/test_console_output.txt | |
| first=1 | |
| for f in artifacts/armadillo-dsbase-*/coveragelist.csv; do | |
| if [ $first -eq 1 ]; then | |
| cat "$f" > logs/coveragelist.csv | |
| first=0 | |
| else | |
| tail -n +2 "$f" >> logs/coveragelist.csv | |
| fi | |
| done | |
| working-directory: dsBaseClient | |
| - name: Check for JUnit errors | |
| run: | | |
| issue_count=$(sed 's/failures="0" errors="0"//' test_results.xml | grep -c errors= || true) | |
| echo "Number of testsuites with issues: $issue_count" | |
| sed 's/failures="0" errors="0"//' test_results.xml | grep errors= > issues.log || true | |
| cat issues.log || true | |
| # continue with workflow even when some tests fail | |
| exit 0 | |
| working-directory: dsBaseClient/logs | |
| - name: Write versions to file | |
| run: | | |
| echo "branch:${{ env.BRANCH_NAME }}" > ${{ env.WORKFLOW_ID }}.txt | |
| echo "os:$(lsb_release -ds)" >> ${{ env.WORKFLOW_ID }}.txt | |
| echo "R:$(R --version | head -n1)" >> ${{ env.WORKFLOW_ID }}.txt | |
| working-directory: dsBaseClient/logs | |
| - name: Parse results from testthat and covr | |
| run: Rscript --verbose --vanilla ../testStatus/source/parse_test_report.R logs/ | |
| working-directory: dsBaseClient | |
| - name: Render report | |
| run: | | |
| cd testStatus | |
| mkdir -p new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/ | |
| mkdir -p new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/ | |
| mkdir -p new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/latest/ | |
| cp -rv ../dsBaseClient/logs/* new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/ | |
| cp -rv ../dsBaseClient/logs/${{ env.WORKFLOW_ID }}.txt new/logs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/ | |
| R -e 'input_dir <- file.path("../new/logs", Sys.getenv("PROJECT_NAME"), Sys.getenv("BRANCH_NAME"), Sys.getenv("WORKFLOW_ID")); quarto::quarto_render("source/test_report.qmd", execute_params = list(input_dir = input_dir))' | |
| mv source/test_report.html new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/index.html | |
| cp -r new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/${{ env.WORKFLOW_ID }}/* new/docs/${{ env.PROJECT_NAME }}/${{ env.BRANCH_NAME }}/latest | |
| env: | |
| PROJECT_NAME: ${{ env.PROJECT_NAME }} | |
| BRANCH_NAME: ${{ env.BRANCH_NAME }} | |
| WORKFLOW_ID: ${{ env.WORKFLOW_ID }} | |
| - name: Upload test logs | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: dsbaseclient-logs-armadillo | |
| path: testStatus/new |