API Reference
Reference documentation for the UnfoldCI GitHub Action and REST API.
GitHub Action
Usage
- name: Analyze Flaky Tests with UnfoldCI
uses: UnfoldAI-Labs/UnfoldCI-flaky-autopilot-action@v1
with:
api-key: ${{ secrets.FLAKY_AUTOPILOT_KEY }}
results-path: '**/test-results/**/*.xml'
comment-on-pr: 'true'
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
api-key | No | — | UnfoldCI API key for authentication. Generate from dashboard settings. |
api-url | No | Production URL | UnfoldCI API endpoint. Only change for testing. |
results-path | No | **/test-results/**/*.xml | Glob pattern for locating JUnit XML test result files. |
comment-on-pr | No | true | When true, posts a comment on PRs when flaky tests are detected. |
enable-historical-backfill | No | true | Fetch past CI runs on first execution for instant analysis. |
max-historical-runs | No | 50 | Number of past runs to fetch for backfill. |
Outputs
| Output | Description |
|---|---|
flakes_detected | Number of flaky tests detected in this run. |
tests_analyzed | Total number of tests analyzed from result files. |
dashboard_url | URL to the UnfoldCI dashboard for detailed analysis. |
status | Action status: success, rate_limited, or api_error. |
REST API
Base URL: https://api.unfoldci.com
Authentication
All API requests require authentication via Bearer token:
Authorization: Bearer unfold_ci_your_api_key
Rate Limits
| Limit | Value |
|---|---|
| Tests per month (free) | Varies by plan |
| API calls per minute | 60 |
When rate limited, the API returns:
{
"error": "Rate limit exceeded",
"retry_after": 60
}
Endpoints
Test Results
Submit Test Results
POST /api/webhooks/github
Submit test results from CI.
Request Body:
{
"repo_url": "https://github.com/org/repo",
"commit_sha": "abc123...",
"test_results": [
{
"name": "should handle async operations",
"file": "src/tests/async.test.ts",
"outcome": "passed",
"duration_ms": 150,
"code_hash": "sha256:..."
}
],
"source": "github_action"
}
Response:
{
"success": true,
"tests_received": 42,
"flakes_detected": 2
}
Repositories
List Repositories
GET /api/repos
Returns all repositories for the authenticated user.
Response:
{
"repos": [
{
"id": "uuid",
"name": "my-repo",
"full_name": "org/my-repo",
"url": "https://github.com/org/my-repo",
"test_count": 150,
"flaky_count": 3,
"health_score": 87.5
}
]
}
Get Repository Details
GET /api/repos/:id
Returns detailed repository information.
Response:
{
"id": "uuid",
"name": "my-repo",
"full_name": "org/my-repo",
"test_count": 150,
"flaky_count": 3,
"pass_rate": 94.2,
"recent_runs": 25,
"last_updated": "2024-01-15T10:30:00Z"
}
Tests
List Tests
GET /api/repos/:id/tests
Returns tests for a repository.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status | string | Filter: all, flaky, failing, passing |
sort | string | Sort by: flake_score, pass_rate, last_seen |
limit | number | Results per page (default: 50) |
offset | number | Pagination offset |
Response:
{
"tests": [
{
"id": "uuid",
"name": "should handle async operations",
"file": "src/tests/async.test.ts",
"flake_score": 0.73,
"pass_rate": 68.5,
"run_count": 25,
"last_seen": "2024-01-15T10:30:00Z"
}
],
"total": 150,
"limit": 50,
"offset": 0
}
Get Test Details
GET /api/tests/:id
Returns detailed test information including AI analysis.
Response:
{
"id": "uuid",
"name": "should handle async operations",
"file": "src/tests/async.test.ts",
"flake_score": 0.73,
"pass_rate": 68.5,
"run_count": 25,
"status": "flaky",
"analysis": {
"category": "race_condition",
"hypothesis": "State is modified concurrently...",
"suggested_fix": "Add proper synchronization...",
"confidence": 0.85
},
"history": [
{
"outcome": "passed",
"duration_ms": 150,
"commit_sha": "abc123",
"timestamp": "2024-01-15T10:30:00Z"
}
]
}
Fix Attempts
List Fix Attempts
GET /api/repos/:id/fixes
Returns AI-generated fix attempts for a repository.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status | string | Filter: all, pending, merged, rejected |
limit | number | Results per page (default: 20) |
Response:
{
"fixes": [
{
"id": "uuid",
"test_id": "uuid",
"test_name": "should handle async operations",
"status": "pending",
"confidence": 0.85,
"pr_url": "https://github.com/org/repo/pull/123",
"created_at": "2024-01-15T10:30:00Z"
}
]
}
Analytics
Get CI Savings
GET /api/analytics/ci-savings
Returns CI time and cost savings metrics.
Response:
{
"time_saved_hours": 24.5,
"reruns_avoided": 156,
"estimated_cost_saved": 245.00,
"period": "last_30_days"
}
Get Pattern Analysis
GET /api/analytics/patterns/:repo_id
Returns code pattern analysis for a repository.
Response:
{
"health_score": 78,
"patterns_detected": [
{
"type": "hardcoded_wait",
"severity": "medium",
"count": 5,
"files": ["test/async.test.ts", "test/api.test.ts"]
},
{
"type": "shared_state",
"severity": "high",
"count": 2,
"files": ["test/integration.test.ts"]
}
],
"recommendations": [
"Replace setTimeout with proper async assertions",
"Isolate test state using beforeEach/afterEach hooks"
]
}
Notifications
Get Notification Config
GET /api/notifications/config
Returns notification configuration for the current installation.
Response:
{
"isEnabled": true,
"hasSlack": true,
"hasDiscord": false,
"hasTeams": false,
"slackWebhookUrl": "https://hooks.slack.com/services/...",
"enabledEvents": ["flaky_test_detected", "pr_created", "pr_merged"]
}
Update Notification Config
PUT /api/notifications/config
Updates notification configuration.
Request Body:
{
"isEnabled": true,
"slackWebhookUrl": "https://hooks.slack.com/services/...",
"discordWebhookUrl": "https://discord.com/api/webhooks/...",
"teamsWebhookUrl": "https://outlook.office.com/webhook/...",
"enabledEvents": ["flaky_test_detected", "pr_created"]
}
Response:
{
"success": true,
"config": { ... }
}
Remove Webhook
DELETE /api/notifications/webhook/:platform
Removes a specific platform webhook.
Parameters:
| Parameter | Type | Description |
|---|---|---|
platform | string | slack, discord, or teams |
Response:
{
"success": true,
"message": "Slack webhook removed"
}
Test Notification
POST /api/notifications/test/:platform
Sends a test notification to verify webhook configuration.
Response:
{
"success": true,
"message": "Test notification sent successfully"
}
Supported Test Result Formats
The action parses JUnit XML format, which is the standard output format for most test frameworks.
JUnit XML Structure
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="MyTestSuite" tests="3" failures="1" time="1.234">
<testcase name="test_example" classname="tests.test_module" time="0.5">
</testcase>
<testcase name="test_failure" classname="tests.test_module" time="0.3">
<failure message="AssertionError">Expected true, got false</failure>
</testcase>
</testsuite>
</testsuites>
Parsed Test Result Fields
| Field | Description |
|---|---|
name | Test name from the name attribute |
file | Test file path, extracted from file attribute or classname |
outcome | passed or failed based on presence of <failure> or <error> |
duration_ms | Test duration in milliseconds |
error_message | Failure message if test failed |
code_hash | Hash of test file and dependencies for change detection |
Configuration File
Create .flaky-autopilot.json in your repository root for advanced configuration:
{
"$schema": "https://unfoldci.com/schemas/flaky-autopilot-config.json",
"version": "1.0",
"importResolver": {
"aliases": {
"@": "./src",
"@utils": "./src/utils",
"@tests": "./tests"
},
"pythonPaths": [
".",
"./src",
"./tests"
],
"extensions": [
".js",
".ts",
".jsx",
".tsx",
".py"
],
"moduleDirectories": [
"node_modules"
]
}
}
Import Resolver Options
| Option | Description |
|---|---|
aliases | Path aliases (e.g., @ → ./src). Supports tsconfig/jsconfig paths. |
pythonPaths | Python module search paths. Parsed from pytest.ini if not specified. |
extensions | File extensions to try when resolving imports. |
moduleDirectories | Directories to search for modules (default: node_modules). |
API Key Format
API keys are prefixed with unfold_ci_ followed by a 64-character hexadecimal string:
unfold_ci_abc123def456789...
Key Scope
- Keys are scoped to a GitHub App installation
- A single key works for all repositories in that installation
- Generate keys from the dashboard Settings page
Key Management
| Action | Location |
|---|---|
| Generate | Dashboard → Settings → Generate New API Key |
| View | Dashboard → Settings (shows masked preview) |
| Revoke | Dashboard → Settings → Revoke button |
Error Handling
The action is designed to be non-blocking:
- API errors: Logged as warnings, workflow continues
- Rate limits: Logged as warnings, workflow continues
- Parse errors: Individual files skipped, others processed
- Missing files: Warning logged, action completes successfully
Status Codes
| Status | Description |
|---|---|
success | Results submitted successfully |
rate_limited | Usage limit exceeded, analysis skipped |
api_error | API error occurred, analysis skipped |
Webhook Events
The UnfoldCI GitHub App receives the following webhook events automatically:
| Event | Purpose |
|---|---|
installation | App installed, updated, or uninstalled |
installation_repositories | Repositories added or removed |
workflow_run | CI workflow completed |
push | Code changes detected |
pull_request | PR opened or updated |
No manual webhook configuration is required.