diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml new file mode 100644 index 00000000..83e9b8c5 --- /dev/null +++ b/.github/workflows/api-tests.yml @@ -0,0 +1,49 @@ +name: API Tests + +on: + push: + paths: + - 'api/**' + - 'shared/**' + - '.github/workflows/api-tests.yml' + - '/*' # include changes in root + - '!client/**' # exclude client folder + - '!infrastructure/**' # exclude infra folder + - 'package.json' + + workflow_dispatch: + + +jobs: + + api-tests-integration: + name: API Integration Tests + runs-on: ubuntu-22.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Node setup + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + + - uses: pnpm/action-setup@v4 + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-node_modules-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-node_modules- + + - name: Install dependencies + working-directory: . + run: pnpm install + + + - name: Run API tests + working-directory: api + run: pnpm test diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..914f606d --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,242 @@ +name: Run deploy + +on: + workflow_dispatch: + push: + branches: + - main + - staging + - dev + + paths: + - 'client/**' + - 'api/**' + - '.github/workflows/*' + - 'infrastructure/**' + - 'package.json' + + + +jobs: + + build_client: + environment: + name: ${{ github.ref_name == 'main' && 'production' || github.ref_name }} + runs-on: ubuntu-latest + name: Build Client image and push to Amazon ECR + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: client-changes + with: + filters: | + client: + - 'client/**' + - '.github/workflows/**' + + - name: Extract branch name + if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} + run: | + { + branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} + echo "branch=${branch}" + echo "branch_upper=${branch^^}" + } >> $GITHUB_OUTPUT + id: extract_branch + + - name: Configure AWS credentials + if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.PIPELINE_USER_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.PIPELINE_USER_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Login to Amazon ECR + if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + with: + mask-password: 'true' + + - name: Set up Docker Buildx + if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} + uses: docker/setup-buildx-action@v3 + + - name: Build, tag, and push Client image to Amazon ECR + if: ${{ github.event_name == 'workflow_dispatch' || steps.client-changes.outputs.client == 'true' }} + uses: docker/build-push-action@v5 + with: + build-args: | + NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL }} + NEXTAUTH_URL=${{ vars.NEXTAUTH_URL }} + NEXTAUTH_SECRET=${{ secrets.NEXTAUTH_SECRET }} + context: . + cache-from: type=gha + cache-to: type=gha,mode=max + file: ./client/Dockerfile + push: true + tags: | + ${{ steps.login-ecr.outputs.registry }}/${{ secrets.CLIENT_REPOSITORY_NAME }}:${{ github.sha }} + ${{ steps.login-ecr.outputs.registry }}/${{ secrets.CLIENT_REPOSITORY_NAME }}:${{ steps.extract_branch.outputs.branch == 'main' && 'production' || steps.extract_branch.outputs.branch }} + + build_api: + environment: + name: ${{ github.ref_name == 'main' && 'production' || github.ref_name }} + runs-on: ubuntu-latest + name: Build API image and push to Amazon ECR + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - uses: dorny/paths-filter@v3 + id: api-changes + with: + filters: | + api: + - 'api/**' + - '.github/workflows/**' + + - name: Extract branch name + if: ${{ github.event_name == 'workflow_dispatch' || steps.api-changes.outputs.api == 'true' }} + run: | + { + branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} + echo "branch=${branch}" + echo "branch_upper=${branch^^}" + } >> $GITHUB_OUTPUT + id: extract_branch + + - name: Configure AWS credentials + if: ${{ github.event_name == 'workflow_dispatch' || steps.api-changes.outputs.api == 'true' }} + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.PIPELINE_USER_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.PIPELINE_USER_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Login to Amazon ECR + if: ${{ github.event_name == 'workflow_dispatch' || steps.api-changes.outputs.api == 'true' }} + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + with: + mask-password: 'true' + + - name: Set up Docker Buildx + if: ${{ github.event_name == 'workflow_dispatch' || steps.api-changes.outputs.api == 'true' }} + uses: docker/setup-buildx-action@v3 + + - name: Build, tag, and push API image to Amazon ECR + if: ${{ github.event_name == 'workflow_dispatch' || steps.api-changes.outputs.api == 'true' }} + uses: docker/build-push-action@v5 + with: + build-args: | + DB_HOST=${{ secrets.DB_HOST }} + DB_PORT=${{ secrets.DB_PORT }} + DB_NAME=${{ secrets.DB_NAME }} + DB_USERNAME=${{ secrets.DB_USERNAME }} + DB_PASSWORD=${{ secrets.DB_PASSWORD }} + JWT_SECRET=${{ secrets.JWT_SECRET }} + context: . + cache-from: type=gha + cache-to: type=gha,mode=max + file: ./api/Dockerfile + push: true + tags: | + ${{ steps.login-ecr.outputs.registry }}/${{ secrets.API_REPOSITORY_NAME }}:${{ github.sha }} + ${{ steps.login-ecr.outputs.registry }}/${{ secrets.API_REPOSITORY_NAME }}:${{ steps.extract_branch.outputs.branch == 'main' && 'production' || steps.extract_branch.outputs.branch }} + + + deploy: + name: Deploy Services to Amazon EBS + needs: [ build_client, build_api ] + runs-on: ubuntu-latest + environment: + name: ${{ github.ref_name == 'main' && 'production' || github.ref_name }} + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.PIPELINE_USER_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.PIPELINE_USER_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Extract branch name + run: | + { + branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} + echo "branch=${branch}" + echo "branch_upper=${branch^^}" + } >> $GITHUB_OUTPUT + id: extract_branch + + - name: Generate docker compose file + working-directory: infrastructure/source_bundle + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + ECR_REPOSITORY_CLIENT: ${{ secrets.CLIENT_REPOSITORY_NAME }} + ECR_REPOSITORY_API: ${{ secrets.API_REPOSITORY_NAME }} + IMAGE_TAG: ${{ steps.extract_branch.outputs.branch == 'main' && 'production' || steps.extract_branch.outputs.branch }} + run: | + cat <> docker-compose.yml + services: + client: + image: $ECR_REGISTRY/$ECR_REPOSITORY_CLIENT:$IMAGE_TAG + restart: always + ports: + - 3000:3000 + api: + image: $ECR_REGISTRY/$ECR_REPOSITORY_API:$IMAGE_TAG + restart: always + ports: + - 4000:4000 + nginx: + image: nginx + restart: always + volumes: + - ./proxy/conf.d:/etc/nginx/conf.d + - "\${EB_LOG_BASE_DIR}/nginx:/var/log/nginx" + ports: + - 80:80 + depends_on: + - api + - client + EOF + + - name: Upload Docker Compose File as Artifact + uses: actions/upload-artifact@v2 + with: + name: docker-compose-file + path: infrastructure/source_bundle/docker-compose.yml + + - name: Generate zip file + working-directory: infrastructure/source_bundle + run: | + zip -r deploy.zip * .[^.]* + + - name: Upload Zip File as Artifact + uses: actions/upload-artifact@v2 + with: + name: deploy-zip + path: infrastructure/source_bundle/deploy.zip + + - name: Deploy to Amazon EB + uses: einaregilsson/beanstalk-deploy@v21 + with: + aws_access_key: ${{ secrets.PIPELINE_USER_ACCESS_KEY_ID }} + aws_secret_key: ${{ secrets.PIPELINE_USER_SECRET_ACCESS_KEY }} + application_name: ${{ secrets.PROJECT_NAME}}-${{ steps.extract_branch.outputs.branch == 'main' && 'production' || steps.extract_branch.outputs.branch }} + environment_name: ${{ secrets.PROJECT_NAME}}-${{ steps.extract_branch.outputs.branch == 'main' && 'production' || steps.extract_branch.outputs.branch }}-environment + region: ${{ secrets.AWS_REGION }} + version_label: ${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }} + deployment_package: infrastructure/source_bundle/deploy.zip \ No newline at end of file