diff --git a/.gitea/workflows/devstar-studio-e2e.yaml b/.gitea/workflows/devstar-studio-e2e.yaml index 564b8dde24..4a6b28df7a 100644 --- a/.gitea/workflows/devstar-studio-e2e.yaml +++ b/.gitea/workflows/devstar-studio-e2e.yaml @@ -11,22 +11,22 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out repository code - uses: actions/checkout@v4 - - - name: Clean - run: | - public/assets/install.sh clean - docker volume rm devstar_data_vol || true + uses: actions/checkout@v4 - name: start DevStar Container 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 run: | - make e2e-test TARGET_URL="http://localhost:80" + make e2e-test TARGET_URL="$TARGET_URL" env: GITEA_I_AM_BEING_UNSAFE_RUNNING_AS_ROOT: "true" - name: 4. Upload E2E Test Report diff --git a/playwright.config.ts b/playwright.config.ts index b3ae2e89f5..90055cebe9 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -15,7 +15,7 @@ const config: PlaywrightTestConfig = { forbidOnly: Boolean(env.CI), retries: env.CI ? 2 : 0, - reporter: env.CI ? 'list' : [['list'], ['html', { + reporter: [['html', { outputFolder: 'playwright-report/html', open: 'never' }]], diff --git a/public/assets/install.sh b/public/assets/install.sh index 5ac4155f4e..0c5582cb99 100755 --- a/public/assets/install.sh +++ b/public/assets/install.sh @@ -2,14 +2,13 @@ # 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_NAME=devstar-studio VERSION=latest # DevStar Studio的默认版本为最新版本 PORT=80 # 设置端口默认值为 80 SSH_PORT=2222 # 设置ssh默认端口号2222 DATA_DIR=${HOME}/devstar_data -APP_INI=${DATA_DIR}/app.ini # 错误处理函数 error_handler() { @@ -111,25 +110,30 @@ function start { mkdir -p $DATA_DIR sudo chown 1000:1000 $DATA_DIR sudo chmod 666 /var/run/docker.sock - if [ ! -f "$APP_INI" ]; then - DOMAIN_NAME=$(hostname -I | awk '{print $1}') + if [[ -n "$CI" ]]; then + 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" else # 读取 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 - DOMAIN_NAME="localhost" + if [[ -n "$DOMAIN_NAME_APP_INI" ]]; then + DOMAIN_NAME=$DOMAIN_NAME_APP_INI fi echo "DOMAIN_NAME=$DOMAIN_NAME" fi # 启动devstar-studio容器 - stop if [[ -z "$IMAGE_STR" ]]; then IMAGE_STR="$IMAGE_REGISTRY_USER/$IMAGE_NAME:$VERSION" fi 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` 完成安装。 success "-------------------------------------------------------" success "DevStar started in http://$DOMAIN_NAME:$PORT successfully!" @@ -139,30 +143,37 @@ function start { # Function to stop function stop { - if [ $(docker ps -a --filter "name=^/${NAME}$" -q | wc -l) -gt 0 ]; then - sudo docker stop $NAME && sudo docker rm -f $NAME - fi - 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 + if [ $(docker ps -a --filter "name=^/DevStar-Studio.*|devstar-studio.*" -q | wc -l) -gt 0 ]; then + sudo docker stop $(docker ps -a --filter "name=^/DevStar-Studio.*|devstar-studio.*" -q) && \ + sudo docker rm -f $(docker ps -a --filter "name=^/DevStar-Studio.*|devstar-studio.*" -q) fi 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) fi 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) - fi + fi } # Function to logs function logs { # 查看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 clean { 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 @@ -173,6 +184,7 @@ function usage { success " start Start DevStar Studio" success " --port= Specify the port number (default port is 80)" success " --ssh-port= Specify the ssh-port number (default ssh-port is 2222)" + success " --data-dir= Specify the data directory (default data directory is ~/devstar_data)" success " --version= Specify the DevStar Studio Image Version (default verson is latest)" success " --image= Specify the DevStar Studio Image example: devstar-studio:latest " success " stop Stop the running DevStar Studio" @@ -188,7 +200,7 @@ case "$1" in usage ;; start) - ARGS=$(getopt --long port::,ssh-port::,version::,image:: -- "$@") + ARGS=$(getopt --long port::,ssh-port::,data-dir::,version::,image:: -- "$@") if [ $? -ne 0 ]; then failure "ARGS ERROR!" exit 1 @@ -205,6 +217,10 @@ case "$1" in SSH_PORT="$2" echo "The SSH_Port is: $SSH_PORT" shift 2 ;; + --data-dir) + DATA_DIR="$2" + echo "The SSH_Port is: $DATA_DIR" + shift 2 ;; --version) VERSION="$2" echo "The DevStar Studio Image Version is: $VERSION" @@ -246,5 +262,4 @@ case "$1" in devstar help fi ;; -esac - +esac \ No newline at end of file diff --git a/tests/e2e/global-setup.ts b/tests/e2e/global-setup.ts index 2fa05979f7..438014c880 100644 --- a/tests/e2e/global-setup.ts +++ b/tests/e2e/global-setup.ts @@ -31,7 +31,7 @@ async function globalSetup(config: FullConfig) { await page.getByRole('textbox', { name: '邮箱地址' }).fill('ilovcatlyn750314@gmail.com'); await page.getByRole('textbox', { name: '管理员密码', exact: true }).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("安装中,请耐心等待"); await page.waitForTimeout(90000); } catch (error) { diff --git a/tests/e2e/run-e2e-tests.sh b/tests/e2e/run-e2e-tests.sh index 7a9ab7582e..e73f043a73 100755 --- a/tests/e2e/run-e2e-tests.sh +++ b/tests/e2e/run-e2e-tests.sh @@ -3,27 +3,18 @@ # 它会处理所有清理、权限、拉取和执行工作 # 任何命令失败立即退出 set -e - -# 获取脚本所在目录和项目根目录,test/e2e和devstar项目根目录 SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) PROJECT_ROOT=$( cd -- "$SCRIPT_DIR/../.." &> /dev/null && pwd ) - -# 导出当前用户 ID,防止 Docker 生成 root 权限文件 export CURRENT_UID=$(id -u) export CURRENT_GID=$(id -g) -# 切换到项目根目录 cd "$PROJECT_ROOT" echo "===== [1/3] 清理旧的测试环境... =====" -#删除旧的e2e-runner if [ "$(docker ps -aq -f name=e2e-test-runner-container)" ]; then docker rm -f e2e-test-runner-container fi -#清理旧的构建缓存 docker image prune -f -#清理并重建报告和数据目录 rm -rf ./tests/e2e/reports ./tests/e2e/test-data mkdir -p ./tests/e2e/reports/html ./tests/e2e/test-data/devstar_data -#赋予目录权限,防止挂载后容器无权写入 chmod -R 777 ./tests/e2e/reports #这里添加的代码是因为需要执行npm install,我们以当前用户启动测试容器,避免root权限冲突,所以先预构建文件夹,也作为缓存,缓存npm install. echo "处理 node_modules 权限..." @@ -39,8 +30,6 @@ echo "清理完成。" echo "" echo "===== [2/3] 准备环境变量... =====" -# 检查从 Makefile 传来的 TARGET_URL 变量是否为空 -echo " 检查devstar位置:TARGET_URL" export DEVSTAR_URL=$TARGET_URL export E2E_MODE="url" if [ -n "$CI" ] || [ "$CI" = "true" ]; then @@ -68,7 +57,6 @@ set +e docker run -d --rm --init --ipc=host \ --name e2e-test-runner-container \ - --network host \ -u "root" \ -e DEVSTAR_URL="$DEVSTAR_URL" \ -e E2E_SKIP_INSTALL="$E2E_SKIP_INSTALL" \ @@ -80,7 +68,6 @@ docker run -d --rm --init --ipc=host \ -e HOME=/tmp \ -w /app \ -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 \ tail -f /dev/null echo "容器已启动,正在使用 docker cp 注入代码..." @@ -96,11 +83,11 @@ docker exec e2e-test-runner-container bash -c " npm install --no-package-lock echo '依赖安装完成,开始测试...' - PLAYWRIGHT_HTML_REPORT=/app/playwright-report npx playwright test + npx playwright test " -# 捕获 test-runner 的退出码 EXIT_CODE=$? set -e +docker cp e2e-test-runner-container:/app/playwright-report/. tests/e2e/reports/html-report/ docker rm -f e2e-test-runner-container echo "========================================" if [ $EXIT_CODE -eq 0 ]; then @@ -109,14 +96,13 @@ else echo "测试执行失败!" fi echo "========================================" -REPORT_DIR="./tests/e2e/reports" -if [ -f "$REPORT_DIR/html/index.html" ]; then - echo "HTML 报告已生成: $REPORT_DIR//html/index.html" +REPORT_DIR="./tests/e2e/reports/" +if [ -f "$REPORT_DIR" ]; then + echo "HTML 报告已生成: $REPORT_DIR" else echo "未检测到HTML报告 " echo "可能是测试运行中途崩溃,或者未生成报告。" echo "请检查日志或目录: $REPORT_DIR" fi echo "" -# 以 test-runner 的退出码退出 exit $EXIT_CODE \ No newline at end of file diff --git a/tests/e2e/specs/devcontainer.e2e.test.ts b/tests/e2e/specs/devcontainer.e2e.test.ts index 43dfdf2397..2982c45d70 100644 --- a/tests/e2e/specs/devcontainer.e2e.test.ts +++ b/tests/e2e/specs/devcontainer.e2e.test.ts @@ -78,6 +78,7 @@ test('DevContainer 功能和配置', async ({ page,context }) => { //第二次刷新,容器应该正常启动了 await page.reload({ waitUntil: 'domcontentloaded' }); await expect(stopButton).toBeVisible({ timeout: 30000 }); + await page.screenshot({ path: 'full-page.png', fullPage: true }); } console.log("Dev container 创建成功!"); await page.getByRole('button',{ name: '停止开发容器'}).click(); @@ -94,6 +95,10 @@ test('DevContainer 功能和配置', async ({ page,context }) => { await page.getByRole('link',{name: 'open with WebTerminal'}).click(); const newPage = await pagePromise; 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: 新标签页已打开!"); //await expect(newPage.getByText('Successfully connected to the container')).toBeVisible(); //这里ttyd里的信息PlayWright看不见,容器的交互没办法自动化测试 await page.getByRole('link', { name: '删除开发容器' }).click();