feat: create start:e2e and test:e2e scripts to launch tests easily

This commit is contained in:
Nicolas Meienberger 2023-04-25 20:16:12 +02:00 committed by Nicolas Meienberger
parent f389d51819
commit 6bbd950d15
6 changed files with 398 additions and 338 deletions

101
docker-compose.e2e.yml Normal file
View file

@ -0,0 +1,101 @@
version: '3.7'
services:
reverse-proxy:
container_name: reverse-proxy
image: traefik:v2.8
restart: unless-stopped
ports:
- 8080:8080
- ${NGINX_PORT-80}:80
command: --providers.docker
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ${PWD}/traefik:/root/.config
- ${PWD}/traefik/shared:/shared
networks:
- tipi_main_network
tipi-db:
container_name: tipi-db
image: postgres:14
restart: unless-stopped
stop_grace_period: 1m
ports:
- 5432:5432
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_USER: ${POSTGRES_USERNAME}
POSTGRES_DB: ${POSTGRES_DBNAME}
healthcheck:
test: ['CMD-SHELL', 'pg_isready -d tipi -U tipi']
interval: 5s
timeout: 10s
retries: 120
networks:
- tipi_main_network
tipi-redis:
container_name: tipi-redis
image: redis:alpine
restart: unless-stopped
volumes:
- ./data/redis:/data
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 5s
timeout: 10s
retries: 120
networks:
- tipi_main_network
dashboard:
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
container_name: dashboard
networks:
- tipi_main_network
depends_on:
tipi-db:
condition: service_healthy
tipi-redis:
condition: service_healthy
environment:
NODE_ENV: production
INTERNAL_IP: ${INTERNAL_IP}
TIPI_VERSION: ${TIPI_VERSION}
JWT_SECRET: ${JWT_SECRET}
NGINX_PORT: ${NGINX_PORT}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_USERNAME: ${POSTGRES_USERNAME}
POSTGRES_DBNAME: ${POSTGRES_DBNAME}
POSTGRES_HOST: ${POSTGRES_HOST}
APPS_REPO_ID: ${APPS_REPO_ID}
APPS_REPO_URL: ${APPS_REPO_URL}
DOMAIN: ${DOMAIN}
ARCHITECTURE: ${ARCHITECTURE}
REDIS_HOST: ${REDIS_HOST}
DEMO_MODE: ${DEMO_MODE}
volumes:
- ${PWD}/state:/runtipi/state
- ${PWD}/repos:/runtipi/repos:ro
- ${PWD}/apps:/runtipi/apps
- ${PWD}/logs:/app/logs
- ${PWD}:/app/storage
labels:
traefik.enable: true
# Web
traefik.http.routers.dashboard.rule: PathPrefix("/")
traefik.http.routers.dashboard.service: dashboard
traefik.http.routers.dashboard.entrypoints: web
traefik.http.services.dashboard.loadbalancer.server.port: 3000
networks:
tipi_main_network:
driver: bridge
ipam:
driver: default
config:
- subnet: 10.21.21.0/24

View file

