Skip to content

Initial import

Initial import #1

name: Nightly Branch CI Monitor

Check failure on line 1 in .github/workflows/nightly-branch-monitor.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/nightly-branch-monitor.yml

Invalid workflow file

(Line: 63, Col: 7): Unrecognized named-value: 'matrix'. Located at position 1 within expression: matrix.branch
on:
schedule:
# 1 AM UTC daily (9 PM ET / 6 PM PT)
- cron: '0 1 * * *'
workflow_dispatch:
inputs:
branch:
description: 'Specific branch to test (optional, defaults to auto-detect)'
required: false
type: string
jobs:
detect-branches:
name: Detect Active Release Branches
runs-on: ubuntu-latest
outputs:
branches: ${{ steps.get-branches.outputs.branches }}
count: ${{ steps.get-branches.outputs.count }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
fetch-depth: 0 # Need full history for branch detection
- name: Set up Python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a20 # v5.3.0
with:
python-version: '3.11'
- name: Install dependencies
run: pip install packaging
- name: Get active branches
id: get-branches
run: |
# Use manual branch if provided, otherwise auto-detect
if [ -n "${{ github.event.inputs.branch }}" ]; then
echo "branches=[\"${{ github.event.inputs.branch }}\"]" >> $GITHUB_OUTPUT
echo "count=1" >> $GITHUB_OUTPUT
else
python scripts/get_active_branches.py >> $GITHUB_OUTPUT
fi
- name: Display detected branches
run: |
echo "Monitoring branches: ${{ steps.get-branches.outputs.branches }}"
echo "Count: ${{ steps.get-branches.outputs.count }}"
validate-branch:
name: Validate Branch ${{ matrix.branch }}
needs: detect-branches
if: needs.detect-branches.outputs.count > 0
runs-on: ubuntu-latest
timeout-minutes: 240 # 4 hours max per branch
strategy:
matrix:
branch: ${{ fromJSON(needs.detect-branches.outputs.branches) }}
fail-fast: false # Continue testing all branches
max-parallel: 3 # Limit parallel jobs
outputs:
result-${{ matrix.branch }}: ${{ steps.set-result.outputs.result }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ matrix.branch }}
persist-credentials: false
fetch-depth: 0
- name: Branch validation info
run: |
echo "Validating branch: ${{ matrix.branch }}"
git log -1 --oneline
echo "Current commit: $(git rev-parse HEAD)"
- uses: actions-rust-lang/setup-rust-toolchain@9d7e65c320fdb52dcd45ffaa68deb6c02c8754d9 # v1.12.0
- name: Install latest stable toolchain
run: rustup update stable && rustup default stable && rustup component add rustfmt clippy
- name: Install hatch
uses: pypa/hatch@257e27e51a6a5616ed08a39a408a21c35c9931bc # install
with:
version: "1.12.0"
- name: Set up Docker for system tests
run: |
# Start Docker service (already available on ubuntu-latest)
docker --version
# Run unit tests
- name: Run unit tests
id: unit-tests
continue-on-error: true
run: |
echo "Running unit tests on branch ${{ matrix.branch }}"
hatch run +py=3.12 multiple_os_tests:test
timeout-minutes: 30
# Run framework tests (subset - most critical frameworks)
- name: Run framework tests
id: framework-tests
continue-on-error: true
run: |
echo "Running framework tests on branch ${{ matrix.branch }}"
# Run a subset of critical framework tests
hatch run +py=3.12 test.django || true
hatch run +py=3.12 test.flask || true
hatch run +py=3.12 test.fastapi || true
timeout-minutes: 90
# Run build validation
- name: Run build validation
id: build-tests
continue-on-error: true
run: |
echo "Running build validation on branch ${{ matrix.branch }}"
# Test that the package can be built
hatch build
timeout-minutes: 40
# Collect results
- name: Collect results
id: collect-results
if: always()
run: |
FAILED_JOBS="[]"
WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
if [ "${{ steps.unit-tests.outcome }}" == "failure" ]; then
FAILED_JOBS=$(echo "$FAILED_JOBS" | jq '. + [{"name":"unit-tests","url":"'"$WORKFLOW_URL"'"}]')
fi
if [ "${{ steps.framework-tests.outcome }}" == "failure" ]; then
FAILED_JOBS=$(echo "$FAILED_JOBS" | jq '. + [{"name":"framework-tests","url":"'"$WORKFLOW_URL"'"}]')
fi
if [ "${{ steps.build-tests.outcome }}" == "failure" ]; then
FAILED_JOBS=$(echo "$FAILED_JOBS" | jq '. + [{"name":"build-tests","url":"'"$WORKFLOW_URL"'"}]')
fi
echo "failed_jobs=$FAILED_JOBS" >> $GITHUB_OUTPUT
if [ "$FAILED_JOBS" != "[]" ]; then
echo "has_failures=true" >> $GITHUB_OUTPUT
else
echo "has_failures=false" >> $GITHUB_OUTPUT
fi
- name: Upload results artifact
if: always()
uses: actions/upload-artifact@4.5.0
with:
name: results-${{ matrix.branch }}
path: |
/tmp/nightly-results-${{ matrix.branch }}.json
retention-days: 7
- name: Write results to file
if: always()
run: |
mkdir -p /tmp/nightly-results
cat > /tmp/nightly-results/${{ matrix.branch }}.json << EOF
{
"branch": "${{ matrix.branch }}",
"failed_jobs": ${{ steps.collect-results.outputs.failed_jobs }},
"has_failures": "${{ steps.collect-results.outputs.has_failures }}"
}
EOF
- name: Upload results file
if: always()
uses: actions/upload-artifact@4.5.0
with:
name: result-${{ matrix.branch }}
path: /tmp/nightly-results/${{ matrix.branch }}.json
retention-days: 7
- name: Set job result output
id: set-result
if: always()
run: |
if [ "${{ steps.collect-results.outputs.has_failures }}" == "true" ]; then
echo "result=failure" >> $GITHUB_OUTPUT
else
echo "result=success" >> $GITHUB_OUTPUT
fi
report-failures:
name: Report Failures and Alert
needs: [detect-branches, validate-branch]
if: always() && needs.detect-branches.outputs.count > 0
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Set up Python
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a20 # v5.3.0
with:
python-version: '3.11'
- name: Download all results
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
path: results/
- name: Process results and create incidents
id: process-results
env:
GH_TOKEN: ${{ github.token }}
run: |
INCIDENTS_CREATED=""
WORKFLOW_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
# Make incident script executable
chmod +x scripts/create_ci_incident.py
# Process each branch result
for result_file in results/result-*/*.json; do
if [ ! -f "$result_file" ]; then
continue
fi
# Extract data from result file
BRANCH=$(jq -r '.branch' "$result_file")
FAILED_JOBS=$(jq -c '.failed_jobs' "$result_file")
HAS_FAILURES=$(jq -r '.has_failures' "$result_file")
echo "Processing branch: $BRANCH, has_failures: $HAS_FAILURES"
if [ "$HAS_FAILURES" == "true" ] && [ "$FAILED_JOBS" != "[]" ]; then
# Create or update incident
ISSUE_OUTPUT=$(python scripts/create_ci_incident.py \
--branch "$BRANCH" \
--failed-jobs "$FAILED_JOBS" \
--workflow-url "$WORKFLOW_URL" 2>&1)
echo "$ISSUE_OUTPUT"
ISSUE_URL=$(echo "$ISSUE_OUTPUT" | grep "issue_url=" | cut -d'=' -f2)
if [ -n "$ISSUE_URL" ]; then
INCIDENTS_CREATED="${INCIDENTS_CREATED}\n- Branch \`${BRANCH}\`: ${ISSUE_URL}"
fi
else
# Branch is passing, close any existing incident
echo "Branch $BRANCH is passing, checking for existing incidents to close..."
python scripts/create_ci_incident.py \
--branch "$BRANCH" \
--resolved || true
fi
done
# Set output for Slack notification
if [ -n "$INCIDENTS_CREATED" ]; then
echo "should_notify=true" >> $GITHUB_OUTPUT
echo "incidents_created<<EOF" >> $GITHUB_OUTPUT
echo -e "$INCIDENTS_CREATED" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
else
echo "should_notify=false" >> $GITHUB_OUTPUT
echo "incidents_created=" >> $GITHUB_OUTPUT
fi
- name: Send Slack notification
if: steps.process-results.outputs.should_notify == 'true'
uses: slackapi/slack-github-action@485a9d42d3a73031f12ec201c457e2162c45d02d # v2.0.0
with:
channel-id: 'CHANNEL_ID_PLACEHOLDER' # Replace with actual #apm-python channel ID
payload: |
{
"text": ":warning: *Nightly CI Failures Detected*",
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": ":warning: Nightly CI Failures Detected"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "The following branches have failing nightly CI runs:\n${{ steps.process-results.outputs.incidents_created }}"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Workflow Run:* ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\n\nAssigned to: @DataDog/apm-core-python"
}
}
]
}
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
- name: Summary
if: always()
run: |
echo "## Nightly Branch Monitor Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Monitored Branches:** ${{ needs.detect-branches.outputs.branches }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.process-results.outputs.should_notify }}" == "true" ]; then
echo "### :warning: Failures Detected" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.process-results.outputs.incidents_created }}" >> $GITHUB_STEP_SUMMARY
else
echo "### :white_check_mark: All monitored branches passing" >> $GITHUB_STEP_SUMMARY
fi
finished:
name: Nightly Monitor Complete
runs-on: ubuntu-latest
needs: [detect-branches, validate-branch, report-failures]
if: always()
steps:
- name: Check overall status
run: |
# This job always succeeds - failures are tracked via GitHub issues
echo "Nightly branch monitoring complete"
echo "Check GitHub issues with label 'ci-nightly-failure' for active incidents"
exit 0