-
Notifications
You must be signed in to change notification settings - Fork 24
add metrics #212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
abdulanu0
wants to merge
9
commits into
main
Choose a base branch
from
users/anabdul/add-metrics
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
add metrics #212
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
26e9305
Add E2E metrics dashboard with SDK validation and error categorization
abdulanu0 14fbbc1
Add embedded fallback data for dashboard offline viewing
abdulanu0 8fd8617
Add dashboard styling enhancements: animations, hover effects, status…
abdulanu0 b3d2eac
Add E2E Metrics Dashboard with Agent 365 SDK tracking
abdulanu0 551cec5
fix: address CodeQL code injection vulnerabilities
abdulanu0 8d25df8
feat: split SDK validation into Node.js, .NET, and Python sections
abdulanu0 62073b4
fix: address Copilot review comments
abdulanu0 0ba6d1b
feat: Update metrics workflow to push to Agent365-metrics repo
abdulanu0 337e0da
refactor: Use GitHub API to collect E2E metrics
abdulanu0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,252 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| # E2E Test Metrics Collection Workflow | ||
| # This workflow runs after E2E tests complete to collect metrics and update the dashboard | ||
| # Uses GitHub API to fetch workflow run job statuses (no artifacts needed) | ||
|
|
||
| name: E2E Metrics Collection | ||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: ["E2E Test Orchestrator"] | ||
| types: | ||
| - completed | ||
|
|
||
| # Allow manual trigger for testing | ||
| workflow_dispatch: | ||
| inputs: | ||
| run_id: | ||
| description: 'Workflow run ID to collect metrics from (optional)' | ||
| required: false | ||
| type: string | ||
|
|
||
abdulanu0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # Prevent concurrent metrics updates to avoid merge conflicts | ||
| concurrency: | ||
| group: metrics-update | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: | ||
| actions: read | ||
|
|
||
| jobs: | ||
| collect-metrics: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout Metrics Repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: microsoft/Agent365-metrics | ||
| ref: main | ||
| token: ${{ secrets.METRICS_REPO_TOKEN }} | ||
|
|
||
| - name: Fetch E2E Test Results from Workflow Run | ||
| id: results | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| // Get the workflow run ID | ||
| let runId; | ||
| if (context.eventName === 'workflow_run') { | ||
| runId = context.payload.workflow_run.id; | ||
| } else if (context.payload.inputs && context.payload.inputs.run_id) { | ||
| runId = parseInt(context.payload.inputs.run_id); | ||
| } else { | ||
| core.setFailed('No workflow run ID available'); | ||
| return; | ||
| } | ||
|
|
||
| console.log(`Fetching results for workflow run: ${runId}`); | ||
|
|
||
| // Get the workflow run details | ||
| const { data: workflowRun } = await github.rest.actions.getWorkflowRun({ | ||
| owner: 'microsoft', | ||
| repo: 'Agent365-Samples', | ||
| run_id: runId | ||
| }); | ||
|
|
||
| console.log(`Workflow: ${workflowRun.name}`); | ||
| console.log(`Status: ${workflowRun.status}`); | ||
| console.log(`Conclusion: ${workflowRun.conclusion}`); | ||
| console.log(`Branch: ${workflowRun.head_branch}`); | ||
| console.log(`Commit: ${workflowRun.head_sha}`); | ||
|
|
||
| // Get all jobs for the workflow run | ||
| const { data: jobsData } = await github.rest.actions.listJobsForWorkflowRun({ | ||
| owner: 'microsoft', | ||
| repo: 'Agent365-Samples', | ||
| run_id: runId | ||
| }); | ||
|
|
||
| // Map job names to sample names | ||
| const sampleMapping = { | ||
| 'Python OpenAI E2E': 'python-openai', | ||
| 'Python Agent Framework E2E': 'python-af', | ||
| 'Node.js OpenAI E2E': 'nodejs-openai', | ||
| 'Node.js LangChain E2E': 'nodejs-langchain', | ||
| '.NET Semantic Kernel E2E': 'dotnet-sk', | ||
| '.NET Agent Framework E2E': 'dotnet-af' | ||
| }; | ||
|
|
||
| // Determine testing stage | ||
| let stage = 'scheduled'; | ||
| if (workflowRun.event === 'pull_request') { | ||
| stage = 'pre-checkin'; | ||
| } else if (workflowRun.event === 'push' && workflowRun.head_branch === 'main') { | ||
| stage = 'post-checkin'; | ||
| } else if (workflowRun.event === 'schedule') { | ||
| stage = 'scheduled'; | ||
| } | ||
|
|
||
| // Create one entry per sample (matches dashboard format) | ||
| const entries = []; | ||
| let passedCount = 0; | ||
| let failedCount = 0; | ||
|
|
||
| for (const job of jobsData.jobs) { | ||
| const sampleName = sampleMapping[job.name]; | ||
| if (!sampleName) { | ||
| console.log(`Skipping job: ${job.name} (not a sample job)`); | ||
| continue; | ||
| } | ||
|
|
||
| const passed = job.conclusion === 'success'; | ||
| const failed = job.conclusion === 'failure'; | ||
|
|
||
| if (passed) passedCount++; | ||
| if (failed) failedCount++; | ||
|
|
||
| // Create entry in dashboard-expected format | ||
| const entry = { | ||
| id: `run-${runId}-${sampleName}`, | ||
| timestamp: workflowRun.created_at, | ||
| stage: stage, | ||
| sampleName: sampleName, | ||
| sdkVersions: {}, // SDK versions not available from API | ||
| testResults: { | ||
| status: passed ? 'passed' : (failed ? 'failed' : 'skipped'), | ||
| total: 1, | ||
| passed: passed ? 1 : 0, | ||
| failed: failed ? 1 : 0, | ||
| skipped: (!passed && !failed) ? 1 : 0 | ||
| }, | ||
| bugsCaught: { | ||
| count: 0, | ||
| details: [] | ||
| }, | ||
| runUrl: workflowRun.html_url | ||
| }; | ||
|
|
||
| entries.push(entry); | ||
| console.log(`${sampleName}: ${job.conclusion}`); | ||
| } | ||
|
|
||
| // Write entries to file | ||
| const fs = require('fs'); | ||
| fs.writeFileSync('new-entries.json', JSON.stringify(entries, null, 2)); | ||
|
|
||
| core.setOutput('run_id', runId); | ||
| core.setOutput('conclusion', workflowRun.conclusion); | ||
| core.setOutput('passed', passedCount); | ||
| core.setOutput('failed', failedCount); | ||
| core.setOutput('stage', stage); | ||
| core.setOutput('branch', workflowRun.head_branch); | ||
| core.setOutput('entry_count', entries.length); | ||
|
|
||
| console.log(`\n=== Created ${entries.length} entries ===`); | ||
|
|
||
| - name: Update History File | ||
| id: update | ||
| run: | | ||
| HISTORY_FILE="docs/history.json" | ||
| NEW_ENTRIES_FILE="new-entries.json" | ||
|
|
||
| echo "=== Updating history file ===" | ||
|
|
||
| # Read the new entries | ||
| NEW_ENTRIES=$(cat "$NEW_ENTRIES_FILE") | ||
| ENTRY_COUNT=$(echo "$NEW_ENTRIES" | jq 'length') | ||
| echo "New entries to add: $ENTRY_COUNT" | ||
|
|
||
| # Read existing history or create new one | ||
| if [ -f "$HISTORY_FILE" ]; then | ||
| HISTORY=$(cat "$HISTORY_FILE") | ||
| else | ||
| HISTORY='{"lastUpdated":null,"totalRuns":0,"entries":[],"summary":{},"pullRequests":[]}' | ||
| fi | ||
|
|
||
| # Get run ID from first entry to check for duplicates | ||
| RUN_ID="${{ steps.results.outputs.run_id }}" | ||
|
|
||
| # Remove any existing entries from this run (by matching run-XXXX- prefix in id) | ||
| HISTORY=$(echo "$HISTORY" | jq --arg runId "run-${RUN_ID}-" ' | ||
| .entries = [.entries[] | select(.id | startswith($runId) | not)] | ||
| ') | ||
|
|
||
| # Add new entries at the beginning | ||
| HISTORY=$(echo "$HISTORY" | jq --argjson newEntries "$NEW_ENTRIES" ' | ||
| .entries = $newEntries + .entries | ||
| ') | ||
|
|
||
| # Update metadata | ||
| TOTAL_RUNS=$(echo "$HISTORY" | jq '.entries | length') | ||
| LAST_UPDATED=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | ||
|
|
||
| # Calculate summary stats | ||
| PASSED=$(echo "$HISTORY" | jq '[.entries[].testResults.passed] | add // 0') | ||
| FAILED=$(echo "$HISTORY" | jq '[.entries[].testResults.failed] | add // 0') | ||
| TOTAL=$((PASSED + FAILED)) | ||
| if [ "$TOTAL" -gt 0 ]; then | ||
| PASS_RATE=$((PASSED * 100 / TOTAL)) | ||
| else | ||
| PASS_RATE=0 | ||
| fi | ||
|
|
||
| HISTORY=$(echo "$HISTORY" | jq --arg updated "$LAST_UPDATED" --argjson total "$TOTAL_RUNS" --argjson passRate "$PASS_RATE" ' | ||
| .lastUpdated = $updated | | ||
| .totalRuns = $total | | ||
| .summary.passRate = $passRate | ||
| ') | ||
|
|
||
| # Keep only last 200 entries to prevent file from growing too large | ||
| HISTORY=$(echo "$HISTORY" | jq '.entries = .entries[:200]') | ||
|
|
||
| # Write updated history | ||
| echo "$HISTORY" | jq '.' > "$HISTORY_FILE" | ||
|
|
||
| echo "✅ History file updated" | ||
| echo "Total entries: $TOTAL_RUNS" | ||
| echo "Pass rate: $PASS_RATE%" | ||
|
|
||
| # Check if there are changes | ||
| git diff --quiet "$HISTORY_FILE" && echo "has_changes=false" >> $GITHUB_OUTPUT || echo "has_changes=true" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Commit and Push Metrics | ||
| if: steps.update.outputs.has_changes == 'true' | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| git add docs/history.json | ||
| git commit -m "📊 Update E2E metrics for run #${{ steps.results.outputs.run_id }} [skip ci]" | ||
| git push origin main | ||
|
|
||
| echo "✅ Metrics committed and pushed to Agent365-metrics" | ||
|
|
||
| - name: Generate Summary | ||
| run: | | ||
| echo "## 📊 E2E Test Metrics Collected" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "**Run ID:** ${{ steps.results.outputs.run_id }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "**Branch:** ${{ steps.results.outputs.branch }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "**Stage:** ${{ steps.results.outputs.stage }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "**Result:** ${{ steps.results.outputs.conclusion }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY | ||
| echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY | ||
| echo "| ✅ Passed | ${{ steps.results.outputs.passed }} |" >> $GITHUB_STEP_SUMMARY | ||
| echo "| ❌ Failed | ${{ steps.results.outputs.failed }} |" >> $GITHUB_STEP_SUMMARY | ||
| echo "| 📝 Entries | ${{ steps.results.outputs.entry_count }} |" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "View the [E2E Testing Dashboard](https://agent365-metrics-dashboard.azurewebsites.net/api/e2e-dashboard) for detailed statistics." >> $GITHUB_STEP_SUMMARY | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "lastUpdated": null, | ||
abdulanu0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "totalRuns": 0, | ||
| "entries": [], | ||
| "summary": {}, | ||
| "pullRequests": [] | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.