Skip to content

Commit 538e3ba

Browse files
committed
initial commit
0 parents  commit 538e3ba

33 files changed

+6317
-0
lines changed

.dockerignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
node_modules
2+
npm-debug.log
3+
.git
4+
.gitignore
5+
README.md
6+
.env
7+
.env.*
8+
.vscode
9+
.idea
10+
coverage
11+
.nyc_output
12+
.DS_Store
13+
*.log
14+
dist
15+
data/*.db
16+
.github

.env.example

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Server Configuration
2+
HOST=0.0.0.0
3+
PORT=3000
4+
5+
# Environment
6+
NODE_ENV=development
7+
8+
# Logging
9+
LOG_LEVEL=info
10+
11+
# Database
12+
DB_PATH=./data/app.db
13+
14+
# CORS
15+
CORS_ORIGIN=http://localhost:3000

.github/workflows/ci.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [18.x, 20.x]
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
- name: Use Node.js ${{ matrix.node-version }}
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
26+
- name: Install dependencies
27+
run: npm ci
28+
29+
- name: Build TypeScript
30+
run: npm run build
31+
32+
- name: Run linter
33+
run: npm run lint
34+
35+
- name: Check formatting
36+
run: npm run format:check
37+
38+
- name: Run tests
39+
run: npm test
40+
41+
- name: Test Docker build
42+
run: docker build -t test-build .

.github/workflows/release.yml

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
inputs:
9+
version:
10+
description: 'Version to release (e.g., 1.0.0, minor, major, patch)'
11+
required: true
12+
default: 'patch'
13+
14+
permissions:
15+
contents: write
16+
packages: write
17+
18+
jobs:
19+
release:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- name: Checkout code
23+
uses: actions/checkout@v4
24+
with:
25+
fetch-depth: 0
26+
token: ${{ secrets.GITHUB_TOKEN }}
27+
28+
- name: Set up Node.js
29+
uses: actions/setup-node@v4
30+
with:
31+
node-version: '20'
32+
33+
- name: Configure Git
34+
run: |
35+
git config user.name "github-actions[bot]"
36+
git config user.email "github-actions[bot]@users.noreply.github.com"
37+
38+
- name: Determine version
39+
id: version
40+
run: |
41+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
42+
VERSION_INPUT="${{ github.event.inputs.version }}"
43+
else
44+
VERSION_INPUT="patch"
45+
fi
46+
47+
# Check if input is a semantic version
48+
if [[ "$VERSION_INPUT" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
49+
npm version $VERSION_INPUT --no-git-tag-version
50+
else
51+
npm version $VERSION_INPUT --no-git-tag-version
52+
fi
53+
54+
NEW_VERSION=$(node -p "require('./package.json').version")
55+
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
56+
57+
- name: Commit version bump
58+
run: |
59+
git add package.json package-lock.json
60+
git commit -m "chore: bump version to ${{ steps.version.outputs.version }}"
61+
git push
62+
63+
- name: Create and push tag
64+
run: |
65+
git tag -a "v${{ steps.version.outputs.version }}" -m "Release v${{ steps.version.outputs.version }}"
66+
git push origin "v${{ steps.version.outputs.version }}"
67+
68+
- name: Create GitHub Release
69+
uses: actions/create-release@v1
70+
env:
71+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
72+
with:
73+
tag_name: v${{ steps.version.outputs.version }}
74+
release_name: Release v${{ steps.version.outputs.version }}
75+
body: |
76+
Release v${{ steps.version.outputs.version }}
77+
78+
## What's Changed
79+
See the [commit history](https://github.com/${{ github.repository }}/compare/v${{ steps.version.outputs.version }}...HEAD) for details.
80+
draft: false
81+
prerelease: false
82+
83+
docker:
84+
needs: release
85+
runs-on: ubuntu-latest
86+
steps:
87+
- name: Checkout code
88+
uses: actions/checkout@v4
89+
with:
90+
ref: main
91+
92+
- name: Get version from package.json
93+
id: package
94+
run: |
95+
VERSION=$(node -p "require('./package.json').version")
96+
echo "version=$VERSION" >> $GITHUB_OUTPUT
97+
98+
- name: Set up Docker Buildx
99+
uses: docker/setup-buildx-action@v3
100+
101+
- name: Log in to GitHub Container Registry
102+
uses: docker/login-action@v3
103+
with:
104+
registry: ghcr.io
105+
username: ${{ github.actor }}
106+
password: ${{ secrets.GITHUB_TOKEN }}
107+
108+
- name: Extract metadata
109+
id: meta
110+
uses: docker/metadata-action@v5
111+
with:
112+
images: ghcr.io/${{ github.repository }}
113+
tags: |
114+
type=raw,value=${{ steps.package.outputs.version }}
115+
type=raw,value=latest
116+
type=sha,prefix={{branch}}-
117+
118+
- name: Build and push Docker image
119+
uses: docker/build-push-action@v5
120+
with:
121+
context: .
122+
push: true
123+
tags: ${{ steps.meta.outputs.tags }}
124+
labels: ${{ steps.meta.outputs.labels }}
125+
cache-from: type=gha
126+
cache-to: type=gha,mode=max
127+
platforms: linux/amd64,linux/arm64

.gitignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
node_modules/
2+
dist/
3+
data/*.db
4+
.env
5+
.env.*
6+
!.env.example
7+
npm-debug.log*
8+
yarn-debug.log*
9+
yarn-error.log*
10+
.DS_Store
11+
*.log
12+
coverage/
13+
.nyc_output/
14+
.vscode/
15+
.idea/
16+
*.swp
17+
*.swo
18+
*~
19+
.claude

.prettierignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules
2+
dist
3+
coverage
4+
*.md
5+
*.json
6+
*.yml
7+
*.yaml
8+
public/index.html

.prettierrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"semi": false,
3+
"singleQuote": true,
4+
"tabWidth": 2,
5+
"trailingComma": "es5",
6+
"printWidth": 100,
7+
"arrowParens": "always"
8+
}

Dockerfile

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Build stage
2+
FROM node:20-alpine AS builder
3+
4+
WORKDIR /app
5+
6+
# Copy package files
7+
COPY package*.json ./
8+
9+
# Install dependencies
10+
RUN npm ci
11+
12+
# Copy source files
13+
COPY tsconfig.json ./
14+
COPY src ./src
15+
16+
# Build TypeScript
17+
RUN npm run build
18+
19+
# Production stage
20+
FROM node:20-alpine
21+
22+
WORKDIR /app
23+
24+
# Copy package files
25+
COPY package*.json ./
26+
27+
# Install production dependencies only
28+
RUN npm ci --omit=dev && npm cache clean --force
29+
30+
# Copy built application
31+
COPY --from=builder /app/dist ./dist
32+
33+
# Copy public directory for UI
34+
COPY public ./public
35+
36+
# Create data directory
37+
RUN mkdir -p /app/data
38+
39+
# Create non-root user
40+
RUN addgroup -g 1001 -S nodejs && \
41+
adduser -S nodejs -u 1001
42+
43+
# Change ownership
44+
RUN chown -R nodejs:nodejs /app
45+
46+
USER nodejs
47+
48+
# Expose port
49+
EXPOSE 3000
50+
51+
# Health check
52+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
53+
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
54+
55+
# Start the application
56+
CMD ["node", "dist/server.js"]

Dockerfile.dev

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM node:20-alpine
2+
3+
WORKDIR /app
4+
5+
# Install dependencies
6+
COPY package*.json ./
7+
RUN npm ci
8+
9+
# Install wget for healthcheck
10+
RUN apk add --no-cache wget
11+
12+
# Create data directory
13+
RUN mkdir -p /app/data
14+
15+
# Expose port
16+
EXPOSE 3000
17+
18+
# Start the application in dev mode
19+
CMD ["npm", "run", "dev"]

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Fastify CRUD App
2+
3+
A demo TypeScript REST API built with Fastify and SQLite, designed to test GitHub Actions workflows for automated version tagging and Docker image publishing to GitHub Container Registry (ghcr.io).
4+
5+
## Quick Start
6+
7+
### Local Development
8+
```bash
9+
# Install dependencies
10+
npm install
11+
12+
# Copy environment variables
13+
cp .env.example .env
14+
15+
# Start development server
16+
npm run dev # Development at http://localhost:3000
17+
18+
# Populate sample data
19+
npm run seed
20+
```
21+
22+
### Docker
23+
```bash
24+
# Using docker-compose
25+
docker-compose up
26+
27+
# Or build and run manually
28+
docker build -t fastify-crud-app .
29+
docker run -p 3000:3000 -v $(pwd)/data:/app/data fastify-crud-app
30+
```
31+
32+
Visit http://localhost:3000 for the web UI or http://localhost:3000/docs for API documentation.
33+
34+
## GitHub Release Workflow
35+
36+
Push to main or manually trigger the workflow to:
37+
1. Bump version in package.json
38+
2. Create git tag and GitHub release
39+
3. Build and publish multi-arch Docker image to ghcr.io
40+
41+
```bash
42+
# Run with docker-compose (includes volume for persistent data)
43+
docker-compose up
44+
45+
# Or pull from registry
46+
docker pull ghcr.io/[username]/fastify-crud-app:latest
47+
docker run -p 3000:3000 -v $(pwd)/data:/app/data ghcr.io/[username]/fastify-crud-app:latest
48+
```
49+
50+
## Stack
51+
52+
- **Fastify** - Fast Node.js web framework
53+
- **TypeScript** - Type safety
54+
- **SQLite** - Embedded database with better-sqlite3
55+
- **Docker** - Multi-stage builds for production
56+
- **GitHub Actions** - Automated releases and container publishing

0 commit comments

Comments
 (0)