Skip to content

Commit

Permalink
Add test orchestrator script to trigger remote workflow runner outsid…
Browse files Browse the repository at this point in the history
…e functional test repo for cypress tests

Issue details - opensearch-project/OpenSearch-Dashboards#5392

Signed-off-by: manasvinibs <[email protected]>
  • Loading branch information
manasvinibs committed Dec 6, 2023
1 parent 652537e commit 11a4668
Show file tree
Hide file tree
Showing 2 changed files with 239 additions and 0 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/remote-cypress-workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Trigger Remote Cypress Workflow

on:
workflow_dispatch:
inputs:
repo:
description: 'Name of the repository in {owner}/{repository} format'
required: true
workflow_name:
description: 'Name of the Github workflow yml file in the component repository'
required: true
os_url:
description: 'Release artifact of OpenSearch'
required: true
osd_url:
description: 'Release artifact of OpenSearch Dashboards'
required: true
branch_ref:
description: 'Test branch name or commit reference id'
required: true

jobs:
trigger-cypress:
runs-on: ubuntu-latest
name: Remote Cypress Tests

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Run Bash Script
env:
GITHUB_SECRET_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
./remoteCypress.sh -r "${{ github.event.inputs.repo }}" -w "${{ github.event.inputs.workflow_name }}" -o "${{ github.event.inputs.os_url }}" -d "${{ github.event.inputs.osd_url }}" -b "${{ github.event.inputs.branch_ref }}"
203 changes: 203 additions & 0 deletions remoteCypress.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#!/bin/bash

set -e

function usage() {
echo ""
echo "This script triggers GitHub workflow runners within the component repository which runs Cypress integration tests on a remote OpenSearch/Dashboards cluster."
echo "--------------------------------------------------------------------------"
echo "Usage: $0 [args]"
echo "Required arguments:"
echo -e "-r REMOTE_REPO\t, Name of the repository in {owner}/{repository} format"
echo -e "-w GITHUB_WORKFLOW_NAME\t, Name of the GitHub workflow file name with .yml extension that contain jobs that run Cypress tests in the component repository. For example, main.yaml"
echo -e "-o OS_URL\t, Release artifact of the OpenSearch"
echo -e "-d OSD_URL\t, Release artifact of the OpenSearch Dashboards"
echo -e "-b BRANCH_REF\t Test Branch name or commit reference id"
echo -e "-i BUILD_ID\t Release-specific build id for reference"
echo "--------------------------------------------------------------------------"
}

# Initialize variables to empty strings
REMOTE_REPO=""
WORKFLOW_NAME=""
OS_URL=""
OSD_URL=""
BRANCH_REF=""
BUILD_ID=""

# Parse command-line arguments
while getopts ":h:r:w:o:d:b:i:" opt; do
case $opt in
h)
usage
exit 1
;;
r)
REMOTE_REPO="$OPTARG"
;;
w)
WORKFLOW_NAME="$OPTARG"
;;
o)
OS_URL="$OPTARG"
;;
d)
OSD_URL="$OPTARG"
;;
b)
BRANCH_REF="$OPTARG"
;;
i)
BUILD_ID="$OPTARG"
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
esac
done

# Check if required arguments are provided
if [[ -z "$REMOTE_REPO" || -z "$WORKFLOW_NAME" || -z "$OS_URL" || -z "$OSD_URL" || -z "$BRANCH_REF" ]]; then
echo "Error: Missing required arguments. See usage below."
usage
exit 1
fi

# Accessing the secret as an environment variable using Github actions while invoking this script
GITHUB_TOKEN=$GITHUB_SECRET_TOKEN
# This is to uniquely identify each execution workflow. This ID has to be appended to the workflow_run
# name in the component repository yaml file for polling purpose.
UNIQUE_WORKFLOW_ID=$(uuidgen)
echo "Unique Execution ID: $UNIQUE_WORKFLOW_ID"
API_URL="https://api.github.com/repos/$REMOTE_REPO/actions/workflows/$WORKFLOW_NAME/dispatches"
PAYLOAD="{\"ref\": \"$BRANCH_REF\",\"inputs\":{\"build_id\":\"$BUILD_ID\", \"OS_URL\":\"$OS_URL\", \"OSD_URL\":\"$OSD_URL\", \"UNIQUE_ID\":\"$UNIQUE_WORKFLOW_ID\"}}"

