diff --git a/.github/workflows/cache.yml b/.github/workflows/cache.yml index 662e7928..20fc00f9 100644 --- a/.github/workflows/cache.yml +++ b/.github/workflows/cache.yml @@ -52,18 +52,28 @@ jobs: ${{ runner.os }}-build-ui-${{ steps.get-sha.outputs.sha }} ${{ runner.os }}-build-ui- - - name: Check cache hit - if: steps.server-cache-action.outputs.cache-hit != 'false' || - steps.ui-cache-action.outputs.cache-hit != 'false' - uses: actions/github-script@v3 + - uses: actions/cache@v3 + id: elasticsearch-cache-action + with: + path: /tmp/cvat_cache_elasticsearch + key: ${{ runner.os }}-build-elasticsearch-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-build-elasticsearch-${{ steps.get-sha.outputs.sha }} + ${{ runner.os }}-build-elasticsearch- + + - uses: actions/cache@v3 + id: logstash-cache-action with: - script: | - core.setFailed('Caching failed due to a cache hit occurred') + path: /tmp/cvat_cache_logstash + key: ${{ runner.os }}-build-logstash-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-build-logstash-${{ steps.get-sha.outputs.sha }} + ${{ runner.os }}-build-logstash- - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - - name: Caching CVAT server + - name: Caching CVAT Server uses: docker/build-push-action@v2 with: context: . @@ -79,9 +89,34 @@ jobs: cache-from: type=local,src=/tmp/cvat_cache_ui cache-to: type=local,dest=/tmp/cvat_cache_ui-new + - name: Caching CVAT Elasticsearch + uses: docker/build-push-action@v2 + with: + context: ./components/analytics/elasticsearch/ + file: ./components/analytics/elasticsearch/Dockerfile + cache-from: type=local,src=/tmp/cvat_cache_elasticsearch + cache-to: type=local,dest=/tmp/cvat_cache_elasticsearch-new + build-args: ELK_VERSION=6.8.23 + + - name: Caching CVAT Logstash + uses: docker/build-push-action@v2 + with: + context: ./components/analytics/logstash/ + file: ./components/analytics/logstash/Dockerfile + cache-from: type=local,src=/tmp/cvat_cache_logstash + cache-to: type=local,dest=/tmp/cvat_cache_logstash-new + build-args: ELK_VERSION=6.8.23 + - name: Moving cache run: | rm -rf /tmp/cvat_cache_server mv /tmp/cvat_cache_server-new /tmp/cvat_cache_server + rm -rf /tmp/cvat_cache_ui mv /tmp/cvat_cache_ui-new /tmp/cvat_cache_ui + + rm -rf /tmp/cvat_cache_elasticsearch + mv /tmp/cvat_cache_elasticsearch-new /tmp/cvat_cache_elasticsearch + + rm -rf /tmp/cvat_cache_logstash + mv /tmp/cvat_cache_logstash-new /tmp/cvat_cache_logstash diff --git a/.github/workflows/comment.yml b/.github/workflows/comment.yml new file mode 100644 index 00000000..91aa7f0c --- /dev/null +++ b/.github/workflows/comment.yml @@ -0,0 +1,92 @@ +# v0.1.2 +name: Comment +on: + issue_comment: + types: [created] + +env: + WORKFLOW_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + +jobs: + verify_author: + if: contains(github.event.issue.html_url, '/pull') && + contains(github.event.comment.body, '/check') + runs-on: ubuntu-latest + outputs: + ref: ${{ steps.get-ref.outputs.ref }} + cid: ${{ steps.send-status.outputs.cid }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Check author of comment + id: check-author + run: | + COLLABORATOR=$(gh api repos/${{ github.repository }}/collaborators | jq ".[] | select((.login == \"${{ github.event.comment.user.login }}\"))") + + echo Author of comment: ${COLLABORATOR} + echo ::set-output name=collaborator::${COLLABORATOR} + + - name: Verify that author of comment is collaborator + if: steps.check-author.outputs.collaborator == '' + uses: actions/github-script@v3 + with: + script: | + core.setFailed('User that send comment with run command is not collaborator') + + - name: Get branch name + id: get-ref + run: | + BRANCH=$(gh api /repos/${{ github.repository }}/pulls/${{ github.event.issue.number }} | jq -r '.head.ref') + echo ::set-output name=ref::${BRANCH} + + - name: Send comment. Test are executing + id: send-status + run: | + BODY=":hourglass: Tests are executing, see more information [here](${{ env.WORKFLOW_RUN_URL }})" + BODY=$BODY"\n :warning: Cancel [this](${{ env.WORKFLOW_RUN_URL }}) workflow manually first, if you want to restart full check" + BODY=$(echo -e $BODY) + + COMMENT_ID=$(gh api --method POST \ + /repos/${{ github.repository }}/issues/${{ github.event.issue.number }}/comments \ + -f body="${BODY}" | jq '.id') + + echo ::set-output name=cid::${COMMENT_ID} + + run-full: + needs: verify_author + uses: ./.github/workflows/full.yml + with: + ref: ${{ needs.verify_author.outputs.ref }} + secrets: + DOCKERHUB_WORKSPACE: ${{ secrets.DOCKERHUB_WORKSPACE }} + DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} + DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} + + send_status: + runs-on: ubuntu-latest + needs: [run-full, verify_author] + if: always() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Send status in comments + run: | + BODY="" + + if [[ "${{ needs.run-full.result }}" == "failure" ]] + then + BODY=":x: Some checks failed" + elif [[ "${{ needs.run-full.result }}" == "success" ]] + then + BODY=":heavy_check_mark: All checks completed successfully" + elif [[ "${{ needs.run-full.result }}" == "cancelled" ]] + then + BODY=":no_entry_sign: Workflows has been canceled" + fi + + BODY=$BODY"\n :page_facing_up: See logs [here](${WORKFLOW_RUN_URL})" + BODY=$(echo -e $BODY) + + gh api --method PATCH \ + /repos/${{ github.repository }}/issues/comments/${{ needs.verify_author.outputs.cid }} \ + -f body="${BODY}" \ No newline at end of file diff --git a/.github/workflows/full.yml b/.github/workflows/full.yml new file mode 100644 index 00000000..5aeb4e5b --- /dev/null +++ b/.github/workflows/full.yml @@ -0,0 +1,335 @@ +name: Full +on: + workflow_call: + inputs: + ref: + type: string + required: true + secrets: + DOCKERHUB_WORKSPACE: + required: true + DOCKERHUB_USERNAME: + required: true + DOCKERHUB_TOKEN: + required: true + +env: + SERVER_IMAGE_TEST_REPO: cvat_server + WORKFLOW_RUN_URL: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} + +jobs: + search_cache: + runs-on: ubuntu-latest + outputs: + sha: ${{ steps.get-sha.outputs.sha}} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + steps: + - name: Getting SHA with cache from the default branch + id: get-sha + run: | + DEFAULT_BRANCH=$(gh api /repos/$REPO | jq -r '.default_branch') + for sha in $(gh api "/repos/$REPO/commits?per_page=100&sha=$DEFAULT_BRANCH" | jq -r '.[].sha'); + do + RUN_status=$(gh api /repos/${REPO}/actions/workflows/cache.yml/runs | \ + jq -r ".workflow_runs[]? | select((.head_sha == \"${sha}\") and (.conclusion == \"success\")) | .status") + if [[ ${RUN_status} == "completed" ]]; then + SHA=$sha + break + fi + done + echo Default branch is ${DEFAULT_BRANCH} + echo Workflow will try to get cache from commit: ${SHA} + echo ::set-output name=default_branch::${DEFAULT_BRANCH} + echo ::set-output name=sha::${SHA} + + build: + needs: search_cache + runs-on: ubuntu-latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: CVAT server. Getting cache from the default branch + uses: actions/cache@v3 + with: + path: /tmp/cvat_cache_server + key: ${{ runner.os }}-build-server-${{ needs.search_cache.outputs.sha }} + + - name: CVAT server. Extract metadata (tags, labels) for Docker + id: meta-server + uses: docker/metadata-action@master + with: + images: ${{ secrets.DOCKERHUB_WORKSPACE }}/${{ env.SERVER_IMAGE_TEST_REPO }} + tags: | + type=raw,value=${{ inputs.ref }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: CVAT server. Build and push + uses: docker/build-push-action@v3 + with: + cache-from: type=local,src=/tmp/cvat_cache_server + context: . + file: Dockerfile + push: true + tags: ${{ steps.meta-server.outputs.tags }} + labels: ${{ steps.meta-server.outputs.labels }} + + unit_testing: + needs: [build, search_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + + - uses: actions/setup-python@v2 + with: + python-version: '3.8' + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@master + + - name: Getting CVAT UI cache from the default branch + uses: actions/cache@v3 + with: + path: /tmp/cvat_cache_ui + key: ${{ runner.os }}-build-ui-${{ needs.search_cache.outputs.sha }} + + - name: Getting CVAT Elasticsearch cache from the default branch + uses: actions/cache@v3 + with: + path: /tmp/cvat_cache_elasticsearch + key: ${{ runner.os }}-build-elasticsearch-${{ needs.search_cache.outputs.sha }} + + - name: Getting CVAT Logstash cache from the default branch + uses: actions/cache@v3 + with: + path: /tmp/cvat_cache_logstash + key: ${{ runner.os }}-build-logstash-${{ needs.search_cache.outputs.sha }} + + - name: Building CVAT UI image + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.ui + cache-from: type=local,src=/tmp/cvat_cache_ui + tags: openvino/cvat_ui:latest + load: true + + - name: Building CVAT Elasticsearch + uses: docker/build-push-action@v2 + with: + context: ./components/analytics/elasticsearch/ + file: ./components/analytics/elasticsearch/Dockerfile + cache-from: type=local,src=/tmp/cvat_cache_elasticsearch + tags: cvat_elasticsearch:latest + load: true + build-args: ELK_VERSION=6.8.23 + + - name: Building CVAT Logstash + uses: docker/build-push-action@v2 + with: + context: ./components/analytics/logstash/ + file: ./components/analytics/logstash/Dockerfile + cache-from: type=local,src=/tmp/cvat_cache_logstash + tags: cvat_logstash:latest + load: true + build-args: ELK_VERSION=6.8.23 + + - name: CVAT server. Extract metadata (tags, labels) for Docker + id: meta-server + uses: docker/metadata-action@master + with: + images: ${{ secrets.DOCKERHUB_WORKSPACE }}/${{ env.SERVER_IMAGE_TEST_REPO }} + tags: | + type=raw,value=${{ inputs.ref }} + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Pull CVAT server image + run: | + docker pull ${{ steps.meta-server.outputs.tags }} + docker tag ${{ steps.meta-server.outputs.tags }} openvino/cvat_server + + - name: Running OPA tests + run: | + curl -L -o opa https://openpolicyagent.org/downloads/v0.34.2/opa_linux_amd64_static + chmod +x ./opa + ./opa test cvat/apps/iam/rules + + - name: Running REST API tests + run: | + pip3 install --user -r tests/rest_api/requirements.txt + pytest tests/rest_api/ -s -v + pytest tests/rest_api/ --stop-services + + - name: Running 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 + max_tries=12 + while [[ $(curl -s -o /dev/null -w "%{http_code}" localhost:8181/health) != "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 cvat_ci /bin/bash \ + -c 'python manage.py test cvat/apps cvat-cli -v 2' + + docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run cvat_ci /bin/bash \ + -c 'cd cvat-data && npm ci --ignore-scripts && cd ../cvat-core && npm ci --ignore-scripts && npm run test' + + - name: Creating a log file from cvat containers + if: failure() + env: + LOGS_DIR: "${{ github.workspace }}/unit_testing" + run: | + mkdir $LOGS_DIR + docker logs cvat > $LOGS_DIR/cvat.log + docker logs cvat_opa 2> $LOGS_DIR/cvat_opa.log + + - name: Uploading "cvat" container logs as an artifact + if: failure() + uses: actions/upload-artifact@v2 + env: + LOGS_DIR: "${{ github.workspace }}/unit_testing" + with: + name: cvat_container_logs + path: $LOGS_DIR + + e2e_testing: + needs: [build, search_cache] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + specs: ['actions_tasks', 'actions_tasks2', 'actions_tasks3', + 'actions_objects', 'actions_objects2', 'actions_users', + 'actions_projects_models', 'actions_organizations', 'canvas3d_functionality', + 'canvas3d_functionality_2', 'issues_prs', 'issues_prs2'] + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + + - uses: actions/setup-node@v2 + with: + node-version: '16.x' + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@master + + - name: Getting CVAT UI cache from the default branch + uses: actions/cache@v3 + with: + path: /tmp/cvat_cache_ui + key: ${{ runner.os }}-build-ui-${{ needs.search_cache.outputs.sha }} + + - name: Building CVAT UI image + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.ui + cache-from: type=local,src=/tmp/cvat_cache_ui + tags: openvino/cvat_ui:latest + load: true + + - name: CVAT server. Extract metadata (tags, labels) for Docker + id: meta-server + uses: docker/metadata-action@master + with: + images: ${{ secrets.DOCKERHUB_WORKSPACE }}/${{ env.SERVER_IMAGE_TEST_REPO }} + tags: | + type=raw,value=${{ inputs.ref }} + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Pull CVAT server image + run: | + docker pull ${{ steps.meta-server.outputs.tags }} + docker tag ${{ steps.meta-server.outputs.tags }} openvino/cvat_server + + - name: Run CVAT instance + run: | + docker-compose \ + -f docker-compose.yml \ + -f docker-compose.dev.yml \ + -f components/serverless/docker-compose.serverless.yml \ + -f tests/docker-compose.file_share.yml up -d + + - name: Waiting for 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 != "401" && 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 + + - name: Run E2E tests + env: + DJANGO_SU_NAME: 'admin' + DJANGO_SU_EMAIL: 'admin@localhost.company' + DJANGO_SU_PASSWORD: '12qwaszx' + run: | + docker exec -i cvat /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" + cd ./tests + npm ci + + shopt -s extglob + if [[ ${{ matrix.specs }} == canvas3d_* ]]; then + npx cypress run \ + --headed \ + --browser chrome \ + --config-file cypress_canvas3d.json \ + --spec 'cypress/integration/${{ matrix.specs }}/**/*.js,cypress/integration/remove_users_tasks_projects_organizations.js' + else + npx cypress run \ + --browser chrome \ + --spec 'cypress/integration/${{ matrix.specs }}/**/*.js,cypress/integration/remove_users_tasks_projects_organizations.js' + fi + + - name: Creating a log file from "cvat" container logs + if: failure() + run: | + docker logs cvat > ${{ github.workspace }}/tests/cvat_${{ matrix.specs }}.log + + - name: Uploading "cvat" container logs as an artifact + if: failure() + uses: actions/upload-artifact@v2 + with: + name: cvat_container_logs + path: ${{ github.workspace }}/tests/cvat_${{ matrix.specs }}.log + + - name: Uploading cypress screenshots as an artifact + if: failure() + uses: actions/upload-artifact@v2 + with: + name: cypress_screenshots_${{ matrix.specs }} + path: ${{ github.workspace }}/tests/cypress/screenshots