feat: 工具配置 Ubuntu 化 + nvm 管理 Node 版本

- 工具目录重写为 Ubuntu 构建环境导向(7 项),每项带安装命令提示
  (apt/nvm,未安装时一键复制)
- 新增 nvm 工具条目(真实检测,本机验证 0.40.6);Node.js 改为
  nvm 管理:默认版本可调,构建时通过 nvm install $NODE_VERSION
  灵活指定版本
- DeployTool 新增 installHint 字段(模型/更新白名单/seed)
- 新增 deploy/Dockerfile.buildnode:Ubuntu 22.04 + JDK17/Maven/Git/
  Docker CLI/Golang + nvm 默认 Node(--build-arg NODE_VERSION 可改)
- 工具页顶部说明条更新构建环境建议
This commit is contained in:
Logan.Li committed 2026-10-27 12:15:16 +08:00
1 parent d9d1dd5e99
commit 6841c1104a
6 files changed
+79 -22

No files matched your search

+8 -7
View File
@@ -224,7 +224,7 @@ func seedResources() {
}
}
// seedTools 工具清单(CheckCommand 为真实版本探测命令,安装走保守检测策略)
// seedTools 工具清单(Ubuntu 构建环境导向;Node 由 nvm 管理默认版本,构建时可按需 nvm install)
func seedTools() {
var n int64
DB.Model(&model.DeployTool{}).Count(&n)
@@ -232,11 +232,12 @@ func seedTools() {
return
}
DB.Create([]model.DeployTool{
{ToolKey: "jdk", DisplayName: "JDK", Category: "build", Version: "17", InstallMode: "preinstalled", Path: "/usr/lib/jvm/java-17", CheckCommand: "java -version", SortOrder: 1},
{ToolKey: "maven", DisplayName: "Maven", Category: "build", Version: "3.9", InstallMode: "lazy", Path: "/opt/maven", CheckCommand: "mvn -version", SortOrder: 2},
{ToolKey: "golang", DisplayName: "Golang", Category: "build", Version: "1.24", InstallMode: "preinstalled", Path: "/usr/local/go", CheckCommand: "go version", SortOrder: 3},
{ToolKey: "nodejs", DisplayName: "Node.js", Category: "build", Version: "20", InstallMode: "lazy", Path: "/usr/local/nvm", CheckCommand: "node -v", SortOrder: 4},
{ToolKey: "git", DisplayName: "Git", Category: "build", Version: "2.40", InstallMode: "preinstalled", Path: "/usr/bin/git", CheckCommand: "git --version", SortOrder: 5},
{ToolKey: "docker-cli", DisplayName: "Docker CLI", Category: "deploy", Version: "26", InstallMode: "lazy", Path: "/usr/bin/docker", CheckCommand: "docker --version", SortOrder: 6},
{ToolKey: "jdk", DisplayName: "JDK", Category: "build", Version: "17", InstallMode: "preinstalled", Path: "/usr/lib/jvm/java-17-openjdk-amd64", CheckCommand: "java -version", InstallHint: "apt update && apt install -y openjdk-17-jdk", SortOrder: 1},
{ToolKey: "maven", DisplayName: "Maven", Category: "build", Version: "3.8", InstallMode: "lazy", Path: "/usr/share/maven", CheckCommand: "mvn -version", InstallHint: "apt install -y maven", SortOrder: 2},
{ToolKey: "golang", DisplayName: "Golang", Category: "build", Version: "1.24", InstallMode: "preinstalled", Path: "/usr/local/go", CheckCommand: "go version", InstallHint: "apt install -y golang-1.24-go 或官方 tar 包解压至 /usr/local/go", SortOrder: 3},
{ToolKey: "nvm", DisplayName: "nvm(Node 版本管理)", Category: "build", Version: "0.40", InstallMode: "preinstalled", Path: "$HOME/.nvm", CheckCommand: `. "$HOME/.nvm/nvm.sh" && nvm --version`, InstallHint: "curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash", SortOrder: 4},
{ToolKey: "nodejs", DisplayName: "Node.js(nvm 管理)", Category: "build", Version: "20", InstallMode: "lazy", Path: "$HOME/.nvm/versions/node", CheckCommand: "node -v", InstallHint: "nvm install 20 && nvm alias default 20(构建时可用 nvm install 18 按需切版本)", SortOrder: 5},
{ToolKey: "git", DisplayName: "Git", Category: "build", Version: "2.40", InstallMode: "preinstalled", Path: "/usr/bin/git", CheckCommand: "git --version", InstallHint: "apt install -y git", SortOrder: 6},
{ToolKey: "docker-cli", DisplayName: "Docker CLI", Category: "deploy", Version: "26", InstallMode: "lazy", Path: "/usr/bin/docker", CheckCommand: "docker --version", InstallHint: "apt install -y docker.io", SortOrder: 7},
})
}
+1 -1
View File
@@ -448,7 +448,7 @@ func UpdateTool(c *gin.Context) {
}
var raw map[string]any
_ = c.ShouldBindJSON(&raw)
for _, k := range []string{"installMode", "version", "path", "enabled"} {
for _, k := range []string{"installMode", "version", "path", "installHint", "enabled"} {
if v, ok := raw[k]; ok {
database.DB.Model(&t).Update(k, v)
}
+1
View File
@@ -225,6 +225,7 @@ type DeployTool struct {
InstallMode string `gorm:"default:lazy" json:"installMode"` // preinstalled|lazy|disabled
Path string `json:"path"`
CheckCommand string `gorm:"type:text" json:"checkCommand"` // 真实版本探测命令
InstallHint string `gorm:"type:text" json:"installHint"` // 安装命令提示(Ubuntu apt / nvm)
Enabled bool `gorm:"default:true" json:"enabled"`
LastCheck *time.Time `json:"lastCheck"`
ErrorMsg string `json:"errorMsg"`
+8 -12
View File
@@ -1,14 +1,10 @@
<!doctype html>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>FlowStack · 发布系统</title>
<script type="module" crossorigin src="/assets/index-Ddr58eTO.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-C7Y81iLv.css">
</head>
<body>
<div id="root"></div>
</body>
<head><meta charset="UTF-8"><title>FlowStack</title></head>
<body style="font-family: -apple-system, sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; background: #f6f8fa;">
<div style="text-align: center; color: #57606a;">
<h1 style="font-size: 20px;">FlowStack 前端尚未构建</h1>
<p>请在项目根目录执行 <code style="background:#eaeef2;padding:2px 6px;border-radius:4px;">./run.sh build</code> 生成前端产物后重新编译。</p>
</div>
</body>
</html>
+46
View File
@@ -0,0 +1,46 @@
# FlowStack 构建节点镜像(Ubuntu 22.04)
# 用法: docker build -f deploy/Dockerfile.buildnode -t flowstack-buildnode .
# 自定义默认 Node 版本: docker build --build-arg NODE_VERSION=18 -f deploy/Dockerfile.buildnode -t flowstack-buildnode .
FROM ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
ARG NODE_VERSION=20
ENV NVM_DIR=/root/.nvm \
NVM_NODE_DEFAULT=${NODE_VERSION}
# 基础工具 + JDK17 + Maven + Git + Docker CLI(Ubuntu apt 一步到位)
RUN apt-get update && apt-get install -y --no-install-recommends \
openjdk-17-jdk-headless \
maven \
git \
docker.io \
curl ca-certificates unzip xz-utils \
tzdata \
&& rm -rf /var/lib/apt/lists/*
# Golang(官方 tar,apt 的 golang 版本较旧)
ARG GOLANG_VERSION=1.24.2
RUN curl -fsSL https://go.dev/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz | tar -C /usr/local -xzf - \
&& ln -s /usr/local/go/bin/go /usr/local/bin/go \
&& ln -s /usr/local/go/bin/gofmt /usr/local/bin/gofmt
# nvm + 默认 Node 版本(构建时可在流水线脚本里 nvm install <ver> 灵活切换)
ARG NVM_VERSION=v0.40.1
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash \
&& . "$NVM_DIR/nvm.sh" \
&& nvm install ${NODE_VERSION} \
&& nvm alias default ${NODE_VERSION} \
&& echo '. "$NVM_DIR/nvm.sh"' >> /root/.bashrc
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
PATH=/usr/local/go/bin:$PATH
# 构建工作空间
RUN mkdir -p /data/flowstack-workspace
WORKDIR /data/flowstack-workspace
# 验证工具链可用
RUN java -version && mvn -version && go version && git --version \
&& . "$NVM_DIR/nvm.sh" && node -v && npm -v
CMD ["bash", "-c", "echo 'FlowStack build node ready' && bash"]
+15 -2
View File
@@ -10,6 +10,7 @@ import {
RefreshCw,
Terminal,
AlertCircle,
Copy,
} from 'lucide-react';
import { toast } from 'sonner';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
@@ -26,6 +27,7 @@ interface DeployTool {
installedVersion: string;
installMode: 'preinstalled' | 'lazy' | 'disabled';
path: string;
installHint: string;
enabled: boolean;
lastCheck: string | null;
errorMsg: string;
@@ -176,7 +178,7 @@ export default function ToolConfig() {
{/* Description bar */}
<div className="px-5 py-2 border-b text-[12px] flex items-center gap-2" style={{ background: 'var(--panel-bg-secondary)', borderColor: 'var(--border-color)', color: 'var(--text-secondary)' }}>
<Terminal className="w-3.5 h-3.5" style={{ color: 'var(--text-tertiary)' }} />
管理 DevOps 工具的安装策略:预装在镜像中、首次使用自动下载(懒加载)、或禁用不安装
构建环境建议 Ubuntu 22.04(apt 安装下方工具);Node 由 nvm 管理——默认版本可在此调整,流水线构建时用 <code className="px-1 rounded font-mono text-[11px]" style={{ background: 'var(--panel-bg)', color: 'var(--accent-blue)' }}>nvm install $NODE_VERSION</code> 灵活指定版本。可用 deploy/Dockerfile.buildnode 一键构建节点镜像
</div>
{/* Content */}
@@ -236,6 +238,17 @@ export default function ToolConfig() {
<div>
<div className="text-[14px] font-semibold mb-0.5" style={{ color: 'var(--text-primary)' }}>{tool.name}</div>
<div className="text-[12px] font-mono mb-1" style={{ color: 'var(--text-tertiary)' }}>{tool.key}</div>
{tool.installHint && tool.status !== 'installed' && (
<button
onClick={() => { navigator.clipboard.writeText(tool.installHint); toast.success('安装命令已复制'); }}
className="mt-1 flex items-center gap-1.5 px-2 py-[3px] rounded font-mono text-[10px] max-w-full hover:opacity-80"
style={{ background: 'var(--panel-bg-secondary)', color: 'var(--text-secondary)' }}
title={tool.installHint}
>
<Copy className="w-2.5 h-2.5 flex-shrink-0" />
<span className="truncate">{tool.installHint}</span>
</button>
)}
{tool.status === 'installed' && tool.path && (
<div className="text-[10px] mt-1 font-mono" style={{ color: 'var(--text-tertiary)' }}>路径: {tool.path}</div>
)}
@@ -262,7 +275,7 @@ export default function ToolConfig() {
) : (
tool.version && (
<div className="text-[11px] mt-0.5" style={{ color: 'var(--text-tertiary)' }} title={tool.errorMsg || undefined}>
期望 v{tool.version}
{tool.key === 'nodejs' ? `默认 v${tool.version}(构建时可覆盖)` : `期望 v${tool.version}`}
</div>
)
)}