Skip to content

Disabled Integration Tests for CI pipeline for now #70

Disabled Integration Tests for CI pipeline for now

Disabled Integration Tests for CI pipeline for now #70

Workflow file for this run

name: CI/CD Pipeline

Check failure on line 1 in .github/workflows/ci-cd.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/ci-cd.yml

Invalid workflow file

(Line: 234, Col: 38): Job 'get_version' depends on unknown job 'integration_tests'., (Line: 305, Col: 13): Job 'build-windows-exe-native' depends on job 'get_version' which creates a cycle in the dependency graph., (Line: 345, Col: 13): Job 'build-android-apk' depends on job 'get_version' which creates a cycle in the dependency graph., (Line: 387, Col: 13): Job 'create_release' depends on job 'get_version' which creates a cycle in the dependency graph., (Line: 387, Col: 26): Job 'create_release' depends on job 'build-windows-exe-native' which creates a cycle in the dependency graph., (Line: 387, Col: 52): Job 'create_release' depends on job 'build-android-apk' which creates a cycle in the dependency graph., (Line: 421, Col: 13): Job 'build-and-push-docker' depends on job 'get_version' which creates a cycle in the dependency graph.
on:
push:
branches:
- main
workflow_dispatch:
env:
APP_PATH: './app'
AS_PATH: './server' # Concord Application Service (Go)
FLUTTER_VERSION: 'stable'
DOCKER_IMAGE: 'concord-as' # Go Application Service image name on Docker Hub
jobs:
# ==================== QA STAGE ====================
flutter_tests:
name: Flutter Unit Tests & Analysis
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install dependencies
working-directory: ${{ env.APP_PATH }}
run: flutter pub get
- name: Analyze code
working-directory: ${{ env.APP_PATH }}
run: flutter analyze | tee ../analyze-output.txt
continue-on-error: true
- name: Run unit and widget tests
working-directory: ${{ env.APP_PATH }}
# Explicitly list test directories to exclude test/integration/ which
# requires a live Docker stack and is run in the integration_tests job.
run: flutter test test/features test/core test/shared --coverage --reporter expanded
- name: Install lcov
if: always()
run: |
sudo apt-get update
sudo apt-get install -y lcov
- name: Generate coverage summary
if: always()
working-directory: ${{ env.APP_PATH }}
run: lcov --summary coverage/lcov.info 2>&1 | tee ../coverage-summary.txt
continue-on-error: true
- name: Upload analysis reports
uses: actions/upload-artifact@v4
if: always()
with:
name: analysis-reports
path: |
analyze-output.txt
coverage-summary.txt
retention-days: 30
continue-on-error: true
- name: Upload coverage report
uses: actions/upload-artifact@v4
if: always()
with:
name: flutter-coverage-report
path: ${{ env.APP_PATH }}/coverage/lcov.info
retention-days: 30
continue-on-error: true
go_tests:
name: Go Application Service Tests
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
cache-dependency-path: ${{ env.AS_PATH }}/go.sum
- name: Run Go tests
working-directory: ${{ env.AS_PATH }}
run: |
go test -v -coverprofile=coverage.out ./...
go tool cover -func=coverage.out | grep total: | awk '{print $3}' > coverage-summary.txt
- name: Upload coverage report
uses: actions/upload-artifact@v4
if: always()
with:
name: go-coverage-report
path: |
${{ env.AS_PATH }}/coverage.out
${{ env.AS_PATH }}/coverage-summary.txt
retention-days: 30
continue-on-error: true
# integration_tests:
# name: Integration Tests
# needs: [flutter_tests, go_tests]
# runs-on: ubuntu-latest
# steps:
# - name: Checkout code
# uses: actions/checkout@v4
# with:
# fetch-depth: 0
# - name: Setup Flutter
# uses: subosito/flutter-action@v2
# with:
# channel: ${{ env.FLUTTER_VERSION }}
# cache: true
# - name: Install Linux dependencies
# run: |
# sudo apt-get update -y
# sudo apt-get install -y \
# clang cmake ninja-build pkg-config \
# libgtk-3-dev liblzma-dev libstdc++-12-dev \
# xvfb x11-utils \
# libegl1-mesa-dev libgles2-mesa-dev libgl1-mesa-dri libgl1 mesa-utils \
# pulseaudio dbus-x11 \
# libolm3 libolm-dev
# - name: Install Flutter dependencies
# working-directory: ${{ env.APP_PATH }}
# run: flutter pub get
# - name: Copy .env for integration stack
# run: cp .env.example .env
# - name: Build Application Service Docker image
# run: docker build -t ${{ env.DOCKER_IMAGE }}:latest -f ${{ env.AS_PATH }}/Dockerfile ${{ env.AS_PATH }}
# - name: Start full stack
# env:
# DOCKER_IMAGE: ${{ env.DOCKER_IMAGE }}
# DOCKER_TAG: latest
# run: |
# docker compose --env-file .env up -d
# echo "Waiting for initial startup..."
# sleep 10
# - name: Wait for all services to be healthy
# run: |
# wait_for() {
# local name=$1 cmd=$2
# for i in $(seq 1 40); do
# if eval "$cmd" > /dev/null 2>&1; then echo "$name is ready!"; return 0; fi
# [ $i -eq 40 ] && { echo "ERROR: $name failed to become ready"; return 1; }
# echo "Waiting for $name... ($i/40)"; sleep 3
# done
# }
# wait_for "PostgreSQL" "docker exec concord-db pg_isready -U concord_user"
# wait_for "Redis" "docker exec concord-redis redis-cli ping"
# wait_for "MinIO" "curl -sf http://localhost:9000/minio/health/live"
# wait_for "LiveKit" "nc -z localhost 7880"
# wait_for "Synapse" "curl -sf http://localhost:8008/health"
# wait_for "Concord AS" "curl -sf http://localhost:3000/health"
# echo "All services are ready!"
# - name: Setup virtual display and audio
# run: |
# pulseaudio --start --exit-idle-time=-1 || true
# sudo Xvfb -ac :99 -screen 0 1920x1080x24 > /dev/null 2>&1 &
# sleep 3
# echo "DISPLAY=:99" >> $GITHUB_ENV
# xdpyinfo -display :99 > /dev/null 2>&1 && echo "Display :99 ready" || echo "WARNING: display not ready"
# - name: Run integration tests
# working-directory: ${{ env.APP_PATH }}
# timeout-minutes: 30
# env:
# DISPLAY: ':99'
# LIBGL_ALWAYS_SOFTWARE: '1'
# MESA_GL_VERSION_OVERRIDE: '4.5'
# MESA_GLSL_VERSION_OVERRIDE: '450'
# run: |
# set -o pipefail
# flutter test integration_test/all_tests.dart --device-id linux --reporter expanded 2>&1 | tee test_output.txt
# - name: Collect service logs on failure
# if: failure()
# run: |
# docker logs concord-synapse > synapse.log 2>&1 || true
# docker logs concord-as > as.log 2>&1 || true
# docker logs concord-db > db.log 2>&1 || true
# - name: Upload logs
# uses: actions/upload-artifact@v4
# if: always()
# with:
# name: integration-test-logs
# path: |
# app/test_output.txt
# synapse.log
# as.log
# db.log
# retention-days: 7
# continue-on-error: true
# - name: Cleanup
# if: always()
# env:
# DOCKER_IMAGE: ${{ env.DOCKER_IMAGE }}
# DOCKER_TAG: latest
# run: docker compose --env-file .env down -v
# ==================== RELEASE STAGE ====================
get_version:
name: Get Version & Coverage
needs: [flutter_tests, go_tests, integration_tests]
runs-on: ubuntu-latest
outputs:
version: ${{ steps.extract.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from git history
id: extract
run: |
if LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null); then
LATEST_VERSION=${LATEST_TAG#v}
MAJOR=$(echo $LATEST_VERSION | cut -d. -f1)
MINOR=$(echo $LATEST_VERSION | cut -d. -f2)
PATCH=$(echo $LATEST_VERSION | cut -d. -f3)
COMMITS_SINCE=$(git rev-list ${LATEST_TAG}..HEAD --count)
NEW_PATCH=$((PATCH + COMMITS_SINCE))
VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}"
else
COMMITS=$(git rev-list HEAD --count)
VERSION="0.0.${COMMITS}"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Resolved version: $VERSION"
- name: Download Flutter coverage report
uses: actions/download-artifact@v4
with:
name: flutter-coverage-report
path: coverage-data/app/coverage
- name: Download Go coverage report
uses: actions/download-artifact@v4
with:
name: go-coverage-report
path: coverage-data/server
- name: Install lcov
run: |
sudo apt-get update
sudo apt-get install -y lcov
- name: Generate Release Notes
run: |
echo "## Test Coverage" > release-notes.md
echo "" >> release-notes.md
if [ -f "coverage-data/app/coverage/lcov.info" ]; then
FLUTTER_COV=$(lcov --summary coverage-data/app/coverage/lcov.info 2>&1 | grep lines | cut -d ':' -f 2 | xargs)
echo "- **Flutter App:** $FLUTTER_COV" >> release-notes.md
else
echo "- **Flutter App:** Coverage not found" >> release-notes.md
fi
if [ -f "coverage-data/server/coverage-summary.txt" ]; then
GO_COV=$(cat coverage-data/server/coverage-summary.txt)
echo "- **Go Application Service:** $GO_COV" >> release-notes.md
else
echo "- **Go Application Service:** Coverage not found" >> release-notes.md
fi
- name: Upload Release Notes
uses: actions/upload-artifact@v4
with:
name: release-notes
path: release-notes.md
retention-days: 1
build-windows-exe-native:
name: Build Windows Executable (Native)
needs: [get_version]
runs-on: windows-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install dependencies
working-directory: ${{ env.APP_PATH }}
run: flutter pub get
- name: Build Windows app
working-directory: ${{ env.APP_PATH }}
run: flutter build windows --release
- name: Package Windows release
shell: pwsh
run: |
Compress-Archive -Path "${{ env.APP_PATH }}\\build\\windows\\x64\\runner\\Release\\*" `
-DestinationPath "concord-windows-v${{ needs.get_version.outputs.version }}.zip"
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
name: windows-release
path: concord-windows-v${{ needs.get_version.outputs.version }}.zip
retention-days: 1
build-android-apk:
name: Build Android APK
needs: [get_version]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install dependencies
working-directory: ${{ env.APP_PATH }}
run: flutter pub get
- name: Build Android APK
working-directory: ${{ env.APP_PATH }}
run: flutter build apk --release
- name: Rename APK
run: |
mv ${{ env.APP_PATH }}/build/app/outputs/flutter-apk/app-release.apk \
concord-android-v${{ needs.get_version.outputs.version }}.apk
- name: Upload Android artifact
uses: actions/upload-artifact@v4
with:
name: android-release
path: concord-android-v${{ needs.get_version.outputs.version }}.apk
retention-days: 1
create_release:
name: Create GitHub Release
needs: [get_version, build-windows-exe-native, build-android-apk]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download Windows artifact
uses: actions/download-artifact@v4
with:
name: windows-release
path: release-files
- name: Download Android artifact
uses: actions/download-artifact@v4
with:
name: android-release
path: release-files
- name: Download Release Notes
uses: actions/download-artifact@v4
with:
name: release-notes
path: .
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.get_version.outputs.version }}
name: Release v${{ needs.get_version.outputs.version }}
files: release-files/*
body_path: release-notes.md
generate_release_notes: true
build-and-push-docker:
name: Build and Push Docker Image (Application Service)
needs: [get_version]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}
tags: |
type=raw,value=${{ needs.get_version.outputs.version }}
type=raw,value=latest
- name: Build and push Application Service image
uses: docker/build-push-action@v5
with:
# Build context is the server/ directory (contains go.mod + Dockerfile)
context: ./server
file: ./server/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
- name: Docker image summary
run: |
echo "### Docker Image Published" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Image:** \`${{ secrets.DOCKER_USERNAME }}/${{ env.DOCKER_IMAGE }}\`" >> $GITHUB_STEP_SUMMARY
echo '${{ steps.meta.outputs.tags }}' | while IFS= read -r tag; do
echo "- \`docker pull $tag\`" >> $GITHUB_STEP_SUMMARY
done