Skip to content

Intg 2133 add cad reporting #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 13, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions browserstack_ci_template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
.set_browserstack_config:
image: alpine:latest
script: |
echo "Setting Browserstack Config vars..."

# Validate required variables
if [ -z "$BROWSERSTACK_USERNAME" ]; then
echo "Error: BROWSERSTACK_USERNAME is not set!"
exit 1
fi

if [ -z "$BROWSERSTACK_ACCESS_KEY" ]; then
echo "Error: BROWSERSTACK_ACCESS_KEY is not set!"
exit 1
fi

# Construct dynamic build name
export BROWSERSTACK_BUILD_NAME="gitlab-ci-${CI_PROJECT_NAME}-${CI_PIPELINE_IID}"

# Write to browserstack_vars.env
echo "BROWSERSTACK_USERNAME=${BROWSERSTACK_USERNAME}" > browserstack_vars.env
echo "BROWSERSTACK_ACCESS_KEY=${BROWSERSTACK_ACCESS_KEY}" >> browserstack_vars.env
echo "BROWSERSTACK_BUILD_NAME=${BROWSERSTACK_BUILD_NAME}" >> browserstack_vars.env
cat browserstack_vars.env
artifacts:
paths:
- browserstack_vars.env

.set_browserstack_test_report:
image: alpine:latest
script: |
echo "Installing bash, curl & jq"
apk add --no-cache bash curl jq
bash <<'EOF'
#!/bin/bash
source browserstack_vars.env
API_PATH="https://api-observability.browserstack.com/ext/v1/builds/buildReport"
REPORT_STATUS_COMPLETED="COMPLETED"
REPORT_STATUS_NOT_AVAILABLE="NOT_AVAILABLE"
REPORT_STATUS_TEST_AVAILABLE="TEST_AVAILABLE"
REPORT_STATUS_IN_PROGRESS="IN_PROGRESS"
REQUESTING_CI="gitlab-ci"
REPORT_FORMAT='["plainText", "richHtml"]'

# Error scenario mappings
declare -A ERROR_SCENARIOS=(
["BUILD_NOT_FOUND"]="Build not found in BrowserStack"
["MULTIPLE_BUILD_FOUND"]="Multiple builds found with the same name"
["DATA_NOT_AVAILABLE"]="Report data not available from BrowserStack"
)

# Check if BROWSERSTACK_BUILD_NAME is set
if [[ -z "$BROWSERSTACK_BUILD_NAME" ]]; then
echo "Error: BROWSERSTACK_BUILD_NAME is not set."
exit 0
fi

if [[ -z "$REPORT_TIMEOUT" ]]; then
REPORT_TIMEOUT=130
fi

if [[ "$REPORT_TIMEOUT" -lt 20 || "$REPORT_TIMEOUT" -gt 600 ]]; then
echo "Error: REPORT_TIMEOUT must be between 20 and 600 seconds."
exit 1
fi

