Skip to content

Commit 3d0e8ad

Browse files
authored
refactor(app): Merge pull request #65 from dev as a stable checkpoint
Dev
2 parents 50d1516 + fc044b1 commit 3d0e8ad

File tree

293 files changed

+49787
-22856
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

293 files changed

+49787
-22856
lines changed

.github/reviewer-map.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"MarioRaafat": ["AmiraKhalid04", "MoBahgat010"],
3+
"MoBahgat010": ["Alyaa242", "MarioRaafat"],
4+
"shady-2004": ["AmiraKhalid04", "MarioRaafat"],
5+
"Alyaa242": ["shady-2004", "MarioRaafat"],
6+
"AmiraKhalid04": ["MoBahgat010", "MarioRaafat"],
7+
"default": ["MarioRaafat"]
8+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Auto Assign Reviewers
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened, ready_for_review]
6+
7+
permissions:
8+
pull-requests: write
9+
contents: read
10+
11+
jobs:
12+
assign_reviewers:
13+
runs-on: ubuntu-latest
14+
if: github.event.pull_request.draft == false
15+
16+
steps:
17+
- name: checkout repo
18+
uses: actions/checkout@v4
19+
20+
- name: Load reviewers map
21+
id: reviewers
22+
run: |
23+
echo "map=$(cat .github/reviewer-map.json | jq -c .)" >> $GITHUB_OUTPUT
24+
25+
- name: Assign reviewers based on PR author
26+
uses: actions/github-script@v7
27+
with:
28+
github-token: ${{ secrets.GITHUB_TOKEN }}
29+
script: |
30+
const author = context.payload.pull_request.user.login;
31+
const map = JSON.parse(process.env.MAP);
32+
33+
let reviewers = map[author];
34+
if (!reviewers) {
35+
core.info(`⚠️ No reviewers defined for ${author}, Default assignment will be applied`)
36+
reviewers = map["default"];
37+
}
38+
39+
if (!reviewers || reviewers.length === 0) {
40+
core.warning(`❌ No default reviewers found in map. Skipping assignment.`);
41+
return;
42+
}
43+
44+
core.info(`Assigning reviewers: ${reviewers.join(', ')} for PR by ${author}`);
45+
46+
await github.rest.pulls.requestReviewers({
47+
owner: context.repo.owner,
48+
repo: context.repo.repo,
49+
pull_number: context.payload.pull_request.number,
50+
reviewers
51+
});
52+
env:
53+
MAP: ${{ steps.reviewers.outputs.map }}
54+

.github/workflows/ci.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [ main, dev ]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
11+
jobs:
12+
checks:
13+
runs-on: ubuntu-latest
14+
strategy:
15+
fail-fast: true
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
- name: Set up Node
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: 22
25+
cache: npm
26+
27+
- name: Install dependencies
28+
run: npm ci
29+
30+
# skip for now, until fixing all lintings, unit tests
31+
32+
# - name: Run ESLint
33+
# run: npm run lint
34+
35+
- name: Check Prettier format
36+
run: npx prettier --write "src/**/*.ts"
37+
38+
# - name: Run unit tests
39+
# run: npm run test:cov
40+
41+
- name: Upload coverage to PR
42+
uses: romeovs/lcov-reporter-action@v0.3.1
43+
with:
44+
lcov-file: ./coverage/lcov.info
45+

