From 4de5f42dc87c67ec7f248d3e600fcaed80dd46a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=9B=E5=85=AE?= Date: Fri, 5 Jun 2026 15:08:12 +0800 Subject: [PATCH] chore: move Jenkins pipeline config out of repo --- Jenkinsfile | 122 -------------------------------- Jenkinsfile.prod | 104 --------------------------- README.md | 24 ++----- deploy/jenkins/deploy-static.sh | 57 --------------- docs/ENVIRONMENT_DEPLOYMENT.md | 81 --------------------- 5 files changed, 7 insertions(+), 381 deletions(-) delete mode 100644 Jenkinsfile delete mode 100644 Jenkinsfile.prod delete mode 100644 deploy/jenkins/deploy-static.sh delete mode 100644 docs/ENVIRONMENT_DEPLOYMENT.md diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 568137a..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,122 +0,0 @@ -def isProductionDeploy() { - return params.DEPLOY_ENV == "production" -} - -def isTestDeploy() { - def branch = env.BRANCH_NAME ?: "" - return params.DEPLOY_ENV == "test" && !params.SKIP_DEPLOY && branch == env.TEST_BRANCH -} - -@NonCPS -boolean isUserTriggeredBuild() { - return currentBuild.rawBuild.getCauses().any { cause -> - cause.class.name == "hudson.model.Cause\$UserIdCause" - } -} - -pipeline { - agent any - - options { - timestamps() - disableConcurrentBuilds() - buildDiscarder(logRotator(numToKeepStr: "30", artifactNumToKeepStr: "10")) - } - - parameters { - choice( - name: "DEPLOY_ENV", - choices: ["test", "production"], - description: "test: develop 合并后自动部署测试环境;production: 仅允许手动输入 Tag 部署" - ) - string(name: "RELEASE_TAG", defaultValue: "", description: "生产部署必填,必须是 Gitea 中已存在的 Tag") - booleanParam(name: "SKIP_DEPLOY", defaultValue: false, description: "只构建检查,不执行部署") - } - - environment { - PROJECT_NAME = "role-admin" - TEST_BRANCH = "develop" - DEPLOY_BASE_DIR = "/srv/www" - } - - stages { - stage("Validate deploy policy") { - steps { - script { - if (isProductionDeploy()) { - if (!isUserTriggeredBuild()) { - error("生产环境禁止自动触发,只能在 Jenkins 手动 Build With Parameters。") - } - if (!params.RELEASE_TAG?.trim()) { - error("生产环境部署必须填写 RELEASE_TAG,且只能从项目 Tag 部署。") - } - } - - if (params.DEPLOY_ENV == "test" && env.BRANCH_NAME && env.BRANCH_NAME != env.TEST_BRANCH) { - echo "当前分支 ${env.BRANCH_NAME} 不是 ${env.TEST_BRANCH},本次只构建检查,不自动部署测试环境。" - } - } - } - } - - stage("Checkout production tag") { - when { - expression { isProductionDeploy() } - } - steps { - sh ''' - set -euo pipefail - git fetch --tags --force origin '+refs/tags/*:refs/tags/*' - tag_commit="$(git rev-parse -q --verify "refs/tags/${RELEASE_TAG}^{commit}")" - if [ -z "${tag_commit}" ]; then - echo "Tag not found: ${RELEASE_TAG}" >&2 - exit 1 - fi - git checkout -f "${tag_commit}" - git log -1 --oneline - ''' - } - } - - stage("Install") { - steps { - sh ''' - corepack enable || true - pnpm install --frozen-lockfile - ''' - } - } - - stage("Verify") { - steps { - sh "pnpm typecheck" - } - } - - stage("Build") { - steps { - script { - sh isProductionDeploy() ? "pnpm build:prod" : "pnpm build:test" - } - } - } - - stage("Deploy test") { - when { - expression { isTestDeploy() } - } - steps { - sh "bash deploy/jenkins/deploy-static.sh test dist" - } - } - - stage("Deploy production") { - when { - expression { isProductionDeploy() && !params.SKIP_DEPLOY } - } - steps { - sh "bash deploy/jenkins/deploy-static.sh production dist" - } - } - } -} diff --git a/Jenkinsfile.prod b/Jenkinsfile.prod deleted file mode 100644 index 4590fbf..0000000 --- a/Jenkinsfile.prod +++ /dev/null @@ -1,104 +0,0 @@ -pipeline { - agent any - - parameters { - gitParameter( - name: 'RELEASE_TAG', - type: 'PT_TAG', - tagFilter: 'v*', - branchFilter: 'origin/(.*)', - sortMode: 'DESCENDING_SMART', - selectedValue: 'TOP', - useRepository: 'http://127.0.0.1:3001/my-project/role-admin.git', - quickFilterEnabled: false, - listSize: '10', - requiredParameter: true, - description: '请选择要部署到生产环境的 Git Tag。列表自动来自当前项目仓库,生产只能从 Tag 发布。' - ) - } - - environment { - CI = 'true' - } - - options { - timestamps() - disableConcurrentBuilds() - buildDiscarder(logRotator(numToKeepStr: '10')) - } - - stages { - stage('Checkout Tag') { - steps { - checkout([ - $class: 'GitSCM', - branches: [[name: '*/master']], - userRemoteConfigs: [[ - url: 'http://127.0.0.1:3001/my-project/role-admin.git' - ]] - ]) - sh ''' - set -eu - test -n "$RELEASE_TAG" - NORMALIZED_RELEASE_TAG="$(printf '%s' "$RELEASE_TAG" | sed 's/\\^{}$//')" - case "$NORMALIZED_RELEASE_TAG" in - v[0-9A-Za-z._-]*) ;; - *) echo "Invalid release tag: $NORMALIZED_RELEASE_TAG"; exit 2 ;; - esac - if ! git ls-remote --exit-code --tags origin "refs/tags/$NORMALIZED_RELEASE_TAG" >/dev/null; then - echo "Release tag does not exist in repository: $NORMALIZED_RELEASE_TAG" - exit 3 - fi - echo "Deploying production tag: $NORMALIZED_RELEASE_TAG" - git fetch --tags --force - git checkout -f "refs/tags/$NORMALIZED_RELEASE_TAG" - git describe --tags --exact-match HEAD - ''' - } - } - - stage('Env') { - steps { - sh ''' - git --version - node -v - corepack --version - corepack enable - corepack prepare pnpm@11.5.0 --activate - pnpm -v - ''' - } - } - - stage('Install') { - steps { - sh ''' - pnpm install --frozen-lockfile - ''' - } - } - - stage('Check') { - steps { - sh ''' - pnpm typecheck - ''' - } - } - - stage('Build') { - steps { - sh ''' - pnpm build:prod - test -f dist/index.html - ''' - } - } - - stage('Deploy Production') { - steps { - sh 'sudo /usr/local/bin/deploy-role-admin-from-jenkins "$WORKSPACE"' - } - } - } -} diff --git a/README.md b/README.md index 2619986..9e0f702 100644 --- a/README.md +++ b/README.md @@ -52,11 +52,7 @@ http://localhost:8848/ ├── .vscode/ # VS Code 推荐配置与 Vue 代码片段 ├── build/ # Vite 插件、CDN、压缩、构建信息与工具函数 ├── docs/ # 项目需求和后台扩展说明 -│ ├── C_APP_ADMIN_REQUIREMENTS.md # C 端正式版管理后台需求文档 -│ └── ENVIRONMENT_DEPLOYMENT.md # 测试/生产环境拆分与 Jenkins 规则 -├── deploy/ # Jenkins 部署脚本 -│ └── jenkins/ -│ └── deploy-static.sh # 静态产物部署脚本 +│ └── C_APP_ADMIN_REQUIREMENTS.md # C 端正式版管理后台需求文档 ├── public/ # 静态资源与运行时平台配置 ├── src/ # 前端源码 │ ├── api/ # HTTP API 封装,业务接口集中在 access.ts @@ -74,7 +70,6 @@ http://localhost:8848/ ├── types/ # 全局类型声明、组件声明、路由声明和 Vue shim ├── AGENTS.md # Codex/Agent 入口规则,转到 RTK.md ├── RTK.md # 本仓库协作规则与 README 同步要求 -├── Jenkinsfile # Jenkins 测试自动部署、生产手动 Tag 部署规则 ├── Dockerfile # 容器构建入口 ├── package.json # 依赖、脚本、engines 与 pnpm preinstall 限制 ├── pnpm-lock.yaml # pnpm 锁文件 @@ -91,15 +86,15 @@ http://localhost:8848/ | `pnpm dev` | 启动 Vite 开发服务,默认端口来自 `.env.development` 的 `VITE_PORT=8848` | 本地开发 | | `pnpm serve` | `pnpm dev` 的别名 | 兼容习惯命令 | | `pnpm build` | 清理 `dist` 后执行生产构建,内存上限设为 8192MB | 发布前打包 | -| `pnpm build:test` | 使用 `test` mode 构建测试环境静态产物 | Jenkins 测试部署 | -| `pnpm build:prod` | `pnpm build` 的生产构建别名 | Jenkins 生产部署 | +| `pnpm build:test` | 使用 `test` mode 构建测试环境静态产物 | 测试环境构建 | +| `pnpm build:prod` | `pnpm build` 的生产构建别名 | 生产环境构建 | | `pnpm build:staging` | 使用 `staging` mode 构建 | 预发布环境验证 | | `pnpm report` | 构建并打开 Rollup 可视化分析报告 | 分析包体积 | | `pnpm preview` | 预览已有 `dist` 构建产物 | 构建后本地验收 | | `pnpm preview:build` | 先构建再预览 | 一步完成打包验收 | | `pnpm typecheck` | 执行 `tsc --noEmit` 和 `vue-tsc --noEmit --skipLibCheck` | 类型检查 | | `pnpm lint` | 依次执行 ESLint、Prettier、Stylelint 自动修复 | 提交前整理代码 | -| `pnpm lint:eslint` | 对 `src`、`build` 下 JS/TS/Vue 做 ESLint 修复 | 脚本或逻辑代码调整后 | +| `pnpm lint:eslint` | 对 `src`、`build` 下 JS/TS/Vue 做 ESLint 修复 | 脚本或逻辑代码调整后 | | `pnpm lint:prettier` | 格式化 `src` 下常见源码与文档格式 | 样式统一 | | `pnpm lint:stylelint` | 修复 HTML/Vue/CSS/SCSS 样式规则 | 样式文件调整后 | | `pnpm svgo` | 递归压缩 SVG | SVG 资源变更后 | @@ -184,19 +179,14 @@ http://localhost:8848/ - `.env`: 全局默认配置,目前包含端口和是否隐藏首页。 - `.env.development`: 开发环境端口、路由模式、API 代理目标。 -- `.env.test`: 测试环境构建配置,Jenkins 测试部署使用;线上测试站点的 `/api` 应由 Nginx 代理到测试后端。 +- `.env.test`: 测试环境构建配置;线上测试站点的 `/api` 应由 Nginx 代理到测试后端。 - `.env.staging`: 预发布构建配置,可开启 CDN。 - `.env.production`: 生产构建配置。 - `public/platform-config.json`: pure-admin 运行时平台配置,例如标题、布局、主题、标签页和菜单搜索历史。 -## Jenkins 环境规则 +## 环境构建约定 -流水线规则见 [docs/ENVIRONMENT_DEPLOYMENT.md](./docs/ENVIRONMENT_DEPLOYMENT.md)。 - -- 测试环境:`develop` 合并后自动触发,执行 `pnpm build:test`,部署到 `/srv/www/test/role-admin/current`。 -- 生产环境:禁止代码合并自动触发,只能在 Jenkins 手动选择 `DEPLOY_ENV=production` 并填写 Gitea 项目 Tag。 -- 生产部署会先 checkout 到 `RELEASE_TAG` 对应的提交,再执行 `pnpm build:prod` 和部署。 -- 测试、生产站点的 `/api` 必须分别代理到测试、生产 `access-manage`,避免环境串线。 +仓库只维护项目自身的构建脚本和环境变量文件,不维护流水线文件。测试、生产的触发规则和部署路径由外部 CI/CD 平台配置;测试、生产站点的 `/api` 必须分别代理到对应的 `access-manage`,避免环境串线。 ## 协作与文档同步 diff --git a/deploy/jenkins/deploy-static.sh b/deploy/jenkins/deploy-static.sh deleted file mode 100644 index 1bc3447..0000000 --- a/deploy/jenkins/deploy-static.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -deploy_env="${1:?Usage: deploy-static.sh test|production [artifact_dir]}" -artifact_dir="${2:-dist}" - -case "${deploy_env}" in - test|production) - ;; - *) - echo "Unknown deploy environment: ${deploy_env}" >&2 - exit 1 - ;; -esac - -if [[ ! -d "${artifact_dir}" ]]; then - echo "Artifact directory not found: ${artifact_dir}" >&2 - exit 1 -fi - -project_name="${PROJECT_NAME:-role-admin}" -base_dir="${DEPLOY_BASE_DIR:-/srv/www}" -target_dir="${DEPLOY_TARGET_DIR:-${base_dir}/${deploy_env}/${project_name}}" -deploy_remote="${DEPLOY_REMOTE:-}" -release_id="${BUILD_NUMBER:-manual}-$(git rev-parse --short=12 HEAD 2>/dev/null || date +%Y%m%d%H%M%S)" - -remote_shell() { - if [[ -n "${deploy_remote}" ]]; then - ssh "${deploy_remote}" "$@" - else - bash -lc "$*" - fi -} - -remote_copy() { - local source_dir="$1" - local dest_dir="$2" - - if [[ -n "${deploy_remote}" ]]; then - rsync -az --delete "${source_dir}/" "${deploy_remote}:${dest_dir}/" - else - mkdir -p "${dest_dir}" - rsync -az --delete "${source_dir}/" "${dest_dir}/" - fi -} - -release_dir="${target_dir}/releases/${release_id}" - -remote_shell "mkdir -p '${release_dir}' '${target_dir}/logs'" -remote_copy "${artifact_dir}" "${release_dir}" -remote_shell "ln -sfn '${release_dir}' '${target_dir}/current'" - -if [[ -n "${DEPLOY_POST_DEPLOY_CMD:-}" ]]; then - remote_shell "cd '${target_dir}/current' && ${DEPLOY_POST_DEPLOY_CMD}" -else - echo "Deployed ${project_name} ${deploy_env} to ${target_dir}/current" -fi diff --git a/docs/ENVIRONMENT_DEPLOYMENT.md b/docs/ENVIRONMENT_DEPLOYMENT.md deleted file mode 100644 index 6c706f2..0000000 --- a/docs/ENVIRONMENT_DEPLOYMENT.md +++ /dev/null @@ -1,81 +0,0 @@ -# 环境拆分与流水线规则 - -`role-admin` 是静态前端项目。测试环境和生产环境通过独立构建模式、独立部署目录和独立 Nginx `/api` 代理拆分。 - -## 环境约定 - -| 环境 | 触发方式 | 代码依据 | 构建命令 | 默认部署目录 | -| --- | --- | --- | --- | --- | -| 测试环境 | `develop` 合并后自动触发 Jenkins | `develop` 最新提交 | `pnpm build:test` | `/srv/www/test/role-admin/current` | -| 生产环境 | Jenkins 手动触发 | Gitea 项目 Tag | `pnpm build:prod` | `/srv/www/production/role-admin/current` | - -生产环境禁止因代码合并自动部署。生产部署时必须在 Jenkins 参数中选择 `DEPLOY_ENV=production` 并填写已存在的 `RELEASE_TAG`。 - -## Jenkins 参数 - -| 参数 | 说明 | -| --- | --- | -| `DEPLOY_ENV` | `test` 或 `production`。默认 `test`。 | -| `RELEASE_TAG` | 生产环境必填,必须是 Gitea 仓库中已存在的 Tag。 | -| `SKIP_DEPLOY` | 为 `true` 时只执行安装、检查、构建,不部署。 | - -`Jenkinsfile` 会强制校验: - -- 测试环境只在 `develop` 分支自动部署。 -- 生产环境必须手动触发。 -- 生产环境必须填写 `RELEASE_TAG`。 -- 生产环境构建会先 checkout 到该 Tag 对应的提交,再部署。 - -## Nginx 拆分要求 - -静态资源部署目录默认如下: - -```text -/srv/www/test/role-admin/current -/srv/www/production/role-admin/current -``` - -两套站点的 `/api` 必须分别代理到对应后端: - -```text -测试 role-admin /api -> 测试 access-manage -生产 role-admin /api -> 生产 access-manage -``` - -不要让测试前端代理到生产后端,也不要让生产前端代理到测试后端。 - -## 生产发布流程 - -1. 在需要发布的提交上创建 Tag。 -2. 推送 Tag 到 Gitea。 -3. Jenkins 手动 Build With Parameters。 -4. 选择 `DEPLOY_ENV=production`。 -5. 填写 `RELEASE_TAG`。 -6. 执行构建部署。 - -示例: - -```bash -git tag -a v2026.06.05-1 -m "role-admin production release 2026-06-05" -git push origin v2026.06.05-1 -``` - -## 部署脚本 - -`deploy/jenkins/deploy-static.sh` 会把 `dist/` 发布到: - -```text -${DEPLOY_BASE_DIR}/${DEPLOY_ENV}/role-admin/releases/- -``` - -并更新: - -```text -${DEPLOY_BASE_DIR}/${DEPLOY_ENV}/role-admin/current -``` - -如果 Jenkins 不在目标服务器上运行,可以配置: - -```text -DEPLOY_REMOTE=user@server -```