mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 21:37:41 +00:00
Previously it failed because GitHub gives the workflow a read-only GITHUB_TOKEN for forks. Writing a PR comment needs write access. This will skip the comment all together in the PR for forks, but allow the job to finish its processing
377 lines
12 KiB
YAML
377 lines
12 KiB
YAML
name: Main
|
|
on:
|
|
push:
|
|
branches: [main, v1]
|
|
pull_request:
|
|
branches: [main, v1]
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
jobs:
|
|
lint:
|
|
timeout-minutes: 8
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
- name: Setup node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version-file: '.nvmrc'
|
|
cache-dependency-path: 'yarn.lock'
|
|
cache: 'yarn'
|
|
- name: Install root dependencies
|
|
run: yarn install
|
|
- name: Build dependencies
|
|
run: make ci-build
|
|
- name: Install core libs
|
|
run: sudo apt-get install --yes curl bc
|
|
- name: Run lint + type check
|
|
run: make ci-lint
|
|
unit:
|
|
timeout-minutes: 8
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
- name: Setup node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version-file: '.nvmrc'
|
|
cache-dependency-path: 'yarn.lock'
|
|
cache: 'yarn'
|
|
- name: Install root dependencies
|
|
run: yarn install
|
|
- name: Build dependencies
|
|
run: make ci-build
|
|
- name: Run unit tests
|
|
run: make ci-unit
|
|
integration:
|
|
timeout-minutes: 8
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
- name: Setup node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version-file: '.nvmrc'
|
|
cache-dependency-path: 'yarn.lock'
|
|
cache: 'yarn'
|
|
- name: Install root dependencies
|
|
run: yarn install
|
|
- name: Expose GitHub Runtime
|
|
uses: crazy-max/ghaction-github-runtime@v2
|
|
- name: Spin up docker services
|
|
run: |
|
|
docker buildx create --use --driver=docker-container
|
|
docker buildx bake -f ./docker-compose.ci.yml --set *.cache-to="type=gha" --set *.cache-from="type=gha" --load
|
|
- name: Build dependencies
|
|
run: make ci-build
|
|
- name: Run integration tests
|
|
run: make ci-int
|
|
otel-unit-test:
|
|
timeout-minutes: 8
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
- name: Get changed files
|
|
id: changed-files
|
|
uses: tj-actions/changed-files@v46
|
|
with:
|
|
files: |
|
|
packages/otel-collector/**
|
|
- name: Setup Go
|
|
if: steps.changed-files.outputs.any_changed == 'true'
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version-file: packages/otel-collector/go.mod
|
|
cache-dependency-path: packages/otel-collector/go.sum
|
|
- name: Run unit tests
|
|
if: steps.changed-files.outputs.any_changed == 'true'
|
|
working-directory: ./packages/otel-collector
|
|
run: go test ./...
|
|
otel-smoke-test:
|
|
timeout-minutes: 8
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
- name: Get changed OTEL collector files
|
|
id: changed-files
|
|
uses: tj-actions/changed-files@v46
|
|
with:
|
|
files: |
|
|
docker/otel-collector/**
|
|
smoke-tests/otel-ccollector/**
|
|
- name: Install required tooling
|
|
if: steps.changed-files.outputs.any_changed == 'true'
|
|
env:
|
|
DEBIAN_FRONTEND: noninteractive
|
|
run: |
|
|
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
|
|
curl -fsSL 'https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key' | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
|
|
ARCH=$(dpkg --print-architecture)
|
|
echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg arch=${ARCH}] https://packages.clickhouse.com/deb stable main" | sudo tee /etc/apt/sources.list.d/clickhouse.list
|
|
sudo apt-get update
|
|
sudo apt-get install --yes curl bats clickhouse-client
|
|
- name: Run Smoke Tests
|
|
if: steps.changed-files.outputs.any_changed == 'true'
|
|
working-directory: ./smoke-tests/otel-collector
|
|
run: bats .
|
|
e2e-tests:
|
|
name: E2E Tests - Shard ${{ matrix.shard }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 15
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
shard: [1, 2, 3, 4]
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version-file: '.nvmrc'
|
|
cache-dependency-path: 'yarn.lock'
|
|
cache: 'yarn'
|
|
|
|
- name: Install dependencies
|
|
run: yarn install
|
|
|
|
- name: Build dependencies
|
|
run: npx nx run-many -t ci:build
|
|
|
|
- name: Install Playwright browsers
|
|
run: cd packages/app && npx playwright install --with-deps chromium
|
|
|
|
- name: Start E2E Docker Compose
|
|
run: |
|
|
docker compose -p e2e -f packages/app/tests/e2e/docker-compose.yml up -d
|
|
echo "Waiting for MongoDB..."
|
|
for i in $(seq 1 30); do
|
|
if docker compose -p e2e -f packages/app/tests/e2e/docker-compose.yml exec -T db mongosh --port 29998 --quiet --eval "db.adminCommand({ping:1})" >/dev/null 2>&1; then
|
|
echo "MongoDB is ready"
|
|
break
|
|
fi
|
|
if [ "$i" -eq 30 ]; then
|
|
echo "MongoDB failed to become ready after 30 seconds"
|
|
exit 1
|
|
fi
|
|
echo "Waiting for MongoDB... ($i/30)"
|
|
sleep 1
|
|
done
|
|
echo "Waiting for ClickHouse..."
|
|
for i in $(seq 1 60); do
|
|
if curl -sf http://localhost:8123/ping >/dev/null 2>&1; then
|
|
echo "ClickHouse is ready"
|
|
break
|
|
fi
|
|
if [ "$i" -eq 60 ]; then
|
|
echo "ClickHouse failed to become ready after 60 seconds"
|
|
exit 1
|
|
fi
|
|
echo "Waiting for ClickHouse... ($i/60)"
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run Playwright tests (full-stack mode)
|
|
# E2E uses local docker-compose (MongoDB on 29998, ClickHouse on 8123)
|
|
env:
|
|
E2E_FULLSTACK: 'true'
|
|
E2E_UNIQUE_USER: 'true'
|
|
E2E_API_HEALTH_CHECK_MAX_RETRIES: '60'
|
|
MONGO_URI: mongodb://localhost:29998/hyperdx-e2e
|
|
run: |
|
|
cd packages/app
|
|
yarn test:e2e --shard=${{ matrix.shard }}/4
|
|
|
|
- name: Upload Playwright report
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: playwright-report-${{ matrix.shard }}
|
|
path: packages/app/playwright-report/
|
|
retention-days: 30
|
|
|
|
- name: Upload test results
|
|
uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: test-results-${{ matrix.shard }}
|
|
path: packages/app/test-results/
|
|
retention-days: 30
|
|
|
|
- name: Stop E2E containers
|
|
if: always()
|
|
run:
|
|
docker compose -p e2e -f packages/app/tests/e2e/docker-compose.yml
|
|
down -v
|
|
|
|
e2e-report:
|
|
name: End-to-End Tests
|
|
if: always()
|
|
needs: e2e-tests
|
|
runs-on: ubuntu-24.04
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
steps:
|
|
- name: Download all test results
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
pattern: test-results-*
|
|
path: all-test-results
|
|
|
|
- name: Aggregate test results
|
|
id: test-results
|
|
if: github.event_name == 'pull_request'
|
|
uses: actions/github-script@v7
|
|
with:
|
|
result-encoding: string
|
|
script: |
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
let totalPassed = 0;
|
|
let totalFailed = 0;
|
|
let totalFlaky = 0;
|
|
let totalSkipped = 0;
|
|
let totalDuration = 0;
|
|
let foundResults = false;
|
|
|
|
try {
|
|
const resultsDir = 'all-test-results';
|
|
const shards = fs.readdirSync(resultsDir);
|
|
|
|
for (const shard of shards) {
|
|
const resultsPath = path.join(resultsDir, shard, 'results.json');
|
|
if (fs.existsSync(resultsPath)) {
|
|
foundResults = true;
|
|
const results = JSON.parse(fs.readFileSync(resultsPath, 'utf8'));
|
|
const { stats } = results;
|
|
|
|
totalPassed += stats.expected || 0;
|
|
totalFailed += stats.unexpected || 0;
|
|
totalFlaky += stats.flaky || 0;
|
|
totalSkipped += stats.skipped || 0;
|
|
totalDuration += stats.duration || 0;
|
|
}
|
|
}
|
|
|
|
if (foundResults) {
|
|
const duration = Math.round(totalDuration / 1000);
|
|
const summary = totalFailed > 0
|
|
? `❌ **${totalFailed} test${totalFailed > 1 ? 's' : ''} failed**`
|
|
: `✅ **All tests passed**`;
|
|
|
|
return `## E2E Test Results
|
|
|
|
${summary} • ${totalPassed} passed • ${totalSkipped} skipped • ${duration}s
|
|
|
|
| Status | Count |
|
|
|--------|-------|
|
|
| ✅ Passed | ${totalPassed} |
|
|
| ❌ Failed | ${totalFailed} |
|
|
| ⚠️ Flaky | ${totalFlaky} |
|
|
| ⏭️ Skipped | ${totalSkipped} |
|
|
|
|
Tests ran across ${shards.length} shards in parallel.
|
|
|
|
[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
|
|
} else {
|
|
return `## E2E Test Results
|
|
|
|
❌ **Test results file not found**
|
|
|
|
[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
|
|
}
|
|
} catch (error) {
|
|
console.log('Could not parse test results:', error.message);
|
|
return `## E2E Test Results
|
|
|
|
❌ **Error reading test results**: ${error.message}
|
|
|
|
[View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
|
|
}
|
|
|
|
- name: Comment PR with test results
|
|
uses: mshick/add-pr-comment@v2
|
|
# Skip for fork PRs: GITHUB_TOKEN cannot write to the base repo
|
|
if:
|
|
always() && github.event_name == 'pull_request' &&
|
|
github.event.pull_request.head.repo.fork != true
|
|
with:
|
|
message: ${{ steps.test-results.outputs.result }}
|
|
message-id: e2e-test-results
|
|
|
|
- name: Check test results
|
|
id: check-results
|
|
run: |
|
|
total_failed=0
|
|
for dir in all-test-results/*/; do
|
|
if [ -f "${dir}results.json" ]; then
|
|
unexpected=$(jq -r '.stats.unexpected // 0' "${dir}results.json")
|
|
total_failed=$((total_failed + unexpected))
|
|
fi
|
|
done
|
|
if [ "$total_failed" -gt 0 ]; then
|
|
echo "::error::$total_failed E2E test(s) failed"
|
|
exit 1
|
|
fi
|
|
# Fail when any shard failed even if we couldn't read failure count from artifacts
|
|
if [ "${{ needs.e2e-tests.result }}" = "failure" ]; then
|
|
echo "::error::One or more E2E test shards failed"
|
|
exit 1
|
|
fi
|
|
|
|
clickhouse-static-build:
|
|
name: ClickHouse Bundle Build
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 10
|
|
permissions:
|
|
contents: read
|
|
strategy:
|
|
fail-fast: false
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version-file: '.nvmrc'
|
|
cache-dependency-path: 'yarn.lock'
|
|
cache: 'yarn'
|
|
|
|
- name: Install dependencies
|
|
run: yarn install
|
|
|
|
- name: Build App
|
|
run: yarn build:clickhouse
|
|
|
|
- name: Verify output directory exists and has size
|
|
run: |
|
|
if [ ! -d "packages/app/out" ]; then
|
|
echo "::error::Output directory 'packages/app/out' does not exist"
|
|
exit 1
|
|
fi
|
|
echo "✓ Output directory exists"
|
|
# Calculate size in bytes and convert to MB
|
|
size_kb=$(du -sk packages/app/out | cut -f1)
|
|
size_mb=$((size_kb / 1024))
|
|
echo "Output directory size: ${size_mb} MB (${size_kb} KB)"
|
|
if [ "$size_mb" -lt 10 ]; then
|
|
echo "::error::Output directory is only ${size_mb} MB, expected at least 10 MB"
|
|
exit 1
|
|
fi
|
|
echo "✓ Output directory size check passed (${size_mb} MB)"
|