.github/workflows/deploy-dev.yml

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
name: Build, Tag & Deploy to Dev
2+
3+
on:
4+
push:
5+
branches:
6+
- dev
7+
8+
jobs:
9+
build-and-deploy:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout code
14+
uses: actions/checkout@v4
15+
16+
- name: Get latest tag from Docker Hub
17+
id: get_tag
18+
run: |
19+
# Fetch tags from Docker Hub
20+
REPO="${{ secrets.DOCKER_USERNAME }}/api-yapper-backend"
21+
22+
echo "🔍 Fetching tags from Docker Hub for $REPO..."
23+
24+
# Get Docker Hub token for authenticated API access
25+
TOKEN=$(curl -s -H "Content-Type: application/json" -X POST \
26+
-d '{"username": "${{ secrets.DOCKER_USERNAME }}", "password": "${{ secrets.DOCKER_PASSWORD }}"}' \
27+
https://hub.docker.com/v2/users/login/ | jq -r .token)
28+
29+
if [ "$TOKEN" = "null" ] || [ -z "$TOKEN" ]; then
30+
echo "❌ Failed to authenticate with Docker Hub"
31+
exit 1
32+
fi
33+
34+
# Get all tags from Docker Hub API
35+
TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" \
36+
"https://hub.docker.com/v2/repositories/$REPO/tags/?page_size=100" | \
37+
jq -r '.results[].name' | \
38+
grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | \
39+
sort -V | \
40+
tail -1)
41+
42+
# If no tags found, start with v0.0.0
43+
if [ -z "$TAGS" ]; then
44+
LATEST_TAG="v0.0.0"
45+
echo "⚠️ No version tags found on Docker Hub, starting from v0.0.0"
46+
else
47+
LATEST_TAG="$TAGS"
48+
echo "📦 Latest tag found on Docker Hub: $LATEST_TAG"
49+
fi
50+
51+
echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT
52+
53+
# Parse version components
54+
VERSION=${LATEST_TAG#v}
55+
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"
56+
57+
# Increment patch version
58+
PATCH=$((PATCH + 1))
59+
NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
60+
61+
echo "new_tag=$NEW_TAG" >> $GITHUB_OUTPUT
62+
echo "🚀 New version: $NEW_TAG"
63+
64+
- name: Log in to Docker Hub
65+
uses: docker/login-action@v3
66+
with:
67+
username: ${{ secrets.DOCKER_USERNAME }}
68+
password: ${{ secrets.DOCKER_PASSWORD }}
69+
70+
- name: Build and push Docker image
71+
uses: docker/build-push-action@v6
72+
with:
73+
context: .
74+
file: ./docker/Dockerfile
75+
76+
push: true
77+
tags: |
78+
${{ secrets.DOCKER_USERNAME }}/api-yapper-backend:${{ steps.get_tag.outputs.new_tag }}
79+
${{ secrets.DOCKER_USERNAME }}/api-yapper-backend:dev
80+
81+
- name: Confirm image push
82+
run: |
83+
echo "✅ Image pushed: ${{ secrets.DOCKER_USERNAME }}/api-yapper-backend:${{ steps.get_tag.outputs.new_tag }}"
84+
echo "✅ Image tagged: ${{ secrets.DOCKER_USERNAME }}/api-yapper-backend:dev"
85+
86+
- name: SSH into Dev VM and deploy
87+
uses: appleboy/ssh-action@v1.0.0
88+
env:
89+
IMG_TAG: ${{ steps.get_tag.outputs.new_tag }}
90+
with:
91+
host: ${{ secrets.DEV_SERVER_HOST }}
92+
username: ${{ secrets.DEV_SERVER_USER }}
93+
key: ${{ secrets.DEV_SERVER_SSH_KEY }}
94+
envs: IMG_TAG
95+
script: |
96+
set -e
97+
cd ~/yapper # path to your app on VM
98+
99+
echo "🧭 Getting current running image tag..."
100+
CURRENT_TAG=$(IMG_TAG="" docker compose ps -q api | xargs docker inspect -f '{{ index .Config.Labels "com.docker.compose.image" }}' | cut -d':' -f2 || echo "unknown")
101+
102+
echo "🐳 Setting new image tag for deployment..."
103+
echo "Deploying version: $IMG_TAG"
104+
105+
echo "🔄 Pulling new image and restarting app container..."
106+
IMG_TAG=$IMG_TAG docker compose pull api api-local
107+
IMG_TAG=$IMG_TAG docker compose up -d api api-local
108+
109+
echo "⏳ Waiting for health check..."
110+
sleep 10
111+
112+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" ${{ secrets.DEV_HEALTHCHECK_URL }})
113+
114+
if [ "$HTTP_CODE" = "200" ]; then
115+
echo "✅ Dev deployment successful for version $IMG_TAG"
116+
else
117+
echo "❌ Health check failed (HTTP $HTTP_CODE)! Rolling back app container..."
118+
if [ "$CURRENT_TAG" != "unknown" ]; then
119+
IMG_TAG=$CURRENT_TAG docker compose up -d api api-local
120+
echo "🔙 Rolled back to $CURRENT_TAG"
121+
fi
122+
exit 1
123+
fi
124+
125+
- name: Deployment summary
126+
if: success()
127+
run: |
128+
echo "🎉 Deployment Complete!"
129+
echo "Version: ${{ steps.get_tag.outputs.new_tag }}"
130+
echo "Branch: dev"
131+
echo "Commit: ${{ github.sha }}"

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,5 @@ pids
5656

5757
# Diagnostic reports (https://nodejs.org/api/report.html)
5858
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
59+
60+
dist

.husky/commit-msg

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
msg_file=$1
2+
msg=$(cat "$msg_file")
3+
4+
# Conventional commits rule
5+
if ! echo "$msg" | grep -Eq "^(feat|fix|chore|docs|refactor|test|style|perf|ci)\(.+\): .+"; then
6+
echo "❌ Invalid commit message format!"
7+
echo "👉 Example: feat(auth): add login endpoint"
8+
exit 1
9+
fi

.husky/pre-commit

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
echo "🔍 Running pre-commit checks..."
2+
npx lint-staged

.husky/pre-push

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
3+
branch_name=$(git symbolic-ref --short HEAD)
4+
5+
echo "$branch_name" | grep -Eq '^(feat|fix|chore|hotfix|docs|ci|test)/[a-z0-9._-]+$'
6+
if [ $? -ne 0 ]; then
7+
echo "❌ Invalid branch name: $branch_name"
8+
echo "👉 Branch name must start with feat/, fix/, chore/, docs/, ci/, test/ or hotfix/ (e.g. feat/signup-page)"
9+
exit 1
10+
fi

.prettierrc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
{
2+
"semi": true,
3+
"trailingComma": "es5",
24
"singleQuote": true,
3-
"trailingComma": "all"
4-
}
5+
"printWidth": 100,
6+
"tabWidth": 4,
7+
"useTabs": false,
8+
"arrowParens": "always",
9+
"endOfLine": "lf",
10+
"bracketSpacing": true,
11+
"bracketSameLine": false
12+
}

Dockerfile

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)