@ -5,6 +5,8 @@
"scripts": {
"copy:migrations": "mkdir -p dist/migrations && cp -r ./src/server/migrations dist",
"test": "dotenv -e .env.test -- jest --colors",
"test:e2e": "NODE_ENV=test dotenv -e .env.e2e -- playwright test",
"test:e2e:ui": "NODE_ENV=test dotenv -e .env.e2e -- playwright test --ui",
"test:client": "jest --colors --selectProjects client --",
"test:server": "jest --colors --selectProjects server --",
"dev": "npm run copy:migrations && nodemon",
@ -18,6 +20,7 @@
"start:dev-container": "./.devcontainer/filewatcher.sh && npm run start:dev",
"start:rc": "docker-compose -f docker-compose.rc.yml --env-file .env up --build",
"start:prod": "docker-compose -f docker-compose.test.yml --env-file .env up --build",
"start:e2e": "./scripts/start-e2e.sh",
"start:pg": "docker run --name test-db -p 5433:5432 -d --rm -e POSTGRES_PASSWORD=postgres postgres:14",
"version": "echo $npm_package_version",
"release:rc": "./scripts/deploy/release-rc.sh",

View file

@ -1,6 +1,8 @@
#!/usr/bin/env bash
ROOT_FOLDER="${PWD}"
STATE_FOLDER="${ROOT_FOLDER}/state"
# Get field from json file
function get_json_field() {
local json_file="$1"
@ -94,3 +96,145 @@ function kill_watcher() {
fi
fi
}
function generate_env_file() {
echo "Generating .env file..."
env_variables=$1
json_file=$(mktemp)
echo "$env_variables" > "$json_file"
local default_tz="Etc\/UTC"
local tz="$(timedatectl | grep "Time zone" | awk '{print $3}' | sed 's/\//\\\//g')"
if [[ -z "$tz" ]]; then
tz="$default_tz"
fi
local architecture="$(uname -m | tr '[:upper:]' '[:lower:]')"
if [[ "$architecture" == "aarch64" ]] || [[ "$architecture" == "armv8"* ]]; then
architecture="arm64"
elif [[ "$architecture" == "x86_64" ]]; then
architecture="amd64"
fi
# If none of the above conditions are met, the architecture is not supported
if [[ "$architecture" != "arm64" ]] && [[ "$architecture" != "amd64" ]]; then
echo "Architecture ${architecture} not supported if you think this is a mistake, please open an issue on GitHub."
exit 1
fi
local dns_ip=$(get_json_field "$json_file" dns_ip)
local internal_ip=$(get_json_field "$json_file" internal_ip)
local jwt_secret=$(get_json_field "$json_file" jwt_secret)
local tipi_version=$(get_json_field "$json_file" tipi_version)
local nginx_port=$(get_json_field "$json_file" nginx_port)
local nginx_port_ssl=$(get_json_field "$json_file" nginx_port_ssl)
local repo_id=$(get_json_field "$json_file" repo_id)
local domain=$(get_json_field "$json_file" domain)
local postgres_password=$(get_json_field "$json_file" postgres_password)
local postgres_username=$(get_json_field "$json_file" postgres_username)
local postgres_dbname=$(get_json_field "$json_file" postgres_dbname)
local postgres_host=$(get_json_field "$json_file" postgres_host)
local postgres_port=$(get_json_field "$json_file" postgres_port)
local redis_host=$(get_json_field "$json_file" redis_host)
local demo_mode=$(get_json_field "$json_file" demo_mode)
local root_folder=$(get_json_field "$json_file" root_folder | sed 's/\//\\\//g')
local apps_repository=$(get_json_field "$json_file" apps_repository | sed 's/\//\\\//g')
local storage_path=$(get_json_field "$json_file" storage_path | sed 's/\//\\\//g')
env_file=$(mktemp)
[[ -f "${ROOT_FOLDER}/.env" ]] && rm -f "${ROOT_FOLDER}/.env"
[[ -f "$ROOT_FOLDER/templates/env-sample" ]] && cp "$ROOT_FOLDER/templates/env-sample" "$env_file"
if [[ -f "${STATE_FOLDER}/settings.json" ]]; then
# If dnsIp is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" dnsIp)" != "null" ]]; then
dns_ip=$(get_json_field "${STATE_FOLDER}/settings.json" dnsIp)
fi
# If domain is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" domain)" != "null" ]]; then
domain=$(get_json_field "${STATE_FOLDER}/settings.json" domain)
fi
# If appsRepoUrl is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" appsRepoUrl)" != "null" ]]; then
apps_repository_temp=$(get_json_field "${STATE_FOLDER}/settings.json" appsRepoUrl)
apps_repository="$(echo "${apps_repository_temp}" | sed 's/\//\\\//g')"
repo_id="$("${ROOT_FOLDER}"/scripts/git.sh get_hash "${apps_repository}")"
fi
# If port is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" port)" != "null" ]]; then
nginx_port=$(get_json_field "${STATE_FOLDER}/settings.json" port)
fi
# If sslPort is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" sslPort)" != "null" ]]; then
nginx_port_ssl=$(get_json_field "${STATE_FOLDER}/settings.json" sslPort)
fi
# If listenIp is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" listenIp)" != "null" ]]; then
internal_ip=$(get_json_field "${STATE_FOLDER}/settings.json" listenIp)
fi
# If demoMode is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" demoMode)" == "true" ]]; then
demo_mode="true"
fi
# If storagePath is set in settings.json, use it
storage_path_settings=$(get_json_field "${STATE_FOLDER}/settings.json" storagePath)
if [[ "${storage_path_settings}" != "null" && "${storage_path_settings}" != "" ]]; then
storage_path_temp="${storage_path_settings}"
storage_path="$(echo "${storage_path_temp}" | sed 's/\//\\\//g')"
fi
fi
# If port is not 80 and domain is not tipi.localhost, we exit
if [[ "${nginx_port}" != "80" ]] && [[ "${domain}" != "tipi.localhost" ]]; then
echo "Using a custom domain with a custom port is not supported"
exit 1
fi
os=$(uname)
sed_args=(-i)
# If os is macos, use gnu sed
if [[ "$os" == "Darwin" ]]; then
echo "Using gnu sed"
sed_args=(-i '')
fi
# Function below is modified from Umbrel
# Required Notice: Copyright
# Umbrel (https://umbrel.com)
for template in ${env_file}; do
sed "${sed_args[@]}" "s/<dns_ip>/${dns_ip}/g" "${template}"
sed "${sed_args[@]}" "s/<internal_ip>/${internal_ip}/g" "${template}"
sed "${sed_args[@]}" "s/<tz>/${tz}/g" "${template}"
sed "${sed_args[@]}" "s/<jwt_secret>/${jwt_secret}/g" "${template}"
sed "${sed_args[@]}" "s/<root_folder>/${root_folder}/g" "${template}"
sed "${sed_args[@]}" "s/<tipi_version>/${tipi_version}/g" "${template}"
sed "${sed_args[@]}" "s/<architecture>/${architecture}/g" "${template}"
sed "${sed_args[@]}" "s/<nginx_port>/${nginx_port}/g" "${template}"
sed "${sed_args[@]}" "s/<nginx_port_ssl>/${nginx_port_ssl}/g" "${template}"
sed "${sed_args[@]}" "s/<apps_repo_id>/${repo_id}/g" "${template}"
sed "${sed_args[@]}" "s/<apps_repo_url>/${apps_repository}/g" "${template}"
sed "${sed_args[@]}" "s/<domain>/${domain}/g" "${template}"
sed "${sed_args[@]}" "s/<storage_path>/${storage_path}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_password>/${postgres_password}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_username>/${postgres_username}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_dbname>/${postgres_dbname}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_port>/${postgres_port}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_host>/${postgres_host}/g" "${template}"
sed "${sed_args[@]}" "s/<redis_host>/${redis_host}/g" "${template}"
sed "${sed_args[@]}" "s/<demo_mode>/${demo_mode}/g" "${template}"
done
mv -f "$env_file" "$ROOT_FOLDER/.env"
chmod a+rwx "$ROOT_FOLDER/.env"
}

View file

@ -15,57 +15,42 @@ clean_logs
### --------------------------------
ROOT_FOLDER="${PWD}"
STATE_FOLDER="${ROOT_FOLDER}/state"
SED_ROOT_FOLDER="$(echo "$ROOT_FOLDER" | sed 's/\//\\\//g')"
NGINX_PORT=3000
NGINX_PORT_SSL=443
DOMAIN=tipi.localhost
DNS_IP="9.9.9.9" # Default to Quad9 DNS
ARCHITECTURE="$(uname -m)"
TZ="UTC"
JWT_SECRET=secret
POSTGRES_PASSWORD=postgres
POSTGRES_USERNAME=tipi
POSTGRES_DBNAME=tipi
POSTGRES_PORT=5432
POSTGRES_HOST=tipi-db
REDIS_HOST=tipi-redis
TIPI_VERSION=$(get_json_field "${ROOT_FOLDER}/package.json" version)
INTERNAL_IP=localhost
DEMO_MODE=false
storage_path="${ROOT_FOLDER}"
STORAGE_PATH_ESCAPED="$(echo "${storage_path}" | sed 's/\//\\\//g')"
if [[ "$ARCHITECTURE" == "aarch64" ]]; then
ARCHITECTURE="arm64"
elif [[ "$ARCHITECTURE" == "armv7l" ]]; then
ARCHITECTURE="arm"
elif [[ "$ARCHITECTURE" == "x86_64" ]]; then
ARCHITECTURE="amd64"
fi
# If none of the above conditions are met, the architecture is not supported
if [[ "$ARCHITECTURE" != "arm64" ]] && [[ "$ARCHITECTURE" != "arm" ]] && [[ "$ARCHITECTURE" != "amd64" ]]; then
echo "Architecture not supported!"
exit 1
fi
### --------------------------------
### Apps repository configuration
### --------------------------------
apps_repository="https://github.com/meienberger/runtipi-appstore"
APPS_REPOSITORY_ESCAPED="$(echo ${apps_repository} | sed 's/\//\\\//g')"
REPO_ID="$("${ROOT_FOLDER}"/scripts/git.sh get_hash ${apps_repository})"
# Override configs with settings.json
if [[ -f "${STATE_FOLDER}/settings.json" ]]; then
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" appsRepoUrl)" != "null" ]]; then
apps_repository=$(get_json_field "${STATE_FOLDER}/settings.json" appsRepoUrl)
APPS_REPOSITORY_ESCAPED="$(echo "${apps_repository}" | sed 's/\//\\\//g')"
REPO_ID="$("${ROOT_FOLDER}"/scripts/git.sh get_hash "${apps_repository}")"
fi
fi
env_variables_json=$(cat <<EOF
{
"dns_ip": "9.9.9.9",
"domain": "tipi.localhost",
"root_folder": "${ROOT_FOLDER}",
"nginx_port": 3000,
"nginx_port_ssl": 443,
"jwt_secret": "secret",
"postgres_password": "postgres",
"postgres_username": "tipi",
"postgres_dbname": "tipi",
"postgres_port": 5432,
"postgres_host": "tipi-db",
"redis_host": "tipi-redis",
"tipi_version": "$(get_json_field "${ROOT_FOLDER}/package.json" version)",
"internal_ip": "localhost",
"demo_mode": false,
"apps_repository": "${apps_repository}",
"storage_path": "${ROOT_FOLDER}",
"repo_id": "$("${ROOT_FOLDER}"/scripts/git.sh get_hash "${apps_repository}")"
}
EOF
)
### --------------------------------
### Watcher and system-info
### --------------------------------
mkdir -p "${ROOT_FOLDER}/state"
if [[ ! -f "${ROOT_FOLDER}/state/events" ]]; then
touch "${ROOT_FOLDER}/state/events"
fi
@ -82,91 +67,9 @@ kill_watcher
### --------------------------------
### env file generation
### --------------------------------
ENV_FILE=$(mktemp)
[[ -f "${ROOT_FOLDER}/.env" ]] && rm -f "${ROOT_FOLDER}/.env"
[[ -f "$ROOT_FOLDER/templates/env-sample" ]] && cp "$ROOT_FOLDER/templates/env-sample" "$ENV_FILE"
OS=$(uname)
sed_args=(-i)
# If os is macos, use gnu sed
if [[ "$OS" == "Darwin" ]]; then
echo "Using gnu sed"
sed_args=(-i '')
fi
if [[ -f "${STATE_FOLDER}/settings.json" ]]; then
# If dnsIp is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" dnsIp)" != "null" ]]; then
DNS_IP=$(get_json_field "${STATE_FOLDER}/settings.json" dnsIp)
fi
# If domain is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" domain)" != "null" ]]; then
DOMAIN=$(get_json_field "${STATE_FOLDER}/settings.json" domain)
fi
# If appsRepoUrl is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" appsRepoUrl)" != "null" ]]; then
apps_repository=$(get_json_field "${STATE_FOLDER}/settings.json" appsRepoUrl)
APPS_REPOSITORY_ESCAPED="$(echo "${apps_repository}" | sed 's/\//\\\//g')"
REPO_ID="$("${ROOT_FOLDER}"/scripts/git.sh get_hash "${apps_repository}")"
fi
# If port is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" port)" != "null" ]]; then
NGINX_PORT=$(get_json_field "${STATE_FOLDER}/settings.json" port)
fi
# If sslPort is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" sslPort)" != "null" ]]; then
NGINX_PORT_SSL=$(get_json_field "${STATE_FOLDER}/settings.json" sslPort)
fi
# If listenIp is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" listenIp)" != "null" ]]; then
INTERNAL_IP=$(get_json_field "${STATE_FOLDER}/settings.json" listenIp)
fi
# If storagePath is set in settings.json, use it
storage_path_settings=$(get_json_field "${STATE_FOLDER}/settings.json" storagePath)
if [[ "${storage_path_settings}" != "null" && "${storage_path_settings}" != "" ]]; then
storage_path="${storage_path_settings}"
STORAGE_PATH_ESCAPED="$(echo "${storage_path}" | sed 's/\//\\\//g')"
fi
fi
# Function below is modified from Umbrel
# Required Notice: Copyright
# Umbrel (https://umbrel.com)
for template in ${ENV_FILE}; do
sed "${sed_args[@]}" "s/<dns_ip>/${DNS_IP}/g" "${template}"
sed "${sed_args[@]}" "s/<internal_ip>/${INTERNAL_IP}/g" "${template}"
sed "${sed_args[@]}" "s/<tz>/${TZ}/g" "${template}"
sed "${sed_args[@]}" "s/<jwt_secret>/${JWT_SECRET}/g" "${template}"
sed "${sed_args[@]}" "s/<root_folder>/${SED_ROOT_FOLDER}/g" "${template}"
sed "${sed_args[@]}" "s/<tipi_version>/${TIPI_VERSION}/g" "${template}"
sed "${sed_args[@]}" "s/<architecture>/${ARCHITECTURE}/g" "${template}"
sed "${sed_args[@]}" "s/<nginx_port>/${NGINX_PORT}/g" "${template}"
sed "${sed_args[@]}" "s/<nginx_port_ssl>/${NGINX_PORT_SSL}/g" "${template}"
sed "${sed_args[@]}" "s/<apps_repo_id>/${REPO_ID}/g" "${template}"
sed "${sed_args[@]}" "s/<apps_repo_url>/${APPS_REPOSITORY_ESCAPED}/g" "${template}"
sed "${sed_args[@]}" "s/<domain>/${DOMAIN}/g" "${template}"
sed "${sed_args[@]}" "s/<storage_path>/${STORAGE_PATH_ESCAPED}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_password>/${POSTGRES_PASSWORD}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_username>/${POSTGRES_USERNAME}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_dbname>/${POSTGRES_DBNAME}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_port>/${POSTGRES_PORT}/g" "${template}"
sed "${sed_args[@]}" "s/<postgres_host>/${POSTGRES_HOST}/g" "${template}"
sed "${sed_args[@]}" "s/<redis_host>/${REDIS_HOST}/g" "${template}"
sed "${sed_args[@]}" "s/<demo_mode>/${DEMO_MODE}/g" "${template}"
done
mv -f "$ENV_FILE" "$ROOT_FOLDER/.env.dev"
cp "$ROOT_FOLDER/.env.dev" "$ROOT_FOLDER/.env"
chmod a+rwx "$ROOT_FOLDER/.env"
chmod a+rwx "${ROOT_FOLDER}/.env.dev"
generate_env_file "${env_variables_json}"
### --------------------------------
### Start the project
### --------------------------------
docker compose -f docker-compose.dev.yml --env-file "${ROOT_FOLDER}/.env.dev" up --build
docker compose -f docker-compose.dev.yml up --build

