# 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

<figure><img src="/files/ZrRWnRNJ8pYr1OJjef9u" alt=""><figcaption></figcaption></figure>

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

{% code overflow="wrap" lineNumbers="true" %}

```bash
#!/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
```

{% endcode %}

{% hint style="info" %}
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)`
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.sealights.io/knowledgebase/setup-and-configuration/integrations/sample-integrations/generating-a-trend-report-tga-report-over-recent-sprints.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
