Skip to content

Merge branch 'main' into copilot/fix-github-actions-job-failure #1580

Merge branch 'main' into copilot/fix-github-actions-job-failure

Merge branch 'main' into copilot/fix-github-actions-job-failure #1580

Workflow file for this run

# =============================================================================
# QAI CI Pipeline - Main continuous integration workflow
# =============================================================================
# Purpose: Validates code quality, runs tests, and performs daily training
# Triggers: Daily scheduled runs and manual dispatch
# Jobs:
# - validate: Code validation, unit & integration tests
# - train: Daily scheduled training workflow (requires validate pass)
# - deploy: Model deployment after successful training
# =============================================================================
name: QAI CI Pipeline
on:
schedule:
- cron: '0 2 * * *' # Daily at 2 AM UTC
workflow_dispatch: {}
permissions:
contents: read
actions: read
checks: write
concurrency:
group: ci-pipeline-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
HARDEN_RUNNER_SHA: 0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.2
CHECKOUT_SHA: 11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
ACTIONS_CACHE_SHA: 1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
UPLOAD_ARTIFACT_SHA: 65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
PYTHON_UNBUFFERED: "1"
PYTHONDONTWRITEBYTECODE: "1"
PIP_DISABLE_PIP_VERSION_CHECK: "1"
defaults:
run:
shell: bash
jobs:
validate:
name: Validate (lint, tests, integration smoke)
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
matrix:
python-version: ['3.11']
steps:

Check failure on line 51 in .github/workflows/ci-pipeline.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/ci-pipeline.yml

Invalid workflow file

You have an error in your yaml syntax on line 51
- name: Harden runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0
with:
egress-policy: audit
disable-sudo: true
# cspell:words pyproject PYTHONDONTWRITEBYTECODE
concurrency:
cancel-in-progress: ${{ github.event_name != 'workflow_dispatch' }}
group: ci-pipeline-${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
env:
ACTIONS_CACHE_SHA: 1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
CHECKOUT_SHA: 11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
HARDEN_RUNNER_SHA: 0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.2
PIP_DISABLE_PIP_VERSION_CHECK: "1"
PYTHONDONTWRITEBYTECODE: "1"
PYTHON_UNBUFFERED: "1"
UPLOAD_ARTIFACT_SHA: 65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
jobs:
deploy:
if: github.event_name == 'schedule'
name: Deploy (scheduled)
needs: train
runs-on: ubuntu-latest
steps:
- name: Harden runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0
with:
disable-sudo: true
egress-policy: audit
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-depth: 0
persist-credentials: false
- name: Cache pip
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57
with:
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt', 'pyproject.toml') }}
path: |
~/.cache/pip
~/.cache/pip-wheel
- name: Setup Python
uses: ./.github/actions/setup-python-env
with:
python-version: '3.11'
- name: Deploy best model
run: |
set -euo pipefail
python scripts/model_deployer.py --deploy best --strategy canary
- name: Upload deployment manifest
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08
with:
name: deployment-manifest
path: deployed_models/model_registry.json
retention-days: 90
timeout-minutes: 30
train:
if: github.event_name == 'schedule'
name: Train (scheduled)
needs: validate
runs-on: ubuntu-latest
steps:
- name: Harden runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0
with:
disable-sudo: false
egress-policy: audit
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-depth: 0
persist-credentials: false
- name: Cache pip
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57
with:
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt', 'pyproject.toml') }}
path: |
~/.cache/pip
~/.cache/pip-wheel
- name: Setup Python
uses: ./.github/actions/setup-python-env
with:
python-version: '3.11'
- name: Run training workflow
run: |
set -euo pipefail
python scripts/master_orchestrator.py --workflow daily_full_pipeline
- if: always()
name: Generate training summary
run: |
set -euo pipefail
{
echo "## Training Results"
} >> "$GITHUB_STEP_SUMMARY"
if [ -f data_out/master_orchestrator/status.json ]; then
{
echo '```json'
cat data_out/master_orchestrator/status.json
echo ''
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
else
echo "⚠️ No master_orchestrator status file found" >> "$GITHUB_STEP_SUMMARY"
fi
if [ "${{ job.status }}" != "success" ]; then
{
echo ""
echo "### ❌ Training job failed — see logs above."
} >> "$GITHUB_STEP_SUMMARY"
fi
- if: always()
name: Upload training results
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08
with:
name: training-results
path: data_out/
retention-days: 30
timeout-minutes: 90
validate:
name: Validate (lint, tests, integration smoke)
runs-on: ubuntu-latest
steps:
- name: Harden runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0
with:
disable-sudo: true
egress-policy: audit
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-depth: 0
persist-credentials: false
- name: Cache pip
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57
with:
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt', 'pyproject.toml') }}
path: |
~/.cache/pip
~/.cache/pip-wheel
- name: Setup Python
uses: ./.github/actions/setup-python-env
with:
extra-packages: 'pytest pytest-timeout pytest-cov'
python-version: ${{ matrix.python-version }}
- name: Run CI validation
run: |
set -euo pipefail
python scripts/ci_orchestrator.py --validate-all
- name: Run integration smoke checks
run: |
set -euo pipefail
python scripts/integration_smoke.py
- name: Run integration contract unit tests
run: |
set -euo pipefail
python scripts/ci_orchestrator.py --integration-contract-tests
- name: Run unit tests
run: |
set -euo pipefail
python scripts/test_runner.py --unit --coverage
- name: Run ai-project tests
run: |
set -euo pipefail
python scripts/test_runner.py --ai-projects
- name: Run integration tests
run: |
set -euo pipefail
python scripts/test_runner.py --integration
- if: always()
name: Generate summary
run: |
set -euo pipefail
{
echo "## CI Validation Results"
echo ""
} >> "$GITHUB_STEP_SUMMARY"
if [ -f data_out/ci_orchestrator/status.json ]; then
{
echo '```json'
cat data_out/ci_orchestrator/status.json
echo ''
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
else
echo "⚠️ No ci_orchestrator status file found" >> "$GITHUB_STEP_SUMMARY"
fi
if [ "${{ job.status }}" != "success" ]; then
{
echo ""
echo "### ❌ Validation failed — see logs above for details."
} >> "$GITHUB_STEP_SUMMARY"
fi
- if: always()
name: Upload validation results
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08
with:
name: validation-results
path: |
data_out/ci_orchestrator/
data_out/integration_smoke/
data_out/test_runner/
retention-days: 14
strategy:
matrix:
python-version: ['3.11']
timeout-minutes: 30
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-depth: 0
persist-credentials: false
- name: Cache pip
with:
path: |
contents: read