修改使install.sh脚本兼容DoD,修复一些错误,增加了一些关键位置的截图和超时判断

This commit is contained in:
jiaojm
2025-11-30 09:52:48 +08:00
repo.diff.parent dd60ca2100
repo.diff.commit decbb3336e
repo.diff.stats_desc%!(EXTRA int=6, int=57, int=51)

repo.diff.view_file

@@ -11,22 +11,22 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Clean
run: |
public/assets/install.sh clean
docker volume rm devstar_data_vol || true
- name: start DevStar Container - name: start DevStar Container
run: | run: |
# 替换数据卷路径
sed -i 's|~/devstar_data|devstar_data_vol|g' public/assets/install.sh
# 启动容器 # 启动容器
public/assets/install.sh start --image=devstar-studio:latest LOGS=$(public/assets/install.sh start \
--port=8082 \
--ssh-port=2224 \
--data-dir=/tmp/devstar_ci \
--image=devstar-studio:latest 2>&1)
echo "$LOGS"
TARGET_URL=$(echo "$LOGS" | grep -o 'http://[^ ]*' | tail -1 | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g")
echo "TARGET_URL=$TARGET_URL" >> $GITHUB_ENV
- name: Run E2E Tests - name: Run E2E Tests
run: | run: |
make e2e-test TARGET_URL="http://localhost:80" make e2e-test TARGET_URL="$TARGET_URL"
env: env:
GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT: "true" GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT: "true"
- name: 4. Upload E2E Test Report - name: 4. Upload E2E Test Report

repo.diff.view_file

@@ -15,7 +15,7 @@ const config: PlaywrightTestConfig = {
forbidOnly: Boolean(env.CI), forbidOnly: Boolean(env.CI),
retries: env.CI ? 2 : 0, retries: env.CI ? 2 : 0,
reporter: env.CI ? 'list' : [['list'], ['html', { reporter: [['html', {
outputFolder: 'playwright-report/html', outputFolder: 'playwright-report/html',
open: 'never' open: 'never'
}]], }]],

repo.diff.view_file

@@ -2,14 +2,13 @@
# Copyright 2024 Mengning Software All rights reserved. # Copyright 2024 Mengning Software All rights reserved.
# 默认值 # 默认值
NAME=DevStar-Studio NAME="DevStar-Studio-$(date +%Y%m%d-%H-%M-%S)"
IMAGE_REGISTRY_USER=mengning997 IMAGE_REGISTRY_USER=mengning997
IMAGE_NAME=devstar-studio IMAGE_NAME=devstar-studio
VERSION=latest # DevStar Studio的默认版本为最新版本 VERSION=latest # DevStar Studio的默认版本为最新版本
PORT=80 # 设置端口默认值为 80 PORT=80 # 设置端口默认值为 80
SSH_PORT=2222 # 设置ssh默认端口号2222 SSH_PORT=2222 # 设置ssh默认端口号2222
DATA_DIR=${HOME}/devstar_data DATA_DIR=${HOME}/devstar_data
APP_INI=${DATA_DIR}/app.ini
# 错误处理函数 # 错误处理函数
error_handler() { error_handler() {
@@ -111,25 +110,30 @@ function start {
mkdir -p $DATA_DIR mkdir -p $DATA_DIR
sudo chown 1000:1000 $DATA_DIR sudo chown 1000:1000 $DATA_DIR
sudo chmod 666 /var/run/docker.sock sudo chmod 666 /var/run/docker.sock
if [ ! -f "$APP_INI" ]; then if [[ -n "$CI" ]]; then
DOMAIN_NAME=$(hostname -I | awk '{print $1}') echo "检测到 CI 环境,正在获取网关 IP..."
DOMAIN_NAME=$(ip route show | grep default | awk '{print $3}')
else
#本地环境不做变化
DOMAIN_NAME=$(hostname -I | awk '{print $1}')
fi
if [ ! -f "${DATA_DIR}/app.ini" ]; then
echo "DOMAIN_NAME=$DOMAIN_NAME" echo "DOMAIN_NAME=$DOMAIN_NAME"
else else
# 读取 DOMAIN 值 # 读取 DOMAIN 值
DOMAIN_NAME=$(grep -E '^\s*DOMAIN\s*=' "$APP_INI" | cut -d'=' -f2 | xargs) DOMAIN_NAME_APP_INI=$(grep -E '^\s*DOMAIN\s*=' "${DATA_DIR}/app.ini" | cut -d'=' -f2 | xargs)
# 检查是否成功读取到值 # 检查是否成功读取到值
if [[ -z "$DOMAIN_NAME" ]]; then if [[ -n "$DOMAIN_NAME_APP_INI" ]]; then
DOMAIN_NAME="localhost" DOMAIN_NAME=$DOMAIN_NAME_APP_INI
fi fi
echo "DOMAIN_NAME=$DOMAIN_NAME" echo "DOMAIN_NAME=$DOMAIN_NAME"
fi fi
# 启动devstar-studio容器 # 启动devstar-studio容器
stop
if [[ -z "$IMAGE_STR" ]]; then if [[ -z "$IMAGE_STR" ]]; then
IMAGE_STR="$IMAGE_REGISTRY_USER/$IMAGE_NAME:$VERSION" IMAGE_STR="$IMAGE_REGISTRY_USER/$IMAGE_NAME:$VERSION"
fi fi
echo "image=$IMAGE_STR" echo "image=$IMAGE_STR"
sudo docker run --restart=always --name $NAME -d -p $PORT:3000 -p $SSH_PORT:$SSH_PORT -v /var/run/docker.sock:/var/run/docker.sock -v ~/devstar_data:/var/lib/gitea -v ~/devstar_data:/etc/gitea $IMAGE_STR sudo docker run --restart=always --name $NAME -d -p $PORT:3000 -p $SSH_PORT:$SSH_PORT -v /var/run/docker.sock:/var/run/docker.sock -v ${DATA_DIR}:/var/lib/gitea -v ${DATA_DIR}:/etc/gitea $IMAGE_STR
# 打开 `http://localhost:8080` 完成安装。 # 打开 `http://localhost:8080` 完成安装。
success "-------------------------------------------------------" success "-------------------------------------------------------"
success "DevStar started in http://$DOMAIN_NAME:$PORT successfully!" success "DevStar started in http://$DOMAIN_NAME:$PORT successfully!"
@@ -139,30 +143,37 @@ function start {
# Function to stop # Function to stop
function stop { function stop {
if [ $(docker ps -a --filter "name=^/${NAME}$" -q | wc -l) -gt 0 ]; then if [ $(docker ps -a --filter "name=^/DevStar-Studio.*|devstar-studio.*" -q | wc -l) -gt 0 ]; then
sudo docker stop $NAME && sudo docker rm -f $NAME sudo docker stop $(docker ps -a --filter "name=^/DevStar-Studio.*|devstar-studio.*" -q) && \
fi sudo docker rm -f $(docker ps -a --filter "name=^/DevStar-Studio.*|devstar-studio.*" -q)
if [ $(docker ps -a --filter "name=^/devstar-studio$" -q | wc -l) -gt 0 ]; then
sudo docker stop devstar-studio && sudo docker rm -f devstar-studio
fi fi
if [ $(docker ps -a --filter "name=^/webterminal-" -q | wc -l) -gt 0 ]; then if [ $(docker ps -a --filter "name=^/webterminal-" -q | wc -l) -gt 0 ]; then
sudo docker stop $(docker ps -a --filter "name=^/webterminal-" -q) && sudo docker rm -f $(docker ps -a --filter "name=^/webterminal-" -q) sudo docker stop $(docker ps -a --filter "name=^/webterminal-" -q) && sudo docker rm -f $(docker ps -a --filter "name=^/webterminal-" -q)
fi fi
if [ $(docker ps -a --filter "name=^/runner-" -q | wc -l) -gt 0 ]; then if [ $(docker ps -a --filter "name=^/runner-" -q | wc -l) -gt 0 ]; then
sudo docker stop $(docker ps -a --filter "name=^/runner-" -q) && sudo docker rm -f $(docker ps -a --filter "name=^/runner-" -q) sudo docker stop $(docker ps -a --filter "name=^/runner-" -q) && sudo docker rm -f $(docker ps -a --filter "name=^/runner-" -q)
fi fi
} }
# Function to logs # Function to logs
function logs { function logs {
# 查看devstar-studio容器的运行日志 # 查看devstar-studio容器的运行日志
sudo docker logs $NAME sudo docker ps -a --filter "name=^/DevStar-Studio.*|devstar-studio.*" --format "table {{.ID}}\t{{.Names}}" | tail -n +2 | while read container_id container_name; do
echo "=== 容器日志: $container_name (ID: $container_id) ==="
sudo docker logs "$container_id"
done
} }
# Function to clean # Function to clean
function clean { function clean {
stop stop
rm -rf $DATA_DIR read -p "警告:即将永久删除目录 $DATA_DIR,此操作不可恢复!请输入 'YES' 确认: " confirm
if [[ "$confirm" == "YES" ]]; then
rm -rf "$DATA_DIR"
echo "目录已删除"
else
echo "操作已取消"
fi
} }
# Function to usage help # Function to usage help
@@ -173,6 +184,7 @@ function usage {
success " start Start DevStar Studio" success " start Start DevStar Studio"
success " --port=<arg> Specify the port number (default port is 80)" success " --port=<arg> Specify the port number (default port is 80)"
success " --ssh-port=<arg> Specify the ssh-port number (default ssh-port is 2222)" success " --ssh-port=<arg> Specify the ssh-port number (default ssh-port is 2222)"
success " --data-dir=<arg> Specify the data directory (default data directory is ~/devstar_data)"
success " --version=<arg> Specify the DevStar Studio Image Version (default verson is latest)" success " --version=<arg> Specify the DevStar Studio Image Version (default verson is latest)"
success " --image=<arg> Specify the DevStar Studio Image example: devstar-studio:latest " success " --image=<arg> Specify the DevStar Studio Image example: devstar-studio:latest "
success " stop Stop the running DevStar Studio" success " stop Stop the running DevStar Studio"
@@ -188,7 +200,7 @@ case "$1" in
usage usage
;; ;;
start) start)
ARGS=$(getopt --long port::,ssh-port::,version::,image:: -- "$@") ARGS=$(getopt --long port::,ssh-port::,data-dir::,version::,image:: -- "$@")
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
failure "ARGS ERROR!" failure "ARGS ERROR!"
exit 1 exit 1
@@ -205,6 +217,10 @@ case "$1" in
SSH_PORT="$2" SSH_PORT="$2"
echo "The SSH_Port is: $SSH_PORT" echo "The SSH_Port is: $SSH_PORT"
shift 2 ;; shift 2 ;;
--data-dir)
DATA_DIR="$2"
echo "The SSH_Port is: $DATA_DIR"
shift 2 ;;
--version) --version)
VERSION="$2" VERSION="$2"
echo "The DevStar Studio Image Version is: $VERSION" echo "The DevStar Studio Image Version is: $VERSION"
@@ -246,5 +262,4 @@ case "$1" in
devstar help devstar help
fi fi
;; ;;
esac esac

repo.diff.view_file

@@ -31,7 +31,7 @@ async function globalSetup(config: FullConfig) {
await page.getByRole('textbox', { name: '邮箱地址' }).fill('ilovcatlyn750314@gmail.com'); await page.getByRole('textbox', { name: '邮箱地址' }).fill('ilovcatlyn750314@gmail.com');
await page.getByRole('textbox', { name: '管理员密码', exact: true }).fill('12345678'); await page.getByRole('textbox', { name: '管理员密码', exact: true }).fill('12345678');
await page.getByRole('textbox', { name: '确认密码' }).fill('12345678'); await page.getByRole('textbox', { name: '确认密码' }).fill('12345678');
await page.getByRole('button', { name: '立即安装'}).click(); await page.getByRole('button', { name: '立即安装'}).click({ timeout: 50000 });
console.log("安装中,请耐心等待"); console.log("安装中,请耐心等待");
await page.waitForTimeout(90000); await page.waitForTimeout(90000);
} catch (error) { } catch (error) {

repo.diff.view_file

@@ -3,27 +3,18 @@
# 它会处理所有清理、权限、拉取和执行工作 # 它会处理所有清理、权限、拉取和执行工作
# 任何命令失败立即退出 # 任何命令失败立即退出
set -e set -e
# 获取脚本所在目录和项目根目录test/e2e和devstar项目根目录
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
PROJECT_ROOT=$( cd -- "$SCRIPT_DIR/../.." &> /dev/null && pwd ) PROJECT_ROOT=$( cd -- "$SCRIPT_DIR/../.." &> /dev/null && pwd )
# 导出当前用户 ID防止 Docker 生成 root 权限文件
export CURRENT_UID=$(id -u) export CURRENT_UID=$(id -u)
export CURRENT_GID=$(id -g) export CURRENT_GID=$(id -g)
# 切换到项目根目录
cd "$PROJECT_ROOT" cd "$PROJECT_ROOT"
echo "===== [1/3] 清理旧的测试环境... =====" echo "===== [1/3] 清理旧的测试环境... ====="
#删除旧的e2e-runner
if [ "$(docker ps -aq -f name=e2e-test-runner-container)" ]; then if [ "$(docker ps -aq -f name=e2e-test-runner-container)" ]; then
docker rm -f e2e-test-runner-container docker rm -f e2e-test-runner-container
fi fi
#清理旧的构建缓存
docker image prune -f docker image prune -f
#清理并重建报告和数据目录
rm -rf ./tests/e2e/reports ./tests/e2e/test-data rm -rf ./tests/e2e/reports ./tests/e2e/test-data
mkdir -p ./tests/e2e/reports/html ./tests/e2e/test-data/devstar_data mkdir -p ./tests/e2e/reports/html ./tests/e2e/test-data/devstar_data
#赋予目录权限,防止挂载后容器无权写入
chmod -R 777 ./tests/e2e/reports chmod -R 777 ./tests/e2e/reports
#这里添加的代码是因为需要执行npm install,我们以当前用户启动测试容器避免root权限冲突所以先预构建文件夹也作为缓存缓存npm install. #这里添加的代码是因为需要执行npm install,我们以当前用户启动测试容器避免root权限冲突所以先预构建文件夹也作为缓存缓存npm install.
echo "处理 node_modules 权限..." echo "处理 node_modules 权限..."
@@ -39,8 +30,6 @@ echo "清理完成。"
echo "" echo ""
echo "===== [2/3] 准备环境变量... =====" echo "===== [2/3] 准备环境变量... ====="
# 检查从 Makefile 传来的 TARGET_URL 变量是否为空
echo " 检查devstar位置:TARGET_URL"
export DEVSTAR_URL=$TARGET_URL export DEVSTAR_URL=$TARGET_URL
export E2E_MODE="url" export E2E_MODE="url"
if [ -n "$CI" ] || [ "$CI" = "true" ]; then if [ -n "$CI" ] || [ "$CI" = "true" ]; then
@@ -68,7 +57,6 @@ set +e
docker run -d --rm --init --ipc=host \ docker run -d --rm --init --ipc=host \
--name e2e-test-runner-container \ --name e2e-test-runner-container \
--network host \
-u "root" \ -u "root" \
-e DEVSTAR_URL="$DEVSTAR_URL" \ -e DEVSTAR_URL="$DEVSTAR_URL" \
-e E2E_SKIP_INSTALL="$E2E_SKIP_INSTALL" \ -e E2E_SKIP_INSTALL="$E2E_SKIP_INSTALL" \
@@ -80,7 +68,6 @@ docker run -d --rm --init --ipc=host \
-e HOME=/tmp \ -e HOME=/tmp \
-w /app \ -w /app \
-v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker.sock:/var/run/docker.sock \
-v "$(pwd)/tests/e2e/reports:/app/playwright-report" \
mcr.microsoft.com/playwright:v1.53.2-jammy \ mcr.microsoft.com/playwright:v1.53.2-jammy \
tail -f /dev/null tail -f /dev/null
echo "容器已启动,正在使用 docker cp 注入代码..." echo "容器已启动,正在使用 docker cp 注入代码..."
@@ -96,11 +83,11 @@ docker exec e2e-test-runner-container bash -c "
npm install --no-package-lock npm install --no-package-lock
echo '依赖安装完成,开始测试...' echo '依赖安装完成,开始测试...'
PLAYWRIGHT_HTML_REPORT=/app/playwright-report npx playwright test npx playwright test
" "
# 捕获 test-runner 的退出码
EXIT_CODE=$? EXIT_CODE=$?
set -e set -e
docker cp e2e-test-runner-container:/app/playwright-report/. tests/e2e/reports/html-report/
docker rm -f e2e-test-runner-container docker rm -f e2e-test-runner-container
echo "========================================" echo "========================================"
if [ $EXIT_CODE -eq 0 ]; then if [ $EXIT_CODE -eq 0 ]; then
@@ -109,14 +96,13 @@ else
echo "测试执行失败!" echo "测试执行失败!"
fi fi
echo "========================================" echo "========================================"
REPORT_DIR="./tests/e2e/reports" REPORT_DIR="./tests/e2e/reports/"
if [ -f "$REPORT_DIR/html/index.html" ]; then if [ -f "$REPORT_DIR" ]; then
echo "HTML 报告已生成: $REPORT_DIR//html/index.html" echo "HTML 报告已生成: $REPORT_DIR"
else else
echo "未检测到HTML报告 " echo "未检测到HTML报告 "
echo "可能是测试运行中途崩溃,或者未生成报告。" echo "可能是测试运行中途崩溃,或者未生成报告。"
echo "请检查日志或目录: $REPORT_DIR" echo "请检查日志或目录: $REPORT_DIR"
fi fi
echo "" echo ""
# 以 test-runner 的退出码退出
exit $EXIT_CODE exit $EXIT_CODE

repo.diff.view_file

@@ -78,6 +78,7 @@ test('DevContainer 功能和配置', async ({ page,context }) => {
//第二次刷新,容器应该正常启动了 //第二次刷新,容器应该正常启动了
await page.reload({ waitUntil: 'domcontentloaded' }); await page.reload({ waitUntil: 'domcontentloaded' });
await expect(stopButton).toBeVisible({ timeout: 30000 }); await expect(stopButton).toBeVisible({ timeout: 30000 });
await page.screenshot({ path: 'full-page.png', fullPage: true });
} }
console.log("Dev container 创建成功!"); console.log("Dev container 创建成功!");
await page.getByRole('button',{ name: '停止开发容器'}).click(); await page.getByRole('button',{ name: '停止开发容器'}).click();
@@ -94,6 +95,10 @@ test('DevContainer 功能和配置', async ({ page,context }) => {
await page.getByRole('link',{name: 'open with WebTerminal'}).click(); await page.getByRole('link',{name: 'open with WebTerminal'}).click();
const newPage = await pagePromise; const newPage = await pagePromise;
await newPage.waitForLoadState(); // 等待新页面加载完成 await newPage.waitForLoadState(); // 等待新页面加载完成
await page.reload({ waitUntil: 'domcontentloaded' });
await page.waitForTimeout(30000);
await page.reload({ waitUntil: 'domcontentloaded' });
await page.screenshot({ path: 'full-page.png', fullPage: true });
console.log("Web Terminal: 新标签页已打开!"); console.log("Web Terminal: 新标签页已打开!");
//await expect(newPage.getByText('Successfully connected to the container')).toBeVisible(); //这里ttyd里的信息PlayWright看不见容器的交互没办法自动化测试 //await expect(newPage.getByText('Successfully connected to the container')).toBeVisible(); //这里ttyd里的信息PlayWright看不见容器的交互没办法自动化测试
await page.getByRole('link', { name: '删除开发容器' }).click(); await page.getByRole('link', { name: '删除开发容器' }).click();