diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index fa076dd736c..00000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,223 +0,0 @@ -version: 2.1 - -orbs: - node: circleci/node@7.1.1 - docker: circleci/docker@1.5.0 - codecov: codecov/codecov@5.0.3 - gcp-cli: circleci/gcp-cli@3.3.2 - -# Reusable commands for Docker jobs -commands: - create-version-json: - description: "Create version.json for Dockerflow" - steps: - - run: - name: Create version.json - command: | - # create a version.json per https://github.com/mozilla-services/Dockerflow/blob/master/docs/version_object.md - printf '{"commit":"%s","version":"%s","source":"https://github.com/%s/%s","build":"%s"}\n' \ - "$CIRCLE_SHA1" \ - "$CIRCLE_TAG" \ - "$CIRCLE_PROJECT_USERNAME" \ - "$CIRCLE_PROJECT_REPONAME" \ - "$CIRCLE_BUILD_URL" > version.json - - setup-docker-env: - description: "Setup Docker environment" - steps: - - setup_remote_docker: - version: docker24 - - create-version-json - - build-docker-image: - description: "Build Docker image" - steps: - - run: - name: Build Docker image - command: DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t app:build . - - deploy-to-dockerhub: - description: "Deploy to Docker Hub" - steps: - - run: - name: Deploy to Dockerhub - command: | - echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin - - # Function to tag and push - tag_and_push() { - local tag=$1 - docker tag app:build "${DOCKERHUB_REPO}:${tag}" - docker push "${DOCKERHUB_REPO}:${tag}" - } - - if [ "${CIRCLE_BRANCH}" == "master" ]; then - tag_and_push "latest" - tag_and_push "${CIRCLE_BRANCH}-${CIRCLE_SHA1}" - elif [ "${CIRCLE_BRANCH}" == "prototype" ]; then - tag_and_push "${CIRCLE_BRANCH}-${CIRCLE_SHA1}" - elif [ ! -z "${CIRCLE_TAG}" ]; then - echo "Deploying release tag: ${DOCKERHUB_REPO}:${CIRCLE_TAG}" - tag_and_push "${CIRCLE_TAG}" - fi - - deploy-to-gcp-gar: - description: "Deploy to GCP Artifact Registry" - steps: - - gcp-cli/setup: - use_oidc: true - google_project_number: GCP_WIP_PROJECT_NUMBER - google_project_id: GCP_PROJECT_ID_OF_GCP_GAR - workload_identity_pool_id: GCP_WIP_ID - workload_identity_pool_provider_id: GCP_WIP_PROVIDER_ID - service_account_email: GCP_GAR_PUSHER_SERVICE_ACCOUNT_EMAIL - - run: - name: Configure Docker for GAR - command: gcloud auth configure-docker ${GCP_GAR_REGISTRY} - - run: - name: Deploy to GCP GAR - command: | - GCP_GAR_REPO="${GCP_GAR_REGISTRY}/${GCP_PROJECT_ID_OF_GCP_GAR}/treeherder-prod/treeherder" - - # Function to tag and push to GCP GAR - tag_and_push_gar() { - local tag=$1 - docker tag app:build "${GCP_GAR_REPO}:${tag}" - docker push "${GCP_GAR_REPO}:${tag}" - } - - if [ "${CIRCLE_BRANCH}" == "master" ]; then - tag_and_push_gar "latest" - tag_and_push_gar "${CIRCLE_BRANCH}-${CIRCLE_SHA1}" - elif [ "${CIRCLE_BRANCH}" == "prototype" ]; then - tag_and_push_gar "${CIRCLE_BRANCH}-${CIRCLE_SHA1}" - elif [ ! -z "${CIRCLE_TAG}" ]; then - echo "Deploying release tag: ${GCP_GAR_REPO}:${CIRCLE_TAG}" - tag_and_push_gar "${CIRCLE_TAG}" - fi - -jobs: - javascript-tests: - executor: - name: node/default - # The Node version here should be compatible with `package.json` engines. - # Note: cimg/node requires at least a minor version (e.g., '22.0'), not just major version - tag: '22.0' - steps: - - checkout - - run: - name: Install pnpm - command: sudo corepack enable && corepack prepare pnpm@9.15.0 --activate - - run: - name: Install dependencies - command: pnpm install --frozen-lockfile - - run: - command: pnpm lint - name: Run linting - - run: - command: pnpm markdownlint - name: Check markdown linting - - run: - command: pnpm test:ci - name: Run Jest tests - - codecov/upload - - builds: - docker: - - image: 'cimg/python:3.10-node' - steps: - - checkout - - run: pip install tox - - run: - command: tox -e docs - name: Build docs - - run: - command: tox -e linters - name: Run linters - - python-tests-general: - machine: - image: default - steps: - - checkout - - docker/install-docker-compose: - version: 1.29.2 - - run: - name: Run tests and coverage within Docker container - command: | - pip install --upgrade pip - pip install tox - tox -e docker-general - - codecov/upload - - python-tests-perf: - machine: - image: default - steps: - - checkout - - docker/install-docker-compose: - version: 1.29.2 - - run: - name: Run tests and coverage within Docker container - command: | - pip install --upgrade pip - pip install tox - tox -e docker-perf - - codecov/upload - - python-tests-frontend: - machine: - image: default - steps: - - checkout - - docker/install-docker-compose: - version: 1.29.2 - - run: - name: Run tests and coverage within Docker container - command: | - pip install --upgrade pip - pip install tox - tox -e docker-frontend - - codecov/upload - - test-docker-build: - docker: - - image: cimg/base:current - environment: - # Required for compatibility between newer Docker client and docker24 remote daemon - DOCKER_API_VERSION: "1.43" - steps: - - checkout - - setup-docker-env - - build-docker-image - - deploy: - docker: - - image: cimg/base:current - environment: - # Required for compatibility between newer Docker client and docker24 remote daemon - DOCKER_API_VERSION: "1.43" - steps: - - checkout - - setup-docker-env - - build-docker-image - - deploy-to-dockerhub - - deploy-to-gcp-gar - -workflows: - run-tests: - jobs: - - javascript-tests - - builds - - python-tests-frontend - - python-tests-general - - python-tests-perf - - test-docker-build - - deploy: - filters: - tags: - only: /.*/ - branches: - only: - - master - - prototype diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000000..b84979cafd7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,146 @@ +name: CI + +on: + push: + pull_request: + +jobs: + javascript-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22.0' + cache: 'pnpm' + - run: pnpm install --frozen-lockfile + - run: pnpm lint + name: Run linting + - run: pnpm markdownlint + name: Check markdown linting + - run: pnpm test:ci + name: Run Jest tests + - uses: codecov/codecov-action@v5 + + builds: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + - run: pip install tox + - run: tox -e docs + name: Build docs + - run: tox -e linters + name: Run linters + + python-tests-general: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + # tox.ini calls docker-compose (v1 CLI); ubuntu-latest only ships the v2 plugin. + # This shim bridges the two so existing scripts work unmodified. + - name: Install docker-compose compatibility shim + run: printf '#!/bin/sh\nexec docker compose "$@"\n' | sudo tee /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose + - run: pip install tox + - name: Run tests and coverage within Docker container + run: tox -e docker-general + - uses: codecov/codecov-action@v5 + + python-tests-perf: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install docker-compose compatibility shim + run: printf '#!/bin/sh\nexec docker compose "$@"\n' | sudo tee /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose + - run: pip install tox + - name: Run tests and coverage within Docker container + run: tox -e docker-perf + - uses: codecov/codecov-action@v5 + + python-tests-frontend: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install docker-compose compatibility shim + run: printf '#!/bin/sh\nexec docker compose "$@"\n' | sudo tee /usr/local/bin/docker-compose && sudo chmod +x /usr/local/bin/docker-compose + - run: pip install tox + - name: Run tests and coverage within Docker container + run: tox -e docker-frontend + - uses: codecov/codecov-action@v5 + + test-docker-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/build-docker + + deploy: + needs: [javascript-tests, builds, python-tests-general, python-tests-perf, python-tests-frontend, test-docker-build] + if: github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/prototype' || startsWith(github.ref, 'refs/tags/')) + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/build-docker + + # Deploy to Docker Hub + - name: Login to Docker Hub + run: echo "${{ secrets.DOCKER_PASS }}" | docker login -u "${{ secrets.DOCKER_USER }}" --password-stdin + - name: Tag and push to Docker Hub + run: | + tag_and_push() { + local tag=$1 + docker tag app:build "${{ secrets.DOCKERHUB_REPO }}:${tag}" + docker push "${{ secrets.DOCKERHUB_REPO }}:${tag}" + } + + if [ "${{ github.ref }}" == "refs/heads/master" ]; then + tag_and_push "latest" + tag_and_push "master-${GITHUB_SHA}" + elif [ "${{ github.ref }}" == "refs/heads/prototype" ]; then + tag_and_push "prototype-${GITHUB_SHA}" + elif [[ "${{ github.ref }}" == refs/tags/* ]]; then + tag_and_push "${{ github.ref_name }}" + fi + + # Deploy to GCP Artifact Registry + - id: gcp-auth + uses: google-github-actions/auth@v2 + with: + workload_identity_provider: projects/${{ secrets.GCP_WIP_PROJECT_NUMBER }}/locations/global/workloadIdentityPools/${{ secrets.GCP_WIP_ID }}/providers/${{ secrets.GCP_WIP_PROVIDER_ID }} + service_account: ${{ secrets.GCP_GAR_PUSHER_SERVICE_ACCOUNT_EMAIL }} + - uses: google-github-actions/setup-gcloud@v2 + - name: Configure Docker for GAR + run: gcloud auth configure-docker ${{ secrets.GCP_GAR_REGISTRY }} + - name: Tag and push to GCP GAR + run: | + GCP_GAR_REPO="${{ secrets.GCP_GAR_REGISTRY }}/${{ secrets.GCP_PROJECT_ID_OF_GCP_GAR }}/treeherder-prod/treeherder" + + tag_and_push_gar() { + local tag=$1 + docker tag app:build "${GCP_GAR_REPO}:${tag}" + docker push "${GCP_GAR_REPO}:${tag}" + } + + if [ "${{ github.ref }}" == "refs/heads/master" ]; then + tag_and_push_gar "latest" + tag_and_push_gar "master-${GITHUB_SHA}" + elif [ "${{ github.ref }}" == "refs/heads/prototype" ]; then + tag_and_push_gar "prototype-${GITHUB_SHA}" + elif [[ "${{ github.ref }}" == refs/tags/* ]]; then + tag_and_push_gar "${{ github.ref_name }}" + fi diff --git a/README.md b/README.md index f02d67b271a..67a48b8b575 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Treeherder [![What's Deployed](https://img.shields.io/badge/whatsdeployed-prototype,stage,prod-green.svg)](https://whatsdeployed.io/s/BIY/Mozilla/Treeherder) -[![Build Status](https://circleci.com/gh/mozilla/treeherder.svg?branch=master&style=shield)](https://app.circleci.com/pipelines/github/mozilla/treeherder) +[![Build Status](https://github.com/mozilla/treeherder/actions/workflows/ci.yml/badge.svg)](https://github.com/mozilla/treeherder/actions/workflows/ci.yml) ![Node dependencies Status](https://shields.io/librariesio/github/mozilla/treeherder) [![Documentation Status](https://readthedocs.org/projects/treeherder/badge/?version=latest)](https://treeherder.readthedocs.io/?badge=latest) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) diff --git a/ui/contribute.json b/ui/contribute.json index a9194d8b825..1854f427f80 100644 --- a/ui/contribute.json +++ b/ui/contribute.json @@ -4,7 +4,7 @@ "repository": { "url": "https://github.com/mozilla/treeherder", "license": "MPL2", - "tests": "https://app.circleci.com/pipelines/github/mozilla/treeherder" + "tests": "https://github.com/mozilla/treeherder/actions" }, "participate": { "home": "https://wiki.mozilla.org/EngineeringProductivity/Projects/Treeherder",