Generating a Trend Report (TGA Report over recent sprints)

If you need to retrieve TGA for several periods in a row you can reuse the following sample code

  • This shell script produces a CSV file aggregating several iterations of TGA reports

  • This shell script is written for linux and requires jq installed on your system

  • You must update lines 4-13 with relevant values from your Sealights account and configuration

The output is a CSV file that looks like this

image-20240708-112452.png

In the script below you have the option to download the detailed coverage for each TGA report (uncomment line 214)

#!/usr/bin/env bash # Copyright Sealights 2024 DOMAIN="mycompany.sealights.co" SL_API_TOKEN="123" APP_NAME="MyApp" BRANCH_NAME="master" #CategoryName="Teams" #LabelName="Backend" Period_StartDate="2024-05-15" Report_Frequency="2 weeks" #For monthly reports use "1 month" Report_Iterations="3" ######## FUNCTIONS ######## getPartialCSVFilePath() { CSV_FILENAME="${APP_NAME// /_}-${BRANCH_NAME//[\/ ]/_}" TARGET_FOLDER="${APP_NAME// /_}" if [ ! -d $TARGET_FOLDER ]; then mkdir -p $TARGET_FOLDER; fi if [ -z "${LabelName}" ] && [ -z "${CategoryName}" ]; then CSV_FILENAME="${CSV_FILENAME}-NoLabel" else CSV_FILENAME="${CSV_FILENAME}-${CategoryName}${LabelName}" fi #Preparing CSV file if [ "$Report_Frequency" = "1 month" ]; then CSV_FILENAME="${CSV_FILENAME}-Monthly" elif [ "$Report_Frequency" = "2 weeks" ]; then CSV_FILENAME="${CSV_FILENAME}-BiWeekly" fi echo "./$TARGET_FOLDER/$CSV_FILENAME-From_${Period_StartDate}" } rawurlencode() { local string="${1}" local strlen=${#string} local encoded="" local pos c o #>&2 echo "encode $string" for (( pos=0 ; pos<strlen ; pos++ )); do c=${string:$pos:1} case "$c" in [-_.~a-zA-Z0-9] ) o="${c}" ;; *) printf -v o '%%%02x' "'$c" esac encoded+="${o}" done echo "${encoded}" # You can either set a return variable (FASTER) REPLY="${encoded}" #+or echo the result (EASIER)... or both... :p } encode_array_for_curl() { local comma_separated_list="${1}" local json_array local encoded_array # Convert comma-separated list to JSON array json_array=$(echo "${comma_separated_list}" | jq -R 'split(",")') # URL encode the JSON array encoded_array=$(echo "${json_array}" | jq -sRr @uri) echo "${encoded_array}" # You can either set a return variable (FASTER) REPLY="${encoded_array}" #+or echo the result (EASIER)... or both... :p } waitForReportReady() { local REPORT_ID=$1 for ((retries=0;retries<600;retries++)); do local TGA_DETAILS=$(curl -s -X GET "https://${DOMAIN}/sl-api/v1/tga/report-templates/reports/${REPORT_ID}" -H 'accept: application/csv' -H "Authorization: Bearer $SL_API_TOKEN") local STATUS=$(echo ${TGA_DETAILS} | jq -r .data.status) if [[ "${STATUS}" != "In Progress" ]]; then break fi >&2 echo ... sleep 10 done if [[ "${STATUS}" == "Ready" ]]; then echo ${TGA_DETAILS} | jq .data else >&2 echo "Report ${REPORT_ID} is not Ready, its status is '${STATUS}'" exit 1 fi } updateTGAReport() { local REPORT_ID=$1 local PERIOD_FROM=$2 local PERIOD_TO=$3 local DATA="{\"range\":{\"dates\":{\"from\":${PERIOD_FROM},\"to\":${PERIOD_TO}}}}" local RESPONSE=$(curl -s -X PUT "https://${DOMAIN}/sl-api/v1/tga/report-templates/reports/${REPORT_ID}" -H 'accept: application/json' -H 'Content-Type: application/json' -H "Authorization: Bearer $SL_API_TOKEN" -H "Accept: application/json" -d "${DATA}") local REPORT_ID=$(echo ${RESPONSE} | jq -r .data.reportId) if [[ "${REPORT_ID}" == "" || "${REPORT_ID}" == "null" ]]; then >&2 echo "RESPONSE='${RESPONSE}'" >&2 echo "Failed to update report ${REPORT_ID} with ${PERIOD_FROM} and ${PERIOD_TO}" exit 1 fi waitForReportReady "${REPORT_ID}" } downloadTgaReportCsvFile() { local reportId="${1}" local fullpath="${2}" # Define the base URL local download_url="https://${DOMAIN}/sl-api/v1/tga/report-templates/reports/${reportId}/csv" # Use curl to download the CSV file and save it to the specified path curl -sX GET "${download_url}" --output "${fullpath}" -H 'Content-Type: text/csv' -H "Authorization: Bearer $SL_API_TOKEN" -H "Accept: application/json" # Check if the download was successful if [ $? -eq 0 ]; then >&2 echo "CSV file downloaded successfully to ${fullpath}" else >&2 echo "Failed to download CSV file from ${download_url}" fi } ######## SCRIPT ######## PERIOD_FROM=$(date -d "${Period_StartDate}" +%s%3N) REPORT_MAX=$(date +%s%3N) echo "Retrieving TGA Report details for $APP_NAME (Branch $BRANCH_NAME)" if { [ -z "${LabelName}" ] && [ -n "${CategoryName}" ]; } || { [ -n "${LabelName}" ] && [ -z "${CategoryName}" ]; }; then echo "> [ERROR] Category and Label: One of them is undefined but not both." echo "> Category: ${CategoryName}, LabelNames: ${LabelNames}" echo "> Ending script." exit 1 fi echo "> Report Start is ${Period_StartDate} to $PERIOD_FROM" echo "> Report Frequency is ${Report_Frequency} for ${Report_Iterations} iterations" TGA_REPORTS_LIST="" TGA_REPORT_ID="" APPNAME_ENCODED=$(rawurlencode "${APP_NAME}") BRANCHNAME_ENCODED=$(rawurlencode "${BRANCH_NAME}") if [ -z "${LabelName}" ] && [ -z "${CategoryName}" ]; then echo "> No Label selected" else echo "> Group $LabelName selected for the Report scope" CATEGORYNAME_ENCODED=$(rawurlencode "${CategoryName}") ##TODO: FIX LABEL NAMES - NOT WORKING YET LABELNAMES_ENCODED=$(encode_array_for_curl "${LabelName}") APPEND_CAT_AND_LABEL_QUERY="&categoryName=${CATEGORYNAME_ENCODED}&labelNames=${LABELNAMES_ENCODED}" fi TGA_REPORTS_LIST=$(curl -sX GET "https://${DOMAIN}/sl-api/v1/tga/report-templates/reports?appName=${APPNAME_ENCODED}&branchName=${BRANCHNAME_ENCODED}${APPEND_CAT_AND_LABEL_QUERY}" -H "Authorization: Bearer $SL_API_TOKEN" -H "Accept: application/json") NUM_OF_REPORTS=$(echo $TGA_REPORTS_LIST | jq -r .data.total ) if [ $NUM_OF_REPORTS != 1 ]; then echo "> $NUM_OF_REPORTS report(s) found for $APP_NAME / $BRANCH_NAME / $LabelName" echo "> Ending script." exit 1 fi TGA_REPORT_ID=$(echo $TGA_REPORTS_LIST | jq -r .data.list[0].reportId ) CSV_FULLPATH_FILE=$(getPartialCSVFilePath) echo "Generating CSV report as $CSV_FULLPATH_FILE" #headers echo '"StartDate","EndDate","Name","overall/totalMethods","overall/uncoveredMethods","overall/coveredMethods","overall/coverage","modifiedCode/totalMethods","modifiedCode/uncoveredMethods","modifiedCode/coveredMethods","modifiedCode/coverage"'>$CSV_FULLPATH_FILE # Preparing variables for While loop REPORT_FROM=${PERIOD_FROM} REPORT_TO=$(date -d "${Period_StartDate}+${Report_Frequency}" +%s%3N) i=1 while [ $i -le $Report_Iterations ] && [ $REPORT_FROM -lt $REPORT_MAX ]; do if [ $REPORT_TO -gt $REPORT_MAX ]; then echo "> Report cannot end in the future." REPORT_TO=$REPORT_MAX fi DATE_FROM=$(date -d@"$((${REPORT_FROM}/1000))" +"%Y-%m-%d") DATE_TO=$(date -d@"$((${REPORT_TO}/1000))" +"%Y-%m-%d") echo ">> Generate TGA iteration #$i from $DATE_FROM to $DATE_TO" JSON_TGA_REPORT=$(updateTGAReport ${TGA_REPORT_ID} ${REPORT_FROM} ${REPORT_TO}) #entire build - extract data from json into CSV echo $JSON_TGA_REPORT | jq --arg DateFrom $DATE_FROM --arg DateTo $DATE_TO -r \ '.coverage.entireBuild | [$DateFrom,$DateTo,"EntireBuild",.overallCoverage.totalMethods,.overallCoverage.uncoveredMethods,.overallCoverage.coveredMethods,.overallCoverage.coverage,.modifiedCodeCoverage.totalMethods,.modifiedCodeCoverage.uncoveredMethods,.modifiedCodeCoverage.coveredMethods,.modifiedCodeCoverage.coverage] | @csv'>>$CSV_FULLPATH_FILE #stage by stage - extract data from json into CSV echo $JSON_TGA_REPORT | jq --arg DateFrom $DATE_FROM --arg DateTo $DATE_TO -r \ '.coverage.testStages[] | [$DateFrom,$DateTo,.name,.overallCoverage.totalMethods,.overallCoverage.uncoveredMethods,.overallCoverage.coveredMethods,.overallCoverage.coverage,.modifiedCodeCoverage.totalMethods,.modifiedCodeCoverage.uncoveredMethods,.modifiedCodeCoverage.coveredMethods,.modifiedCodeCoverage.coverage] | @csv'>>$CSV_FULLPATH_FILE echo #Next iteration should use recent report TGA_REPORT_ID=$(echo $JSON_TGA_REPORT | jq -r .reportId ) #Optional - download the CSV file with coverage details #downloadTgaReportCsvFile $TGA_REPORT_ID "./$TARGET_FOLDER/Report-${i}-CoverageDetails.csv" ((i+=1)) REPORT_FROM=$REPORT_TO REPORT_TO=$(date -d "${DATE_TO}+${Report_Frequency}" +%s%3N) done mv $CSV_FULLPATH_FILE "${CSV_FULLPATH_FILE}_To_${DATE_TO}.csv" echo script completed exit 0

If running on Mac OS, the date command syntax differs slightly from regular Linux. Below is a Mac OS equivalent syntax for line 134 above.

PERIOD_FROM=$(date -j -f "%Y-%m-%d %H:%M" "${Period_StartDate}" +%s000)