74
scripts/start-e2e.sh Executable file
View file

@ -0,0 +1,74 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
if [[ "${TRACE-0}" == "1" ]]; then
set -o xtrace
fi
source "${BASH_SOURCE%/*}/common.sh"
clean_logs
### --------------------------------
### General variables
### --------------------------------
ROOT_FOLDER="${PWD}"
STATE_FOLDER="${ROOT_FOLDER}/state"
### --------------------------------
### Apps repository configuration
### --------------------------------
apps_repository="https://github.com/meienberger/runtipi-appstore"
env_variables_json=$(cat <<EOF
{
"dns_ip": "9.9.9.9",
"domain": "tipi.localhost",
"root_folder": "${ROOT_FOLDER}",
"nginx_port": 3000,
"nginx_port_ssl": 443,
"jwt_secret": "secret",
"postgres_password": "postgres",
"postgres_username": "tipi",
"postgres_dbname": "tipi",
"postgres_port": 5432,
"postgres_host": "tipi-db",
"redis_host": "tipi-redis",
"tipi_version": "$(get_json_field "${ROOT_FOLDER}/package.json" version)",
"internal_ip": "localhost",
"demo_mode": false,
"apps_repository": "${apps_repository}",
"storage_path": "${ROOT_FOLDER}",
"repo_id": "$("${ROOT_FOLDER}"/scripts/git.sh get_hash ${apps_repository})"
}
EOF
)
### --------------------------------
### Watcher and system-info
### --------------------------------
mkdir -p "${ROOT_FOLDER}/state"
if [[ ! -f "${ROOT_FOLDER}/state/events" ]]; then
touch "${ROOT_FOLDER}/state/events"
fi
if [[ ! -f "${ROOT_FOLDER}/state/system-info.json" ]]; then
echo "{}" >"${ROOT_FOLDER}/state/system-info.json"
fi
chmod -R a+rwx "${ROOT_FOLDER}/state/events"
chmod -R a+rwx "${ROOT_FOLDER}/state/system-info.json"
kill_watcher
"${ROOT_FOLDER}/scripts/watcher.sh" &
### --------------------------------
### env file generation
### --------------------------------
generate_env_file "${env_variables_json}"
### --------------------------------
### Start the project
### --------------------------------
docker compose -f docker-compose.e2e.yml up -d --build