# Maximum number of retries for triggering the remote runner
MAX_RETRIES=3

# Trigger the remote GitHub workflow using curl and the PAT token
trigger_remote_workflow() {
curl -L -X POST -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-w "%{http_code}" \
"$API_URL" -d "$PAYLOAD"
}

echo "Triggering the remote GitHub workflow for Cypress tests in the repository: $REMOTE_REPO"

# Attempt to trigger the remote workflow with retries
for ((i = 1; i <= MAX_RETRIES; i++)); do
echo "Attempting to trigger the remote workflow (Attempt $i)"
status_code=$(trigger_remote_workflow)
echo "status_code: $status_code"

if [[ $status_code -ge 200 && $status_code -lt 300 ]]; then
echo "Remote workflow triggered successfully."
break
else
echo "Failed to trigger the remote workflow. Retrying..."
sleep 10 # Adds a delay between retries
fi

if [ $i -eq $MAX_RETRIES ]; then
echo "Maximum number of retries reached. Exiting."
exit 1
fi
done

# Function to check the status of the remote workflow by constantly polling the workflow-run
check_remote_workflow_status() {
local run_id
local status
local conclusion
local run_details
local workflow_runs
local matching_workflow
local polling_run_id_retries=1
local polling_workflow_completion_retries=1
local max_polling_run_id_retries=5 # Keep polling for the first 5 minutes to fetch the workflow run id till the workflow gets generated
local max_polling_workflow_completion_retries=12 # Set the polling window period to be 1 hour

# Check if a matching workflow object was found
while [ -z "$matching_workflow" ] && [ $polling_run_id_retries -le $max_polling_run_id_retries ]; do
echo "Querying for the workflow run id..."
sleep 60 # Wait for 1 minute before polling for the workflow run_id till it gets created

# Make a GET request to the GitHub API to get the list of workflow runs
workflow_runs=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/$REMOTE_REPO/actions/workflows/$WORKFLOW_NAME/runs")

# Extract the JSON object whose "name" field contains the string with a unique id of the workflow
matching_workflow=$(echo "$workflow_runs" | jq --arg unique_id "$UNIQUE_WORKFLOW_ID" '.workflow_runs[] | select(.name | contains($unique_id))')
((polling_run_id_retries++))

done
echo "matching_workflow: $matching_workflow"

if [ -n "$matching_workflow" ]; then
# Extract the "jobs_url" and "run_id" values from the matching object
jobs_url=$(echo "$matching_workflow" | jq -r '.jobs_url')
run_id=$(echo "$matching_workflow" | jq -r '.id')
echo "Jobs URL: $jobs_url"
echo "Run Id: $run_id"

# Poll the status until the workflow is completed
while [ $polling_workflow_completion_retries -le $max_polling_workflow_completion_retries ]; do
echo "Checking the workflow run API status, attempt: $polling_workflow_completion_retries"

run_details=$(curl -L -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"https://api.github.com/repos/$REMOTE_REPO/actions/runs/$run_id")
echo "Workflow run details: $run_details"

# Extract status and conclusion from the run details
status=$(echo "$run_details" | jq -r ".status")
conclusion=$(echo "$run_details" | jq -r ".conclusion")

# Check if the status indicates that the workflow is complete
if [[ "$status" == "completed" ]]; then
echo "Workflow completed with status: $status"

# Check if it was successful
if [[ $conclusion == "success" ]]; then
echo "Remote workflow completed successfully."
return 0 # Success
elif [[ $conclusion == "failure" ]]; then
echo "Remote workflow completed with errors. Conclusion: $conclusion"

# Parse the workflow to find any failures in the test
failures=$(echo "$run_details" | jq -r '.jobs[] | select(.conclusion == "failure") | .name')
echo "Test failures: $failures"

return 1 # Failure
else
echo "Remote workflow completed with unexpected conclusion. Conclusion: $conclusion"
return 1 # Failure
fi
else
echo "Remote workflow is still running. Waiting..."
sleep 300 # Wait for 5 minutes before checking again
((polling_workflow_completion_retries++))
fi
done
else
echo "No matching workflow run object found even after retries. Exiting..."
fi

echo "Remote workflow didn't complete within the specified time."
return 1 # Failure
}

# Check the status of the remote workflow
check_remote_workflow_status

exit 0

0 comments on commit 11a4668

Please sign in to comment.