Skip to content

Commit 714f937

Browse files
committed
Initial commit
0 parents  commit 714f937

23 files changed

Lines changed: 5007 additions & 0 deletions

.dockerignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules
2+
.dist
3+
/dist
4+
npm-debug.log
5+
.DS_Store
6+
.git
7+
.gitignore

.github/workflows/ci.yml

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
types: [opened, reopened, synchronize, closed]
8+
release:
9+
types: [published]
10+
11+
permissions:
12+
contents: read
13+
packages: write
14+
15+
jobs:
16+
test-and-build:
17+
runs-on: ubuntu-latest
18+
env:
19+
GITOPS_REPO: ${{ vars.GITOPS_REPO }}
20+
APP_NAME: ${{ vars.APP_NAME }}
21+
IMAGE_TAG: ${{ github.sha }}
22+
VALUES_ENV: ${{ github.event_name == 'release' && 'prod' || 'test' }}
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
27+
- name: Resolve image tag for release
28+
if: github.event_name == 'release'
29+
run: |
30+
echo "IMAGE_TAG=$(git rev-parse HEAD)" >> "$GITHUB_ENV"
31+
32+
- name: Setup Node
33+
uses: actions/setup-node@v4
34+
with:
35+
node-version: 20
36+
cache: "npm"
37+
38+
- name: Install deps
39+
run: npm ci
40+
41+
- name: Run tests
42+
run: npm test
43+
44+
- name: Set up Docker Buildx
45+
if: github.event_name != 'release' && (github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.head.repo.fork == false))
46+
uses: docker/setup-buildx-action@v3
47+
48+
- name: Set up QEMU
49+
if: github.event_name != 'release' && (github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.head.repo.fork == false))
50+
uses: docker/setup-qemu-action@v3
51+
52+
- name: Log in to GHCR
53+
if: github.event_name != 'release' && (github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.head.repo.fork == false))
54+
uses: docker/login-action@v3
55+
with:
56+
registry: ghcr.io
57+
username: ${{ github.actor }}
58+
password: ${{ secrets.GITHUB_TOKEN }}
59+
60+
- name: Build and push image
61+
if: github.event_name != 'release' && (github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.head.repo.fork == false))
62+
id: build
63+
uses: docker/build-push-action@v6
64+
with:
65+
context: .
66+
push: true
67+
platforms: linux/amd64,linux/arm64
68+
tags: |
69+
ghcr.io/${{ github.repository }}:${{ env.IMAGE_TAG }}
70+
labels: |
71+
org.opencontainers.image.source=${{ github.repository }}
72+
org.opencontainers.image.revision=${{ github.sha }}
73+
74+
- name: Checkout GitOps repo
75+
if: github.event_name == 'push' || github.event_name == 'release' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false)
76+
uses: actions/checkout@v4
77+
with:
78+
repository: ${{ env.GITOPS_REPO }}
79+
token: ${{ secrets.GITOPS_TOKEN }}
80+
path: gitops
81+
82+
- name: Update GitOps values
83+
if: github.event_name == 'push' || github.event_name == 'release'
84+
run: |
85+
VALUES_PATH="gitops/environments/${{ env.VALUES_ENV }}/values.yaml"
86+
mkdir -p "$(dirname "$VALUES_PATH")"
87+
if [ ! -f "$VALUES_PATH" ]; then
88+
printf '%s\n' \
89+
"image:" \
90+
" repository: ghcr.io/${{ github.repository }}" \
91+
" tag: ${{ env.IMAGE_TAG }}" \
92+
> "$VALUES_PATH"
93+
fi
94+
sed -i -E "s#^([[:space:]]*repository:).*#\\1 ghcr.io/${{ github.repository }}#" "$VALUES_PATH" || true
95+
sed -i -E "s#^([[:space:]]*tag:).*#\\1 ${{ env.IMAGE_TAG }}#" "$VALUES_PATH" || true
96+
git -C gitops status --short
97+
98+
- name: Commit and push GitOps changes
99+
if: github.event_name == 'push' || github.event_name == 'release'
100+
run: |
101+
cd gitops
102+
git config user.name "github-actions[bot]"
103+
git config user.email "github-actions[bot]@users.noreply.github.com"
104+
git add "environments/${{ env.VALUES_ENV }}/values.yaml"
105+
if git diff --cached --quiet; then
106+
echo "No GitOps changes to commit."
107+
exit 0
108+
fi
109+
git commit -m "chore: update ${APP_NAME} image tag to ${{ env.IMAGE_TAG }}"
110+
git push
111+
112+
- name: Update GitOps PR values
113+
if: github.event_name == 'pull_request' && github.event.action != 'closed' && github.event.pull_request.head.repo.fork == false
114+
run: |
115+
PR_NAMESPACE="pr-${{ github.event.pull_request.number }}"
116+
PR_RESOURCE_NAME="${APP_NAME}-${PR_NAMESPACE}"
117+
VALUES_PATH="gitops/environments/dev/${PR_NAMESPACE}/values.yaml"
118+
mkdir -p "$(dirname "$VALUES_PATH")"
119+
if [ ! -f "$VALUES_PATH" ]; then
120+
printf '%s\n' \
121+
"namespace: ${PR_NAMESPACE}" \
122+
"deploymentName: ${PR_RESOURCE_NAME}" \
123+
"serviceName: ${PR_RESOURCE_NAME}" \
124+
"image:" \
125+
" repository: ghcr.io/${{ github.repository }}" \
126+
" tag: ${{ env.IMAGE_TAG }}" \
127+
> "$VALUES_PATH"
128+
fi
129+
sed -i -E "s#^([[:space:]]*namespace:).*#\\1 ${PR_NAMESPACE}#" "$VALUES_PATH" || true
130+
sed -i -E "s#^([[:space:]]*deploymentName:).*#\\1 ${PR_RESOURCE_NAME}#" "$VALUES_PATH" || true
131+
sed -i -E "s#^([[:space:]]*serviceName:).*#\\1 ${PR_RESOURCE_NAME}#" "$VALUES_PATH" || true
132+
grep -qE '^[[:space:]]*deploymentName:' "$VALUES_PATH" || echo "deploymentName: ${PR_RESOURCE_NAME}" >> "$VALUES_PATH"
133+
grep -qE '^[[:space:]]*serviceName:' "$VALUES_PATH" || echo "serviceName: ${PR_RESOURCE_NAME}" >> "$VALUES_PATH"
134+
sed -i -E "s#^([[:space:]]*repository:).*#\\1 ghcr.io/${{ github.repository }}#" "$VALUES_PATH" || true
135+
sed -i -E "s#^([[:space:]]*tag:).*#\\1 ${{ env.IMAGE_TAG }}#" "$VALUES_PATH" || true
136+
git -C gitops status --short
137+
138+
- name: Commit and push GitOps PR values
139+
if: github.event_name == 'pull_request' && github.event.action != 'closed' && github.event.pull_request.head.repo.fork == false
140+
run: |
141+
cd gitops
142+
git config user.name "github-actions[bot]"
143+
git config user.email "github-actions[bot]@users.noreply.github.com"
144+
git add "environments/dev/pr-${{ github.event.pull_request.number }}/values.yaml"
145+
if git diff --cached --quiet; then
146+
echo "No PR values changes to commit."
147+
exit 0
148+
fi
149+
git commit -m "chore: update ${APP_NAME} PR-${{ github.event.pull_request.number }} values"
150+
git push
151+
152+
- name: Delete GitOps PR environment
153+
if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.head.repo.fork == false
154+
run: |
155+
PR_DIR="gitops/environments/dev/pr-${{ github.event.pull_request.number }}"
156+
if [ -d "$PR_DIR" ]; then
157+
rm -rf "$PR_DIR"
158+
fi
159+
git -C gitops status --short
160+
161+
- name: Commit and push GitOps PR cleanup
162+
if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.head.repo.fork == false
163+
run: |
164+
cd gitops
165+
git config user.name "github-actions[bot]"
166+
git config user.email "github-actions[bot]@users.noreply.github.com"
167+
git add -A "environments/dev/pr-${{ github.event.pull_request.number }}"
168+
if git diff --cached --quiet; then
169+
echo "No PR environment changes to commit."
170+
exit 0
171+
fi
172+
git commit -m "chore: remove ${APP_NAME} PR-${{ github.event.pull_request.number }} environment"
173+
git push
174+
175+
helm-publish:
176+
runs-on: ubuntu-latest
177+
steps:
178+
- name: Checkout
179+
uses: actions/checkout@v4
180+
with:
181+
fetch-depth: 0
182+
183+
- name: Check chart changes
184+
id: chart_changes
185+
run: |
186+
if git diff --name-only HEAD~1 | grep -q "^chart/"; then
187+
echo "changed=true" >> "$GITHUB_OUTPUT"
188+
else
189+
echo "changed=false" >> "$GITHUB_OUTPUT"
190+
fi
191+
192+
- name: Setup Helm
193+
if: steps.chart_changes.outputs.changed == 'true'
194+
uses: azure/setup-helm@v4
195+
196+
- name: Log in to GHCR for Helm
197+
if: steps.chart_changes.outputs.changed == 'true'
198+
run: |
199+
helm registry login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}
200+
201+
- name: Package and push Helm chart
202+
if: steps.chart_changes.outputs.changed == 'true'
203+
run: |
204+
helm package chart --destination .
205+
CHART_TGZ="$(ls -1 *.tgz | head -1)"
206+
helm push "$CHART_TGZ" oci://ghcr.io/${{ github.repository }}

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules
2+
.DS_Store
3+
/dist
4+
.env
5+
.env.local
6+
.env.*.local
7+
npm-debug.log*

