migrate from github

This commit is contained in:
2026-07-15 23:28:04 +08:00
commit eb25aa19d9
17 changed files with 1433 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
#Requires -Version 5.1
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
$BasePath = (Resolve-Path "$ScriptDir\..\.." ).Path
$DeployDir = "$BasePath\deploy"
$EnvFile = "$DeployDir\.env"
$EnvExampleFile = "$DeployDir\.env.example"
if (-not (Test-Path $EnvExampleFile)) {
Write-Error "Missing required file: $EnvExampleFile"
exit 1
}
if (-not (Test-Path $EnvFile)) {
Copy-Item $EnvExampleFile $EnvFile
}
# Load key=value pairs from a .env file into a hashtable (last value wins)
function Read-EnvFile([string]$Path) {
$map = @{}
foreach ($line in (Get-Content $Path)) {
if ($line -match '^\s*#' -or $line.Trim() -eq '') { continue }
$idx = $line.IndexOf('=')
if ($idx -lt 1) { continue }
$map[$line.Substring(0, $idx).Trim()] = $line.Substring($idx + 1)
}
return $map
}
# Write or update a single key in the .env file
function Update-EnvKey([string]$Key, [string]$Value) {
$lines = Get-Content $EnvFile
$updated = $false
$result = foreach ($line in $lines) {
if ($line -match "^$Key=") { "$Key=$Value"; $updated = $true }
else { $line }
}
if (-not $updated) { $result += "$Key=$Value" }
$result | Set-Content $EnvFile
}
# Prompt the user for a value, showing the current default in brackets
function Prompt-Value([string]$Key, [string]$Label, [string]$Fallback) {
$current = if ($script:cfg.ContainsKey($Key) -and $script:cfg[$Key] -ne '') {
$script:cfg[$Key]
} else { $Fallback }
$input = Read-Host "$Label [$current]"
if ([string]::IsNullOrEmpty($input)) { $input = $current }
$script:cfg[$Key] = $input
Update-EnvKey $Key $input
}
# Merge example defaults then overlay with actual .env values
$script:cfg = Read-EnvFile $EnvExampleFile
foreach ($kv in (Read-EnvFile $EnvFile).GetEnumerator()) {
$script:cfg[$kv.Key] = $kv.Value
}
Write-Host "== Yoresee Deploy Config Init =="
Write-Host "Press Enter to keep the default value in brackets."
# Host exposed ports
Prompt-Value 'NGINX_HTTP_PORT' 'Host port for Nginx HTTP' '8080'
Prompt-Value 'NGINX_HTTPS_PORT' 'Host port for Nginx HTTPS' '8443'
Prompt-Value 'BACKEND_GRPC_HOST_PORT' 'Host port for backend gRPC' '9090'
Prompt-Value 'BACKEND_DEBUG_HOST_PORT' 'Host port for backend debug (dev only)' '2345'
Prompt-Value 'POSTGRES_HOST_PORT' 'Host port for Postgres (dev only)' '5432'
Prompt-Value 'REDIS_HOST_PORT' 'Host port for Redis (dev only)' '6379'
Prompt-Value 'RABBITMQ_AMQP_HOST_PORT' 'Host port for RabbitMQ AMQP (dev only)' '5672'
Prompt-Value 'CONSUL_HOST_PORT' 'Host port for Consul UI/API' '8500'
Prompt-Value 'ELASTICSEARCH_HOST_PORT' 'Host port for Elasticsearch (dev only)' '9200'
# Credentials and app secrets
Prompt-Value 'POSTGRES_USER' 'Postgres user' 'root'
Prompt-Value 'POSTGRES_PASSWORD' 'Postgres password' 'your_password'
Prompt-Value 'POSTGRES_DB' 'Postgres database' 'yoresee_doc_db'
Prompt-Value 'REDIS_PASSWORD' 'Redis password' 'your_redis_password'
Prompt-Value 'RABBITMQ_DEFAULT_USER' 'RabbitMQ user' 'guest'
Prompt-Value 'RABBITMQ_DEFAULT_PASS' 'RabbitMQ password' 'guest'
Prompt-Value 'MINIO_ROOT_USER' 'MinIO root user' 'minioadmin'
Prompt-Value 'MINIO_ROOT_PASSWORD' 'MinIO root password' 'minioadmin'
Prompt-Value 'CONSUL_ROOT_TOKEN' 'Consul root token' 'yoresee_doc_root_token'
Prompt-Value 'BACKEND_INTERNAL_RPC_KEY' 'Internal RPC key' 'yoresee_doc_internal_key'
Prompt-Value 'JWT_SECRET' 'JWT secret' 'yoresee_doc_jwt_secret_key'
# App behaviour
$defaultApiUrl = "http://localhost:$($script:cfg['NGINX_HTTP_PORT'])"
Prompt-Value 'VITE_API_BASE_URL' 'Frontend API base URL' $defaultApiUrl
Prompt-Value 'VITE_GRPC_WEB_ENDPOINT' 'Frontend gRPC-web endpoint' '/grpc'
Prompt-Value 'DIRTY_DOC_NOTIFY_THRESHOLD' 'Dirty doc notify threshold' '5'
# Derived value — keep MinIO redirect bound to API base URL
$minioRedirect = "$($script:cfg['VITE_API_BASE_URL'].TrimEnd('/'))/minio"
Update-EnvKey 'MINIO_BROWSER_REDIRECT_URL' $minioRedirect
Write-Host "MinIO browser redirect URL (derived): $minioRedirect"
Prompt-Value 'ELASTICSEARCH_ENABLED' 'Enable Elasticsearch' 'true'
Prompt-Value 'ELASTICSEARCH_INDEX_PREFIX' 'Elasticsearch index prefix' 'yoresee_doc'
Prompt-Value 'ELASTICSEARCH_USERNAME' 'Elasticsearch username (optional)' ''
Prompt-Value 'ELASTICSEARCH_PASSWORD' 'Elasticsearch password (optional)' ''
Write-Host "Written: $EnvFile"
& powershell -ExecutionPolicy Bypass -File "$ScriptDir\prepare.ps1"
Write-Host "Initialization completed."
Write-Host "You can start services with: powershell -ExecutionPolicy Bypass -File deploy/script/start.ps1 dev up"
+119
View File
@@ -0,0 +1,119 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BASE_PATH="$(cd "$SCRIPT_DIR/../.." && pwd)"
DEPLOY_DIR="$BASE_PATH/deploy"
ENV_FILE="$DEPLOY_DIR/.env"
ENV_EXAMPLE_FILE="$DEPLOY_DIR/.env.example"
if [ ! -t 0 ]; then
echo "Interactive terminal is required."
echo "Fallback: copy deploy/.env.example to deploy/.env then run bash deploy/script/prepare.sh"
exit 1
fi
if [ ! -f "$ENV_EXAMPLE_FILE" ]; then
echo "Missing required file: $ENV_EXAMPLE_FILE"
exit 1
fi
if [ ! -f "$ENV_FILE" ]; then
cp "$ENV_EXAMPLE_FILE" "$ENV_FILE"
fi
set -a
# shellcheck disable=SC1090
source "$ENV_EXAMPLE_FILE"
# shellcheck disable=SC1090
source "$ENV_FILE"
set +a
update_env_key() {
local key="$1"
local value="$2"
local tmp_file=""
tmp_file="$(mktemp)"
awk -v key="$key" -v val="$value" '
BEGIN { updated = 0 }
$0 ~ "^" key "=" {
print key "=" val
updated = 1
next
}
{ print }
END {
if (!updated) {
print key "=" val
}
}
' "$ENV_FILE" > "$tmp_file"
mv "$tmp_file" "$ENV_FILE"
}
prompt_value() {
local key="$1"
local label="$2"
local fallback="$3"
local current_value=""
local input=""
current_value="${!key:-$fallback}"
read -r -p "$label [$current_value]: " input
if [ -z "$input" ]; then
input="$current_value"
fi
printf -v "$key" '%s' "$input"
update_env_key "$key" "$input"
}
echo "== Yoresee Deploy Config Init =="
echo "Press Enter to keep the default value in brackets."
# Host exposed ports
prompt_value NGINX_HTTP_PORT "Host port for Nginx HTTP" "8080"
prompt_value NGINX_HTTPS_PORT "Host port for Nginx HTTPS" "8443"
prompt_value BACKEND_GRPC_HOST_PORT "Host port for backend gRPC" "9090"
prompt_value BACKEND_DEBUG_HOST_PORT "Host port for backend debug (dev only)" "2345"
prompt_value POSTGRES_HOST_PORT "Host port for Postgres (dev only)" "5432"
prompt_value REDIS_HOST_PORT "Host port for Redis (dev only)" "6379"
prompt_value RABBITMQ_AMQP_HOST_PORT "Host port for RabbitMQ AMQP (dev only)" "5672"
prompt_value CONSUL_HOST_PORT "Host port for Consul UI/API" "8500"
prompt_value ELASTICSEARCH_HOST_PORT "Host port for Elasticsearch (dev only)" "9200"
# Credentials and app secrets
prompt_value POSTGRES_USER "Postgres user" "root"
prompt_value POSTGRES_PASSWORD "Postgres password" "your_password"
prompt_value POSTGRES_DB "Postgres database" "yoresee_doc_db"
prompt_value REDIS_PASSWORD "Redis password" "your_redis_password"
prompt_value RABBITMQ_DEFAULT_USER "RabbitMQ user" "guest"
prompt_value RABBITMQ_DEFAULT_PASS "RabbitMQ password" "guest"
prompt_value MINIO_ROOT_USER "MinIO root user" "minioadmin"
prompt_value MINIO_ROOT_PASSWORD "MinIO root password" "minioadmin"
prompt_value CONSUL_ROOT_TOKEN "Consul root token" "yoresee_doc_root_token"
prompt_value BACKEND_INTERNAL_RPC_KEY "Internal RPC key" "yoresee_doc_internal_key"
prompt_value JWT_SECRET "JWT secret" "yoresee_doc_jwt_secret_key"
# App behavior
prompt_value VITE_API_BASE_URL "Frontend API base URL" "http://localhost:${NGINX_HTTP_PORT}"
prompt_value VITE_GRPC_WEB_ENDPOINT "Frontend gRPC-web endpoint" "/grpc"
prompt_value DIRTY_DOC_NOTIFY_THRESHOLD "Dirty doc notify threshold" "5"
# Keep MinIO browser redirect bound to API base URL to avoid host drift in deployments.
MINIO_BROWSER_REDIRECT_URL="${VITE_API_BASE_URL%/}/minio"
update_env_key MINIO_BROWSER_REDIRECT_URL "$MINIO_BROWSER_REDIRECT_URL"
echo "MinIO browser redirect URL (derived): $MINIO_BROWSER_REDIRECT_URL"
prompt_value ELASTICSEARCH_ENABLED "Enable Elasticsearch" "true"
prompt_value ELASTICSEARCH_INDEX_PREFIX "Elasticsearch index prefix" "yoresee_doc"
prompt_value ELASTICSEARCH_USERNAME "Elasticsearch username (optional)" ""
prompt_value ELASTICSEARCH_PASSWORD "Elasticsearch password (optional)" ""
echo "Written: $ENV_FILE"
bash "$SCRIPT_DIR/prepare.sh"
echo "Initialization completed."
echo "You can start services with: bash deploy/script/start.sh dev up"
+20
View File
@@ -0,0 +1,20 @@
#Requires -Version 5.1
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
$DeployDir = Resolve-Path "$ScriptDir\.."
if (Get-Command buf -ErrorAction SilentlyContinue) {
Write-Host "buf found locally, generating directly..."
Push-Location "$DeployDir\..\proto"
buf generate --template buf.gen.backend.yaml
buf generate --template buf.gen.collab-go.yaml
buf generate --template buf.gen.frontend.yaml
buf generate --template buf.gen.node.yaml
Pop-Location
Write-Host "Proto generation complete."
} else {
Write-Host "buf not found locally, using proto-gen container..."
docker compose -f "$DeployDir\docker-compose.dev.yml" run --rm proto-gen
}
+18
View File
@@ -0,0 +1,18 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPLOY_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
if command -v buf &>/dev/null; then
echo "buf found locally, generating directly..."
cd "$DEPLOY_DIR/../proto"
buf generate --template buf.gen.backend.yaml
buf generate --template buf.gen.collab-go.yaml
buf generate --template buf.gen.frontend.yaml
buf generate --template buf.gen.node.yaml
echo "Proto generation complete."
else
echo "buf not found locally, using proto-gen container..."
docker compose -f "$DEPLOY_DIR/docker-compose.dev.yml" run --rm proto-gen
fi
+86
View File
@@ -0,0 +1,86 @@
#Requires -Version 5.1
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
$BasePath = (Resolve-Path "$ScriptDir\..\.." ).Path
$DeployDir = "$BasePath\deploy"
$EnvExampleFile = "$DeployDir\.env.example"
$EnvFile = "$DeployDir\.env"
if (-not (Test-Path $EnvExampleFile)) {
Write-Error "Missing required file: $EnvExampleFile"
exit 1
}
if (-not (Test-Path $EnvFile)) {
Write-Host "deploy\.env not found, creating from .env.example"
Copy-Item $EnvExampleFile $EnvFile
}
# Load key=value pairs from a .env file into a hashtable (last value wins)
function Read-EnvFile([string]$Path) {
$map = @{}
foreach ($line in (Get-Content $Path)) {
if ($line -match '^\s*#' -or $line.Trim() -eq '') { continue }
$idx = $line.IndexOf('=')
if ($idx -lt 1) { continue }
$map[$line.Substring(0, $idx).Trim()] = $line.Substring($idx + 1)
}
return $map
}
# Expand ${VAR} placeholders in a template string using the provided env hashtable
function Expand-Template([string]$Text, [hashtable]$Env) {
return [regex]::Replace($Text, '\$\{([A-Z0-9_]+)\}', {
param($m)
$key = $m.Groups[1].Value
if ($Env.ContainsKey($key)) { $Env[$key] } else { '' }
})
}
# Render a template file to an output path, substituting ${VAR} with env values
function Render-Template([string]$Template, [string]$Output, [hashtable]$Env) {
if (-not (Test-Path $Template)) {
Write-Error "Template not found: $Template"
return
}
$outDir = Split-Path -Parent $Output
if (-not (Test-Path $outDir)) { New-Item -ItemType Directory -Force -Path $outDir | Out-Null }
# If a directory exists at the output path, back it up
if (Test-Path $Output -PathType Container) {
$backup = "$Output.backup.$([DateTimeOffset]::UtcNow.ToUnixTimeSeconds())"
Move-Item $Output $backup
Write-Host "Detected directory at $Output, moved to $backup"
}
$content = Get-Content $Template -Raw
$rendered = Expand-Template $content $Env
[System.IO.File]::WriteAllText($Output, $rendered)
}
# Merge example defaults then overlay with actual .env values
$env_map = Read-EnvFile $EnvExampleFile
foreach ($kv in (Read-EnvFile $EnvFile).GetEnumerator()) {
$env_map[$kv.Key] = $kv.Value
}
$templateMappings = @(
@{ Template = "$BasePath\backend\config.toml.tmpl"; Output = "$BasePath\backend\config.toml" }
@{ Template = "$BasePath\frontend\nginx.conf.tmpl"; Output = "$BasePath\frontend\nginx.conf" }
@{ Template = "$DeployDir\nginx\nginx.conf.tmpl"; Output = "$DeployDir\nginx\nginx.conf" }
@{ Template = "$DeployDir\nginx\conf.d\default.conf.tmpl"; Output = "$DeployDir\nginx\conf.d\default.conf" }
@{ Template = "$DeployDir\redis\redis.conf.tmpl"; Output = "$DeployDir\redis\redis.conf" }
@{ Template = "$DeployDir\rabbitmq\rabbitmq.conf.tmpl"; Output = "$DeployDir\rabbitmq\rabbitmq.conf" }
)
Write-Host "Rendering configuration files from templates..."
foreach ($m in $templateMappings) {
Render-Template $m.Template $m.Output $env_map
$rel = $m.Output.Replace("$BasePath\", '')
Write-Host " - $rel"
}
Write-Host "Configuration preparation completed!"
+75
View File
@@ -0,0 +1,75 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BASE_PATH="$(cd "$SCRIPT_DIR/../.." && pwd)"
DEPLOY_DIR="$BASE_PATH/deploy"
ENV_EXAMPLE_FILE="$DEPLOY_DIR/.env.example"
ENV_FILE="$DEPLOY_DIR/.env"
if [ ! -f "$ENV_EXAMPLE_FILE" ]; then
echo "Missing required file: $ENV_EXAMPLE_FILE"
exit 1
fi
if [ ! -f "$ENV_FILE" ]; then
echo "deploy/.env not found, creating from .env.example"
cp "$ENV_EXAMPLE_FILE" "$ENV_FILE"
fi
set -a
# shellcheck disable=SC1090
source "$ENV_EXAMPLE_FILE"
# shellcheck disable=SC1090
source "$ENV_FILE"
set +a
prepare_target_file() {
local target="$1"
if [ -d "$target" ]; then
local backup="${target}.backup.$(date +%s)"
mv "$target" "$backup"
echo "Detected directory at $target, moved to $backup"
fi
}
render_template() {
local template="$1"
local output="$2"
local tmp_file=""
if [ ! -f "$template" ]; then
echo "Template not found: $template"
return 1
fi
mkdir -p "$(dirname "$output")"
prepare_target_file "$output"
tmp_file="$(mktemp)"
perl -pe 's/\$\{([A-Z0-9_]+)\}/defined $ENV{$1} ? $ENV{$1} : ""/ge' "$template" > "$tmp_file"
mv "$tmp_file" "$output"
}
TEMPLATE_MAPPINGS=(
"$BASE_PATH/backend/config.toml.tmpl:$BASE_PATH/backend/config.toml"
"$BASE_PATH/frontend/nginx.conf.tmpl:$BASE_PATH/frontend/nginx.conf"
"$DEPLOY_DIR/nginx/nginx.conf.tmpl:$DEPLOY_DIR/nginx/nginx.conf"
"$DEPLOY_DIR/nginx/conf.d/default.conf.tmpl:$DEPLOY_DIR/nginx/conf.d/default.conf"
"$DEPLOY_DIR/redis/redis.conf.tmpl:$DEPLOY_DIR/redis/redis.conf"
"$DEPLOY_DIR/rabbitmq/rabbitmq.conf.tmpl:$DEPLOY_DIR/rabbitmq/rabbitmq.conf"
)
echo "Rendering configuration files from templates..."
for mapping in "${TEMPLATE_MAPPINGS[@]}"; do
template="${mapping%%:*}"
output="${mapping#*:}"
render_template "$template" "$output"
rel_output="${output#$BASE_PATH/}"
if [ "$rel_output" = "$output" ]; then
rel_output="$output"
fi
echo " - $rel_output"
done
echo "Configuration preparation completed!"
+61
View File
@@ -0,0 +1,61 @@
#Requires -Version 5.1
param(
[Parameter(Mandatory)][ValidateSet('dev','release')][string]$Environment,
[Parameter(Mandatory)][ValidateSet('rebuild','clear','restart','up','build')][string]$Action
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
$BasePath = (Resolve-Path "$ScriptDir\..\.." ).Path
$DeployDir = "$BasePath\deploy"
Write-Host "Environment: $Environment"
Write-Host "Action: $Action"
Write-Host "Base path: $BasePath"
$ComposeFile = if ($Environment -eq 'dev') { 'docker-compose.dev.yml' } else { 'docker-compose.yml' }
Write-Host "Compose file: $ComposeFile"
if ($Environment -eq 'dev') {
Write-Host "Generating proto code..."
docker compose -f "$DeployDir\$ComposeFile" run --rm proto-gen
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
}
Push-Location $DeployDir
try {
switch ($Action) {
'rebuild' {
Write-Host "Rebuilding and starting services..."
docker compose -f $ComposeFile down -v
docker compose -f $ComposeFile up -d --build
}
'clear' {
Write-Host "Clearing containers and volumes..."
docker compose -f $ComposeFile down -v
}
'restart' {
Write-Host "Restarting services..."
docker compose -f $ComposeFile down
docker compose -f $ComposeFile up -d
}
'up' {
Write-Host "Starting services..."
docker compose -f $ComposeFile up -d
}
'build' {
Write-Host "Building images..."
docker compose -f $ComposeFile build
}
}
} finally {
Pop-Location
}
if ($LASTEXITCODE -ne 0) {
Write-Error "Operation failed."
exit $LASTEXITCODE
}
Write-Host "Operation completed successfully."
+91
View File
@@ -0,0 +1,91 @@
#!/bin/bash
# Check parameter count
if [ $# -lt 2 ]; then
echo "Usage: $0 <dev|release> <rebuild|clear|restart|up|build>"
echo " dev|release: Use docker-compose.dev.yml or docker-compose.yml"
echo " rebuild: Clean containers and volumes, then rebuild and start"
echo " clear: Clean containers and volumes"
echo " restart: Stop and restart services"
echo " up: Start services"
echo " build: Build images without starting"
exit 1
fi
ENVIRONMENT=$1
ACTION=$2
# Parameter validation
if [[ "$ENVIRONMENT" != "dev" && "$ENVIRONMENT" != "release" ]]; then
echo "Error: First argument must be 'dev' or 'release'"
exit 1
fi
if [[ "$ACTION" != "rebuild" && "$ACTION" != "clear" && "$ACTION" != "restart" && "$ACTION" != "up" && "$ACTION" != "build" ]]; then
echo "Error: Second argument must be 'rebuild', 'clear', 'restart', 'up', or 'build'"
exit 1
fi
ORIGINAL_DIR=$(pwd)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BASE_PATH="$(cd "$SCRIPT_DIR/../.." && pwd)"
echo "Environment: $ENVIRONMENT"
echo "Action: $ACTION"
echo "Script directory: $SCRIPT_DIR"
echo "Base path: $BASE_PATH"
cd "$BASE_PATH"/deploy/
# Select compose file based on environment
if [ "$ENVIRONMENT" = "dev" ]; then
COMPOSE_FILE="docker-compose.dev.yml"
else
COMPOSE_FILE="docker-compose.yml"
fi
echo "Using compose file: $COMPOSE_FILE"
if [ "$ENVIRONMENT" = "dev" ]; then
echo "Generating proto code..."
docker compose -f "$COMPOSE_FILE" run --rm proto-gen
fi
case "$ACTION" in
"rebuild")
echo "Rebuilding and starting services..."
docker compose -f "$COMPOSE_FILE" down -v
docker compose -f "$COMPOSE_FILE" up -d --build
;;
"clear")
echo "Clearing containers and volumes..."
docker compose -f "$COMPOSE_FILE" down -v
;;
"restart")
echo "Restarting services..."
docker compose -f "$COMPOSE_FILE" down
docker compose -f "$COMPOSE_FILE" up -d
;;
"up")
echo "Starting services..."
docker compose -f "$COMPOSE_FILE" up -d
;;
"build")
echo "Building images..."
docker compose -f "$COMPOSE_FILE" build
;;
*)
echo "Unknown action: $ACTION"
cd "$ORIGINAL_DIR"
exit 1
;;
esac
cd "$ORIGINAL_DIR"
if [ $? -eq 0 ]; then
echo "Operation completed successfully."
else
echo "Operation failed."
exit 1
fi