Merge pull request 'Consolidate CI and deployment workflows' (#62) from improve/workflow into dev
Reviewed-on: #62
This commit was merged in pull request #62.
This commit is contained in:
+14
-257
@@ -1,270 +1,27 @@
|
|||||||
# =============================================================================
|
|
||||||
# CI Workflow — Continuous Integration
|
|
||||||
# =============================================================================
|
|
||||||
# Triggers on push and pull_request.
|
|
||||||
#
|
|
||||||
# Detection logic:
|
|
||||||
# 1. Python: if requirements.txt exists → install deps, lint, test.
|
|
||||||
# 2. Node/JS: if package.json exists → install deps, lint, test, build.
|
|
||||||
# 3. Neither detected → print a message and exit 0 (never fail).
|
|
||||||
#
|
|
||||||
# Controlled by .ci/config.env:
|
|
||||||
# ENABLE_CI — master switch (default: true)
|
|
||||||
# CI_STRICT — if true, lint/test failures fail the workflow
|
|
||||||
# if false, failures are warnings only
|
|
||||||
#
|
|
||||||
# See docs/CI.md for full details.
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
name: CI
|
name: CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
pull_request:
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [ovh-vps-1, hiddenden]
|
||||||
|
container:
|
||||||
|
image: node:20-alpine
|
||||||
steps:
|
steps:
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 1: Checkout the code
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
- name: Install build deps
|
||||||
# Step 2: Load configuration from .ci/config.env
|
run: apk add --no-cache python3 make g++
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Load config
|
|
||||||
id: config
|
|
||||||
run: |
|
|
||||||
# Source config.env to get ENABLE_CI, CI_STRICT, etc.
|
|
||||||
if [ -f .ci/config.env ]; then
|
|
||||||
# Export all non-comment, non-empty lines
|
|
||||||
set -a
|
|
||||||
source .ci/config.env
|
|
||||||
set +a
|
|
||||||
echo "Config loaded from .ci/config.env"
|
|
||||||
else
|
|
||||||
echo "WARNING: .ci/config.env not found, using defaults"
|
|
||||||
ENABLE_CI=true
|
|
||||||
CI_STRICT=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Pass values to subsequent steps via environment file
|
- name: Install dependencies
|
||||||
echo "ENABLE_CI=${ENABLE_CI:-true}" >> "$GITHUB_ENV"
|
run: npm ci
|
||||||
echo "CI_STRICT=${CI_STRICT:-true}" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
- name: Build
|
||||||
# Step 3: Check master switch
|
run: npm run build
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Check if CI is enabled
|
|
||||||
run: |
|
|
||||||
if [ "$ENABLE_CI" != "true" ]; then
|
|
||||||
echo "CI is disabled (ENABLE_CI=$ENABLE_CI). Exiting."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 4: Detect project type
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Detect project type
|
|
||||||
id: detect
|
|
||||||
run: |
|
|
||||||
HAS_PYTHON=false
|
|
||||||
HAS_NODE=false
|
|
||||||
|
|
||||||
if [ -f requirements.txt ] || [ -f setup.py ] || [ -f pyproject.toml ]; then
|
|
||||||
HAS_PYTHON=true
|
|
||||||
echo "Detected: Python project"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f package.json ]; then
|
|
||||||
HAS_NODE=true
|
|
||||||
echo "Detected: Node.js project"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$HAS_PYTHON" = "false" ] && [ "$HAS_NODE" = "false" ]; then
|
|
||||||
echo "No Python or Node.js project detected. CI will skip gracefully."
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "HAS_PYTHON=${HAS_PYTHON}" >> "$GITHUB_ENV"
|
|
||||||
echo "HAS_NODE=${HAS_NODE}" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 5: Python — Setup & Install
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Set up Python
|
|
||||||
if: env.HAS_PYTHON == 'true'
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: "3.x"
|
|
||||||
|
|
||||||
- name: Install Python dependencies
|
|
||||||
if: env.HAS_PYTHON == 'true'
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
if [ -f requirements.txt ]; then
|
|
||||||
pip install -r requirements.txt
|
|
||||||
fi
|
|
||||||
# Install optional dev tools (won't fail if not needed)
|
|
||||||
pip install ruff black flake8 pytest 2>/dev/null || true
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 6: Python — Lint
|
|
||||||
# Runs ruff, then black --check, then flake8. Each is optional:
|
|
||||||
# only runs if the tool is installed AND relevant config exists.
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Python lint
|
|
||||||
if: env.HAS_PYTHON == 'true'
|
|
||||||
run: |
|
|
||||||
EXIT_CODE=0
|
|
||||||
|
|
||||||
# --- ruff ---
|
|
||||||
if command -v ruff >/dev/null 2>&1; then
|
|
||||||
echo ">>> ruff check ."
|
|
||||||
ruff check . || EXIT_CODE=$?
|
|
||||||
else
|
|
||||||
echo "SKIP: ruff not installed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- black ---
|
|
||||||
if command -v black >/dev/null 2>&1; then
|
|
||||||
echo ">>> black --check ."
|
|
||||||
black --check . || EXIT_CODE=$?
|
|
||||||
else
|
|
||||||
echo "SKIP: black not installed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# --- flake8 ---
|
|
||||||
if command -v flake8 >/dev/null 2>&1; then
|
|
||||||
echo ">>> flake8 ."
|
|
||||||
flake8 . || EXIT_CODE=$?
|
|
||||||
else
|
|
||||||
echo "SKIP: flake8 not installed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$EXIT_CODE" -ne 0 ]; then
|
|
||||||
if [ "$CI_STRICT" = "true" ]; then
|
|
||||||
echo "ERROR: Lint failed (CI_STRICT=true)"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "WARNING: Lint issues found (CI_STRICT=false, continuing)"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 7: Python — Test
|
|
||||||
# Runs pytest if a tests/ directory or pytest config is detected.
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Python test
|
|
||||||
if: env.HAS_PYTHON == 'true'
|
|
||||||
run: |
|
|
||||||
# Check if tests exist
|
|
||||||
HAS_TESTS=false
|
|
||||||
if [ -d tests ] || [ -d test ]; then
|
|
||||||
HAS_TESTS=true
|
|
||||||
fi
|
|
||||||
# Check for pytest config in pyproject.toml or pytest.ini
|
|
||||||
if [ -f pytest.ini ] || [ -f setup.cfg ]; then
|
|
||||||
HAS_TESTS=true
|
|
||||||
fi
|
|
||||||
if [ -f pyproject.toml ] && grep -q '\[tool\.pytest' pyproject.toml 2>/dev/null; then
|
|
||||||
HAS_TESTS=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$HAS_TESTS" = "true" ]; then
|
|
||||||
echo ">>> pytest"
|
|
||||||
if ! pytest; then
|
|
||||||
if [ "$CI_STRICT" = "true" ]; then
|
|
||||||
echo "ERROR: Tests failed (CI_STRICT=true)"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "WARNING: Tests failed (CI_STRICT=false, continuing)"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "SKIP: No tests detected (no tests/ dir or pytest config)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 8: Node.js — Setup & Install
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Set up Node.js
|
|
||||||
if: env.HAS_NODE == 'true'
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
# Keep CI on Node 20 to match runtime/Docker and better-sqlite3 compatibility.
|
|
||||||
node-version: "20.x"
|
|
||||||
|
|
||||||
- name: Install Node dependencies
|
|
||||||
if: env.HAS_NODE == 'true'
|
|
||||||
run: |
|
|
||||||
# Lockfile is currently not authoritative; use install to refresh dependency tree.
|
|
||||||
npm install
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 9: Node.js — Lint (only if "lint" script exists in package.json)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Node lint
|
|
||||||
if: env.HAS_NODE == 'true'
|
|
||||||
run: |
|
|
||||||
if grep -q '"lint"' package.json 2>/dev/null; then
|
|
||||||
echo ">>> npm run lint"
|
|
||||||
if ! npm run lint; then
|
|
||||||
if [ "$CI_STRICT" = "true" ]; then
|
|
||||||
echo "ERROR: Lint failed (CI_STRICT=true)"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "WARNING: Lint issues found (CI_STRICT=false, continuing)"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "SKIP: no 'lint' script in package.json"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 10: Node.js — Test (only if "test" script exists)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Node test
|
|
||||||
if: env.HAS_NODE == 'true'
|
|
||||||
run: |
|
|
||||||
if grep -q '"test"' package.json 2>/dev/null; then
|
|
||||||
echo ">>> npm test"
|
|
||||||
if ! npm test; then
|
|
||||||
if [ "$CI_STRICT" = "true" ]; then
|
|
||||||
echo "ERROR: Tests failed (CI_STRICT=true)"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "WARNING: Tests failed (CI_STRICT=false, continuing)"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "SKIP: no 'test' script in package.json"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 11: Node.js — Build (only if "build" script exists)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Node build
|
|
||||||
if: env.HAS_NODE == 'true'
|
|
||||||
run: |
|
|
||||||
if grep -q '"build"' package.json 2>/dev/null; then
|
|
||||||
echo ">>> npm run build"
|
|
||||||
npm run build
|
|
||||||
else
|
|
||||||
echo "SKIP: no 'build' script in package.json"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 12: Summary
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: CI Summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
echo "=============================="
|
|
||||||
echo " CI Complete"
|
|
||||||
echo " Python detected: $HAS_PYTHON"
|
|
||||||
echo " Node detected: $HAS_NODE"
|
|
||||||
echo " Strict mode: $CI_STRICT"
|
|
||||||
echo "=============================="
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
name: Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: [ovh-vps-1, deploy, hiddenden]
|
||||||
|
steps:
|
||||||
|
- name: Pull latest code
|
||||||
|
working-directory: /home/ubuntu/appdata/Cozy-Den
|
||||||
|
run: |
|
||||||
|
git fetch origin
|
||||||
|
git reset --hard origin/main
|
||||||
|
|
||||||
|
- name: Login to Gitea registry
|
||||||
|
run: echo "${{ secrets.GITEA_TOKEN }}" | docker login git.hiddenden.cafe -u ${{ secrets.GITEA_USERNAME }} --password-stdin
|
||||||
|
|
||||||
|
- name: Build & push image
|
||||||
|
working-directory: /home/ubuntu/appdata/Cozy-Den
|
||||||
|
run: |
|
||||||
|
docker build -t git.hiddenden.cafe/hiddenden/cozy-den:latest .
|
||||||
|
docker push git.hiddenden.cafe/hiddenden/cozy-den:latest
|
||||||
|
|
||||||
|
- name: Deploy
|
||||||
|
working-directory: /home/ubuntu/appdata/Cozy-Den
|
||||||
|
env:
|
||||||
|
SECRET_KEY: ${{ secrets.SECRET_KEY }}
|
||||||
|
ADMIN_SECRET_TOKEN: ${{ secrets.ADMIN_SECRET_TOKEN }}
|
||||||
|
COOKIE_SECURE: "true"
|
||||||
|
run: docker compose up -d
|
||||||
@@ -1,288 +0,0 @@
|
|||||||
# =============================================================================
|
|
||||||
# Docker Workflow — Build & Push to Gitea Container Registry
|
|
||||||
# =============================================================================
|
|
||||||
#
|
|
||||||
# PURPOSE:
|
|
||||||
# Build Docker images generically; optionally push to the Gitea Container
|
|
||||||
# Registry at git.hiddenden.cafe.
|
|
||||||
#
|
|
||||||
# TRIGGERS:
|
|
||||||
# - pull_request → build only (never push)
|
|
||||||
# - push to main → build; push only if ENABLE_DOCKER=true AND DOCKER_PUSH=true
|
|
||||||
# - tag v* → build; push only if DOCKER_PUSH=true AND DOCKER_PUSH_ON_TAG=true
|
|
||||||
#
|
|
||||||
# DETECTION:
|
|
||||||
# - Dockerfile exists → docker build
|
|
||||||
# - docker-compose.yml exists → docker compose build
|
|
||||||
# - Neither → exit 0 gracefully
|
|
||||||
#
|
|
||||||
# NAMING (Gitea convention):
|
|
||||||
# Image ref: ${REGISTRY_HOST}/${IMAGE_OWNER}/${IMAGE_NAME}:${TAG}
|
|
||||||
# Example: git.hiddenden.cafe/myorg/myrepo:1.2.3
|
|
||||||
#
|
|
||||||
# AUTHENTICATION:
|
|
||||||
# Uses PAT-based secrets (recommended for Gitea Actions):
|
|
||||||
# - REGISTRY_USERNAME — your Gitea username or bot account
|
|
||||||
# - REGISTRY_TOKEN — a Personal Access Token with package:write scope
|
|
||||||
# Set these in: Repository Settings → Secrets (or Organization Secrets).
|
|
||||||
# NEVER echo secrets in logs.
|
|
||||||
#
|
|
||||||
# CONFIG:
|
|
||||||
# All settings loaded from .ci/config.env. See docs/DOCKER.md.
|
|
||||||
#
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
name: Docker
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
docker:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 1: Checkout
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 2: Load configuration
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Load config
|
|
||||||
run: |
|
|
||||||
if [ -f .ci/config.env ]; then
|
|
||||||
set -a
|
|
||||||
source .ci/config.env
|
|
||||||
set +a
|
|
||||||
echo "Config loaded from .ci/config.env"
|
|
||||||
else
|
|
||||||
echo "WARNING: .ci/config.env not found, using defaults"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Export with defaults
|
|
||||||
echo "ENABLE_DOCKER=${ENABLE_DOCKER:-true}" >> "$GITHUB_ENV"
|
|
||||||
echo "DOCKER_PUSH=${DOCKER_PUSH:-false}" >> "$GITHUB_ENV"
|
|
||||||
echo "DOCKER_PUSH_ON_BRANCH=${DOCKER_PUSH_ON_BRANCH:-true}" >> "$GITHUB_ENV"
|
|
||||||
echo "DOCKER_PUSH_ON_TAG=${DOCKER_PUSH_ON_TAG:-true}" >> "$GITHUB_ENV"
|
|
||||||
echo "REGISTRY_HOST=${REGISTRY_HOST:-git.hiddenden.cafe}" >> "$GITHUB_ENV"
|
|
||||||
echo "IMAGE_OWNER_CFG=${IMAGE_OWNER:-auto}" >> "$GITHUB_ENV"
|
|
||||||
echo "IMAGE_NAME_CFG=${IMAGE_NAME:-auto}" >> "$GITHUB_ENV"
|
|
||||||
echo "DOCKER_TAG_STRATEGY=${DOCKER_TAG_STRATEGY:-semver+latest}" >> "$GITHUB_ENV"
|
|
||||||
echo "DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 3: Check if Docker is enabled
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Check if Docker is enabled
|
|
||||||
run: |
|
|
||||||
if [ "$ENABLE_DOCKER" != "true" ]; then
|
|
||||||
echo "Docker is disabled (ENABLE_DOCKER=$ENABLE_DOCKER). Exiting."
|
|
||||||
# We still exit 0 — graceful skip.
|
|
||||||
echo "SKIP_DOCKER=true" >> "$GITHUB_ENV"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 4: Detect Dockerfile or docker-compose.yml
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Detect Docker files
|
|
||||||
if: env.SKIP_DOCKER != 'true'
|
|
||||||
run: |
|
|
||||||
if [ -f Dockerfile ]; then
|
|
||||||
echo "DOCKER_MODE=dockerfile" >> "$GITHUB_ENV"
|
|
||||||
echo "Detected: Dockerfile"
|
|
||||||
elif [ -f docker-compose.yml ] || [ -f docker-compose.yaml ]; then
|
|
||||||
echo "DOCKER_MODE=compose" >> "$GITHUB_ENV"
|
|
||||||
echo "Detected: docker-compose.yml"
|
|
||||||
else
|
|
||||||
echo "No Dockerfile or docker-compose.yml found. Skipping."
|
|
||||||
echo "SKIP_DOCKER=true" >> "$GITHUB_ENV"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 5: Derive image owner and name dynamically
|
|
||||||
#
|
|
||||||
# Logic:
|
|
||||||
# FULL_REPO is derived from (in priority order):
|
|
||||||
# 1. $GITEA_REPOSITORY (Gitea native env var)
|
|
||||||
# 2. github.repository (Gitea Actions compatibility fallback)
|
|
||||||
# Format: "owner/repo"
|
|
||||||
#
|
|
||||||
# If IMAGE_OWNER=auto → use the owner part
|
|
||||||
# If IMAGE_NAME=auto → use the repo part
|
|
||||||
# Otherwise, use the explicit config values.
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Derive image naming
|
|
||||||
if: env.SKIP_DOCKER != 'true'
|
|
||||||
run: |
|
|
||||||
# Determine FULL_REPO (owner/repo)
|
|
||||||
# Gitea Actions sets GITEA_REPOSITORY natively in some versions.
|
|
||||||
# It also maps github.repository for compatibility.
|
|
||||||
FULL_REPO="${GITEA_REPOSITORY:-${{ github.repository }}}"
|
|
||||||
|
|
||||||
if [ -z "$FULL_REPO" ]; then
|
|
||||||
echo "ERROR: Could not determine repository (GITEA_REPOSITORY and github.repository are both empty)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Split into OWNER and REPO
|
|
||||||
OWNER="$(echo "$FULL_REPO" | cut -d'/' -f1)"
|
|
||||||
REPO="$(echo "$FULL_REPO" | cut -d'/' -f2)"
|
|
||||||
|
|
||||||
echo "Derived FULL_REPO=$FULL_REPO OWNER=$OWNER REPO=$REPO"
|
|
||||||
|
|
||||||
# Apply config overrides
|
|
||||||
if [ "$IMAGE_OWNER_CFG" = "auto" ]; then
|
|
||||||
FINAL_OWNER="$OWNER"
|
|
||||||
else
|
|
||||||
FINAL_OWNER="$IMAGE_OWNER_CFG"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$IMAGE_NAME_CFG" = "auto" ]; then
|
|
||||||
FINAL_NAME="$REPO"
|
|
||||||
else
|
|
||||||
FINAL_NAME="$IMAGE_NAME_CFG"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Docker requires all image references to be lowercase
|
|
||||||
FINAL_OWNER="$(echo "$FINAL_OWNER" | tr '[:upper:]' '[:lower:]')"
|
|
||||||
FINAL_NAME="$(echo "$FINAL_NAME" | tr '[:upper:]' '[:lower:]')"
|
|
||||||
|
|
||||||
# Construct the full image reference (without tag)
|
|
||||||
IMAGE_REF="${REGISTRY_HOST}/${FINAL_OWNER}/${FINAL_NAME}"
|
|
||||||
echo "Image reference: ${IMAGE_REF}:<tag>"
|
|
||||||
|
|
||||||
echo "IMAGE_REF=${IMAGE_REF}" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 6: Determine tags based on trigger and strategy
|
|
||||||
#
|
|
||||||
# Tag rules:
|
|
||||||
# - PR: build only, tag = "pr-<number>" (local only)
|
|
||||||
# - Push to branch: tag = branch name (e.g., "main")
|
|
||||||
# - Tag v1.2.3: tag = "1.2.3"; also "latest" if strategy includes it
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Determine tags
|
|
||||||
if: env.SKIP_DOCKER != 'true'
|
|
||||||
run: |
|
|
||||||
TAGS=""
|
|
||||||
SHOULD_PUSH=false
|
|
||||||
REF="${GITHUB_REF:-}"
|
|
||||||
|
|
||||||
echo "Event: ${{ github.event_name }}"
|
|
||||||
echo "Ref: ${REF}"
|
|
||||||
|
|
||||||
# --- Pull Request: build only ---
|
|
||||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
||||||
TAGS="${IMAGE_REF}:pr-${{ github.event.number }}"
|
|
||||||
SHOULD_PUSH=false
|
|
||||||
echo "PR build — will NOT push"
|
|
||||||
|
|
||||||
# --- Tag push (v*) ---
|
|
||||||
elif echo "${REF}" | grep -qE '^refs/tags/v'; then
|
|
||||||
# Extract version: refs/tags/v1.2.3 → 1.2.3
|
|
||||||
VERSION="$(echo "${REF}" | sed 's|refs/tags/v||')"
|
|
||||||
TAGS="${IMAGE_REF}:${VERSION}"
|
|
||||||
|
|
||||||
# Optionally add :latest
|
|
||||||
if echo "$DOCKER_TAG_STRATEGY" | grep -qi 'latest'; then
|
|
||||||
TAGS="${TAGS},${IMAGE_REF}:latest"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$DOCKER_PUSH" = "true" ] && [ "$DOCKER_PUSH_ON_TAG" = "true" ]; then
|
|
||||||
SHOULD_PUSH=true
|
|
||||||
fi
|
|
||||||
echo "Tag push — version=${VERSION}, push=${SHOULD_PUSH}"
|
|
||||||
|
|
||||||
# --- Branch push ---
|
|
||||||
elif echo "${REF}" | grep -q '^refs/heads/'; then
|
|
||||||
BRANCH="$(echo "${REF}" | sed 's|refs/heads/||')"
|
|
||||||
TAGS="${IMAGE_REF}:${BRANCH}"
|
|
||||||
|
|
||||||
if [ "$DOCKER_PUSH" = "true" ] && [ "$DOCKER_PUSH_ON_BRANCH" = "true" ]; then
|
|
||||||
SHOULD_PUSH=true
|
|
||||||
fi
|
|
||||||
echo "Branch push — branch=${BRANCH}, push=${SHOULD_PUSH}"
|
|
||||||
|
|
||||||
else
|
|
||||||
echo "Unknown ref type: ${REF}. Building with tag 'dev'."
|
|
||||||
TAGS="${IMAGE_REF}:dev"
|
|
||||||
SHOULD_PUSH=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "DOCKER_TAGS=${TAGS}" >> "$GITHUB_ENV"
|
|
||||||
echo "SHOULD_PUSH=${SHOULD_PUSH}" >> "$GITHUB_ENV"
|
|
||||||
echo "Final tags: ${TAGS}"
|
|
||||||
echo "Will push: ${SHOULD_PUSH}"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 7: Build the Docker image
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Build Docker image
|
|
||||||
if: env.SKIP_DOCKER != 'true'
|
|
||||||
run: |
|
|
||||||
if [ "$DOCKER_MODE" = "dockerfile" ]; then
|
|
||||||
# Build with the first tag; additional tags are added after
|
|
||||||
PRIMARY_TAG="$(echo "$DOCKER_TAGS" | cut -d',' -f1)"
|
|
||||||
echo ">>> docker build -t ${PRIMARY_TAG} ."
|
|
||||||
docker build -t "${PRIMARY_TAG}" .
|
|
||||||
|
|
||||||
# Tag additional images if present
|
|
||||||
IFS=',' read -ra TAG_ARRAY <<< "$DOCKER_TAGS"
|
|
||||||
for tag in "${TAG_ARRAY[@]:1}"; do
|
|
||||||
echo ">>> docker tag ${PRIMARY_TAG} ${tag}"
|
|
||||||
docker tag "${PRIMARY_TAG}" "${tag}"
|
|
||||||
done
|
|
||||||
|
|
||||||
elif [ "$DOCKER_MODE" = "compose" ]; then
|
|
||||||
echo ">>> docker compose build"
|
|
||||||
docker compose build
|
|
||||||
fi
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 8: Login to registry (only when pushing)
|
|
||||||
#
|
|
||||||
# Uses PAT-based auth. Requires secrets:
|
|
||||||
# REGISTRY_USERNAME — Gitea username or bot
|
|
||||||
# REGISTRY_TOKEN — PAT with package:write scope
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Login to container registry
|
|
||||||
if: env.SKIP_DOCKER != 'true' && env.SHOULD_PUSH == 'true'
|
|
||||||
run: |
|
|
||||||
echo "Logging in to ${REGISTRY_HOST}..."
|
|
||||||
# Use --password-stdin to avoid leaking the token in process list
|
|
||||||
echo "${{ secrets.REGISTRY_TOKEN }}" | \
|
|
||||||
docker login "${REGISTRY_HOST}" \
|
|
||||||
-u "${{ secrets.REGISTRY_USERNAME }}" \
|
|
||||||
--password-stdin
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 9: Push Docker image(s)
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Push Docker image
|
|
||||||
if: env.SKIP_DOCKER != 'true' && env.SHOULD_PUSH == 'true'
|
|
||||||
run: |
|
|
||||||
IFS=',' read -ra TAG_ARRAY <<< "$DOCKER_TAGS"
|
|
||||||
for tag in "${TAG_ARRAY[@]}"; do
|
|
||||||
echo ">>> docker push ${tag}"
|
|
||||||
docker push "${tag}"
|
|
||||||
done
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
# Step 10: Summary
|
|
||||||
# -----------------------------------------------------------------------
|
|
||||||
- name: Docker Summary
|
|
||||||
if: always()
|
|
||||||
run: |
|
|
||||||
echo "=============================="
|
|
||||||
echo " Docker Workflow Complete"
|
|
||||||
echo " Mode: ${DOCKER_MODE:-skipped}"
|
|
||||||
echo " Tags: ${DOCKER_TAGS:-none}"
|
|
||||||
echo " Pushed: ${SHOULD_PUSH:-false}"
|
|
||||||
echo "=============================="
|
|
||||||
+6
-17
@@ -1,37 +1,26 @@
|
|||||||
# Stage 1: Build the Astro app
|
# Stage 1: Build
|
||||||
FROM node:20-alpine AS builder
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install build dependencies for native modules (e.g. better-sqlite3)
|
# Native module build deps (better-sqlite3)
|
||||||
RUN apk add --no-cache python3 make g++
|
RUN apk add --no-cache python3 make g++
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm install
|
RUN npm ci
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build
|
RUN npm run build && npm prune --omit=dev
|
||||||
|
|
||||||
# Stage 2: Install production dependencies only
|
# Stage 2: Runtime
|
||||||
FROM node:20-alpine AS deps
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
RUN apk add --no-cache python3 make g++
|
|
||||||
|
|
||||||
COPY package*.json ./
|
|
||||||
RUN npm install --omit=dev
|
|
||||||
|
|
||||||
# Stage 3: Runtime image
|
|
||||||
FROM node:20-alpine AS runtime
|
FROM node:20-alpine AS runtime
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Data directory for SQLite database
|
|
||||||
RUN mkdir -p /data
|
RUN mkdir -p /data
|
||||||
|
|
||||||
COPY --from=builder /app/dist ./dist
|
COPY --from=builder /app/dist ./dist
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|||||||
+9
-3
@@ -1,10 +1,12 @@
|
|||||||
services:
|
services:
|
||||||
cozy-den:
|
cozy-den:
|
||||||
build: .
|
image: git.hiddenden.cafe/hiddenden/cozy-den:latest
|
||||||
container_name: cozy-den
|
container_name: cozy-den
|
||||||
ports:
|
# ports:
|
||||||
- "3000:3000"
|
# - "3000:3000"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- HOST=0.0.0.0
|
- HOST=0.0.0.0
|
||||||
@@ -18,3 +20,7 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
guestbook_data:
|
guestbook_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
|||||||
Reference in New Issue
Block a user