Dockerfile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Build stage
2+
FROM node:20-alpine AS builder
3+
WORKDIR /app
4+
5+
COPY package.json package-lock.json* ./
6+
RUN npm install
7+
8+
COPY . .
9+
RUN npm run build
10+
11+
# Runtime stage
12+
FROM nginx:alpine
13+
14+
COPY --from=builder /app/dist /usr/share/nginx/html
15+
16+
# SPA fallback for client-side routing (safe even for single page)
17+
RUN printf 'server {\n listen 80;\n server_name _;\n root /usr/share/nginx/html;\n index index.html;\n location / {\n try_files $uri $uri/ /index.html;\n }\n}\n' > /etc/nginx/conf.d/default.conf
18+
19+
EXPOSE 80
20+
CMD ["nginx", "-g", "daemon off;"]

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# challenge-app

chart/Chart.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: v2
2+
name: challenge-app-chart
3+
description: Helm chart for the Hitachi challenge app
4+
type: application
5+
version: 0.1.1
6+
appVersion: "1.0.0"

chart/templates/deployment.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: {{ .Values.deploymentName }}
5+
namespace: {{ .Values.namespace }}
6+
spec:
7+
replicas: {{ .Values.replicaCount }}
8+
selector:
9+
matchLabels:
10+
app: {{ .Values.deploymentName }}
11+
template:
12+
metadata:
13+
labels:
14+
app: {{ .Values.deploymentName }}
15+
spec:
16+
containers:
17+
- name: app
18+
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
19+
imagePullPolicy: {{ .Values.image.pullPolicy }}
20+
ports:
21+
- containerPort: {{ .Values.containerPort }}

chart/templates/namespace.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
apiVersion: v1
2+
kind: Namespace
3+
metadata:
4+
name: {{ .Values.namespace }}

chart/templates/service.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: {{ .Values.serviceName }}
5+
namespace: {{ .Values.namespace }}
6+
spec:
7+
type: {{ .Values.service.type }}
8+
selector:
9+
app: {{ .Values.deploymentName }}
10+
ports:
11+
- name: http
12+
port: {{ .Values.service.port }}
13+
targetPort: {{ .Values.service.targetPort }}
14+
{{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }}
15+
nodePort: {{ .Values.service.nodePort }}
16+
{{- end }}

chart/values.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
name: challenge-app
2+
namespace: challenge-app
3+
deploymentName: challenge-app
4+
serviceName: challenge-app
5+
6+
replicaCount: 1
7+
8+
image:
9+
repository: ghcr.io/bl4ckj4c/challenge-app
10+
pullPolicy: IfNotPresent
11+
12+
containerPort: 80
13+
14+
service:
15+
type: NodePort
16+
port: 80
17+
targetPort: 80
18+
# Leave unset to let Kubernetes auto-assign a NodePort.
19+
# nodePort: 30080

0 commit comments

Comments
 (0)