Skip to content

Build

Build #969

Workflow file for this run

name: Build
on:
pull_request:
paths-ignore:
- "**.md"
- "**.mdx"
schedule:
# runs the CI everyday at 10AM
- cron: "0 10 * * *"
workflow_dispatch:
inputs:
dart_version:
description: 'Dart version to test (stable or beta)'
required: false
default: 'stable'
jobs:
lint:
name: Lint (Dart ${{ matrix.dart-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
dart-version: [stable, beta]
defaults:
run:
working-directory: packages/dart_firebase_admin
steps:
- uses: actions/checkout@v3.1.0
- uses: subosito/flutter-action@v2.7.1
with:
channel: ${{ matrix.dart-version }}
- name: Cache pub dependencies
uses: actions/cache@v3
with:
path: ~/.pub-cache
key: pub-${{ matrix.dart-version }}-${{ hashFiles('**/pubspec.lock') }}
restore-keys: |
pub-${{ matrix.dart-version }}-
pub-
- name: Install Melos
run: dart pub global activate melos
working-directory: .
- name: Bootstrap workspace
run: melos bootstrap
working-directory: .
- name: Check format
run: dart format --set-exit-if-changed .
- name: Analyze
run: dart analyze
test:
name: Test (Dart ${{ matrix.dart-version }})
runs-on: ubuntu-latest
permissions:
contents: 'read'
id-token: 'write'
strategy:
fail-fast: false
matrix:
dart-version: [stable, beta]
defaults:
run:
working-directory: packages/dart_firebase_admin
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- uses: actions/setup-node@v4
- uses: subosito/flutter-action@v2.7.1
with:
channel: ${{ matrix.dart-version }}
- name: Authenticate to Google Cloud/Firebase
uses: google-github-actions/auth@v2
with:
workload_identity_provider: '${{ secrets.WORKLOAD_IDENTITY_PROVIDER }}'
service_account: '${{ secrets.SERVICE_ACCOUNT }}'
- name: Cache pub dependencies
uses: actions/cache@v3
with:
path: ~/.pub-cache
key: pub-${{ matrix.dart-version }}-${{ hashFiles('**/pubspec.lock') }}
restore-keys: |
pub-${{ matrix.dart-version }}-
pub-
- name: Cache Firebase CLI
uses: actions/cache@v3
with:
path: ~/.cache/firebase/emulators
key: firebase-emulators
restore-keys: |
firebase-
- name: Add pub cache bin to PATH
run: |
echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
echo "PUB_CACHE=$HOME/.pub-cache" >> $GITHUB_ENV
- name: Install Melos
run: dart pub global activate melos
working-directory: .
- name: Bootstrap workspace
run: melos bootstrap
working-directory: .
- name: Install Firebase CLI
run: npm install -g firebase-tools
- name: Run dart_firebase_admin tests with coverage
run: ${{ github.workspace }}/scripts/coverage.sh
- name: Run google_cloud_firestore tests with coverage
run: ${{ github.workspace }}/scripts/firestore-coverage.sh
- name: Merge coverage reports
run: |
# Save individual package coverage files before merging
cp coverage.lcov coverage_admin.lcov
cp ../google_cloud_firestore/coverage.lcov coverage_firestore.lcov
# Merge coverage reports from all packages (relative to packages/dart_firebase_admin)
# Only merge files that exist
COVERAGE_FILES=""
[ -f coverage.lcov ] && COVERAGE_FILES="$COVERAGE_FILES coverage.lcov"
[ -f ../google_cloud_firestore/coverage.lcov ] && COVERAGE_FILES="$COVERAGE_FILES ../google_cloud_firestore/coverage.lcov"
if [ -n "$COVERAGE_FILES" ]; then
cat $COVERAGE_FILES > merged_coverage.lcov
mv merged_coverage.lcov coverage.lcov
else
echo "No coverage files found!"
exit 1
fi
- name: Check coverage threshold and generate report
if: matrix.dart-version == 'stable'
id: coverage
run: |
# Calculate coverage for each package
calculate_coverage() {
local file=$1
if [ -f "$file" ]; then
local total=$(grep -E "^LF:" "$file" | awk -F: '{sum+=$2} END {print sum}')
local hit=$(grep -E "^LH:" "$file" | awk -F: '{sum+=$2} END {print sum}')
if [ "$total" -gt 0 ]; then
local pct=$(awk "BEGIN {printf \"%.2f\", ($hit/$total)*100}")
echo "$pct|$hit|$total"
else
echo "0.00|0|0"
fi
else
echo "0.00|0|0"
fi
}
# Get individual package coverage from saved copies
ADMIN_COV=$(calculate_coverage "coverage_admin.lcov")
FIRESTORE_COV=$(calculate_coverage "coverage_firestore.lcov")
STORAGE_COV=$(calculate_coverage "coverage_storage.lcov")
ADMIN_PCT=$(echo $ADMIN_COV | cut -d'|' -f1)
ADMIN_HIT=$(echo $ADMIN_COV | cut -d'|' -f2)
ADMIN_TOTAL=$(echo $ADMIN_COV | cut -d'|' -f3)
FIRESTORE_PCT=$(echo $FIRESTORE_COV | cut -d'|' -f1)
FIRESTORE_HIT=$(echo $FIRESTORE_COV | cut -d'|' -f2)
FIRESTORE_TOTAL=$(echo $FIRESTORE_COV | cut -d'|' -f3)
STORAGE_PCT=$(echo $STORAGE_COV | cut -d'|' -f1)
STORAGE_HIT=$(echo $STORAGE_COV | cut -d'|' -f2)
STORAGE_TOTAL=$(echo $STORAGE_COV | cut -d'|' -f3)
# Calculate total coverage from merged file
TOTAL_LINES=$(grep -E "^(DA|LF):" coverage.lcov | grep "^LF:" | awk -F: '{sum+=$2} END {print sum}')
HIT_LINES=$(grep -E "^(DA|LH):" coverage.lcov | grep "^LH:" | awk -F: '{sum+=$2} END {print sum}')
if [ "$TOTAL_LINES" -gt 0 ]; then
COVERAGE_PCT=$(awk "BEGIN {printf \"%.2f\", ($HIT_LINES/$TOTAL_LINES)*100}")
else
COVERAGE_PCT="0.00"
fi
# Output for GitHub Actions
echo "coverage=${COVERAGE_PCT}" >> $GITHUB_OUTPUT
echo "total_lines=${TOTAL_LINES}" >> $GITHUB_OUTPUT
echo "hit_lines=${HIT_LINES}" >> $GITHUB_OUTPUT
echo "admin_coverage=${ADMIN_PCT}" >> $GITHUB_OUTPUT
echo "firestore_coverage=${FIRESTORE_PCT}" >> $GITHUB_OUTPUT
echo "storage_coverage=${STORAGE_PCT}" >> $GITHUB_OUTPUT
# Console output
echo "=== Coverage Report ==="
echo "dart_firebase_admin: ${ADMIN_PCT}% (${ADMIN_HIT}/${ADMIN_TOTAL} lines)"
echo "google_cloud_firestore: ${FIRESTORE_PCT}% (${FIRESTORE_HIT}/${FIRESTORE_TOTAL} lines)"
echo "----------------------"
echo "Total: ${COVERAGE_PCT}% (${HIT_LINES}/${TOTAL_LINES} lines)"
# Check threshold
if (( $(echo "$COVERAGE_PCT < 40" | bc -l) )); then
echo "status=❌ Coverage ${COVERAGE_PCT}% is below 40% threshold" >> $GITHUB_OUTPUT
exit 1
else
echo "status=✅ Coverage ${COVERAGE_PCT}% meets 40% threshold" >> $GITHUB_OUTPUT
fi
- name: Comment coverage on PR
if: matrix.dart-version == 'stable' && github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const coverage = '${{ steps.coverage.outputs.coverage }}';
const status = '${{ steps.coverage.outputs.status }}';
const hitLines = '${{ steps.coverage.outputs.hit_lines }}';
const totalLines = '${{ steps.coverage.outputs.total_lines }}';
const adminCov = '${{ steps.coverage.outputs.admin_coverage }}';
const firestoreCov = '${{ steps.coverage.outputs.firestore_coverage }}';
const storageCov = '${{ steps.coverage.outputs.storage_coverage }}';
const body = `## Coverage Report
${status}
**Total Coverage:** ${coverage}%
**Lines Covered:** ${hitLines}/${totalLines}
### Package Breakdown
| Package | Coverage |
|---------|----------|
| dart_firebase_admin | ${adminCov}% |
| google_cloud_firestore | ${firestoreCov}% |
_Minimum threshold: 40%_`;
// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('Coverage Report')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body
});
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}
- name: Upload coverage to codecov
if: matrix.dart-version == 'stable'
continue-on-error: true
uses: codecov/codecov-action@v3
with:
files: packages/dart_firebase_admin/coverage.lcov
flags: unittests
fail_ci_if_error: false
build:
name: Build verification (Dart ${{ matrix.dart-version }})
runs-on: ubuntu-latest
needs: [lint, test]
strategy:
fail-fast: false
matrix:
dart-version: [stable, beta]
defaults:
run:
working-directory: packages/dart_firebase_admin
steps:
- uses: actions/checkout@v3.1.0
- uses: subosito/flutter-action@v2.7.1
with:
channel: ${{ matrix.dart-version }}
- name: Cache pub dependencies
uses: actions/cache@v3
with:
path: ~/.pub-cache
key: pub-${{ matrix.dart-version }}-${{ hashFiles('**/pubspec.lock') }}
restore-keys: |
pub-${{ matrix.dart-version }}-
pub-
- name: Install Melos
run: dart pub global activate melos
working-directory: .
- name: Bootstrap workspace
run: melos bootstrap
working-directory: .
- name: Verify package
run: dart pub publish --dry-run