Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions .github/WORKFLOWS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# GitHub Actions Workflows

This repository uses GitHub Actions for CI/CD automation. The workflows are located in `.github/workflows/`.

## Workflows

### 1. CI - Pull Request (`ci.yml`)
**Trigger:** Pull requests to `main` or `develop` branches

**Jobs:**
- **test-build**: Tests the application with multiple Node.js versions (18.x, 20.x)
- Installs dependencies
- Runs build script
- Executes tests
- Performs health check
- **docker-build-test**: Tests Docker image building
- Builds Docker image without pushing
- Tests the container startup and health endpoint
- **security-scan**: Runs Trivy vulnerability scanner

### 2. CD - Main Branch (`cd.yml`)
**Trigger:** Pushes to `main` branch

**Jobs:**
- **test**: Runs tests on Node.js 18.x
- **docker-build-push**: Builds and pushes Docker images
- Pushes to Docker Hub (`stackapp/docker-stack-api`)
- Pushes to GitHub Container Registry (`ghcr.io/code-mini/stack-app`)
- Supports multi-architecture (linux/amd64, linux/arm64)
- **semantic-release**: Handles automatic versioning and releases
- **deploy-notification**: Reports deployment status

### 3. Release (`release.yml`)
**Trigger:** Published releases or manual workflow dispatch

**Jobs:**
- **build-and-release**: Complete release process
- Builds and tests the application
- Pushes versioned Docker images
- Publishes to NPM registry
- Creates release assets

### 4. Security & Dependencies (`security.yml`)
**Trigger:** Weekly schedule (Mondays at 2 AM UTC) or manual

**Jobs:**
- **security-audit**: NPM security audit and Snyk scanning
- **docker-security-scan**: Trivy vulnerability scanning for Docker images
- **dependency-review**: Reviews dependencies in pull requests

## Required Secrets

Configure these secrets in your GitHub repository settings:

### Docker Registry
- `DOCKER_USERNAME`: Docker Hub username
- `DOCKER_PASSWORD`: Docker Hub password/token

### NPM Publishing
- `NPM_TOKEN`: NPM registry authentication token

### Security Scanning (Optional)
- `SNYK_TOKEN`: Snyk API token for enhanced security scanning

## Container Registries

### Docker Hub
- Repository: `stackapp/docker-stack-api`
- Tags: `latest`, `main-<sha>`, version tags

### GitHub Container Registry
- Repository: `ghcr.io/code-mini/stack-app`
- Tags: `latest`, `main-<sha>`, version tags

## Semantic Release

The project uses semantic-release for automated versioning based on conventional commits:

- `fix:` → Patch release (0.1.0 → 0.1.1)
- `feat:` → Minor release (0.1.0 → 0.2.0)
- `BREAKING CHANGE:` → Major release (0.1.0 → 1.0.0)

## Manual Workflows

All workflows can be triggered manually via the GitHub Actions tab using the "Run workflow" button.

## Cache Strategy

- **NPM dependencies**: Cached using `actions/setup-node@v4`
- **Docker layers**: Cached using GitHub Actions cache (`type=gha`)

## Multi-Platform Support

Docker images are built for multiple architectures:
- `linux/amd64` (x86_64)
- `linux/arm64` (ARM64/Apple Silicon)

## Health Checks

All workflows include health checks to ensure the application starts correctly:
- Node.js: Starts server and tests `/health` endpoint
- Docker: Runs container and validates health endpoint response
128 changes: 128 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
name: CD - Main Branch

on:
push:
branches: [ main ]
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18.x'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run build
run: npm run build

- name: Run tests
run: npm test

docker-build-push:
needs: test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
if: ${{ secrets.DOCKER_USERNAME && secrets.DOCKER_PASSWORD }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
${{ secrets.DOCKER_USERNAME && 'stackapp/docker-stack-api' || '' }}
ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64

semantic-release:
needs: [test, docker-build-push]
runs-on: ubuntu-latest
if: ${{ secrets.NPM_TOKEN }}

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18.x'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run semantic release
run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

deploy-notification:
needs: [test, docker-build-push]
runs-on: ubuntu-latest
if: always()

steps:
- name: Deployment Status
run: |
if [ "${{ needs.test.result }}" == "success" ] && [ "${{ needs.docker-build-push.result }}" == "success" ]; then
echo "✅ Deployment successful!"
echo "Docker images pushed to:"
echo "- GHCR: ghcr.io/${{ github.repository }}:latest"
if [ -n "${{ secrets.DOCKER_USERNAME }}" ]; then
echo "- Docker Hub: stackapp/docker-stack-api:latest"
else
echo "- Docker Hub: Skipped (credentials not configured)"
fi
else
echo "❌ Deployment failed!"
echo "Test result: ${{ needs.test.result }}"
echo "Docker build result: ${{ needs.docker-build-push.result }}"
exit 1
fi
128 changes: 128 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
name: CI - Pull Request

on:
pull_request:
branches: [ main, develop ]
workflow_dispatch:

jobs:
test-build:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x, 20.x]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run build
run: npm run build

- name: Run tests
run: npm test

- name: Start application (health check)
run: |
# Create a minimal config for testing
mkdir -p data
echo "database:
type: sqlite
path: ./data/test.db
api:
port: 3001
keys:
- test-key
docker:
socketPath: /var/run/docker.sock
logging:
level: error" > test-config.yaml

# Start app in background using CLI
timeout 30s ./bin/stack-app --config test-config.yaml &
APP_PID=$!

# Wait for startup
sleep 5

# Test health endpoint
curl -f http://localhost:3001/health || (echo "Health check failed" && kill $APP_PID && exit 1)

# Clean up
kill $APP_PID || true
rm -f test-config.yaml
env:
NODE_ENV: test

docker-build-test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
push: false
tags: stack-app:test
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Test Docker image
run: |
# Test Docker image without mounting Docker socket (to avoid permission issues in CI)
docker run -d --name stack-app-test -p 3001:3001 \
-e NODE_ENV=test \
stack-app:test

# Wait for startup
sleep 15

# Test health endpoint (Docker status may show as unavailable, which is expected in CI)
if curl -f http://localhost:3001/health; then
echo "✅ Health check passed"
else
echo "❌ Health check failed"
docker logs stack-app-test
exit 1
fi

# Clean up
docker stop stack-app-test || true
docker rm stack-app-test || true

security-scan:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'

- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
Loading