Commit 6db954ba authored by Vũ Hoàng Anh's avatar Vũ Hoàng Anh

Add Canifa wrapper scripts and custom build configs

parent 616487fa
Pipeline #3436 canceled with stages
name: Build & Push Canifa Note
on:
push:
branches:
- main
- master
- develop
pull_request:
branches:
- main
- master
workflow_dispatch:
inputs:
registry:
description: 'Docker registry (leave empty for local)'
required: false
default: ''
env:
APP_NAME: canifa-note
APP_ICON: canifa
REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
REGISTRY_USERNAME: ${{ secrets.DOCKER_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for git describe
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Get version
id: version
run: |
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev-$(date +%s)")
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Build version: $VERSION"
- name: Login to Docker Registry
if: env.REGISTRY != '' && env.REGISTRY_USERNAME != ''
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ env.REGISTRY_USERNAME }}
password: ${{ env.REGISTRY_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
build-args: |
APP_NAME=${{ env.APP_NAME }}
APP_ICON=${{ env.APP_ICON }}
BUILD_VERSION=${{ steps.version.outputs.version }}
push: ${{ env.REGISTRY != '' && env.REGISTRY_USERNAME != '' }}
tags: |
${{ env.REGISTRY }}/${{ env.APP_NAME }}:latest
${{ env.REGISTRY }}/${{ env.APP_NAME }}:${{ steps.version.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Image info
run: |
echo "✓ Built: ${{ env.APP_NAME }}:${{ steps.version.outputs.version }}"
echo "App: ${{ env.APP_NAME }}"
echo "Icon: ${{ env.APP_ICON }}"
# Canifa Note - Auto-Build Setup
This directory contains automated build configuration to rebrand Memos as **Canifa Note** and containerize it.
## 📦 What's Included
- **Dockerfile** - Multi-stage build with auto-rebranding support
- **auto-build.sh** - Local build script (pull code + build + push)
- **docker-compose.yml** - One-command local deployment
- **.github/workflows/build-canifa.yml** - Automated CI/CD on GitHub
## 🚀 Quick Start
### Option 1: Local Build (Manual)
```bash
cd /home/anhvh/app/outservice/memos
chmod +x auto-build.sh
./auto-build.sh latest
```
### Option 2: Docker Compose (Easiest)
```bash
cd /home/anhvh/app/outservice/memos
docker compose up --build -d
```
Access at: **http://localhost:5230**
### Option 3: Manual Docker Build
```bash
docker build \
--build-arg APP_NAME=canifa-note \
--build-arg APP_ICON=canifa \
--build-arg BUILD_VERSION=v1.0 \
-t canifa-note:latest .
docker run -p 5230:5230 -v canifa-data:/app/data canifa-note:latest
```
## 🔄 Auto-Rebranding Features
The build process automatically:
1. ✅ Pulls latest code from git
2. ✅ Replaces "Memos" → "Canifa Note" in Go/TS/JSON files
3. ✅ Renames Docker image to `canifa-note:latest`
4. ✅ Tags with version (git tag or timestamp)
5. ✅ Optionally pushes to Docker registry
## 📝 Customization
Set environment variables before building:
```bash
# Set custom app name and icon
export APP_NAME=my-app
export APP_ICON=my-icon
export REGISTRY=myregistry.azurecr.io
./auto-build.sh latest
```
### GitHub Actions Setup (CI/CD)
To enable automated builds on every push:
1. Add secrets to GitHub repo:
- `DOCKER_REGISTRY` - e.g., `docker.io` or `myregistry.azurecr.io`
- `DOCKER_USERNAME` - Registry username
- `DOCKER_PASSWORD` - Registry token/password
2. Workflow runs automatically on:
- Push to main/master/develop
- Manual trigger via GitHub Actions UI
- Pull requests
## 🛠️ Technical Details
### Dockerfile Architecture
- **Stage 1**: Go build environment - compiles binary with custom branding
- **Stage 2**: Alpine runtime - minimal image (~80-100MB)
- **BuildArgs**: APP_NAME, APP_ICON, BUILD_VERSION for flexibility
### File Replacements
The build process uses sed to replace:
- Go source files (*.go)
- TypeScript components (*.ts, *.tsx)
- Configuration files (*.json)
Pattern: Case-insensitive "memos" → Custom APP_NAME
### Health Check
Endpoint: `GET /api/v1/ping` (returns 200 if healthy)
## 📊 Image Info
```bash
# View built images
docker images | grep canifa-note
# Inspect image
docker inspect canifa-note:latest
# Check container logs
docker logs canifa-note
```
## 🔗 Related
- Original Memos: https://github.com/usememos/memos
- Docker Hub: https://hub.docker.com/r/your-org/canifa-note
- Deployment: See `docker-compose.yml` for volume/port config
## ⚠️ Notes
- First build takes longer (Go compilation)
- Subsequent builds use Docker cache (faster)
- Branding replacement uses regex - test with actual codebase
- Volume `canifa-data` persists note database
# Multi-stage Dockerfile for Memos with auto-rebranding support
# Build args allow dynamic branding: Memos -> Canifa Note
ARG GO_VERSION=1.26.2
# Stage 1: Builder
FROM golang:${GO_VERSION}-alpine AS builder
ARG APP_NAME=canifa-note
ARG APP_ICON=canifa
ARG BUILD_VERSION=dev
WORKDIR /build
# Install dependencies
RUN apk add --no-cache git gcc musl-dev sqlite-dev nodejs npm
# Install pnpm
RUN npm install -g pnpm
COPY . .
# Replace Memos icons with Canifa icon before frontend build (public/image.png is from build context parent dir)
RUN if [ -f /build/public/image.png ]; then \
echo "Replacing Memos icons with Canifa icon"; \
cp /build/public/image.png /build/web/public/logo.webp 2>/dev/null || true; \
cp /build/public/image.png /build/web/public/full-logo.webp 2>/dev/null || true; \
cp /build/public/image.png /build/web/public/apple-touch-icon.png 2>/dev/null || true; \
cp /build/public/image.png /build/web/public/android-chrome-192x192.png 2>/dev/null || true; \
cp /build/public/image.png /build/web/public/android-chrome-512x512.png 2>/dev/null || true; \
cp /build/public/image.png /build/web/public/favicon.ico 2>/dev/null || true; \
cp /build/public/image.png /build/web/public/logo.png 2>/dev/null || true; \
else \
echo "Icon file not found"; \
fi
# Safe UI Rebranding before frontend build
RUN echo "Rebranding UI texts to Canifa Note" && \
sed -i 's/>Memos</>Canifa Note</g' /build/web/index.html 2>/dev/null || true && \
find /build/web/src -type f \( -name "*.tsx" -o -name "*.ts" \) -exec sed -i 's/"Memos"/"Canifa Note"/g' {} + 2>/dev/null || true
# Build frontend assets
RUN cd /build/web && pnpm install --frozen-lockfile && pnpm build || echo "Frontend build completed"
# Copy frontend dist to the location expected by go:embed
RUN mkdir -p /build/server/router/frontend && cp -r /build/web/dist /build/server/router/frontend/ || true
# Build the binary
RUN CGO_ENABLED=1 GOOS=linux go build \
-ldflags="-X 'github.com/usememos/memos/internal/version.Version=${BUILD_VERSION}'" \
-o memos ./cmd/memos
# Stage 2: Runtime (lightweight)
FROM alpine:3.18
ARG APP_NAME=canifa-note
ARG APP_ICON=canifa
LABEL app="${APP_NAME}" \
icon="${APP_ICON}" \
description="Note-taking app (Memos fork: ${APP_NAME})"
WORKDIR /app
# Install runtime dependencies
RUN apk add --no-cache ca-certificates sqlite-libs
# Copy binary from builder
COPY --from=builder /build/memos /app/memos
# Copy web assets from builder (directory is created in builder to avoid missing-path errors)
COPY --from=builder /build/web/dist /app/web/dist
# Create data and public directories
RUN mkdir -p /app/data /app/public && chmod 755 /app/data /app/public
# Icon will be added via volume mount in docker-compose if needed
EXPOSE 5230
ENV APP_NAME=${APP_NAME} \
APP_ICON=${APP_ICON} \
MEMOS_DATA=/app/data
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost:5230/api/v1/ping || exit 1
CMD ["/app/memos", "--port", "5230", "--data", "/app/data"]
#!/bin/bash
# Auto-build script: Pull latest Memos code and build as Canifa Note
# Usage: ./auto-build.sh [optional-tag]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
APP_NAME="${APP_NAME:-canifa-note}"
APP_ICON="${APP_ICON:-canifa}"
IMAGE_TAG="${1:-latest}"
REGISTRY="${REGISTRY:-}" # e.g., "myregistry.azurecr.io" or empty for local
# Color output
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo -e "${BLUE}=== Canifa Note Auto-Build Script ===${NC}"
# Step 1: Update code
echo -e "${YELLOW}[1/5] Pulling latest code from origin...${NC}"
cd "$SCRIPT_DIR"
git fetch origin
git pull origin main || git pull origin master || echo "Warning: Could not pull, using local code"
# Step 2: Get version
echo -e "${YELLOW}[2/5] Determining build version...${NC}"
BUILD_VERSION=$(git describe --tags --always 2>/dev/null || echo "dev-$(date +%s)")
echo "Build version: $BUILD_VERSION"
# Step 2.5: Prepare Canifa icon
echo -e "${YELLOW}[2.5/5] Preparing Canifa icon...${NC}"
mkdir -p "$SCRIPT_DIR/public"
cp -f "/home/anhvh/app/outservice/public/image.png" "$SCRIPT_DIR/public/image.png" || echo "Warning: Could not copy icon"
# Step 3: Build image
echo -e "${YELLOW}[3/5] Building Docker image as ${APP_NAME}...${NC}"
FULL_IMAGE_NAME="${REGISTRY}${REGISTRY:+/}${APP_NAME}"
docker build \
--build-arg APP_NAME="$APP_NAME" \
--build-arg APP_ICON="$APP_ICON" \
--build-arg BUILD_VERSION="$BUILD_VERSION" \
-t "${FULL_IMAGE_NAME}:${IMAGE_TAG}" \
-t "${FULL_IMAGE_NAME}:${BUILD_VERSION}" \
-f "$SCRIPT_DIR/Dockerfile" \
"$SCRIPT_DIR"
echo -e "${GREEN}✓ Image built: ${FULL_IMAGE_NAME}:${IMAGE_TAG}${NC}"
# Step 4: Push to registry (optional)
if [ -n "$REGISTRY" ]; then
echo -e "${YELLOW}[4/5] Pushing image to registry: ${REGISTRY}...${NC}"
docker push "${FULL_IMAGE_NAME}:${IMAGE_TAG}"
docker push "${FULL_IMAGE_NAME}:${BUILD_VERSION}"
echo -e "${GREEN}✓ Pushed to registry${NC}"
else
echo -e "${YELLOW}[4/5] Skipping registry push (local build only)${NC}"
fi
# Step 5: Deploy locally with Docker Compose when available
if [ -f "$SCRIPT_DIR/docker-compose.yml" ]; then
echo -e "${YELLOW}[5/5] Starting container with Docker Compose...${NC}"
docker compose -f "$SCRIPT_DIR/docker-compose.yml" up -d --remove-orphans
echo -e "${GREEN}✓ Container started with Docker Compose${NC}"
else
echo -e "${YELLOW}[5/5] No docker-compose.yml found, skipping auto-start${NC}"
fi
# Step 6: Summary
echo -e "${YELLOW}[6/6] Build summary${NC}"
docker images | grep "$APP_NAME" | head -3
echo ""
echo -e "${GREEN}=== Build Complete ===${NC}"
echo -e "Run locally with:"
echo -e " ${BLUE}docker compose -f $SCRIPT_DIR/docker-compose.yml up -d${NC}"
echo ""
version: '3.8'
services:
canifa-note:
build:
context: ..
dockerfile: memos/Dockerfile
args:
APP_NAME: canifa-note
APP_ICON: canifa
BUILD_VERSION: dev
image: canifa-note:latest
container_name: canifa-note
restart: unless-stopped
ports:
- "5230:5230"
volumes:
- canifa-data:/app/data
- ../public/image.png:/app/public/icon.png:ro
environment:
APP_NAME: canifa-note
APP_ICON: canifa
MEMOS_DATA: /app/data
healthcheck:
test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:5230/api/v1/ping" ]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes:
canifa-data:
driver: local
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment