Skip to content

Commit d69e30b

Browse files
committed
Update
1 parent 653f678 commit d69e30b

File tree

8 files changed

+263
-1
lines changed

8 files changed

+263
-1
lines changed

.github/dependabot.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
version: 2
2+
updates:
3+
# NPM (Angular app)
4+
- package-ecosystem: "npm"
5+
directory: "/"
6+
schedule:
7+
interval: "daily"
8+
time: "02:00"
9+
timezone: "Asia/Bangkok"
10+
open-pull-requests-limit: 10
11+
target-branch: "main"
12+
labels: ["dependencies", "npm"]
13+
allow:
14+
- dependency-type: "direct"
15+
- dependency-type: "all"
16+
ignore:
17+
# ví dụ giữ cố định major của Angular 19
18+
- dependency-name: "@angular/*"
19+
versions: [">=20"]
20+
21+
# GitHub Actions
22+
- package-ecosystem: "github-actions"
23+
directory: "/"
24+
schedule:
25+
interval: "weekly"
26+
day: "monday"
27+
time: "03:00"
28+
timezone: "Asia/Bangkok"
29+
labels: ["dependencies", "github-actions"]
30+
31+
# Docker base images (Nginx, Node…)
32+
- package-ecosystem: "docker"
33+
directory: "/docker"
34+
schedule:
35+
interval: "weekly"
36+
day: "tuesday"
37+
time: "04:00"
38+
timezone: "Asia/Bangkok"
39+
labels: ["dependencies", "docker"]
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
name: Frontend CI + Sonar
2+
3+
on:
4+
push:
5+
branches: ["**"]
6+
paths:
7+
- "src/**"
8+
- "package.json"
9+
- "package-lock.json"
10+
- "angular.json"
11+
- ".github/workflows/ci-sonar-angular.yml"
12+
- "sonar-project.properties"
13+
pull_request:
14+
15+
permissions:
16+
contents: read
17+
pull-requests: write
18+
19+
jobs:
20+
build-test-and-analyze:
21+
runs-on: ubuntu-latest
22+
env:
23+
NODE_VERSION: 20
24+
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
25+
CI: true
26+
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 0 # Sonar cần full history để tính blame
32+
33+
- name: Set up JDK (for Sonar scanner)
34+
uses: actions/setup-java@v4
35+
with:
36+
distribution: temurin
37+
java-version: "21"
38+
39+
- name: Set up Node
40+
uses: actions/setup-node@v4
41+
with:
42+
node-version: ${{ env.NODE_VERSION }}
43+
cache: "npm"
44+
45+
- name: Install Chrome (for Karma Headless)
46+
id: chrome
47+
uses: browser-actions/setup-chrome@v1
48+
49+
- name: Install dependencies
50+
run: npm ci
51+
52+
- name: Build (production)
53+
run: npm run build
54+
55+
- name: Unit Test + Coverage (Karma headless)
56+
env:
57+
CHROME_BIN: ${{ steps.chrome.outputs.chrome-path }}
58+
run: |
59+
# nếu bạn đã có cấu hình Karma CI riêng thì thay lệnh dưới bằng script đó
60+
npx ng test --watch=false --browsers=ChromeHeadless --code-coverage
61+
62+
- name: Upload coverage artifact
63+
if: always()
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: coverage-frontend
67+
path: coverage/**
68+
if-no-files-found: warn
69+
70+
# --- SonarCloud (mặc định) ---
71+
- name: SonarCloud Scan
72+
if: ${{ env.SONAR_HOST_URL == '' }}
73+
uses: SonarSource/sonarcloud-github-action@v2
74+
env:
75+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
76+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
77+
with:
78+
args: >
79+
-Dsonar.qualitygate.wait=true
80+
81+
# --- SonarQube self-hosted (nếu bạn set SONAR_HOST_URL) ---
82+
- name: SonarQube Scan (self-hosted)
83+
if: ${{ env.SONAR_HOST_URL != '' }}
84+
uses: SonarSource/sonarqube-scan-action@v4
85+
env:
86+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
87+
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
88+
with:
89+
args: >
90+
-Dsonar.qualitygate.wait=true
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: Frontend Docker Publish
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
tags: ["v*.*.*"]
7+
paths:
8+
- "src/**"
9+
- "angular.json"
10+
- "package.json"
11+
- "package-lock.json"
12+
- "docker/angular-frontend.Dockerfile"
13+
- "docker/nginx.conf"
14+
- ".github/workflows/frontend-docker-publish.yml"
15+
workflow_dispatch:
16+
17+
permissions:
18+
contents: read
19+
packages: write
20+
21+
env:
22+
DOCKER_REPO: ${{ secrets.DOCKERHUB_USER }}/codecampus-frontend
23+
DOCKERFILE_PATH: docker/angular-frontend.Dockerfile
24+
PLATFORMS: linux/amd64
25+
26+
jobs:
27+
build-and-push:
28+
runs-on: ubuntu-latest
29+
30+
steps:
31+
- name: Checkout
32+
uses: actions/checkout@v4
33+
34+
- name: Set up QEMU
35+
uses: docker/setup-qemu-action@v3
36+
37+
- name: Set up Buildx
38+
uses: docker/setup-buildx-action@v3
39+
40+
- name: Derive tags
41+
id: meta
42+
run: |
43+
TAGS=""
44+
if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
45+
VERSION="${GITHUB_REF_NAME#v}"
46+
echo "IMAGE_TAG=${VERSION}" >> $GITHUB_ENV
47+
TAGS="${{ env.DOCKER_REPO }}:${VERSION}"
48+
else
49+
SHA_TAG="${GITHUB_SHA::12}"
50+
echo "IMAGE_TAG=${SHA_TAG}" >> $GITHUB_ENV
51+
TAGS="${{ env.DOCKER_REPO }}:${SHA_TAG}"
52+
if [ "${GITHUB_REF_NAME}" = "main" ]; then
53+
TAGS="${TAGS},${{ env.DOCKER_REPO }}:latest"
54+
fi
55+
fi
56+
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
57+
58+
- name: Login to Docker Hub
59+
uses: docker/login-action@v3
60+
with:
61+
username: ${{ secrets.DOCKERHUB_USER }}
62+
password: ${{ secrets.DOCKERHUB_TOKEN }}
63+
64+
- name: Build & Push
65+
uses: docker/build-push-action@v6
66+
with:
67+
context: .
68+
file: ${{ env.DOCKERFILE_PATH }}
69+
platforms: ${{ env.PLATFORMS }}
70+
push: true
71+
tags: ${{ steps.meta.outputs.tags }}
72+
cache-from: type=gha
73+
cache-to: type=gha,mode=max

docker/angular-frontend.Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# ====== Build stage ======
2+
FROM node:20-alpine AS build
3+
WORKDIR /app
4+
5+
# Copy & install
6+
COPY package*.json ./
7+
RUN npm ci
8+
9+
# Copy source & build
10+
COPY . .
11+
# Angular 19 đã default prod; nhưng dùng cấu hình production vẫn OK
12+
RUN npm run build
13+
14+
# ====== Runtime stage ======
15+
FROM nginx:1.27-alpine
16+
# file Nginx phục vụ SPA & fallback
17+
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
18+
# copy artefact Angular
19+
COPY --from=build /app/dist/codecampus /usr/share/nginx/html
20+
21+
EXPOSE 80
22+
CMD ["nginx", "-g", "daemon off;"]

docker/nginx.conf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
server {
2+
listen 80;
3+
server_name _;
4+
5+
root /usr/share/nginx/html;
6+
index index.html;
7+
8+
# Cache tĩnh nhẹ nhàng
9+
location ~* \.(?:js|css|png|jpg|jpeg|gif|svg|ico|woff2?)$ {
10+
try_files $uri =404;
11+
add_header Cache-Control "public, max-age=31536000, immutable";
12+
}
13+
14+
# SPA fallback
15+
location / {
16+
try_files $uri $uri/ /index.html;
17+
}
18+
}

karma.conf.js

Whitespace-only changes.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"start": "ng serve",
77
"build": "ng build",
88
"watch": "ng build --watch --configuration development",
9-
"test": "ng test"
9+
"test": "ng test",
10+
"test:ci": "ng test --watch=false --browsers=ChromeHeadless --code-coverage"
1011
},
1112
"private": true,
1213
"dependencies": {

sonar-project.properties

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# ==== Sonar basics ====
2+
sonar.projectKey=cc7b85d74edf7c1d0ceb639e2a0f9c44da3b1a55
3+
sonar.projectName=Codecampus-project
4+
sonar.projectVersion=1.0
5+
sonar.organization=capstone-project-cmc-uni
6+
7+
sonar.sourceEncoding=UTF-8
8+
9+
# ==== Sources / Tests ====
10+
sonar.sources=src
11+
sonar.tests=src
12+
sonar.test.inclusions=**/*.spec.ts
13+
14+
# Loại trừ những file không cần phân tích
15+
sonar.exclusions=dist/**,node_modules/**,**/*.spec.ts,**/*.stories.ts,**/*.mock.ts,**/*.module.ts,**/environment*.ts,**/*.generated.ts
16+
17+
# ==== TypeScript / Coverage ====
18+
sonar.typescript.tsconfigPath=tsconfig.app.json
19+
sonar.javascript.lcov.reportPaths=coverage/codecampus/lcov.info

0 commit comments

Comments
 (0)