# Function to make API requests
make_api_request() {
local request_type=$1
local auth_header
local header_file
local response

# Encode username:accesskey to base64
auth_header=$(echo -n "${BROWSERSTACK_USERNAME}:${BROWSERSTACK_ACCESS_KEY}" | base64)
# Create a temporary file for headers
header_file=$(mktemp)
response=$(curl -s -w "%{http_code}" -X POST "$API_PATH" \
-H "Content-Type: application/json" \
-H "Authorization: Basic $auth_header" \
-D "$header_file" \
-d "{
\"originalBuildName\": \"${BROWSERSTACK_BUILD_NAME}\",
\"buildStartedAt\": \"$(date +%s)\",
\"requestingCi\": \"$REQUESTING_CI\",
\"reportFormat\": $REPORT_FORMAT,
\"requestType\": \"$request_type\",
\"userTimeout\": \"${REPORT_TIMEOUT}\"
}")

# Extract the HTTP status code from the response
local http_status=${response: -3}
# Extract the response body (everything except the last 3 characters)
local body=${response:0:${#response}-3}

# Clean up the temporary file
rm -f "$header_file"

if [[ -z "$body" ]]; then
body='""'
fi

# Return both status code and body as a JSON object
echo "{\"status_code\": $http_status, \"body\": $body}"
}

# Function to extract report data
extract_report_data() {
local response=$1
rich_html_response=$(echo "$response" | jq -r '.report.richHtml // empty')
rich_css_response=$(echo "$response" | jq -r '.report.richCss // empty')
plain_text_response=$(echo "$response" | jq -r '.report.plainText // empty')
}

# Function to check report status
check_report_status() {
local response=$1
local status_code
local body
local error_message

status_code=$(echo "$response" | jq -r '.status_code')
body=$(echo "$response" | jq -r '.body')

if [[ $status_code -ne 200 ]]; then
echo "Error: API returned status code $status_code"
error_message=$(echo "$body" | jq -r '.message // "Unknown error"')
echo "Error message: $error_message"
return 1
fi

REPORT_STATUS=$(echo "$body" | jq -r '.reportStatus // empty')
if [[ "$REPORT_STATUS" == "$REPORT_STATUS_COMPLETED" ||
"$REPORT_STATUS" == "$REPORT_STATUS_TEST_AVAILABLE" ||
"$REPORT_STATUS" == "$REPORT_STATUS_NOT_AVAILABLE" ]]; then
extract_report_data "$body"
return 0
fi
return 2
}
echo "Build Name: $BROWSERSTACK_BUILD_NAME will be used to fetch the report."
echo "Making initial API request to Browserstack Test Report API..."

# Initial API Request
RESPONSE=$(make_api_request "FIRST")
check_report_status "$RESPONSE" || true
RETRY_COUNT=$(echo "$RESPONSE" | jq -r '.body.retryCount // 3')
POLLING_DURATION=$(echo "$RESPONSE" | jq -r '.body.pollingInterval // 3')

# Polling Mechanism
[ "$REPORT_STATUS" == "$REPORT_STATUS_IN_PROGRESS" ] && {
echo "Starting polling mechanism to fetch Test report..."
}
local_retry=0
ELAPSED_TIME=0

while [[ $local_retry -lt $RETRY_COUNT && $REPORT_STATUS == "$REPORT_STATUS_IN_PROGRESS" ]]; do
if [[ -n "$REPORT_TIMEOUT" && "$ELAPSED_TIME" -ge "$REPORT_TIMEOUT" ]]; then
echo "User report timeout reached. Making final API request..."
RESPONSE=$(make_api_request "LAST")
check_report_status "$RESPONSE" && break
break
fi

ELAPSED_TIME=$((ELAPSED_TIME + POLLING_DURATION))
local_retry=$((local_retry + 1))

RESPONSE=$(make_api_request "POLL")
echo "Polling attempt $local_retry/$RETRY_COUNT"
# Stop polling if API response is non-200
status_code=$(echo "$RESPONSE" | jq -r '.status_code')
if [[ $status_code -ne 200 ]]; then
echo "Polling stopped due to non-200 response from API. Status code: $status_code"
break
fi

check_report_status "$RESPONSE" && {
echo "Valid report status received. Exiting polling loop...."
break
}

sleep "$POLLING_DURATION"
done
# Handle Report
if [[ -n "$rich_html_response" ]]; then
# Embed CSS into the rich HTML report
mkdir -p browserstack
echo "<!DOCTYPE html>
<html>
<head>
<style>
$rich_css_response
</style>
</head>
$rich_html_response
</html>" > browserstack/testreport.html
echo "Rich html report saved as browserstack/testreport.html. To download the report, open artifacts tab & go to a job which extends set_browserstack_test_report job."

# Generate plain text report
if [[ -n "$plain_text_response" ]]; then
echo ""
echo "Browserstack textual report"
echo "$plain_text_response"
else
echo "Plain text response is empty."
fi
elif [[ "$REPORT_STATUS" == "$REPORT_STATUS_NOT_AVAILABLE" ]]; then
error_reason=$(echo "$RESPONSE" | jq -r '.body.errorReason // empty')
default_error_message="Failed to retrieve report. Reason:"
if [[ -n "$error_reason" ]]; then
echo "$default_error_message ${ERROR_SCENARIOS[$error_reason]:-$error_reason}"
else
echo "$default_error_message Unexpected error"
fi
else
echo "Failed to retrieve report."
fi
# Ensure pipeline doesn't exit with non-zero status
exit 0
EOF
artifacts:
paths:
- browserstack/testreport.html