diff --git a/.coveralls.yml b/.coveralls.yml index a253acc08e..cb1718c859 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1,2 +1,2 @@ -service_name: travis-ci +service_name: github-actions repo_token: s4vXsUN3KoBjArm1eb7o1jg0RQHYIBr0R diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9310201b8d..5a0b09ca8a 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -68,7 +68,7 @@ Our central development branch is development. Coding is done on feature branche - On your GitHub fork, select your branch and click “New pull request”. Select “master” as the base branch and your branch in the “compare” dropdown. If the code is mergeable (you get a message saying “Able to merge”), go ahead and create the pull request. - - Check back after some time to see if the Travis checks have passed, if not you should click on “Details” link on your PR thread at the right of “The Travis CI build failed”, which will take you to the dashboard for your PR. You will see what failed / stalled, and will need to resolve them. + - Check back after a few minutes to see if the GitHub Actions workflow has completed. If it hasn’t passed, click the "View details" link next to the failed check in your PR’s Job checks section—this will open the Actions run page for your workflow. There you can review the logs, pinpoint any errors or stalled steps, and fix them before pushing another commit. - If your checks have passed, your PR will be assigned a reviewer who will review your code and provide comments. Please address each review comment by pushing new commits to the same branch (the PR will automatically update, so you don’t need to submit a new one). Once you are done, comment below each review comment marking it as “Done”. Feel free to use the thread to have a discussion about comments that you don’t understand completely or don’t agree with. - Once all comments are addressed, the maintainer will approve the PR. diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 0000000000..936591a606 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,229 @@ +name: EvalAI CI/CD Pipeline + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +env: + COMPOSE_BAKE: true + COMPOSE_BAKE_ARGS: "--build-arg PIP_NO_CACHE_DIR=1" + CHROME_BIN: chromium-browser + DISPLAY: :99.0 + PYTHON_VERSION: '3.9.21' + AWSCLI_VERSION: '1.18.66' + REGISTRY: ${{ secrets.DOCKER_USERNAME }} + IMAGE_TAG: ${{ github.sha }} + +jobs: + quality-check: + name: Code Quality & Migration Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Python and dependencies + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Setup Docker Compose + uses: docker/setup-compose-action@v1 + with: + version: latest + + - name: Install dependencies and configure system + run: | + pip install --upgrade pip + pip install awscli==${{ env.AWSCLI_VERSION }} + sudo rm -f /etc/boto.cfg + mkdir -p $HOME/.config/pip + echo "[build_ext]" > $HOME/.config/pip/pip.conf + echo "parallel = 1" >> $HOME/.config/pip/pip.conf + ulimit -u 16384 + ulimit -n 4096 + + - name: Run code quality checks + run: | + docker compose run -e DJANGO_SETTINGS_MODULE=settings.dev -e VERBOSE=1 django bash -c " + echo 'Installing black, flake8, pylint and isort...' && + pip install black==24.8.0 flake8==3.8.2 pylint==3.3.6 isort==5.12.0 && + echo 'Running black check...' && + black --check --diff ./ || { echo 'Black check failed!'; exit 1; } && + echo 'Running isort check...' && + isort --check-only --diff --profile=black ./ || { echo 'isort check failed!'; exit 1; } && + echo 'Running flake8 check...' && + flake8 --config=.flake8 ./ || { echo 'Flake8 check failed!'; exit 1; } && + echo 'Running pylint check...' && + pylint --rcfile=.pylintrc --output-format=colorized --score=y --fail-under=7.5 ./ || { echo 'Pylint check failed!'; exit 1; } && + echo 'All code quality checks passed!'" + + - name: Django Migration Check + if: github.event_name == 'pull_request' + run: | + docker compose run -e DJANGO_SETTINGS_MODULE=settings.dev django python manage.py makemigrations --check --dry-run + + build-and-push: + name: Build & Push Docker Images + runs-on: ubuntu-latest + # REMOVED: No dependencies - runs in parallel + outputs: + image-digest: ${{ steps.build.outputs.digest }} + steps: + - uses: actions/checkout@v4 + + - name: Setup Docker Compose + uses: docker/setup-compose-action@v1 + with: + version: latest + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Docker login + if: github.event_name == 'push' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push Docker images + id: build + run: | + export COMPOSE_DOCKER_CLI_BUILD=1 + export DOCKER_BUILDKIT=1 + + docker compose --profile worker_py3_7 --profile worker_py3_8 --profile worker_py3_9 --profile statsd build ${{ env.COMPOSE_BAKE_ARGS }} + + if [ "${{ github.event_name }}" = "push" ]; then + docker compose --profile worker_py3_7 --profile worker_py3_8 --profile worker_py3_9 --profile statsd push + fi + + test: + name: Run Tests + runs-on: ubuntu-latest + # REMOVED: No dependencies - runs in parallel with build + strategy: + matrix: + test-type: [frontend, backend] + fail-fast: false + steps: + - uses: actions/checkout@v4 + + - name: Setup Python and dependencies + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Setup Docker Compose + uses: docker/setup-compose-action@v1 + with: + version: latest + + - name: Install test dependencies + run: | + pip install --upgrade pip + pip install awscli==${{ env.AWSCLI_VERSION }} coveralls + + - name: Build images for testing (if not available) + run: | + docker compose --profile worker_py3_7 --profile worker_py3_8 --profile worker_py3_9 --profile statsd build ${{ env.COMPOSE_BAKE_ARGS }} + + - name: Setup display for frontend tests + if: matrix.test-type == 'frontend' + run: | + sudo apt-get update + sudo apt-get install -y xvfb chromium-browser + Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + + - name: Run frontend tests + if: matrix.test-type == 'frontend' + run: | + docker compose run nodejs bash -c "gulp dev && karma start --single-run && gulp staging" + + - name: Run backend tests + if: matrix.test-type == 'backend' + run: | + docker compose run -e DJANGO_SETTINGS_MODULE=settings.test django python manage.py flush --noinput + docker compose run -e DJANGO_SETTINGS_MODULE=settings.test django pytest --cov . --cov-config .coveragerc + + - name: Upload coverage to Codecov + if: matrix.test-type == 'backend' + run: | + bash <(curl -s https://codecov.io/bash) + + - name: Upload coverage to Coveralls + if: matrix.test-type == 'backend' + continue-on-error: true + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + run: | + coveralls --rcfile=.coveragerc + + deploy: + name: Package & Deploy Services + runs-on: ubuntu-latest + needs: [build-and-push, test, quality-check] # Waits for ALL jobs to complete + if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main') + environment: production + steps: + - uses: actions/checkout@v4 + + - name: Setup Python and dependencies + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + cache: 'pip' + + - name: Install deployment dependencies + run: | + pip install --upgrade pip + pip install awscli==${{ env.AWSCLI_VERSION }} + + - name: Configure SSH and decrypt keys + run: | + eval "$(ssh-agent -s)" + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts + ssh-keyscan -H ${{ secrets.DEPLOY_HOST }} >> ~/.ssh/known_hosts + + - name: Deploy services + run: | + ssh-add ~/.ssh/deploy_key + ./scripts/deployment/push.sh + ./scripts/deployment/deploy.sh auto_deploy + + - name: Clean up pip cache + run: | + rm -f $HOME/.cache/pip/log/debug.log + + - name: Notify on failure + if: failure() + uses: 8398a7/action-slack@v3 + with: + status: failure + channel: '#ci-cd' + webhook_url: ${{ secrets.SLACK_WEBHOOK }} + + - name: Notify on success + if: success() + uses: 8398a7/action-slack@v3 + with: + status: success + channel: '#ci-cd' + webhook_url: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100755 index c2c4959b18..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,84 +0,0 @@ -language: python -sudo: required -os: linux -dist: focal -virt: vm -services: - - docker - - xvfb -python: - - '3.9.21' -cache: - directories: - - $HOME/.cache/pip - -env: - global: - - COMPOSE_BAKE=true - - COMPOSE_BAKE_ARGS="--build-arg PIP_NO_CACHE_DIR=1" - -before_install: - - sudo rm -f /etc/boto.cfg - - export CHROME_BIN=chromium-browser - - export DISPLAY=:99.0 - - pip install --upgrade pip - - mkdir -p $HOME/.config/pip - - echo "[build_ext]" > $HOME/.config/pip/pip.conf - - echo "parallel = 1" >> $HOME/.config/pip/pip.conf - - ulimit -u 16384 # Increase process/thread limit - - ulimit -n 4096 # Increase open file limit - -install: - - pip install awscli==1.18.66 - -jobs: - fast_finish: true - include: - - stage: Build, Test & Check Code Quality - name: Build, Test & Check Code Quality - script: - # Build steps - - if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin || travis_terminate 1; fi - - docker-compose --profile worker_py3_7 --profile worker_py3_8 --profile worker_py3_9 --profile statsd build || travis_terminate 1; - - # Frontend Tests - - docker-compose run nodejs bash -c "gulp dev && karma start --single-run && gulp staging" || travis_terminate 1; - - # Backend Tests - - docker-compose run -e DJANGO_SETTINGS_MODULE=settings.test django python manage.py flush --noinput || travis_terminate 1; - - docker-compose run -e DJANGO_SETTINGS_MODULE=settings.test django pytest --cov . --cov-config .coveragerc || travis_terminate 1; - - # Check Code Quality - - docker-compose run -e DJANGO_SETTINGS_MODULE=settings.dev -e VERBOSE=1 django bash -c " - echo 'Installing black, flake8, pylint and isort...' && - pip install black==24.8.0 flake8==3.8.2 pylint==3.3.6 isort==5.12.0 && - echo 'Running black check...' && - black --check --diff ./ || { echo 'Black check failed!'; travis_terminate 1; } && - echo 'Running isort check...' && - isort --check-only --diff --profile=black ./ || { echo 'isort check failed!'; travis_terminate 1; } && - echo 'Running flake8 check...' && - flake8 --config=.flake8 ./ || { echo 'Flake8 check failed!'; travis_terminate 1; } && - echo 'Running pylint check...' && - pylint --rcfile=.pylintrc --output-format=colorized --score=y --fail-under=7.5 ./ || { echo 'Pylint check failed!'; travis_terminate 1; } && - echo 'All code quality checks passed!'" || travis_terminate 1; - - after_success: - - bash <(curl -s https://codecov.io/bash) - - coveralls --rcfile=.coveragerc - - - stage: Package & Deployment - name: Push & Deploy Services - script: - - eval "$(ssh-agent -s)" - - openssl aes-256-cbc -K $encrypted_77d2d82026f6_key -iv $encrypted_77d2d82026f6_iv -in scripts/deployment/evalai.pem.enc -out scripts/deployment/evalai.pem -d || true - - ./scripts/deployment/push.sh || travis_terminate 1; - - ./scripts/deployment/deploy.sh auto_deploy || travis_terminate 1; - -before_cache: - - rm -f $HOME/.cache/pip/log/debug.log - -notifications: - email: - on_success: change - on_failure: always - slack: cloudcv:gy3CGQGNXLwXOqVyzXGZfdea \ No newline at end of file diff --git a/README.md b/README.md index 89ef03313e..6a9a5de336 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------ [![Join the chat on Slack](https://img.shields.io/badge/Join%20Slack-Chat-blue?logo=slack)](https://join.slack.com/t/cloudcv-community/shared_invite/zt-3252n6or8-e0QuZKIZFLB0zXtQ6XgxfA) -[![Build Status](https://travis-ci.org/Cloud-CV/EvalAI.svg?branch=master)](https://travis-ci.org/Cloud-CV/EvalAI) +[![Build Status](https://github.com/Cloud-CV/EvalAI/actions/workflows/ci-cd.yml/badge.svg?branch=master)](https://github.com/Cloud-CV/EvalAI/actions/workflows/ci-cd.yml) [![codecov](https://codecov.io/gh/Cloud-CV/EvalAI/branch/master/graph/badge.svg)](https://codecov.io/gh/Cloud-CV/EvalAI) [![Coverage Status](https://coveralls.io/repos/github/Cloud-CV/EvalAI/badge.svg)](https://coveralls.io/github/Cloud-CV/EvalAI) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) diff --git a/docker/prod/celery/Dockerfile b/docker/prod/celery/Dockerfile index bb99580046..c034b12f0e 100644 --- a/docker/prod/celery/Dockerfile +++ b/docker/prod/celery/Dockerfile @@ -1,7 +1,7 @@ ARG AWS_ACCOUNT_ID ARG COMMIT_ID -ARG TRAVIS_BRANCH +ARG GITHUB_BRANCH_NAME -FROM ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/evalai-${TRAVIS_BRANCH}-backend:${COMMIT_ID} +FROM ${AWS_ACCOUNT_ID}.dkr.ecr.us-east-1.amazonaws.com/evalai-${GITHUB_BRANCH_NAME}-backend:${COMMIT_ID} CMD ["sh", "/code/docker/prod/celery/container-start.sh"] diff --git a/docs/source/04-development/contributing/contribution-guide.md b/docs/source/04-development/contributing/contribution-guide.md index b64ac1ab0c..d84e08c0d6 100644 --- a/docs/source/04-development/contributing/contribution-guide.md +++ b/docs/source/04-development/contributing/contribution-guide.md @@ -67,7 +67,7 @@ Our central development branch is development. Coding is done on feature branche - On your GitHub fork, select your branch and click “New pull request”. Select “master” as the base branch and your branch in the “compare” dropdown. If the code is mergeable (you get a message saying “Able to merge”), go ahead and create the pull request. - - Check back after some time to see if the Travis checks have passed, if not you should click on “Details” link on your PR thread at the right of “The Travis CI build failed”, which will take you to the dashboard for your PR. You will see what failed / stalled, and will need to resolve them. + - - Check back after a few minutes to see if the GitHub Actions workflow has completed. If it hasn’t passed, click the "View details" link next to the failed check in your PR’s Job checks section—this will open the Actions run page for your workflow. There you can review the logs, pinpoint any errors or stalled steps, and fix them before pushing another commit. - If your checks have passed, your PR will be assigned a reviewer who will review your code and provide comments. Please address each review comment by pushing new commits to the same branch (the PR will automatically update, so you don’t need to submit a new one). Once you are done, comment below each review comment marking it as “Done”. Feel free to use the thread to have a discussion about comments that you don’t understand completely or don’t agree with. - Once all comments are addressed, the maintainer will approve the PR. diff --git a/docs/source/contribution.rst b/docs/source/contribution.rst index 9b6b00ef73..d96cfa7fd2 100644 --- a/docs/source/contribution.rst +++ b/docs/source/contribution.rst @@ -75,11 +75,12 @@ reviewed. To submit code, follow these steps: the “compare” dropdown. If the code is mergeable (you get a message saying “Able to merge”), go ahead and create the pull request. - - Check back after some time to see if the Travis checks have - passed, if not you should click on “Details” link on your PR - thread at the right of “The Travis CI build failed”, which will - take you to the dashboard for your PR. You will see what failed / - stalled, and will need to resolve them. + - Check back after a few minutes to see if the GitHub Actions + workflow has completed. If it hasn’t passed, click the "View details" + link next to the failed check in your PR’s Job checks section—this + will open the Actions run page for your workflow. There you can review + the logs, pinpoint any errors or stalled steps, and fix them before + pushing another commit. - If your checks have passed, your PR will be assigned a reviewer who will review your code and provide comments. Please address each review comment by pushing new commits to the same branch (the diff --git a/frontend_v2/README.md b/frontend_v2/README.md index 8459585cdc..1665d4fa44 100644 --- a/frontend_v2/README.md +++ b/frontend_v2/README.md @@ -4,9 +4,9 @@ Revamped codebase of EvalAI Frontend ### For deploying with [Surge](https://surge.sh/): -Surge will automatically generate deployment link whenever a pull request passes Travis CI. +Surge will automatically generate deployment link whenever a pull request passes Github Actions. -Suppose pull request number is 123 and it passes Travis CI. The deployment link can be found here: `https://pr-123-evalai.surge.sh` +Suppose pull request number is 123 and it passes Github Actions. The deployment link can be found here: `https://pr-123-evalai.surge.sh` ## Code scaffolding diff --git a/frontend_v2/pr_deploy.sh b/frontend_v2/pr_deploy.sh index 9ddc65c119..16b314b89b 100644 --- a/frontend_v2/pr_deploy.sh +++ b/frontend_v2/pr_deploy.sh @@ -1,13 +1,17 @@ #!/usr/bin/env bash -if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then + +# Check if this is a pull request +if [ "$GITHUB_EVENT_NAME" != "pull_request" ]; then echo "Not a Pull Request. Skipping surge deployment" exit 0 fi echo "PR deployment start" npm i -g surge echo "Installed surge successfully" -export DEPLOY_DOMAIN=https://pr-${TRAVIS_PULL_REQUEST}-evalai.surge.sh -echo "Deployment domain -" + +# Use GitHub's pull request number from the event payload +export DEPLOY_DOMAIN=https://pr-${GITHUB_PR_NUMBER}-evalai.surge.sh +echo "Deployment domain:" echo $DEPLOY_DOMAIN surge --project ./dist --domain $DEPLOY_DOMAIN --token $SURGE_TOKEN diff --git a/karma.conf.js b/karma.conf.js index 293e4e9e48..4f21c2a511 100755 --- a/karma.conf.js +++ b/karma.conf.js @@ -99,9 +99,11 @@ module.exports = function(config) { } }; - // Detect if this is TravisCI running the tests and tell it to use chromium - if(process.env.TRAVIS){ + // Detect if this is Github Actions running the tests and tell it to use chromium + if(process.env.GITHUB_ACTIONS){ configuration.browsers = ['ChromeWithNoSandbox']; + configuration.singleRun = true; + configuration.autoWatch = false; } config.set(configuration); diff --git a/scripts/deployment/deploy.sh b/scripts/deployment/deploy.sh index 93688c1dcc..ec9ec58506 100755 --- a/scripts/deployment/deploy.sh +++ b/scripts/deployment/deploy.sh @@ -17,11 +17,11 @@ if [ -z ${COMMIT_ID} ]; then export COMMIT_ID="latest" fi -if [ -z ${TRAVIS_BRANCH} ]; then - echo "Please set the TRAVIS_BRANCH first." +if [ -z ${GITHUB_BRANCH_NAME} ]; then + echo "Please set the GITHUB_BRANCH_NAME first." fi -env=${TRAVIS_BRANCH} +env=${GITHUB_BRANCH_NAME} JUMPBOX=${JUMPBOX_INSTANCE} if [[ ${env} == "production" ]]; then diff --git a/scripts/deployment/deploy_ec2_worker.sh b/scripts/deployment/deploy_ec2_worker.sh index 33048ba603..1b0b02c3e0 100644 --- a/scripts/deployment/deploy_ec2_worker.sh +++ b/scripts/deployment/deploy_ec2_worker.sh @@ -33,7 +33,7 @@ aws configure set default.region ${AWS_REGION} export AWS_ACCOUNT_ID=${AWS_ACCOUNT_ID} export COMMIT_ID="latest" export AWS_DEFAULT_REGION=${AWS_REGION} -export TRAVIS_BRANCH=${ENVIRONMENT} +export GITHUB_BRANCH_NAME=${ENVIRONMENT} eval $(aws ecr get-login --no-include-email) # Step 7: Copying Docker environment file diff --git a/scripts/deployment/push.sh b/scripts/deployment/push.sh index c2e91788c4..27db44a10d 100755 --- a/scripts/deployment/push.sh +++ b/scripts/deployment/push.sh @@ -9,11 +9,11 @@ build_and_push() { echo "Pulling ssl certificates and nginx configuration..." aws s3 cp s3://cloudcv-secrets/eval.ai/ssl/ ./ssl/ --recursive # Need ssl files related to *.cloudcv.org since we want to provide backward compatibility - aws s3 cp s3://cloudcv-secrets/evalai/${TRAVIS_BRANCH}/ssl/ ./ssl/ --recursive + aws s3 cp s3://cloudcv-secrets/evalai/${GITHUB_BRANCH_NAME}/ssl/ ./ssl/ --recursive echo "Pulled ssl certificates and nginx configuration successfully" docker-compose -f docker-compose-$1.yml build \ --build-arg COMMIT_ID=${COMMIT_ID} \ - --build-arg TRAVIS_BRANCH=${TRAVIS_BRANCH} \ + --build-arg GITHUB_BRANCH_NAME=${GITHUB_BRANCH_NAME} \ --build-arg AWS_ACCOUNT_ID=${AWS_ACCOUNT_ID} --compress docker-compose -f docker-compose-$1.yml push @@ -29,11 +29,11 @@ build_and_push() { done } -if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then +if [ "${GITHUB_EVENT_NAME}" != "push" ]; then echo "Skipping deploy to staging or production server; The request or commit is not on staging or production branch" exit 0 -elif [ "${TRAVIS_BRANCH}" == "staging" -o "${TRAVIS_BRANCH}" == "production" ]; then - build_and_push $TRAVIS_BRANCH +elif [ "${GITHUB_BRANCH_NAME}" == "staging" -o "${GITHUB_BRANCH_NAME}" == "production" ]; then + build_and_push $GITHUB_BRANCH_NAME exit 0 else echo "Skipping deploy!" diff --git a/tests/unit/jobs/test_views.py b/tests/unit/jobs/test_views.py index 9945dc5164..3361923486 100644 --- a/tests/unit/jobs/test_views.py +++ b/tests/unit/jobs/test_views.py @@ -2478,7 +2478,7 @@ def test_update_submission_for_invalid_data_in_result_key(self): # } self.client.force_authenticate(user=self.challenge_host.user) response = self.client.put(self.url, self.data) - # Fix the travis build by un-commenting this line. + # Fix the build by un-commenting this line. # self.assertEqual(response.data, expected) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)