View file

@ -33,106 +33,17 @@ fi
### --------------------------------
### General variables
### --------------------------------
DEFAULT_TZ="Etc\/UTC"
TZ="$(timedatectl | grep "Time zone" | awk '{print $3}' | sed 's/\//\\\//g')"
if [[ -z "$TZ" ]]; then
TZ="$DEFAULT_TZ"
fi
NGINX_PORT=80
NGINX_PORT_SSL=443
DOMAIN=tipi.localhost
SED_ROOT_FOLDER="$(echo "$ROOT_FOLDER" | sed 's/\//\\\//g')"
DNS_IP="9.9.9.9" # Default to Quad9 DNS
ARCHITECTURE="$(uname -m | tr '[:upper:]' '[:lower:]')"
apps_repository="https://github.com/meienberger/runtipi-appstore"
REPO_ID="$("${ROOT_FOLDER}"/scripts/git.sh get_hash ${apps_repository})"
APPS_REPOSITORY_ESCAPED="$(echo ${apps_repository} | sed 's/\//\\\//g')"
JWT_SECRET=$(derive_entropy "jwt")
POSTGRES_PASSWORD=$(derive_entropy "postgres")
POSTGRES_USERNAME=tipi
POSTGRES_DBNAME=tipi
POSTGRES_PORT=5432
POSTGRES_HOST=tipi-db
TIPI_VERSION=$(get_json_field "${ROOT_FOLDER}/package.json" version)
storage_path="${ROOT_FOLDER}"
STORAGE_PATH_ESCAPED="$(echo "${storage_path}" | sed 's/\//\\\//g')"
REDIS_HOST=tipi-redis
DEMO_MODE=false
INTERNAL_IP=
if [[ "$ARCHITECTURE" == "aarch64" ]] || [[ "$ARCHITECTURE" == "armv8"* ]]; then
ARCHITECTURE="arm64"
elif [[ "$ARCHITECTURE" == "x86_64" ]]; then
ARCHITECTURE="amd64"
if [[ -f "${STATE_FOLDER}/settings.json" ]]; then
# If listenIp is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" listenIp)" != "null" ]]; then
INTERNAL_IP=$(get_json_field "${STATE_FOLDER}/settings.json" listenIp)
fi
fi
# If none of the above conditions are met, the architecture is not supported
if [[ "$ARCHITECTURE" != "arm64" ]] && [[ "$ARCHITECTURE" != "amd64" ]]; then
echo "Architecture ${ARCHITECTURE} not supported if you think this is a mistake, please open an issue on GitHub."
exit 1
fi
### --------------------------------
### CLI arguments
### --------------------------------
while [ -n "${1-}" ]; do
case "$1" in
--rc) rc="true" ;;
--ci) ci="true" ;;
--demo) DEMO_MODE=true ;;
--port)
port="${2-}"
if [[ "${port}" =~ ^[0-9]+$ ]]; then
NGINX_PORT="${port}"
else
echo "--port must be a number"
exit 1
fi
shift
;;
--ssl-port)
ssl_port="${2-}"
if [[ "${ssl_port}" =~ ^[0-9]+$ ]]; then
NGINX_PORT_SSL="${ssl_port}"
else
echo "--ssl-port must be a number"
exit 1
fi
shift
;;
--domain)
domain="${2-}"
if [[ "${domain}" =~ ^[a-zA-Z0-9.-]+$ ]]; then
DOMAIN="${domain}"
else
echo "--domain must be a valid domain"
exit 1
fi
shift
;;
--listen-ip)
listen_ip="${2-}"
if [[ "${listen_ip}" =~ ^[a-fA-F0-9.:]+$ ]]; then
INTERNAL_IP="${listen_ip}"
else
echo "--listen-ip must be a valid IP address"
exit 1
fi
shift
;;
--)
shift # The double dash makes them parameters
break
;;
*) echo "Option $1 not recognized" && exit 1 ;;
esac
shift
done
if [[ -z "${INTERNAL_IP:-}" ]]; then
network_interface="$(ip route | grep default | awk '{print $5}' | uniq)"
network_interface_count=$(echo "$network_interface" | wc -l)
@ -175,11 +86,33 @@ if [[ -z "${INTERNAL_IP:-}" ]]; then
fi
fi
# If port is not 80 and domain is not tipi.localhost, we exit
if [[ "${NGINX_PORT}" != "80" ]] && [[ "${DOMAIN}" != "tipi.localhost" ]]; then
echo "Using a custom domain with a custom port is not supported"
exit 1
fi
env_variables_json=$(cat <<EOF
{
"dns_ip": "9.9.9.9",
"internal_ip": "${INTERNAL_IP}",
"jwt_secret": "$(derive_entropy "jwt")",
"root_folder": "${ROOT_FOLDER}",
"tipi_version": "$(get_json_field "${ROOT_FOLDER}/package.json" version)",
"nginx_port": 80,
"nginx_port_ssl": 443,
"postgres_password": "$(derive_entropy "postgres")
"postgres_username": "tipi",
"postgres_dbname": "tipi",
"postgres_port": 5432,
"postgres_host": "tipi-db",
"redis_host": "tipi-redis",
"repo_id": "$("${ROOT_FOLDER}"/scripts/git.sh get_hash "${apps_repository}")",
"apps_repository": "${apps_repository}",
"domain": "tipi.localhost",
"storage_path": "${ROOT_FOLDER}",
"demo_mode": false,
}
EOF
)
echo "Generating config files..."
write_log "Final values: \n${env_variables_json}"
generate_env_file "${env_variables_json}"
### --------------------------------
### Watcher and system-info
@ -190,117 +123,24 @@ echo "Running system-info.sh..."
kill_watcher
"${ROOT_FOLDER}/scripts/watcher.sh" &
### --------------------------------
### settings.json overrides
### --------------------------------
echo "Generating config files..."
# Override vars with values from settings.json
if [[ -f "${STATE_FOLDER}/settings.json" ]]; then
# If dnsIp is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" dnsIp)" != "null" ]]; then
DNS_IP=$(get_json_field "${STATE_FOLDER}/settings.json" dnsIp)
fi
# If domain is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" domain)" != "null" ]]; then
DOMAIN=$(get_json_field "${STATE_FOLDER}/settings.json" domain)
fi
# If appsRepoUrl is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" appsRepoUrl)" != "null" ]]; then
apps_repository=$(get_json_field "${STATE_FOLDER}/settings.json" appsRepoUrl)
APPS_REPOSITORY_ESCAPED="$(echo "${apps_repository}" | sed 's/\//\\\//g')"
REPO_ID="$("${ROOT_FOLDER}"/scripts/git.sh get_hash "${apps_repository}")"
fi
# If port is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" port)" != "null" ]]; then
NGINX_PORT=$(get_json_field "${STATE_FOLDER}/settings.json" port)
fi
# If sslPort is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" sslPort)" != "null" ]]; then
NGINX_PORT_SSL=$(get_json_field "${STATE_FOLDER}/settings.json" sslPort)
fi
# If listenIp is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" listenIp)" != "null" ]]; then
INTERNAL_IP=$(get_json_field "${STATE_FOLDER}/settings.json" listenIp)
fi
# If demoMode is set in settings.json, use it
if [[ "$(get_json_field "${STATE_FOLDER}/settings.json" demoMode)" == "true" ]]; then
DEMO_MODE="true"
fi
# If storagePath is set in settings.json, use it
storage_path_settings=$(get_json_field "${STATE_FOLDER}/settings.json" storagePath)
if [[ "${storage_path_settings}" != "null" && "${storage_path_settings}" != "" ]]; then
storage_path="${storage_path_settings}"
STORAGE_PATH_ESCAPED="$(echo "${storage_path}" | sed 's/\//\\\//g')"
fi
fi
new_values="DOMAIN=${DOMAIN}\nDNS_IP=${DNS_IP}\nAPPS_REPOSITORY=${APPS_REPOSITORY_ESCAPED}\nREPO_ID=${REPO_ID}\nNGINX_PORT=${NGINX_PORT}\nNGINX_PORT_SSL=${NGINX_PORT_SSL}\nINTERNAL_IP=${INTERNAL_IP}\nSTORAGE_PATH=${STORAGE_PATH_ESCAPED}\nTZ=${TZ}\nJWT_SECRET=${JWT_SECRET}\nROOT_FOLDER=${SED_ROOT_FOLDER}\nTIPI_VERSION=${TIPI_VERSION}\nARCHITECTURE=${ARCHITECTURE}"
write_log "Final values: \n${new_values}"
### --------------------------------
### env file generation
### --------------------------------
ENV_FILE=$(mktemp)
[[ -f "${ROOT_FOLDER}/.env" ]] && rm -f "${ROOT_FOLDER}/.env"
[[ -f "$ROOT_FOLDER/templates/env-sample" ]] && cp "$ROOT_FOLDER/templates/env-sample" "$ENV_FILE"
# Function below is modified from Umbrel
# Required Notice: Copyright
# Umbrel (https://umbrel.com)
for template in ${ENV_FILE}; do
sed -i "s/<dns_ip>/${DNS_IP}/g" "${template}"
sed -i "s/<internal_ip>/${INTERNAL_IP}/g" "${template}"
sed -i "s/<tz>/${TZ}/g" "${template}"
sed -i "s/<jwt_secret>/${JWT_SECRET}/g" "${template}"
sed -i "s/<root_folder>/${SED_ROOT_FOLDER}/g" "${template}"
sed -i "s/<tipi_version>/${TIPI_VERSION}/g" "${template}"
sed -i "s/<architecture>/${ARCHITECTURE}/g" "${template}"
sed -i "s/<nginx_port>/${NGINX_PORT}/g" "${template}"
sed -i "s/<nginx_port_ssl>/${NGINX_PORT_SSL}/g" "${template}"
sed -i "s/<postgres_password>/${POSTGRES_PASSWORD}/g" "${template}"
sed -i "s/<postgres_username>/${POSTGRES_USERNAME}/g" "${template}"
sed -i "s/<postgres_dbname>/${POSTGRES_DBNAME}/g" "${template}"
sed -i "s/<postgres_port>/${POSTGRES_PORT}/g" "${template}"
sed -i "s/<postgres_host>/${POSTGRES_HOST}/g" "${template}"
sed -i "s/<apps_repo_id>/${REPO_ID}/g" "${template}"
sed -i "s/<apps_repo_url>/${APPS_REPOSITORY_ESCAPED}/g" "${template}"
sed -i "s/<domain>/${DOMAIN}/g" "${template}"
sed -i "s/<storage_path>/${STORAGE_PATH_ESCAPED}/g" "${template}"
sed -i "s/<redis_host>/${REDIS_HOST}/g" "${template}"
sed -i "s/<demo_mode>/${DEMO_MODE}/g" "${template}"
done
mv -f "$ENV_FILE" "$ROOT_FOLDER/.env"
### --------------------------------
### Start the project
### --------------------------------
if [[ ! "${ci-false}" == "true" ]]; then
if [[ "${rc-false}" == "true" ]]; then
docker compose -f docker-compose.rc.yml --env-file "${ROOT_FOLDER}/.env" pull
# Run docker compose
docker compose -f docker-compose.rc.yml --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --build || {
echo "Failed to start containers"
exit 1
}
else
docker compose --env-file "${ROOT_FOLDER}/.env" pull
# Run docker compose
docker compose --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --build || {
echo "Failed to start containers"
exit 1
}
fi
if [[ "${rc-false}" == "true" ]]; then
docker compose -f docker-compose.rc.yml --env-file "${ROOT_FOLDER}/.env" pull
# Run docker compose
docker compose -f docker-compose.rc.yml --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --build || {
echo "Failed to start containers"
exit 1
}
else
docker compose --env-file "${ROOT_FOLDER}/.env" pull
# Run docker compose
docker compose --env-file "${ROOT_FOLDER}/.env" up --detach --remove-orphans --build || {
echo "Failed to start containers"
exit 1
}
fi
echo "Tipi is now running"
@ -328,11 +168,6 @@ cat <<"EOF"
()`
EOF
port_display=""
if [[ $NGINX_PORT != "80" ]]; then
port_display=":${NGINX_PORT}"
fi
echo ""
echo "Visit http://${INTERNAL_IP}${port_display}/ to view the dashboard"
echo "Visit http://${INTERNAL_IP}/ to view the dashboard"
echo ""