name: CI-nightly on: schedule: - cron: '0 22 * * *' workflow_dispatch: env: CYPRESS_VERIFY_TIMEOUT: 180000 # https://docs.cypress.io/guides/guides/command-line#cypress-verify CVAT_VERSION: "local" jobs: check_updates: runs-on: ubuntu-latest env: REPO: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} outputs: last_commit_time: ${{ steps.check_updates.outputs.last_commit_time }} last_night_time: ${{ steps.check_updates.outputs.last_night_time }} steps: - id: check_updates run: | default_branch=$(gh api /repos/$REPO | jq -r '.default_branch') last_commit_date=$(gh api /repos/${REPO}/branches/${default_branch} | jq -r '.commit.commit.author.date') last_night_date=$(gh api /repos/${REPO}/actions/workflows/schedule.yml/runs | \ jq -r '.workflow_runs[]? | select((.status == "completed")) | .updated_at' \ | sort | tail -1) last_night_time=$(date +%s -d $last_night_date) last_commit_time=$(date +%s -d $last_commit_date) echo Last CI-nightly workflow run time: $last_night_date echo Last commit time in develop branch: $last_commit_date echo "last_commit_time=${last_commit_time}" >> $GITHUB_OUTPUT echo "last_night_time=${last_night_time}" >> $GITHUB_OUTPUT search_cache: needs: check_updates uses: ./.github/workflows/search-cache.yml build: needs: search_cache runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - name: CVAT server. Getting cache from the default branch uses: actions/cache@v6 with: path: /tmp/cvat_cache_server key: ${{ runner.os }}-build-server-${{ needs.search_cache.outputs.sha }} - name: CVAT UI. Getting cache from the default branch uses: actions/cache@v6 with: path: /tmp/cvat_cache_ui key: ${{ runner.os }}-build-ui-${{ needs.search_cache.outputs.sha }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - name: Create artifact directories run: | mkdir /tmp/cvat_server mkdir /tmp/cvat_ui mkdir /tmp/cvat_sdk - name: CVAT server. Build and push uses: docker/build-push-action@v7 with: cache-from: type=local,src=/tmp/cvat_cache_server context: . file: Dockerfile tags: cvat/server:${{ env.CVAT_VERSION }} outputs: type=docker,dest=/tmp/cvat_server/image.tar - name: CVAT UI. Build and push uses: docker/build-push-action@v7 with: cache-from: type=local,src=/tmp/cvat_cache_ui context: . file: Dockerfile.ui tags: cvat/ui:${{ env.CVAT_VERSION }} outputs: type=docker,dest=/tmp/cvat_ui/image.tar - name: Upload CVAT server artifact uses: actions/upload-artifact@v7 with: name: cvat_server path: /tmp/cvat_server/image.tar - name: Upload CVAT UI artifact uses: actions/upload-artifact@v7 with: name: cvat_ui path: /tmp/cvat_ui/image.tar unit_testing: needs: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - uses: actions/setup-python@v6 with: python-version: '3.10' - name: Download CVAT server image uses: actions/download-artifact@v8 with: name: cvat_server path: /tmp/cvat_server/ - name: Download CVAT UI images uses: actions/download-artifact@v8 with: name: cvat_ui path: /tmp/cvat_ui/ - name: Load Docker images run: | docker load --input /tmp/cvat_server/image.tar docker load --input /tmp/cvat_ui/image.tar docker image ls -a - name: OPA tests run: | python cvat/apps/iam/rules/tests/generate_tests.py docker compose run --rm -v "$PWD:/mnt/src:ro" -w /mnt/src \ cvat_opa test cvat/apps/*/rules - name: Generate SDK run: | pip3 install -r cvat-sdk/gen/requirements.txt ./cvat-sdk/gen/generate.sh - name: Install test requirements run: | pip3 install -e ./cvat-sdk -e ./cvat-cli -r ./tests/python/requirements.txt - name: REST API and SDK tests run: | echo 'Run 1: without cache' pytest tests/python/ --alluredir=tests/python/allure-results pytest tests/python/ --stop-services echo 'Run 2: with cache' CVAT_ALLOW_STATIC_CACHE="true" pytest tests/python pytest tests/python/ --stop-services - name: Upload allure results for REST API tests if: always() uses: actions/upload-artifact@v7 with: name: allure-results-rest-api path: tests/python/allure-results - name: Unit tests env: HOST_COVERAGE_DATA_DIR: ${{ github.workspace }} CONTAINER_COVERAGE_DATA_DIR: "/coverage_data" run: | docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d cvat_opa cvat_server cvat_db max_tries=12 while [[ $(curl -s -o /dev/null -w "%{http_code}" localhost:8181/health?bundles) != "200" && max_tries -gt 0 ]]; do (( max_tries-- )); sleep 5; done docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml \ run --env PYTHONDEVMODE=1 cvat_ci /bin/bash \ -c 'python manage.py test cvat/apps -v 2' docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml down -v e2e_testing: needs: build runs-on: ubuntu-latest strategy: fail-fast: false matrix: specs: ['actions_tasks', 'actions_tasks2', 'actions_tasks3', 'actions_tasks4', 'actions_objects', 'actions_objects2', 'actions_users', 'actions_projects_models', 'canvas3d_functionality', 'issues_prs', 'issues_prs2', 'features'] steps: - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: node-version: '22.x' - name: Download CVAT server image uses: actions/download-artifact@v8 with: name: cvat_server path: /tmp/cvat_server/ - name: Download CVAT UI image uses: actions/download-artifact@v8 with: name: cvat_ui path: /tmp/cvat_ui/ - name: Load Docker images run: | docker load --input /tmp/cvat_server/image.tar docker load --input /tmp/cvat_ui/image.tar docker image ls -a - name: Run CVAT instance run: | docker compose \ -f docker-compose.yml \ -f docker-compose.dev.yml \ -f tests/docker-compose.file_share.yml \ -f tests/docker-compose.minio.yml \ -f components/serverless/docker-compose.serverless.yml up -d - name: Waiting for server id: wait-server env: API_ABOUT_PAGE: "localhost:8080/api/server/about" run: | max_tries=60 status_code=$(curl -s -o /tmp/server_response -w "%{http_code}" ${API_ABOUT_PAGE}) while [[ $status_code != "200" && max_tries -gt 0 ]] do echo Number of attempts left: $max_tries echo Status code of response: $status_code sleep 5 status_code=$(curl -s -o /tmp/server_response -w "%{http_code}" ${API_ABOUT_PAGE}) (( max_tries-- )) done if [[ $status_code != "200" ]]; then echo Response from server is incorrect, output: cat /tmp/server_response fi echo "status_code=${status_code}" >> $GITHUB_OUTPUT - name: Fail on bad response from server if: steps.wait-server.outputs.status_code != '200' uses: actions/github-script@v9 with: script: | core.setFailed('Workflow failed: incorrect response from server. See logs artifact to get more info') - name: Add user for tests env: DJANGO_SU_NAME: "admin" DJANGO_SU_EMAIL: "admin@localhost.company" DJANGO_SU_PASSWORD: "12qwaszx" run: | docker exec -i cvat_server /bin/bash -c "echo \"from django.contrib.auth.models import User; User.objects.create_superuser('${DJANGO_SU_NAME}', '${DJANGO_SU_EMAIL}', '${DJANGO_SU_PASSWORD}')\" | python3 ~/manage.py shell" - name: Run tests run: | cd ./tests corepack enable yarn yarn --immutable shopt -s extglob if [[ ${{ matrix.specs }} == canvas3d_* ]]; then npx cypress run \ --headed \ --browser chrome \ --config-file cypress_canvas3d.config.js \ --spec 'cypress/e2e/setup/setup_canvas3d.js,cypress/e2e/canvas3d_*/**/*.js,cypress/e2e/remove_users_tasks_projects_organizations.js' else npx cypress run \ --browser chrome \ --spec 'cypress/e2e/setup/setup.js,cypress/e2e/setup/setup_project.js,cypress/e2e/${{ matrix.specs }}/**/*.js,cypress/e2e/remove_users_tasks_projects_organizations.js' fi - name: Creating a log file from "cvat" container logs if: failure() run: | docker logs cvat_server > ${{ github.workspace }}/tests/cvat.log - name: Uploading cypress screenshots as an artifact if: failure() uses: actions/upload-artifact@v7 with: name: cypress_screenshots_${{ matrix.specs }} path: ${{ github.workspace }}/tests/cypress/screenshots - name: Uploading cypress videos as an artifact if: failure() uses: actions/upload-artifact@v7 with: name: cypress_videos_${{ matrix.specs }} path: ${{ github.workspace }}/tests/cypress/videos - name: Uploading "cvat" container logs as an artifact if: failure() uses: actions/upload-artifact@v7 with: name: cvat_container_logs_${{ matrix.specs }} path: ${{ github.workspace }}/tests/cvat.log - name: Upload Allure results as an artifact if: always() uses: actions/upload-artifact@v7 with: name: allure-results-e2e-${{ matrix.specs }} path: tests/allure-results-e2e generate_report: name: Generate Allure Report and Upload to S3 needs: [unit_testing, e2e_testing] if: always() uses: ./.github/workflows/generate-allure-report.yml secrets: AWS_ALLURE_REPORTS_ROLE: ${{ secrets.AWS_ALLURE_REPORTS_ROLE }}