Skip to content

Commit d9e93d8

Browse files
committed
feat: add Docker support and GHCR CI/CD
1 parent 75a28a0 commit d9e93d8

File tree

9 files changed

+191
-174
lines changed

9 files changed

+191
-174
lines changed

.dockerignore

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Dependencies
2+
node_modules/
3+
.pnp
4+
.pnp.js
5+
6+
# Build artifacts
7+
.output/
8+
.nuxt/
9+
dist/
10+
build/
11+
12+
# Development files
13+
.env
14+
.env.*
15+
!.env.example
16+
17+
# Logs
18+
*.log
19+
npm-debug.log*
20+
pnpm-debug.log*
21+
yarn-debug.log*
22+
yarn-error.log*
23+
bun-debug.log*
24+
25+
# Testing
26+
coverage/
27+
.nyc_output/
28+
*.test.ts
29+
*.test.js
30+
*.spec.ts
31+
*.spec.js
32+
__tests__/
33+
test/
34+
tests/
35+
36+
# IDE and editor files
37+
.vscode/
38+
.idea/
39+
*.swp
40+
*.swo
41+
*.swn
42+
*.bak
43+
.DS_Store
44+
.project
45+
.classpath
46+
.c9/
47+
*.launch
48+
.settings/
49+
*.sublime-workspace
50+
51+
# Version control
52+
.git/
53+
.gitignore
54+
.gitattributes
55+
.github/
56+
57+
# CI/CD
58+
.gitlab-ci.yml
59+
.travis.yml
60+
.circleci/
61+
azure-pipelines.yml
62+
63+
# Documentation (optional, comment out if you want to include docs)
64+
README.md
65+
CHANGELOG.md
66+
LICENSE
67+
CONTRIBUTING.md
68+
*.md
69+
70+
# Docker files
71+
Dockerfile*
72+
docker-compose*.yml
73+
.dockerignore
74+
75+
# Temporary files
76+
tmp/
77+
temp/
78+
.tmp/
79+
.temp/
80+
81+
# OS files
82+
Thumbs.db
83+
Desktop.ini
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Docker Image CI
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository }}
11+
12+
jobs:
13+
build-and-push:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
packages: write
18+
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v5
22+
23+
- name: Set up Docker Buildx
24+
uses: docker/setup-buildx-action@v3
25+
26+
- name: Log in to GitHub Container Registry
27+
uses: docker/login-action@v3
28+
with:
29+
registry: ${{ env.REGISTRY }}
30+
username: ${{ github.actor }}
31+
password: ${{ secrets.GITHUB_TOKEN }}
32+
33+
- name: Extract metadata (tags, labels)
34+
id: meta
35+
uses: docker/metadata-action@v5
36+
with:
37+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
38+
tags: |
39+
type=semver,pattern={{version}}
40+
type=semver,pattern={{major}}.{{minor}}
41+
type=semver,pattern={{major}},enable=${{ !contains(github.ref, '-') }}
42+
type=raw,value=latest,enable=${{ !contains(github.ref, '-') }}
43+
labels: |
44+
org.opencontainers.image.title=Registry UI
45+
org.opencontainers.image.description=Docker Registry UI - Web interface for Docker Registry
46+
org.opencontainers.image.vendor=${{ github.repository_owner }}
47+
48+
- name: Build and push Docker image
49+
uses: docker/build-push-action@v6
50+
with:
51+
context: .
52+
push: true
53+
tags: ${{ steps.meta.outputs.tags }}
54+
labels: ${{ steps.meta.outputs.labels }}
55+
cache-from: type=gha
56+
cache-to: type=gha,mode=max
57+
platforms: linux/amd64,linux/arm64

.husky/commit-msg

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

Dockerfile

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# syntax=docker/dockerfile:1
2+
3+
# Base stage with common workdir
4+
FROM oven/bun:1 AS base
5+
WORKDIR /usr/src/app
6+
7+
# Dependencies installation with cache mount
8+
FROM base AS deps
9+
COPY package.json bun.lock ./
10+
RUN --mount=type=cache,target=/root/.bun/install/cache \
11+
bun install --frozen-lockfile
12+
13+
# Build stage
14+
FROM base AS build
15+
COPY --from=deps /usr/src/app/node_modules ./node_modules
16+
COPY . .
17+
ENV NODE_ENV=production
18+
RUN bun run build
19+
20+
# Production release
21+
FROM node:22-alpine AS release
22+
WORKDIR /usr/src/app
23+
24+
COPY --from=build /usr/src/app/.output ./
25+
26+
ENV NODE_ENV=production \
27+
HOST=0.0.0.0 \
28+
PORT=3000
29+
30+
USER node
31+
EXPOSE 3000
32+
33+
HEALTHCHECK --interval=10s --timeout=3s --start-period=10s --retries=3 \
34+
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
35+
36+
CMD ["node", "server/index.mjs"]

bun.lock

Lines changed: 7 additions & 117 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

commitlint.config.js

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

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "nuxt-boilerplate",
2+
"name": "registry-ui",
33
"private": true,
44
"version": "3.0.1",
55
"type": "module",
@@ -20,8 +20,6 @@
2020
"prepare": "husky"
2121
},
2222
"devDependencies": {
23-
"@commitlint/cli": "^20.1.0",
24-
"@commitlint/config-conventional": "^20.0.0",
2523
"@dargmuesli/nuxt-cookie-control": "^9.1.5",
2624
"@nuxt/eslint": "^1.6.0",
2725
"@nuxt/icon": "^2.0.0",

server/api/health.get.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default defineEventHandler(() => {
2+
return {
3+
status: 'healthy',
4+
timestamp: new Date().toISOString(),
5+
}
6+
})

server/utils/validation.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,7 @@ export const envSchema = z.object({
4040
.optional()
4141
.transform(val => (val ? Number(val) : undefined)),
4242

43-
HOST: z
44-
.string()
45-
.default('127.0.0.1')
46-
.refine(
47-
val => {
48-
// In production, enforce localhost binding for security
49-
if (process.env.NODE_ENV === 'production' && val !== '127.0.0.1') {
50-
return false
51-
}
52-
return true
53-
},
54-
{
55-
message:
56-
'HOST must be 127.0.0.1 in production for security (only expose via reverse proxy)',
57-
}
58-
),
43+
HOST: z.string().default('127.0.0.1'),
5944

6045
PORT: z
6146
.string()

0 commit comments

Comments
 (0)