private-repo-rust-ci #4539
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
| name: Rust-CI | |
| on: | |
| pull_request: | |
| branches: [main] | |
| repository_dispatch: | |
| types: [private-repo-rust-ci] | |
| workflow_dispatch: | |
| inputs: | |
| pr_number: | |
| description: "PR number from private repo" | |
| required: false | |
| type: string | |
| pr_ref: | |
| description: "Git ref to checkout from private repo" | |
| required: false | |
| type: string | |
| default: "main" | |
| env: | |
| CARGO_TERM_COLOR: always | |
| CLOUD_VERSION: latest-amd64 | |
| RUST_TOOLCHAIN: "1.92.0" | |
| CARGO_PROFILE_TEST_DEBUG: "0" | |
| # Speed up crate downloads with sparse registry | |
| CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse | |
| # Faster for git dependencies | |
| CARGO_NET_GIT_FETCH_WITH_CLI: true | |
| # Disable incremental compilation in CI (faster clean builds) | |
| CARGO_INCREMENTAL: "0" | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.client_payload.pr_number || github.event.inputs.pr_number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout private repository | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: AppFlowy-IO/AppFlowy-Premium | |
| token: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| ref: ${{ github.event.client_payload.pr_ref || github.event.inputs.pr_ref || 'main' }} | |
| - name: Install Rust toolchain | |
| uses: actions-rs/toolchain@v1 | |
| with: | |
| toolchain: ${{ env.RUST_TOOLCHAIN }} | |
| override: true | |
| components: rustfmt, clippy | |
| profile: minimal | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| prefix-key: ${{ runner.os }} | |
| shared-key: "rust-ci" | |
| cache-on-failure: true | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| workspaces: | | |
| frontend/rust-lib | |
| - name: Configure Git credentials for Cargo | |
| run: | | |
| git config --global credential.helper store | |
| echo "https://${{ secrets.ADMIN_GITHUB_TOKEN }}:x-oauth-basic@github.com" > ~/.git-credentials | |
| - name: Build (generate code from build.rs) | |
| working-directory: frontend/rust-lib | |
| env: | |
| GH_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| run: cargo check --workspace --no-default-features --features="dart" | |
| - name: rustfmt rust-lib | |
| run: cargo fmt --all -- --check | |
| env: | |
| GH_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| working-directory: frontend/rust-lib/ | |
| - name: clippy rust-lib | |
| run: cargo clippy --all-targets -- -D warnings | |
| env: | |
| GH_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| working-directory: frontend/rust-lib | |
| test: | |
| name: Tests (${{ matrix.test_group }}) | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Integration test group 1 | |
| - test_group: "integration_group1" | |
| test_modules: "folder user" | |
| # Integration test group 2 | |
| - test_group: "integration_group2" | |
| test_modules: "database document sql_test chat search" | |
| # All other rust-lib crate tests | |
| - test_group: "other_crates" | |
| test_modules: "" | |
| steps: | |
| - name: Set timezone for action | |
| uses: szenius/set-timezone@v2.0 | |
| with: | |
| timezoneLinux: "US/Pacific" | |
| - name: Maximize build space | |
| run: | | |
| sudo rm -rf /usr/share/dotnet | |
| sudo rm -rf /opt/ghc | |
| sudo rm -rf "/usr/local/share/boost" | |
| sudo rm -rf "$AGENT_TOOLSDIRECTORY" | |
| sudo docker image prune --all --force | |
| - name: Checkout private repository | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: AppFlowy-IO/AppFlowy-Premium | |
| token: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| ref: ${{ github.event.client_payload.pr_ref || github.event.inputs.pr_ref || 'main' }} | |
| - name: Install Rust toolchain | |
| uses: actions-rs/toolchain@v1 | |
| with: | |
| toolchain: ${{ env.RUST_TOOLCHAIN }} | |
| override: true | |
| components: rustfmt, clippy | |
| profile: minimal | |
| - name: Setup sccache | |
| id: sccache | |
| uses: mozilla-actions/sccache-action@v0.0.6 | |
| continue-on-error: true | |
| - name: Configure sccache | |
| id: sccache-config | |
| if: steps.sccache.outcome == 'success' | |
| run: | | |
| # Unset RUSTC_WRAPPER first (sccache-action sets it automatically) | |
| echo "RUSTC_WRAPPER=" >> $GITHUB_ENV | |
| # Stop any existing sccache server | |
| sccache --stop-server 2>/dev/null || true | |
| # Test if sccache can actually connect to GitHub cache | |
| export SCCACHE_GHA_ENABLED=true | |
| export RUSTC_WRAPPER= | |
| if timeout 10 sccache --start-server 2>&1; then | |
| if timeout 5 sccache --show-stats 2>&1; then | |
| echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV | |
| echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV | |
| echo "sccache_enabled=true" >> $GITHUB_OUTPUT | |
| echo "✓ sccache is available and configured" | |
| else | |
| sccache --stop-server 2>/dev/null || true | |
| echo "sccache_enabled=false" >> $GITHUB_OUTPUT | |
| echo "⚠ sccache stats failed, proceeding without it" | |
| fi | |
| else | |
| echo "sccache_enabled=false" >> $GITHUB_OUTPUT | |
| echo "⚠ sccache server startup failed, proceeding without it" | |
| fi | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| prefix-key: ${{ runner.os }} | |
| shared-key: "rust-ci" | |
| cache-on-failure: true | |
| save-if: ${{ github.ref == 'refs/heads/main' }} | |
| workspaces: | | |
| frontend/rust-lib | |
| - name: Checkout AppFlowy-Cloud-Premium code | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: AppFlowy-IO/AppFlowy-Cloud-Premium | |
| path: AppFlowy-Cloud-Premium | |
| token: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| ref: "main" | |
| - name: Clean and Run Docker-Compose | |
| working-directory: AppFlowy-Cloud-Premium | |
| run: | | |
| echo "Stopping existing compose services..." | |
| docker compose -f docker-compose-ci.yml down -v --remove-orphans || true | |
| echo "Removing project-specific resources..." | |
| docker compose -f docker-compose-ci.yml rm -f -s -v || true | |
| echo "Cleaning up unused Docker resources..." | |
| docker container prune -f || true | |
| docker image prune -f || true | |
| docker network prune -f || true | |
| docker volume prune -f || true | |
| echo "Docker cleanup completed successfully" | |
| - name: Run Server | |
| working-directory: AppFlowy-Cloud-Premium | |
| run: | | |
| cp deploy.env .env | |
| sed -i 's|RUST_LOG=.*|RUST_LOG=appflowy_cloud=debug,appflowy_collaborate=debug,appflowy_worker=debug|' .env | |
| sed -i 's|GOTRUE_MAILER_AUTOCONFIRM=.*|GOTRUE_MAILER_AUTOCONFIRM=true|' .env | |
| sed -i 's|API_EXTERNAL_URL=.*|API_EXTERNAL_URL=http://localhost|' .env | |
| sed -i 's|APPFLOWY_SPAM_DETECT_ENABLED=.*|APPFLOWY_SPAM_DETECT_ENABLED=false|' .env | |
| sed -i 's|AI_OPENAI_API_KEY=.*|AI_OPENAI_API_KEY=${{ secrets.CI_OPENAI_API_KEY }}|' .env | |
| sed -i 's|APPFLOWY_DATABASE_BLOB_APPEND_FLUSH_INTERVAL_MS=.*|APPFLOWY_DATABASE_BLOB_APPEND_FLUSH_INTERVAL_MS=500|' .env | |
| sed -i 's|^# APPFLOWY_S3_PRESIGNED_URL_ENDPOINT=.*|APPFLOWY_S3_PRESIGNED_URL_ENDPOINT=${APPFLOWY_BASE_URL}/minio-api|' .env | |
| echo '' >> .env | |
| echo 'APPFLOWY_PAGE_HISTORY_ENABLE=true' >> .env | |
| cat .env | |
| export APP_ENVIRONMENT=local | |
| export APPFLOWY_CLOUD_VERSION=${{ env.CLOUD_VERSION }} | |
| export APPFLOWY_WORKER_VERSION=${{ env.CLOUD_VERSION }} | |
| export APPFLOWY_ADMIN_FRONTEND_VERSION=${{ env.CLOUD_VERSION }} | |
| export APPFLOWY_AI_VERSION=${{ env.CLOUD_VERSION }} | |
| docker login -u appflowyinc -p ${{ secrets.DOCKER_TOKEN }} | |
| docker compose -f docker-compose-ci.yml pull | |
| docker compose -f docker-compose-ci.yml up -d | |
| docker ps -a | |
| docker compose -f docker-compose-ci.yml logs appflowy_cloud | |
| echo "Cleaning up unused Docker images..." | |
| docker image prune -f | |
| - name: Wait for appflowy cloud to be ready | |
| working-directory: AppFlowy-Cloud-Premium | |
| run: | | |
| echo "Waiting for services to be ready..." | |
| for i in {1..60}; do | |
| if curl -f http://localhost/api/health 2>/dev/null; then | |
| echo "Health check passed after $((i*5)) seconds" | |
| exit 0 | |
| fi | |
| echo "Attempt $i: Health check failed, waiting 5 seconds..." | |
| sleep 5 | |
| done | |
| echo "Health check timeout after 300 seconds - proceeding anyway" | |
| - name: AppFlowy-Cloud Logs | |
| working-directory: AppFlowy-Cloud-Premium | |
| run: | | |
| docker compose -f docker-compose-ci.yml logs appflowy_cloud | |
| - name: AppFlowy-AI Logs | |
| working-directory: AppFlowy-Cloud-Premium | |
| run: | | |
| docker compose -f docker-compose-ci.yml logs ai | |
| - name: Configure Git credentials for Cargo | |
| run: | | |
| git config --global credential.helper store | |
| echo "https://${{ secrets.ADMIN_GITHUB_TOKEN }}:x-oauth-basic@github.com" > ~/.git-credentials | |
| - name: Fetch dependencies | |
| working-directory: frontend/rust-lib | |
| env: | |
| GH_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| run: cargo fetch | |
| - name: Build (generate code from build.rs) | |
| working-directory: frontend/rust-lib | |
| env: | |
| GH_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| run: cargo check --workspace --no-default-features --features="dart" | |
| - name: Run Tests | |
| working-directory: frontend/rust-lib | |
| env: | |
| RUST_LOG: info | |
| RUST_BACKTRACE: 1 | |
| af_cloud_test_base_url: http://localhost | |
| af_cloud_test_ws_url: ws://localhost/ws/v2 | |
| af_cloud_test_gotrue_url: http://localhost/gotrue | |
| GH_TOKEN: ${{ secrets.ADMIN_GITHUB_TOKEN }} | |
| run: | | |
| set -e | |
| echo "Running tests for ${{ matrix.test_group }}" | |
| if [ "${{ matrix.test_group }}" = "other_crates" ]; then | |
| # Run all workspace crate tests except the integration test crate | |
| DISABLE_CI_TEST_LOG="true" cargo test \ | |
| --workspace --exclude event-integration-test \ | |
| --no-default-features --features="dart" \ | |
| -- --skip local_ai_test --test-threads=2 | |
| else | |
| # Run integration tests module by module | |
| for module in ${{ matrix.test_modules }}; do | |
| echo "==> Testing module: ${module}" | |
| DISABLE_CI_TEST_LOG="true" cargo test \ | |
| -p event-integration-test \ | |
| --no-default-features --features="dart" "${module}" \ | |
| -- --skip local_ai_test --test-threads=2 | |
| done | |
| fi | |
| - name: Show sccache stats | |
| if: always() && steps.sccache-config.outputs.sccache_enabled == 'true' | |
| run: sccache --show-stats || true | |
| - name: "Appflowy-Cloud container logs" | |
| if: always() | |
| working-directory: AppFlowy-Cloud-Premium | |
| run: | | |
| docker compose -f docker-compose-ci.yml logs appflowy_cloud > appflowy_cloud.log 2>&1 | |
| - name: "Appflowy-Worker container logs" | |
| if: always() | |
| working-directory: AppFlowy-Cloud-Premium | |
| run: | | |
| docker compose -f docker-compose-ci.yml logs appflowy_worker > appflowy_worker.log 2>&1 | |
| - name: "Minio container logs" | |
| if: always() | |
| working-directory: AppFlowy-Cloud-Premium | |
| run: | | |
| docker compose -f docker-compose-ci.yml logs minio > minio.log 2>&1 | |
| - name: Upload Appflowy-Cloud logs | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: appflowy-cloud-logs-${{ matrix.test_group }} | |
| path: | | |
| AppFlowy-Cloud-Premium/appflowy_cloud.log | |
| AppFlowy-Cloud-Premium/appflowy_worker.log | |
| AppFlowy-Cloud-Premium/minio.log | |
| retention-days: 1 | |
| - name: Clean up Docker images | |
| run: | | |
| docker image prune -af | |
| docker volume prune -f |