diff --git a/.github/workflows/integration-test-iOS16_2.yaml b/.github/workflows/integration-test-iOS16_2.yaml index ef3f45e55..b6b72cca7 100644 --- a/.github/workflows/integration-test-iOS16_2.yaml +++ b/.github/workflows/integration-test-iOS16_2.yaml @@ -109,6 +109,7 @@ jobs: if: always() env: TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: Scripts/upload_test_results.sh - name: Swift Package Manager - Installation Test diff --git a/.github/workflows/integration-test-macOS.yaml b/.github/workflows/integration-test-macOS.yaml index 2cf7ff101..e1df90319 100644 --- a/.github/workflows/integration-test-macOS.yaml +++ b/.github/workflows/integration-test-macOS.yaml @@ -104,6 +104,7 @@ jobs: if: always() env: TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: Scripts/upload_test_results.sh - name: Swift Package Manager - Installation Test diff --git a/.github/workflows/integration-test-tvOS16_1.yaml b/.github/workflows/integration-test-tvOS16_1.yaml index d259d0856..80d02eee7 100644 --- a/.github/workflows/integration-test-tvOS16_1.yaml +++ b/.github/workflows/integration-test-tvOS16_1.yaml @@ -104,6 +104,7 @@ jobs: if: always() env: TEST_OBSERVABILITY_SERVER_AUTH_KEY: ${{ secrets.TEST_OBSERVABILITY_SERVER_AUTH_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: Scripts/upload_test_results.sh - name: Swift Package Manager - Installation Test diff --git a/Scripts/upload_test_results.sh b/Scripts/upload_test_results.sh index 59286bd9a..8171fcfba 100755 --- a/Scripts/upload_test_results.sh +++ b/Scripts/upload_test_results.sh @@ -6,6 +6,11 @@ # Options: # -u / --upload-server-base-url : Allows you to specify a URL to use as the upload server base URL. Defaults to https://test-observability.herokuapp.com. # -i / --iteration : If running the tests in a loop inside a single CI job, indicates which iteration of the loop is currently executing. Defaults to 1. +# -j / --job-index : The index to which the current job corresponds in the response from the "list jobs for a workflow run attempt" GitHub API (https://docs.github.com/en/rest/actions/workflow-jobs?apiVersion=2022-11-28#list-jobs-for-a-workflow-run-attempt). If you specify `GITHUB_TOKEN` but not `--job-index`, and the response from this API contains more than one job, the script will fail. +# +# Optional environment variables: +# +# GITHUB_TOKEN: A GitHub access token. If provided, the script will perform a GitHub API call in order to discover the web URL for the current job, and will include this URL in the observability server upload. set -e @@ -17,6 +22,12 @@ then exit 1 fi +if ! which gh > /dev/null +then + echo "You need to install the GitHub CLI." 2>&1 + exit 1 +fi + if [[ ! -d xcparse ]] then echo "You need to check out the xcparse repository." 2>&1 @@ -92,6 +103,7 @@ while [[ "$#" -gt 0 ]]; do case $1 in -i|--iteration) iteration="$2"; shift ;; -u|--upload-server-base-url) upload_server_base_url="$2"; shift ;; + -j|--job-index) job_index="$2"; shift ;; *) echo "Unknown parameter passed: $1"; exit 1 ;; esac shift @@ -196,7 +208,44 @@ do crash_reports_json_file="${temp_crash_reports_json_file}" done -# 8. Create the JSON request body. +# 8. Fetch the details of the current GitHub job, so that we can add a link to it in the upload. +# +# It’s a bit surprising that there’s no built-in functionality for this (see e.g. https://stackoverflow.com/questions/71240338/obtain-job-id-from-a-workflow-run-using-contexts or https://github.com/orgs/community/discussions/8945). + +if [[ ! -z $GITHUB_TOKEN ]] +then + temp_github_jobs_response_file=$(mktemp) + gh api "/repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/attempts/${GITHUB_RUN_ATTEMPT}/jobs" > $temp_github_jobs_response_file + + number_of_jobs=$(jq '.jobs | length' < "${temp_github_jobs_response_file}") + + if [[ -z $job_index && $number_of_jobs -gt 1 ]] + then + echo -e "Got ${number_of_jobs} jobs from GitHub API but don’t know which one to pick. You need to provide a --job-index argument." 2>&1 + exit 1 + fi + + if [[ -n $job_index ]] + then + if [[ $job_index -gt $number_of_jobs ]] + then + echo -e "The --job-index argument has value ${job_index}, but there are only ${number_of_jobs} jobs. This script does not currently handle pagination." 2>&1 + exit 1 + fi + else + if [[ $number_of_jobs -eq 0 ]] + then + echo -e "The GitHub API response contains no jobs." 2>&1 + exit 1 + fi + job_index=0 + fi + + github_job_api_url=$(jq --exit-status --raw-output ".jobs[${job_index}].url" < "${temp_github_jobs_response_file}") + github_job_html_url=$(jq --exit-status --raw-output ".jobs[${job_index}].html_url" < "${temp_github_jobs_response_file}") +fi + +# 9. Create the JSON request body. temp_request_body_file=$(mktemp) @@ -217,6 +266,20 @@ else optional_params+=(--argjson github_head_ref null) fi +if [[ ! -z $github_job_api_url ]] +then + optional_params+=(--arg github_job_api_url "${github_job_api_url}") +else + optional_params+=(--argjson github_job_api_url null) +fi + +if [[ ! -z $github_job_html_url ]] +then + optional_params+=(--arg github_job_html_url "${github_job_html_url}") +else + optional_params+=(--argjson github_job_html_url null) +fi + jq -n \ --rawfile junit_report_xml "${test_reports}" \ --slurpfile crash_reports "${crash_reports_json_file}" \ @@ -231,12 +294,12 @@ jq -n \ --arg github_job "${GITHUB_JOB}" \ --arg iteration "${iteration}" \ "${optional_params[@]}" \ - '{ junit_report_xml: $junit_report_xml | @base64, crash_reports: $crash_reports[0], github_repository: $github_repository, github_sha: $github_sha, github_ref_name: $github_ref_name, github_retention_days: $github_retention_days, github_action: $github_action, github_run_number: $github_run_number, github_run_attempt: $github_run_attempt, github_run_id: $github_run_id, github_base_ref: $github_base_ref, github_head_ref: $github_head_ref, github_job: $github_job, iteration: $iteration }' \ + '{ junit_report_xml: $junit_report_xml | @base64, crash_reports: $crash_reports[0], github_repository: $github_repository, github_sha: $github_sha, github_ref_name: $github_ref_name, github_retention_days: $github_retention_days, github_action: $github_action, github_run_number: $github_run_number, github_run_attempt: $github_run_attempt, github_run_id: $github_run_id, github_base_ref: $github_base_ref, github_head_ref: $github_head_ref, github_job: $github_job, github_job_api_url: $github_job_api_url, github_job_html_url: $github_job_html_url, iteration: $iteration }' \ > "${temp_request_body_file}" printf "Created request body:\n$(cat "${temp_request_body_file}")\n\n" 2>&1 -# 9. Send the request. +# 10. Send the request. echo "Uploading test report." 2>&1 @@ -251,7 +314,7 @@ temp_response_body_file=$(mktemp) curl -vvv --fail-with-body --data-binary "@${temp_request_body_file}" --header "Content-Type: application/json" --header "Test-Observability-Auth-Key: ${TEST_OBSERVABILITY_SERVER_AUTH_KEY}" --header "X-Request-ID: ${request_id}" "${upload_server_base_url}/uploads" | tee "${temp_response_body_file}" echo 2>&1 # Print a newline to separate the `curl` output from the next log line. -# 10. Extract the ID of the created upload and log the web UI URL. +# 11. Extract the ID of the created upload and log the web UI URL. upload_id=$(jq --exit-status --raw-output '.id' < "${temp_response_body_file}") web_ui_url="${upload_server_base_url}/repos/${GITHUB_REPOSITORY}/uploads/${upload_id}"