feat(docker): add one-command installer
This commit is contained in:
1 parent
6fafbe1dba
commit
ff41c5091a
9 files changed
+503
-11
No files matched your search
@@ -0,0 +1,61 @@
|
||||
name: Sync Docker installer mirror
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "apps/site/public/install.sh"
|
||||
- "apps/site/public/compose.yaml"
|
||||
- ".github/workflows/sync-docker-installer.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
if: github.repository == 'tianma-if/edgeever'
|
||||
name: Publish Tencent COS mirror
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install Tencent COSCMD
|
||||
run: |
|
||||
python3 -m venv "${RUNNER_TEMP}/coscmd"
|
||||
"${RUNNER_TEMP}/coscmd/bin/pip" install --disable-pip-version-check 'coscmd==1.9.0.6'
|
||||
echo "${RUNNER_TEMP}/coscmd/bin" >> "${GITHUB_PATH}"
|
||||
|
||||
- name: Configure COSCMD
|
||||
env:
|
||||
COS_BUCKET: ${{ vars.TENCENT_COS_INSTALLER_BUCKET }}
|
||||
COS_REGION: ${{ vars.TENCENT_COS_INSTALLER_REGION }}
|
||||
COS_SECRET_ID: ${{ secrets.TENCENT_COS_INSTALLER_SECRET_ID }}
|
||||
COS_SECRET_KEY: ${{ secrets.TENCENT_COS_INSTALLER_SECRET_KEY }}
|
||||
run: |
|
||||
test -n "${COS_BUCKET}"
|
||||
test -n "${COS_REGION}"
|
||||
test -n "${COS_SECRET_ID}"
|
||||
test -n "${COS_SECRET_KEY}"
|
||||
coscmd config \
|
||||
-a "${COS_SECRET_ID}" \
|
||||
-s "${COS_SECRET_KEY}" \
|
||||
-b "${COS_BUCKET}" \
|
||||
-r "${COS_REGION}"
|
||||
|
||||
- name: Upload installer files
|
||||
run: |
|
||||
coscmd upload -f apps/site/public/install.sh install.sh
|
||||
coscmd upload -f apps/site/public/compose.yaml compose.yaml
|
||||
|
||||
- name: Verify public mirror
|
||||
env:
|
||||
COS_BUCKET: ${{ vars.TENCENT_COS_INSTALLER_BUCKET }}
|
||||
COS_REGION: ${{ vars.TENCENT_COS_INSTALLER_REGION }}
|
||||
run: |
|
||||
base_url="https://${COS_BUCKET}.cos.${COS_REGION}.myqcloud.com"
|
||||
curl --fail --silent --show-error "${base_url}/install.sh" | cmp apps/site/public/install.sh -
|
||||
curl --fail --silent --show-error "${base_url}/compose.yaml" | cmp apps/site/public/compose.yaml -
|
||||
@@ -95,12 +95,16 @@ Complete setup in 5 simple web steps:
|
||||
### Option C: Docker on a VPS or NAS
|
||||
|
||||
```sh
|
||||
export EDGE_EVER_VERSION=vX.Y.Z
|
||||
export EDGE_EVER_AUTH_PASSWORD='replace-with-a-long-random-password'
|
||||
docker compose up -d
|
||||
curl -fsSL https://edgeever.org/install.sh | bash
|
||||
```
|
||||
|
||||
Docker persists SQLite and local attachments in `/data` and supports S3-compatible storage. Users in mainland China can select the Tencent Cloud mirror with `EDGE_EVER_IMAGE=ccr.ccs.tencentyun.com/edgeever/edgeever`. See the [Docker deployment guide](docs/deploy-docker.md) for details.
|
||||
The script pulls the latest image, generates an administrator password, and starts EdgeEver with Docker Compose. Users in mainland China can use the Tencent COS and TCR mirrors:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://edgeever-installer-1256854452.cos.ap-guangzhou.myqcloud.com/install.sh | bash -s -- --mirror tcr
|
||||
```
|
||||
|
||||
See the [Docker deployment guide](docs/deploy-docker.md) for manual deployment and configuration.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+2
-4
@@ -95,12 +95,10 @@ Cloudflare 在线部署可以选择以下两种方式之一:
|
||||
### 方案三:在 VPS 或 NAS 上使用 Docker
|
||||
|
||||
```sh
|
||||
export EDGE_EVER_VERSION=vX.Y.Z
|
||||
export EDGE_EVER_AUTH_PASSWORD='请替换为足够长的随机密码'
|
||||
docker compose up -d
|
||||
curl -fsSL https://edgeever-installer-1256854452.cos.ap-guangzhou.myqcloud.com/install.sh | bash -s -- --mirror tcr
|
||||
```
|
||||
|
||||
Docker 将 SQLite 与本地附件持久化到 `/data`,并支持 S3 兼容存储。中国大陆用户可通过 `EDGE_EVER_IMAGE=ccr.ccs.tencentyun.com/edgeever/edgeever` 选择腾讯云镜像。详见 [Docker 部署文档](docs/deploy-docker.zh-CN.md)。
|
||||
脚本和 Compose 配置由腾讯云 COS 提供中国大陆入口,并自动从腾讯云 TCR 拉取最新镜像、生成管理员密码及启动 EdgeEver。手动部署与配置说明见 [Docker 部署文档](docs/deploy-docker.zh-CN.md)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
services:
|
||||
edgeever:
|
||||
image: "${EDGE_EVER_IMAGE:-ghcr.io/tianma-if/edgeever}:${EDGE_EVER_VERSION:-latest}"
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
ports:
|
||||
- "${EDGE_EVER_PORT:-8787}:8787"
|
||||
environment:
|
||||
EDGE_EVER_AUTH_USERNAME: "${EDGE_EVER_AUTH_USERNAME:-admin}"
|
||||
EDGE_EVER_AUTH_PASSWORD: "${EDGE_EVER_AUTH_PASSWORD:?Set EDGE_EVER_AUTH_PASSWORD before starting EdgeEver}"
|
||||
volumes:
|
||||
- edgeever-data:/data
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
cap_drop:
|
||||
- ALL
|
||||
stop_grace_period: 30s
|
||||
|
||||
volumes:
|
||||
edgeever-data:
|
||||
Executable
+250
@@ -0,0 +1,250 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
umask 077
|
||||
|
||||
readonly GHCR_IMAGE="ghcr.io/tianma-if/edgeever"
|
||||
readonly TCR_IMAGE="ccr.ccs.tencentyun.com/edgeever/edgeever"
|
||||
readonly GLOBAL_COMPOSE_URL="https://edgeever.org/compose.yaml"
|
||||
readonly TENCENT_COMPOSE_URL="https://edgeever-installer-1256854452.cos.ap-guangzhou.myqcloud.com/compose.yaml"
|
||||
|
||||
install_dir="${EDGE_EVER_INSTALL_DIR:-${HOME:-}/edgeever}"
|
||||
compose_url="${EDGE_EVER_COMPOSE_URL:-}"
|
||||
image="${EDGE_EVER_IMAGE:-}"
|
||||
version="${EDGE_EVER_VERSION:-}"
|
||||
port="${EDGE_EVER_PORT:-}"
|
||||
username="${EDGE_EVER_AUTH_USERNAME:-}"
|
||||
password="${EDGE_EVER_AUTH_PASSWORD:-}"
|
||||
project_name="${EDGE_EVER_PROJECT_NAME:-edgeever}"
|
||||
generated_password=false
|
||||
temporary_compose=""
|
||||
temporary_env=""
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Install or upgrade EdgeEver with Docker Compose.
|
||||
|
||||
Usage:
|
||||
curl -fsSL https://edgeever.org/install.sh | bash
|
||||
curl -fsSL https://edgeever-installer-1256854452.cos.ap-guangzhou.myqcloud.com/install.sh | bash -s -- --mirror tcr
|
||||
|
||||
Options:
|
||||
--mirror ghcr|tcr Select the image registry (default: ghcr)
|
||||
--image IMAGE Use a custom image repository
|
||||
--version TAG Deploy an image tag (default: latest)
|
||||
--compose-url URL Download Compose configuration from URL
|
||||
--install-dir DIR Store Compose configuration in DIR (default: ~/edgeever)
|
||||
--port PORT Publish EdgeEver on PORT (default: 8787)
|
||||
-h, --help Show this help
|
||||
|
||||
The same options can be provided with EDGE_EVER_IMAGE, EDGE_EVER_VERSION,
|
||||
EDGE_EVER_COMPOSE_URL, EDGE_EVER_INSTALL_DIR, EDGE_EVER_PORT, and
|
||||
EDGE_EVER_AUTH_PASSWORD.
|
||||
EOF
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf 'EdgeEver installer: %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
on_error() {
|
||||
local exit_code=$?
|
||||
printf 'EdgeEver installer: command failed at line %s\n' "${BASH_LINENO[0]}" >&2
|
||||
exit "$exit_code"
|
||||
}
|
||||
|
||||
trap on_error ERR
|
||||
|
||||
require_value() {
|
||||
[[ $# -ge 2 && -n "$2" ]] || fail "$1 requires a value"
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--mirror)
|
||||
require_value "$@"
|
||||
case "$2" in
|
||||
ghcr) image="$GHCR_IMAGE" ;;
|
||||
tcr) image="$TCR_IMAGE" ;;
|
||||
*) fail "--mirror must be ghcr or tcr" ;;
|
||||
esac
|
||||
shift 2
|
||||
;;
|
||||
--image)
|
||||
require_value "$@"
|
||||
image="$2"
|
||||
shift 2
|
||||
;;
|
||||
--version)
|
||||
require_value "$@"
|
||||
version="$2"
|
||||
shift 2
|
||||
;;
|
||||
--compose-url)
|
||||
require_value "$@"
|
||||
compose_url="$2"
|
||||
shift 2
|
||||
;;
|
||||
--install-dir)
|
||||
require_value "$@"
|
||||
install_dir="$2"
|
||||
shift 2
|
||||
;;
|
||||
--port)
|
||||
require_value "$@"
|
||||
port="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*) fail "unknown option: $1" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -n "$install_dir" ]] || fail "set HOME or EDGE_EVER_INSTALL_DIR"
|
||||
[[ "$project_name" =~ ^[a-z0-9][a-z0-9_-]*$ ]] || fail "invalid EDGE_EVER_PROJECT_NAME"
|
||||
|
||||
command -v curl >/dev/null 2>&1 || fail "curl is required"
|
||||
command -v docker >/dev/null 2>&1 || fail "Docker is required: https://docs.docker.com/engine/install/"
|
||||
docker compose version >/dev/null 2>&1 || fail "Docker Compose v2 is required"
|
||||
docker info >/dev/null 2>&1 || fail "cannot connect to the Docker daemon"
|
||||
|
||||
mkdir -p "$install_dir"
|
||||
env_file="$install_dir/.env"
|
||||
compose_file="$install_dir/compose.yaml"
|
||||
|
||||
read_env_value() {
|
||||
local key="$1"
|
||||
local line value
|
||||
[[ -f "$env_file" ]] || return 1
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
"$key="*)
|
||||
value="${line#*=}"
|
||||
if [[ "$value" == "'"*"'" && ${#value} -ge 2 ]]; then
|
||||
value="${value:1:${#value}-2}"
|
||||
fi
|
||||
printf '%s' "$value"
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done < "$env_file"
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ -z "$image" ]]; then
|
||||
image="$(read_env_value EDGE_EVER_IMAGE || true)"
|
||||
image="${image:-$GHCR_IMAGE}"
|
||||
fi
|
||||
|
||||
if [[ -z "$compose_url" ]]; then
|
||||
if [[ "$image" == "$TCR_IMAGE" ]]; then
|
||||
compose_url="$TENCENT_COMPOSE_URL"
|
||||
else
|
||||
compose_url="$GLOBAL_COMPOSE_URL"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$version" ]]; then
|
||||
version="$(read_env_value EDGE_EVER_VERSION || true)"
|
||||
version="${version:-latest}"
|
||||
fi
|
||||
|
||||
if [[ -z "$port" ]]; then
|
||||
port="$(read_env_value EDGE_EVER_PORT || true)"
|
||||
port="${port:-8787}"
|
||||
fi
|
||||
|
||||
if [[ -z "$username" ]]; then
|
||||
username="$(read_env_value EDGE_EVER_AUTH_USERNAME || true)"
|
||||
username="${username:-admin}"
|
||||
fi
|
||||
|
||||
if [[ -z "$password" ]]; then
|
||||
password="$(read_env_value EDGE_EVER_AUTH_PASSWORD || true)"
|
||||
fi
|
||||
|
||||
if [[ -z "$password" ]]; then
|
||||
if command -v openssl >/dev/null 2>&1; then
|
||||
password="$(openssl rand -hex 16)"
|
||||
elif command -v od >/dev/null 2>&1; then
|
||||
password="$(od -An -N16 -tx1 /dev/urandom | tr -d ' \n')"
|
||||
else
|
||||
fail "openssl or od is required to generate a password"
|
||||
fi
|
||||
generated_password=true
|
||||
fi
|
||||
|
||||
[[ "$image" != *[[:space:]]* ]] || fail "image must not contain whitespace"
|
||||
[[ "$version" != *[[:space:]]* ]] || fail "version must not contain whitespace"
|
||||
[[ "$port" =~ ^[0-9]+$ ]] && ((port >= 1 && port <= 65535)) || fail "port must be between 1 and 65535"
|
||||
[[ "$username" != *$'\n'* && "$username" != *"'"* ]] || fail "invalid administrator username"
|
||||
[[ "$password" != *$'\n'* && "$password" != *"'"* ]] || fail "password must not contain a newline or single quote"
|
||||
|
||||
cleanup() {
|
||||
[[ -z "$temporary_compose" || ! -e "$temporary_compose" ]] || rm -f "$temporary_compose"
|
||||
[[ -z "$temporary_env" || ! -e "$temporary_env" ]] || rm -f "$temporary_env"
|
||||
return 0
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
temporary_compose="$(mktemp "$install_dir/.compose.yaml.XXXXXX")"
|
||||
curl --fail --silent --show-error --location --output "$temporary_compose" "$compose_url"
|
||||
grep -q '^services:' "$temporary_compose" || fail "downloaded Compose file is invalid"
|
||||
chmod 0644 "$temporary_compose"
|
||||
mv "$temporary_compose" "$compose_file"
|
||||
temporary_compose=""
|
||||
|
||||
temporary_env="$(mktemp "$install_dir/.env.XXXXXX")"
|
||||
{
|
||||
printf "EDGE_EVER_IMAGE='%s'\n" "$image"
|
||||
printf "EDGE_EVER_VERSION='%s'\n" "$version"
|
||||
printf "EDGE_EVER_PORT='%s'\n" "$port"
|
||||
printf "EDGE_EVER_AUTH_USERNAME='%s'\n" "$username"
|
||||
printf "EDGE_EVER_AUTH_PASSWORD='%s'\n" "$password"
|
||||
} > "$temporary_env"
|
||||
chmod 0600 "$temporary_env"
|
||||
mv "$temporary_env" "$env_file"
|
||||
temporary_env=""
|
||||
|
||||
compose=(
|
||||
docker compose
|
||||
--project-name "$project_name"
|
||||
--project-directory "$install_dir"
|
||||
--env-file "$env_file"
|
||||
--file "$compose_file"
|
||||
)
|
||||
|
||||
printf 'Pulling %s:%s...\n' "$image" "$version"
|
||||
"${compose[@]}" pull
|
||||
"${compose[@]}" up -d --remove-orphans
|
||||
|
||||
container_id=""
|
||||
health=""
|
||||
for _ in {1..60}; do
|
||||
container_id="$("${compose[@]}" ps -q edgeever 2>/dev/null || true)"
|
||||
if [[ -n "$container_id" ]]; then
|
||||
health="$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$container_id" 2>/dev/null || true)"
|
||||
[[ "$health" == "healthy" ]] && break
|
||||
[[ "$health" == "exited" || "$health" == "dead" ]] && break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [[ "$health" != "healthy" ]]; then
|
||||
"${compose[@]}" logs --tail 80 edgeever >&2 || true
|
||||
fail "container did not become healthy (status: ${health:-unknown})"
|
||||
fi
|
||||
|
||||
printf '\nEdgeEver is ready.\n'
|
||||
printf 'URL: http://<server-ip>:%s\n' "$port"
|
||||
printf 'Username: %s\n' "$username"
|
||||
if [[ "$generated_password" == true ]]; then
|
||||
printf 'Password: %s\n' "$password"
|
||||
else
|
||||
printf 'Password: unchanged (stored in %s)\n' "$env_file"
|
||||
fi
|
||||
printf 'Install directory: %s\n' "$install_dir"
|
||||
+24
-1
@@ -13,7 +13,30 @@ Cloudflare uses Workers with D1 and R2.
|
||||
- A reverse proxy with HTTPS when the instance is reachable outside a trusted
|
||||
local network.
|
||||
|
||||
## Start with Compose
|
||||
## One-command install
|
||||
|
||||
With Docker Compose v2 already installed:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://edgeever.org/install.sh | bash
|
||||
```
|
||||
|
||||
Use Tencent Cloud TCR in mainland China:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://edgeever-installer-1256854452.cos.ap-guangzhou.myqcloud.com/install.sh | bash -s -- --mirror tcr
|
||||
```
|
||||
|
||||
The installer creates `~/edgeever`, generates an administrator password, pulls
|
||||
`latest`, starts the container, and waits for it to become healthy. Run the same
|
||||
command again to upgrade without replacing the password or `/data` volume. The
|
||||
mainland command downloads the installer and Compose configuration from Tencent
|
||||
COS and pulls the image from Tencent TCR.
|
||||
|
||||
Use `--version vX.Y.Z`, `--port PORT`, or `--install-dir DIR` when needed. Run
|
||||
`curl -fsSL https://edgeever.org/install.sh | bash -s -- --help` for all options.
|
||||
|
||||
## Manual Compose
|
||||
|
||||
Download `compose.yaml`, choose the release you want to run, and provide a
|
||||
strong instance password:
|
||||
|
||||
@@ -11,7 +11,26 @@ Cloudflare 使用 Workers + D1 + R2。
|
||||
- `amd64` 或 `arm64` Linux 主机。
|
||||
- 实例离开可信局域网时,必须使用带 HTTPS 的反向代理。
|
||||
|
||||
## 使用 Compose 启动
|
||||
## 一键安装
|
||||
|
||||
已安装 Docker Compose v2 的主机可直接执行:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://edgeever-installer-1256854452.cos.ap-guangzhou.myqcloud.com/install.sh | bash -s -- --mirror tcr
|
||||
```
|
||||
|
||||
脚本会创建 `~/edgeever`、生成管理员密码、拉取 `latest`、启动容器并等待健康
|
||||
检查通过。中国大陆命令从腾讯云 COS 获取脚本与 Compose 配置,并从腾讯云 TCR
|
||||
拉取镜像。再次执行同一命令即可升级,已有密码和 `/data` 卷保持不变。
|
||||
|
||||
海外服务器可去掉 `--mirror tcr` 使用 GHCR。按需使用 `--version vX.Y.Z`、
|
||||
`--port PORT` 或 `--install-dir DIR`;执行以下命令可查看全部参数:
|
||||
|
||||
```sh
|
||||
curl -fsSL https://edgeever-installer-1256854452.cos.ap-guangzhou.myqcloud.com/install.sh | bash -s -- --help
|
||||
```
|
||||
|
||||
## 手动使用 Compose
|
||||
|
||||
下载 `compose.yaml`,选择要运行的正式版本,并设置高强度实例密码:
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@
|
||||
"dev:api:demo": "bun scripts/local-dev.mjs api demo",
|
||||
"dev:self-hosted": "bun --watch scripts/self-hosted-server.mjs",
|
||||
"start:self-hosted": "bun scripts/self-hosted-server.mjs",
|
||||
"test:docker-release": "bun test scripts/docker-release.test.mjs scripts/build-cloudflare-worker.test.mjs tests/storage-adapter.test.ts",
|
||||
"test:docker-release": "bun test scripts/docker-release.test.mjs scripts/docker-installer.test.mjs scripts/build-cloudflare-worker.test.mjs tests/storage-adapter.test.ts",
|
||||
"dev:remote": "concurrently -k -n api,web -c cyan,magenta \"bun run dev:api:remote\" \"bun run dev:web\"",
|
||||
"dev:api:remote": "bun scripts/run-wrangler.mjs dev --remote --port 8787",
|
||||
"dev:web": "vite --config apps/web/vite.config.ts --host 127.0.0.1 --port 5173",
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
const projectRoot = resolve(import.meta.dir, "..");
|
||||
const installerPath = resolve(projectRoot, "apps/site/public/install.sh");
|
||||
const composePath = resolve(projectRoot, "compose.yaml");
|
||||
const hostedComposePath = resolve(projectRoot, "apps/site/public/compose.yaml");
|
||||
|
||||
describe("Docker installer", () => {
|
||||
test("publishes the repository Compose file unchanged", async () => {
|
||||
expect(await readFile(hostedComposePath, "utf8")).toBe(await readFile(composePath, "utf8"));
|
||||
});
|
||||
|
||||
test("installs with TCR and preserves the generated password on rerun", async () => {
|
||||
const fixture = await mkdtemp(resolve(tmpdir(), "edgeever-installer-"));
|
||||
const fakeBin = resolve(fixture, "bin");
|
||||
const installDirectory = resolve(fixture, "edgeever");
|
||||
const dockerLog = resolve(fixture, "docker.log");
|
||||
const curlLog = resolve(fixture, "curl.log");
|
||||
const fakeDocker = resolve(fakeBin, "docker");
|
||||
const fakeCurl = resolve(fakeBin, "curl");
|
||||
|
||||
try {
|
||||
await mkdir(fakeBin, { recursive: true });
|
||||
await writeFile(
|
||||
fakeDocker,
|
||||
`#!/usr/bin/env bash
|
||||
set -eu
|
||||
printf '%s\\n' "$*" >> "$EDGE_EVER_TEST_DOCKER_LOG"
|
||||
if [[ "$1" == "inspect" ]]; then
|
||||
printf 'healthy\\n'
|
||||
elif [[ "$1" == "compose" && "$*" == *" ps -q edgeever"* ]]; then
|
||||
printf 'edgeever-test-container\\n'
|
||||
fi
|
||||
`,
|
||||
);
|
||||
await writeFile(
|
||||
fakeCurl,
|
||||
`#!/usr/bin/env bash
|
||||
set -eu
|
||||
printf '%s\n' "$*" >> "$EDGE_EVER_TEST_CURL_LOG"
|
||||
output=''
|
||||
while [[ $# -gt 0 ]]; do
|
||||
if [[ "$1" == "--output" ]]; then
|
||||
output="$2"
|
||||
shift 2
|
||||
else
|
||||
shift
|
||||
fi
|
||||
done
|
||||
cp "$EDGE_EVER_TEST_COMPOSE_SOURCE" "$output"
|
||||
`,
|
||||
);
|
||||
await chmod(fakeDocker, 0o755);
|
||||
await chmod(fakeCurl, 0o755);
|
||||
|
||||
const environment = {
|
||||
...process.env,
|
||||
PATH: `${fakeBin}:${process.env.PATH}`,
|
||||
EDGE_EVER_INSTALL_DIR: installDirectory,
|
||||
EDGE_EVER_TEST_COMPOSE_SOURCE: composePath,
|
||||
EDGE_EVER_TEST_CURL_LOG: curlLog,
|
||||
EDGE_EVER_TEST_DOCKER_LOG: dockerLog,
|
||||
};
|
||||
const first = spawnSync("bash", [installerPath, "--mirror", "tcr", "--port", "18789"], {
|
||||
env: environment,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "ignore", "pipe"],
|
||||
});
|
||||
if (first.status !== 0) {
|
||||
const commands = await readFile(dockerLog, "utf8").catch(() => "no Docker commands");
|
||||
throw new Error(
|
||||
`installer failed (exit=${first.status}, signal=${first.signal}):\n${first.stderr}\n${commands}`,
|
||||
);
|
||||
}
|
||||
expect(first.status).toBe(0);
|
||||
|
||||
const firstEnvironment = await readFile(resolve(installDirectory, ".env"), "utf8");
|
||||
expect(firstEnvironment).toContain(
|
||||
"EDGE_EVER_IMAGE='ccr.ccs.tencentyun.com/edgeever/edgeever'",
|
||||
);
|
||||
expect(firstEnvironment).toContain("EDGE_EVER_VERSION='latest'");
|
||||
expect(firstEnvironment).toContain("EDGE_EVER_PORT='18789'");
|
||||
expect(firstEnvironment).toMatch(/EDGE_EVER_AUTH_PASSWORD='[a-f0-9]{32}'/);
|
||||
|
||||
const second = spawnSync("bash", [installerPath], {
|
||||
env: environment,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "ignore", "pipe"],
|
||||
});
|
||||
if (second.status !== 0) {
|
||||
throw new Error(
|
||||
`installer rerun failed (exit=${second.status}, signal=${second.signal}):\n${second.stdout}\n${second.stderr}`,
|
||||
);
|
||||
}
|
||||
expect(second.status).toBe(0);
|
||||
expect(await readFile(resolve(installDirectory, ".env"), "utf8")).toBe(firstEnvironment);
|
||||
|
||||
const log = await readFile(dockerLog, "utf8");
|
||||
expect(log).toContain("compose version");
|
||||
expect(log.match(/ pull$/gm)).toHaveLength(2);
|
||||
expect(log.match(/ up -d --remove-orphans$/gm)).toHaveLength(2);
|
||||
expect(log).toContain("inspect --format");
|
||||
const curlRequests = await readFile(curlLog, "utf8");
|
||||
expect(
|
||||
curlRequests.match(
|
||||
/edgeever-installer-1256854452\.cos\.ap-guangzhou\.myqcloud\.com\/compose\.yaml/g,
|
||||
),
|
||||
).toHaveLength(2);
|
||||
} finally {
|
||||
await rm(fixture, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user