Skip to content

πŸ› fix(ci): env variables #34

πŸ› fix(ci): env variables

πŸ› fix(ci): env variables #34

Workflow file for this run

name: πŸš€ CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
jobs:
# Test & Lint both client and server
test-and-lint:
name: πŸ§ͺ Test & Lint
runs-on: ubuntu-latest
strategy:
matrix:
package: [client, server]
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
- name: πŸ“¦ Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: '${{ matrix.package }}/package-lock.json'
- name: πŸ“₯ Install Dependencies
run: |
cd ${{ matrix.package }}
rm -f package-lock.json
npm install --package-lock-only
npm ci
- name: πŸ” Lint
run: |
cd ${{ matrix.package }}
npm run lint
- name: πŸ§ͺ Test
run: |
cd ${{ matrix.package }}
npm run test:ci || npm run test:coverage || npm run test
- name: πŸ“Š Upload Coverage
uses: codecov/codecov-action@v4
with:
files: ./${{ matrix.package }}/coverage/lcov.info
flags: ${{ matrix.package }}
name: ${{ matrix.package }}-coverage
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
# Build applications (only on main branch)
build:
name: πŸ—οΈ Build
runs-on: ubuntu-latest
needs: test-and-lint
if: github.ref == 'refs/heads/main'
strategy:
matrix:
package: [client, server]
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
- name: πŸ“¦ Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: '${{ matrix.package }}/package-lock.json'
- name: πŸ“₯ Install Dependencies
run: |
cd ${{ matrix.package }}
npm ci --include=optional || npm ci --omit=optional || (rm -rf node_modules package-lock.json && npm install --omit=optional)
- name: πŸ”¨ Build Version Info
env:
BUILD_NUMBER: ${{ github.run_number }}
NODE_ENV: production
run: |
cd ${{ matrix.package }}
npm run build:version
- name: πŸ—οΈ Build Client
if: matrix.package == 'client'
env:
NODE_ENV: production
EXPO_PUBLIC_SUPABASE_URL: ${{ secrets.EXPO_PUBLIC_SUPABASE_URL }}
EXPO_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.EXPO_PUBLIC_SUPABASE_ANON_KEY }}
EXPO_PUBLIC_API_URL: http://56.228.14.41/api
EXPO_PUBLIC_APP_VERSION: ${{ github.ref_name }}
EXPO_PUBLIC_BUILD_NUMBER: ${{ github.run_number }}
EXPO_PUBLIC_BUILD_DATE: ${{ github.run_started_at }}
EXPO_PUBLIC_COMMIT_HASH: ${{ github.sha }}
EXPO_PUBLIC_BUILD_ENV: production
run: |
cd client
echo "\n--- ENVIRONMENT VARIABLES ---"
printenv | sort
echo "\n--- constants/api.ts ---"
cat constants/api.ts
echo "\n--- constants/version.ts ---"
cat constants/version.ts
echo "\n--- .env.local (if exists) ---"
if [ -f .env.local ]; then cat .env.local; else echo "(no .env.local)"; fi
npm run build:version
echo "\n--- constants/version.ts (after build-version) ---"
cat constants/version.ts
npm run build
- name: πŸ—οΈ Build Server
if: matrix.package == 'server'
run: |
cd server
npm run build
- name: πŸ“€ Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.package }}-build
path: |
${{ matrix.package }}/dist
${{ matrix.package }}/web/dist
${{ matrix.package }}/package.json
${{ matrix.package }}/package-lock.json
retention-days: 30
# Release with semantic versioning (only on main)
release:
name: πŸ”– Release
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
outputs:
new-release-published: ${{ steps.semantic.outputs.new-release-published }}
new-release-version: ${{ steps.semantic.outputs.new-release-version }}
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
persist-credentials: false
- name: πŸ“¦ Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
- name: πŸ“₯ Install Dependencies
run: npm ci
- name: πŸ”§ Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git
- name: πŸ”– Semantic Release
id: semantic
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GIT_AUTHOR_NAME: github-actions[bot]
GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
SEMANTIC_RELEASE: true
run: |
npm run release > semantic-release-output.txt 2>&1
cat semantic-release-output.txt
# Check if a new release was published
if grep -q "Published release" semantic-release-output.txt; then
echo "new-release-published=true" >> $GITHUB_OUTPUT
# Extract version from the output
VERSION=$(grep "Published release" semantic-release-output.txt | sed -n 's/.*Published release \([0-9.]*\).*/\1/p')
echo "new-release-version=$VERSION" >> $GITHUB_OUTPUT
echo "βœ… New release published: $VERSION"
else
echo "new-release-published=false" >> $GITHUB_OUTPUT
echo "No new release published"
fi
# Deploy to AWS (only if new release)
deploy:
name: πŸš€ Deploy
runs-on: ubuntu-latest
needs: release
if: needs.release.outputs.new-release-published == 'true'
environment: production
steps:
- name: πŸ“₯ Checkout
uses: actions/checkout@v3
- name: πŸ“₯ Download Build Artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: πŸ”§ Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}
# Deploy Client to S3
- name: 🌐 Deploy Client to S3
run: |
if [ -d "./artifacts/client-build/web/dist" ]; then
aws s3 sync ./artifacts/client-build/web/dist/ s3://${{ secrets.S3_BUCKET }} --delete
echo "βœ… Client deployed to S3"
else
echo "❌ Client build not found"
fi
# Deploy Server to EC2
- name: πŸ“¦ Build Server Docker Image
run: |
cd server
# Update package-lock.json to fix npm ci sync issues
rm -f package-lock.json
npm install --package-lock-only
docker build -t lab1-todoapp-server:${{ needs.release.outputs.new-release-version }} --target production .
docker save lab1-todoapp-server:${{ needs.release.outputs.new-release-version }} | gzip > lab1-todoapp-server.tar.gz
- name: πŸš€ Deploy Server to EC2
uses: appleboy/[email protected]
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
source: 'server/lab1-todoapp-server.tar.gz'
target: '/home/ubuntu/'
- name: πŸ”„ Update Server on EC2
uses: appleboy/[email protected]
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_PRIVATE_KEY }}
script: |
# Load new image
cd /home/ubuntu
sudo docker load < server/lab1-todoapp-server.tar.gz
# Stop and remove old container
sudo docker stop lab1-todoapp-server || true
sudo docker rm lab1-todoapp-server || true
# Run new container
sudo docker run -d \
--name lab1-todoapp-server \
--restart unless-stopped \
-p 80:3000 \
-e NODE_ENV=production \
-e PORT=3000 \
-e SUPABASE_DB_URL="${{ secrets.SUPABASE_DB_URL }}" \
-e SUPABASE_KEY="${{ secrets.SUPABASE_KEY }}" \
-e SUPABASE_URL="${{ secrets.SUPABASE_URL }}" \
-e ALLOWED_ORIGINS="http://56.228.14.41,https://lab1.warteamx.com,http://lab1-todoapp.s3-website.eu-north-1.amazonaws.com" \
lab1-todoapp-server:${{ needs.release.outputs.new-release-version }}
# Clean up old images
sudo docker image prune -f
- name: βœ… Deployment Summary
run: |
echo "πŸŽ‰ Deployment completed for version ${{ needs.release.outputs.new-release-version }}"
echo "🌐 Client: http://${{ secrets.S3_BUCKET }}.s3-website.eu-north-1.amazonaws.com"
echo "πŸ–₯️ Server: http://${{ secrets.EC2_HOST }}/api"
- name: πŸ” Health Check
run: |
sleep 30
if curl -f http://${{ secrets.EC2_HOST }}/api/health; then
echo "βœ… Server health check passed"
else
echo "❌ Server health check failed"
exit 1
fi