name: Frontend CI/CD Pipeline on: push: branches: [main] paths: - '**' - '!**.md' - '!.github/**' - '.github/workflows/cicd.yaml' jobs: build: name: Build runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Run tests run: npm test -- --coverage --passWithNoTests - name: SonarQube Scan uses: SonarSource/sonarqube-scan-action@v2 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} with: args: > -Dsonar.projectKey=lifesub-web -Dsonar.sources=src -Dsonar.tests=src -Dsonar.test.inclusions=src/**/*.test.js,src/**/*.test.jsx -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info - name: SonarQube Quality Gate check uses: SonarSource/sonarqube-quality-gate-action@v1 timeout-minutes: 5 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} - name: Build project run: npm run build - name: Upload build artifact uses: actions/upload-artifact@v4 with: name: build path: build/ retention-days: 1 release: name: Release needs: build runs-on: ubuntu-latest outputs: image_tag: ${{ steps.set_image_tag.outputs.image_tag }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Set Image Tag id: set_image_tag run: | IMAGE_TAG=$(date +'%Y%m%d%H%M%S') echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT - name: Load environment variables run: | if [[ -f deployment/deploy_env_vars ]]; then grep -v '^#' deployment/deploy_env_vars | while IFS= read -r line; do [[ -z "$line" ]] && continue echo "$line" >> $GITHUB_ENV done fi - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Azure Container Registry uses: docker/login-action@v3 with: registry: ${{ env.registry }} username: ${{ secrets.ACR_USERNAME }} password: ${{ secrets.ACR_PASSWORD }} - name: Download build artifact uses: actions/download-artifact@v4 with: name: build path: build/ - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: deployment/Dockerfile-lifesub-web push: true tags: ${{ env.registry }}/${{ env.image_org }}/lifesub-web:${{ steps.set_image_tag.outputs.image_tag }} build-args: | PROJECT_FOLDER=. REACT_APP_MEMBER_URL=${{ env.react_app_member_url }} REACT_APP_MYSUB_URL=${{ env.react_app_mysub_url }} REACT_APP_RECOMMEND_URL=${{ env.react_app_recommend_url }} BUILD_FOLDER=deployment EXPORT_PORT=${{ env.export_port }} deploy: name: Deploy needs: release runs-on: ubuntu-latest env: IMAGE_TAG: ${{ needs.release.outputs.image_tag }} steps: - name: Checkout code uses: actions/checkout@v4 - name: Load environment variables run: | if [[ -f deployment/deploy_env_vars ]]; then grep -v '^#' deployment/deploy_env_vars | while IFS= read -r line; do [[ -z "$line" ]] && continue echo "$line" >> $GITHUB_ENV done fi - name: Install envsubst run: | sudo apt-get update sudo apt-get install -y gettext-base - name: Generate Kubernetes manifests run: | export namespace=${namespace} export lifesub_web_image_path=${registry}/${image_org}/lifesub-web:${IMAGE_TAG} export replicas=${replicas} export export_port=${export_port} export resources_requests_cpu=${resources_requests_cpu} export resources_requests_memory=${resources_requests_memory} export resources_limits_cpu=${resources_limits_cpu} export resources_limits_memory=${resources_limits_memory} envsubst < deployment/deploy.yaml.template > deployment/deploy.yaml echo "Generated Kubernetes manifest:" cat deployment/deploy.yaml - name: Set up kubectl uses: azure/setup-kubectl@v3 with: version: 'latest' - name: Azure login uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - name: Set up kubeconfig uses: azure/aks-set-context@v3 with: resource-group: ictcoe-edu cluster-name: ${{ env.teamid }}-aks - name: Create namespace if not exists run: | kubectl create namespace ${{ env.namespace }} --dry-run=client -o yaml | kubectl apply -f - - name: Deploy to AKS run: | kubectl apply -f deployment/deploy.yaml - name: Wait for deployment to be ready run: | kubectl -n ${{ env.namespace }} wait --for=condition=available deployment/lifesub-web --timeout=300s echo "Waiting for service external IP..." while [[ -z $(kubectl -n ${{ env.namespace }} get svc lifesub-web -o jsonpath='{.status.loadBalancer.ingress[0].ip}') ]]; do sleep 5 done echo "Service external IP: $(kubectl -n ${{ env.namespace }} get svc lifesub-web -o jsonpath='{.status.loadBalancer.ingress[0].ip}')"