name: "CallQA voice test" description: > Run a CallQA scenario (real phone calls to your voice agent or IVR), wait for the result, publish a summary and fail the job when quality drops below a threshold. author: "CallQA" branding: icon: "phone-call" color: "green" inputs: api-key: description: "CallQA API key with the read and run scopes. Pass it from a secret." required: true scenario-id: description: "Scenario id (UUID). All its enabled variants run as one run." required: true threshold: description: > Minimum suite score (0-100). The job fails under it, or if a call ended in error or was blocked. Empty: the job passes only on verdict "pass". required: false default: "80" version: description: "Version of your code under test, e.g. v2.3.0 (created in the environment if new)." required: false default: "" git-sha: description: "Commit of that version." required: false default: "" environment: description: "Environment slug, e.g. staging. Empty: the default environment." required: false default: "" release: description: "Deprecated: use version." required: false default: "" tags: description: "Comma-separated tags for the run, e.g. nightly,staging." required: false default: "" variants: description: "Comma-separated variant ids to run. Empty: all enabled variants." required: false default: "" wait: description: "Wait for the result and gate on it (true/false)." required: false default: "true" timeout: description: "Seconds to wait before giving up (the run keeps going)." required: false default: "1800" poll-interval: description: "Seconds between two status checks while waiting." required: false default: "10" api-url: description: "API base URL." required: false default: "https://app.callqa.dev/api/v1" outputs: run-id: description: "Run id." value: ${{ steps.callqa.outputs.run-id }} run-url: description: "Link to the report in the dashboard." value: ${{ steps.callqa.outputs.run-url }} verdict: description: "pass, warn or fail (empty if not waited)." value: ${{ steps.callqa.outputs.verdict }} score: description: "Run score 0-100 (empty if not waited or not scored)." value: ${{ steps.callqa.outputs.score }} passed: description: "true when the quality gate passed." value: ${{ steps.callqa.outputs.passed }} runs: using: "composite" steps: - id: callqa shell: bash # Inputs go through env variables, never inline in the script (no injection). env: CALLQA_API_KEY: ${{ inputs.api-key }} CALLQA_API_URL: ${{ inputs.api-url }} CALLQA_SCENARIO: ${{ inputs.scenario-id }} CALLQA_THRESHOLD: ${{ inputs.threshold }} CALLQA_VERSION: ${{ inputs.version }} CALLQA_RELEASE: ${{ inputs.release }} CALLQA_GIT_SHA: ${{ inputs.git-sha }} CALLQA_ENVIRONMENT: ${{ inputs.environment }} CALLQA_TAGS: ${{ inputs.tags }} CALLQA_VARIANTS: ${{ inputs.variants }} CALLQA_WAIT: ${{ inputs.wait }} CALLQA_TIMEOUT: ${{ inputs.timeout }} CALLQA_POLL: ${{ inputs.poll-interval }} run: | set -euo pipefail cli="$GITHUB_ACTION_PATH/callqa" [ -f "$cli" ] || cli="$GITHUB_ACTION_PATH/../../cli/callqa" args=(run --scenario "$CALLQA_SCENARIO" --outputs "$GITHUB_OUTPUT") [ -n "$CALLQA_THRESHOLD" ] && args+=(--threshold "$CALLQA_THRESHOLD") version="${CALLQA_VERSION:-$CALLQA_RELEASE}" # release: former name of the input [ -n "$version" ] && args+=(--code-version "$version") [ -n "$CALLQA_GIT_SHA" ] && args+=(--git-sha "$CALLQA_GIT_SHA") [ -n "$CALLQA_ENVIRONMENT" ] && args+=(--environment "$CALLQA_ENVIRONMENT") IFS=',' read -ra tags <<< "$CALLQA_TAGS" for t in ${tags[@]+"${tags[@]}"}; do [ -n "${t// }" ] && args+=(--tag "${t// }"); done IFS=',' read -ra variants <<< "$CALLQA_VARIANTS" for v in ${variants[@]+"${variants[@]}"}; do [ -n "${v// }" ] && args+=(--variant "${v// }") done if [ "$CALLQA_WAIT" = "true" ]; then args+=(--wait --timeout "$CALLQA_TIMEOUT" --poll "$CALLQA_POLL") args+=(--summary "$GITHUB_STEP_SUMMARY") fi python3 "$cli" "${args[@]}"