diff --git a/.dockerignore b/.dockerignore index 487d98b..6d6d711 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,7 @@ target/ .git/ .idea/ outputs/ +**/node_modules/ +**/dist/ +**/node/ +outputs.nobody-backup-*/ diff --git a/AGENTS.md b/AGENTS.md index b35a784..e03946c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,7 @@ - 核心目录: - `src/main/java/com/svnlog/` - `docs/` - - SVN 预设地址:`src/main/resources/application.properties`(`svn.presets[*]`) + - SVN 预设地址:通过仓库管理页维护,持久化至 `outputs/repository-configs.json` ## 2. 常用命令(Build / Lint / Test / Run) 以下命令默认在仓库根目录执行。 diff --git a/Dockerfile b/Dockerfile index d809107..7c2eb9d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,11 @@ # ============================================================ # Docker 镜像仓库加速(默认使用 docker.1ms.run 国内代理) # 如需切换回 Docker Hub: -# docker compose build --build-arg REGISTRY_MIRROR=docker.io/library +# DOCKER_REGISTRY_MIRROR=docker.io/library make up # ============================================================ ARG REGISTRY_MIRROR=docker.1ms.run/library +# 内部/开发用途,推荐通过 make fast-up 触发快速构建 +ARG FAST_BUILD=false # ============================================================ # Stage 1: 前端构建(Vue 3 + Vite) @@ -14,7 +16,7 @@ WORKDIR /frontend COPY frontend-vue/package.json frontend-vue/package-lock.json ./ -RUN npm ci +RUN --mount=type=cache,target=/root/.npm npm ci COPY frontend-vue/ ./ @@ -23,20 +25,20 @@ RUN npm run build # ============================================================ # Stage 2: 后端构建(Maven + Java 8) # ============================================================ -FROM ${REGISTRY_MIRROR}/maven:3.9.6-eclipse-temurin-8 AS builder +FROM ${REGISTRY_MIRROR}/maven:3.9.6-eclipse-temurin-8 AS builder-base # Maven JVM 调优:增大堆内存、启用并行 ENV MAVEN_OPTS="-Xmx2g -XX:MaxMetaspaceSize=512m -Djava.util.concurrent.ForkJoinPool.common.parallelism=4" WORKDIR /app -# 使用阿里云 Maven 镜像加速依赖下载(替换 Maven Central) -COPY maven-settings.xml /root/.m2/settings.xml +# 使用阿里云 Maven 镜像加速依赖下载(避免被 /root/.m2 缓存挂载点隐藏) +COPY maven-settings.xml /app/maven-settings.xml COPY pom.xml . RUN --mount=type=cache,target=/root/.m2 \ - mvn -B -DskipTests -T 1C dependency:go-offline + mvn -s /app/maven-settings.xml -B -DskipTests -T 1C dependency:go-offline COPY src ./src @@ -44,11 +46,21 @@ COPY src ./src # vite.config.js 中 outDir 为相对 __dirname 的路径,容器内 __dirname=/frontend COPY --from=frontend-builder /src/main/resources/static/v2 /app/src/main/resources/static/v2 -# 前端产物已由 frontend-builder 阶段构建并 COPY 进来; -# 此阶段不含 frontend-vue/,且离线模式无法下载 Node,必须跳过前端构建。 -# -T 1C: 按 CPU 核数并行; -o: 离线模式(依赖已缓存,跳过元数据检查) +# 默认构建分支(不缓存 /app/target,执行 clean) +FROM builder-base AS builder-false RUN --mount=type=cache,target=/root/.m2 \ - mvn -B -DskipTests -T 1C -o clean package -Dskip.frontend.build=true + mvn -s /app/maven-settings.xml -B -DskipTests -T 1C clean package -Dskip.frontend.build=true && \ + cp /app/target/svn-log-tool-1.0.0-jar-with-dependencies.jar /app/svn-log-tool-1.0.0-jar-with-dependencies.jar + +# 快速开发迭代构建分支(缓存 /app/target,不执行 clean) +FROM builder-base AS builder-true +RUN --mount=type=cache,target=/root/.m2 \ + --mount=type=cache,target=/app/target \ + mvn -s /app/maven-settings.xml -B -DskipTests -T 1C package -Dskip.frontend.build=true && \ + cp /app/target/svn-log-tool-1.0.0-jar-with-dependencies.jar /app/svn-log-tool-1.0.0-jar-with-dependencies.jar + +# 根据 FAST_BUILD 的值决定最终作为 builder 的阶段 +FROM builder-${FAST_BUILD} AS builder # ============================================================ # Stage 3: 运行镜像(最小化 JRE) @@ -56,7 +68,7 @@ RUN --mount=type=cache,target=/root/.m2 \ FROM ${REGISTRY_MIRROR}/eclipse-temurin:8-jre-alpine WORKDIR /app -COPY --from=builder /app/target/svn-log-tool-1.0.0-jar-with-dependencies.jar app.jar +COPY --from=builder /app/svn-log-tool-1.0.0-jar-with-dependencies.jar app.jar EXPOSE 18088 diff --git a/Makefile b/Makefile index 00d26c6..f41e6ef 100644 --- a/Makefile +++ b/Makefile @@ -5,14 +5,14 @@ # ============================================================ DOCKER_REGISTRY_MIRROR ?= docker.1ms.run/library -.PHONY: up down status +.PHONY: up down status fast-up COMPOSE_CMD := $(shell if command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then echo "docker compose"; elif command -v docker-compose >/dev/null 2>&1; then echo "docker-compose"; fi) BUILD_ENV := DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 up: @if [ -z "$(COMPOSE_CMD)" ]; then echo "docker compose/docker-compose not found"; exit 1; fi - @REGISTRY_MIRROR=$(DOCKER_REGISTRY_MIRROR) $(BUILD_ENV) $(COMPOSE_CMD) up -d --build + @DOCKER_REGISTRY_MIRROR=$(DOCKER_REGISTRY_MIRROR) FAST_BUILD=false $(BUILD_ENV) $(COMPOSE_CMD) up -d --build @echo "Application is starting at http://localhost:18088" down: @@ -23,3 +23,10 @@ status: @if [ -z "$(COMPOSE_CMD)" ]; then echo "docker compose/docker-compose not found"; exit 1; fi @$(BUILD_ENV) $(COMPOSE_CMD) ps @echo "Access URL: http://localhost:18088" + +fast-up: + @if [ -z "$(COMPOSE_CMD)" ]; then echo "docker compose/docker-compose not found"; exit 1; fi + @echo "WARNING: fast-up is for Java incremental dev only." + @echo "WARNING: Use 'make up' if you changed frontend resources, or deleted/renamed Java files." + @DOCKER_REGISTRY_MIRROR=$(DOCKER_REGISTRY_MIRROR) FAST_BUILD=true $(BUILD_ENV) $(COMPOSE_CMD) up -d --build + @echo "Application is starting at http://localhost:18088" diff --git a/README.md b/README.md index 986a912..d5fb52d 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,12 @@ SVN 日志抓取与 AI 工作量分析工具,统一使用 Web 工作台入口 ## 常用命令 ```bash -# 一键启动(Docker,每次会重新构建镜像并打包最新代码) +# 一键启动(Docker,每次会重新构建镜像并打包最新代码,安全默认构建) make up +# 快速开发迭代启动(Docker,保留 Java 编译缓存,仅适合本地 Java 增量开发) +make fast-up + # 查看状态 make status diff --git a/docker-compose.yml b/docker-compose.yml index 094728d..dfcb417 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,9 +4,10 @@ services: context: . dockerfile: Dockerfile args: - # Docker 镜像加速(默认 Docker Hub,国内可设阿里云) - # 使用方式: REGISTRY_MIRROR=registry.cn-hangzhou.aliyuncs.com/library docker compose build - REGISTRY_MIRROR: ${REGISTRY_MIRROR:-docker.1ms.run/library} + # Docker 镜像加速(使用 DOCKER_REGISTRY_MIRROR 传递,国内可选阿里云,例如 registry.cn-hangzhou.aliyuncs.com/library,不能带 https://) + # 内部/开发用途,推荐通过 make fast-up 使用快速构建 + REGISTRY_MIRROR: ${DOCKER_REGISTRY_MIRROR:-docker.1ms.run/library} + FAST_BUILD: ${FAST_BUILD:-false} container_name: svn-log-tool network_mode: host volumes: diff --git a/docs/README_Web.md b/docs/README_Web.md index 437ad79..daf03cd 100644 --- a/docs/README_Web.md +++ b/docs/README_Web.md @@ -34,12 +34,19 @@ mvn spring-boot:run -Dspring-boot.run.mainClass=com.svnlog.web.WebApplication http://localhost:18088 ``` -## Docker 构建行为 +## Docker 构建行为与优化 -- `make up` 保持“重新构建并启动”的语义,每次都会执行一次 Maven 打包,确保容器内是最新代码。 -- Docker 构建使用 BuildKit 缓存 Maven 本地仓库;首次构建会下载依赖,后续在 `pom.xml` 未变更时会优先命中缓存,不会在每次构建时重复下载全部依赖。 -- 如果修改了 `pom.xml`、执行了 `docker builder prune`、或切换到新的 Docker 环境,依赖缓存会失效并重新下载。 -- 如果本机 Docker 未启用 BuildKit,可显式设置 `DOCKER_BUILDKIT=1` 和 `COMPOSE_DOCKER_CLI_BUILD=1` 后再执行 `make up`。 +- **Docker 镜像加速**:默认使用 `docker.1ms.run/library` 代理。如果需要切换回 Docker Hub 或使用国内其他镜像(如阿里云镜像,例如 `registry.cn-hangzhou.aliyuncs.com/library`,注意不能带 `https://`),可以通过命令行传递 `DOCKER_REGISTRY_MIRROR` 变量: + ```bash + DOCKER_REGISTRY_MIRROR=registry.cn-hangzhou.aliyuncs.com/library make up + ``` +- **快速开发迭代(可选 Fast Build)**:默认情况下,构建仍会执行 `mvn clean package` 以确保打包的正确性(防旧 class 或资源残留)。如果在本地频繁修改 Java 代码,可以使用 `fast-up` 实现秒级编译与构建重启。**注意:如果修改了前端静态资源,或删除/重命名了 Java 类与资源文件,应使用默认构建(`make up`),不要用 Fast Build。** + ```bash + make fast-up + ``` + 该模式下,Docker 会使用 BuildKit 挂载缓存 `/app/target` 目录,并不再执行 `clean` 目标,使 Maven 能进行增量编译。 +- **依赖缓存**:Docker 构建使用 BuildKit 缓存了 Maven 本地仓库(`.m2`)与 npm 缓存(`.npm`)。在依赖文件未变更时,不会重复下载依赖包。 +- 如果本机 Docker 未启用 BuildKit,可显式设置 `DOCKER_BUILDKIT=1` 和 `COMPOSE_DOCKER_CLI_BUILD=1` 后再执行构建。 ## 页面说明 @@ -78,8 +85,9 @@ http://localhost:18088 ## SVN 凭据读取优先级 1. 单次请求显式传入的 `username/password`(兼容旧接口) -2. 设置页保存的运行时 `svnUsername/svnPassword` -3. 环境变量 `SVN_USERNAME` / `SVN_PASSWORD` +2. 预设凭据 +3. 全局设置保存的运行时 `svnUsername/svnPassword` +4. 环境变量 `SVN_USERNAME` / `SVN_PASSWORD` `GET /api/settings` 不会回显 `openaiApiKey` 或 `svnPassword` 明文,前端通过 `openaiApiKeyConfigured` 和 `svnCredentialsConfigured` 展示配置状态。 @@ -105,7 +113,7 @@ http://localhost:18088 ## SVN 预设来源与调用方式 -- SVN 地址统一维护在 `application.properties` 的 `svn.presets[*]` 中。 +- SVN 地址统一通过仓库管理页维护,并持久化到 `outputs/repository-configs.json` 文件中。 - 前端不再传 SVN URL,业务接口统一传 `presetId`,后端按 `presetId` 解析地址。 - `GET /api/svn/presets` 仅返回 `id` 与 `name`(不返回 `url`)。 diff --git a/frontend-vue/src/components/AppSidebar.vue b/frontend-vue/src/components/AppSidebar.vue index 367ade4..c758707 100644 --- a/frontend-vue/src/components/AppSidebar.vue +++ b/frontend-vue/src/components/AppSidebar.vue @@ -14,7 +14,11 @@ - SVN 日志抓取 + 日志抓取 + + + + 仓库管理 diff --git a/frontend-vue/src/main.js b/frontend-vue/src/main.js index 78f0c7f..93a878a 100644 --- a/frontend-vue/src/main.js +++ b/frontend-vue/src/main.js @@ -5,13 +5,15 @@ import DashboardView from './views/DashboardView.vue' import SvnFetchView from './views/SvnFetchView.vue' import HistoryView from './views/HistoryView.vue' import SettingsView from './views/SettingsView.vue' +import SvnPresetsView from './views/SvnPresetsView.vue' import './styles/main.css' const routes = [ { path: '/', redirect: '/dashboard' }, { path: '/dashboard', name: 'dashboard', component: DashboardView, meta: { title: '工作台', desc: '查看系统状态与最近产物' } }, - { path: '/svn-fetch', name: 'svn-fetch', component: SvnFetchView, meta: { title: 'SVN 日志抓取', desc: '一键抓取 SVN 日志并导出工作量 Excel' } }, + { path: '/svn-fetch', name: 'svn-fetch', component: SvnFetchView, meta: { title: '日志抓取', desc: '一键抓取 SVN 日志并导出工作量 Excel' } }, { path: '/history', name: 'history', component: HistoryView, meta: { title: '任务历史', desc: '查看任务执行状态、日志与产物' } }, + { path: '/presets', name: 'presets', component: SvnPresetsView, meta: { title: '仓库管理', desc: '管理 SVN 仓库预设' } }, { path: '/settings', name: 'settings', component: SettingsView, meta: { title: '系统设置', desc: '配置 API Key 与输出目录' } }, ] diff --git a/frontend-vue/src/views/SvnFetchView.vue b/frontend-vue/src/views/SvnFetchView.vue index 326d673..a5ece11 100644 --- a/frontend-vue/src/views/SvnFetchView.vue +++ b/frontend-vue/src/views/SvnFetchView.vue @@ -1,12 +1,22 @@