feat: optimize backend build with conditional martial-tool install

This commit is contained in:
2026-02-15 18:22:50 +08:00
parent 728cbdf57c
commit 0add18b2ae
4 changed files with 192 additions and 2 deletions
+7
View File
@@ -44,3 +44,10 @@ nul
minio_data/
minio_data/
.m2-repo/
# Keep deploy scripts tracked
!scripts/ensure-martial-tool-installed.sh
!scripts/deploy-backend.sh
# Local build cache
.build-cache/
+12 -2
View File
@@ -62,10 +62,20 @@ docker compose ps
### 快速构建(开发迭代)
```bash
# 本地编译后构建镜像
mvn clean package -DskipTests && docker-compose up --build
# 只做后端打包(不会重建容器)
./scripts/deploy-backend.sh --skip-docker
# 打包 + 重建并重启 martial-api 容器
./scripts/deploy-backend.sh
```
说明:
- `./scripts/ensure-martial-tool-installed.sh` 会自动检测 `martial-tool` 是否已安装到本地 Maven 仓库。
- 只有在以下情况才会重新执行 `martial-tool``mvn install`
- 本地 Maven 仓库缺少 BladeX 依赖产物。
- `martial-tool` 代码发生变化(基于 git 状态检测)。
- 日常迭代只改后端业务代码时,会跳过 `martial-tool` 编译,减少构建时间。
> 详细的 Docker 部署说明请参考 [Docker 部署指南](docs/guides/docker-deployment.md)
## 项目结构
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
usage() {
cat <<'USAGE'
Usage: ./scripts/deploy-backend.sh [--skip-docker]
Options:
--skip-docker Build jar only, skip docker compose build/up
USAGE
}
log() {
printf '[deploy] %s\n' "$*"
}
SKIP_DOCKER=0
while [[ $# -gt 0 ]]; do
case "$1" in
--skip-docker)
SKIP_DOCKER=1
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1" >&2
usage
exit 1
;;
esac
done
"$SCRIPT_DIR/ensure-martial-tool-installed.sh"
log "Packaging backend jar ..."
(
cd "$PROJECT_DIR"
mvn clean package -DskipTests
)
if [[ "$SKIP_DOCKER" -eq 1 ]]; then
log "--skip-docker enabled, jar build finished."
exit 0
fi
log "Building and restarting martial-api ..."
(
cd "$PROJECT_DIR"
docker compose build martial-api
docker compose up -d --no-deps martial-api
)
log "Waiting for martial-api health ..."
for _ in $(seq 1 60); do
json="$(cd "$PROJECT_DIR" && docker compose ps --format json martial-api 2>/dev/null || true)"
health="$(printf '%s\n' "$json" | sed -n 's/.*"Health":"\([^"]*\)".*/\1/p' | head -n 1)"
status="$(printf '%s\n' "$json" | sed -n 's/.*"Status":"\([^"]*\)".*/\1/p' | head -n 1)"
if [[ "$health" == "healthy" ]]; then
log "martial-api is healthy."
exit 0
fi
if printf '%s' "$status" | grep -Eiq 'unhealthy|exited|dead'; then
echo "[deploy] ERROR: martial-api status=$status" >&2
exit 1
fi
sleep 3
done
echo "[deploy] ERROR: timed out waiting for martial-api health" >&2
(cd "$PROJECT_DIR" && docker compose ps martial-api)
exit 1
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
TOOL_DIR="${TOOL_DIR:-$PROJECT_DIR/../martial-tool}"
CACHE_DIR="$PROJECT_DIR/.build-cache"
STATE_FILE="$CACHE_DIR/martial-tool.state"
log() {
printf '[martial-tool] %s\n' "$*"
}
fail() {
printf '[martial-tool] ERROR: %s\n' "$*" >&2
exit 1
}
[[ -d "$TOOL_DIR" ]] || fail "martial-tool directory not found: $TOOL_DIR"
[[ -f "$TOOL_DIR/pom.xml" ]] || fail "pom.xml not found in $TOOL_DIR"
command -v mvn >/dev/null 2>&1 || fail "mvn command not found"
revision="$(sed -n 's:.*<revision>\([^<]*\)</revision>.*:\1:p' "$TOOL_DIR/pom.xml" | head -n 1)"
[[ -n "$revision" ]] || fail "Unable to parse <revision> from $TOOL_DIR/pom.xml"
mapfile -t modules < <(sed -n 's:.*<module>\([^<]*\)</module>.*:\1:p' "$TOOL_DIR/pom.xml")
(( ${#modules[@]} > 0 )) || fail "No modules found in $TOOL_DIR/pom.xml"
missing=()
for artifact in "${modules[@]}"; do
if [[ "$artifact" == "blade-bom" ]]; then
group_path="org/springblade/platform"
else
group_path="org/springblade"
fi
version_dir="$HOME/.m2/repository/$group_path/$artifact/$revision"
if [[ ! -d "$version_dir" ]]; then
missing+=("$artifact")
continue
fi
if ! find "$version_dir" -maxdepth 1 -type f \( -name "$artifact-$revision.jar" -o -name "$artifact-$revision.pom" \) | grep -q .; then
missing+=("$artifact")
fi
done
if git -C "$TOOL_DIR" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
git_head="$(git -C "$TOOL_DIR" rev-parse HEAD)"
git_status="$(git -C "$TOOL_DIR" status --porcelain)"
if [[ -n "$git_status" ]]; then
if command -v sha256sum >/dev/null 2>&1; then
dirty_hash="$(printf '%s' "$git_status" | sha256sum | awk '{print $1}')"
else
dirty_hash="$(printf '%s' "$git_status" | shasum -a 256 | awk '{print $1}')"
fi
tool_state="${git_head}-dirty-${dirty_hash}"
else
tool_state="$git_head"
fi
else
pom_hash="$(find "$TOOL_DIR" -name pom.xml -type f -print0 | sort -z | xargs -0 cat | sha256sum | awk '{print $1}')"
tool_state="nogit-${pom_hash}"
fi
mkdir -p "$CACHE_DIR"
previous_state=""
if [[ -f "$STATE_FILE" ]]; then
previous_state="$(cat "$STATE_FILE")"
fi
if [[ ${#missing[@]} -eq 0 && "$tool_state" == "$previous_state" ]]; then
log "Artifacts already installed for revision $revision and source state unchanged, skip install."
exit 0
fi
if [[ ${#missing[@]} -gt 0 ]]; then
log "Missing artifacts detected (${#missing[@]}): ${missing[*]}"
else
log "martial-tool source changed, reinstall required."
log "cached state: ${previous_state:-<none>}"
log "current state: $tool_state"
fi
log "Installing martial-tool from $TOOL_DIR ..."
(
cd "$TOOL_DIR"
mvn -T 1C -DskipTests install
)
printf '%s\n' "$tool_state" > "$STATE_FILE"
log "Install complete. State cache updated: $STATE_FILE"