agentleFS
nieyuanqingnieyuanqing/software-engineering-skills/.claude/skills/new-deploy/SKILL.md

new-deploy

Skill4 starsChanged 25 days agoApache-2.0View on GitHub

为 Java/Spring Boot 工程生成 scripts/deploy.sh 和 scripts/apply-ssl.sh。deploy.sh 支持本地/远程部署(--remote)、三套环境(dev/test/prod)、backend/web/ssl/android/db 目标、inline supervisord 配置、nginx 自动同步、numbered phase 日志、[STATUS] 机器可读输出。当用户要求"生成部署脚本"、"更新 deploy.sh"、"初始化 deploy"时触发。支持 /new-deploy -h 查看帮助。

  • Reads credentials

The file

Files
SKILL.md

new-deploy

为工程生成标准化的 scripts/deploy.sh 和 scripts/apply-ssl.sh。

触发条件:用户要求为某工程创建或更新部署脚本(deploy.sh),或单独需要部署脚本而不需要完整的 /new-java-project 配置套件。


零、参数处理

如果用户传入 -h 或 --help,不执行任何文件操作,直接把下面的帮助信息原样输出在本次回复正文里后结束(斜杠命令把 SKILL.md 注入我的上下文不等于已展示给用户,正文里只回一句"已输出"就是没输出)。-h 与其它参数或说明文字同时出现时,一律只出帮助、忽略其余参数:本轮不猜附加要求,需要同时执行就把 -h 去掉分两次调用:


用法: /new-deploy [SERVICE_NAME] [选项]

  SERVICE_NAME    可选位置参数,直接指定服务名。
                  不传时提示采用当前目录名称作为默认值。

选项(通过命令行传入的参数直接使用,不再交互询问)
  --app-port=N            Spring Boot 内部端口(如 --app-port=50001)
  --nginx-port=N          nginx 对外监听端口(如 --nginx-port=50000)
  --test-domain=DOMAIN    test 环境域名(如 --test-domain=svc.test.example.com)
  --prod-domain=DOMAIN    prod 环境域名(如 --prod-domain=svc.example.com)
  --has-web=true|false    是否有前端静态资源,影响 deploy.sh 默认 target(默认 false)
  --has-android=true|false  是否有 Android 工程(src/android/),影响 usage 说明(默认 false)
  -h, --help              显示本帮助(出现即忽略其它参数,只出帮助)

生成文件
  scripts/deploy.sh       部署脚本(Maven 构建、supervisord 管理、健康检查、远程部署、nginx 同步)
  scripts/apply-ssl.sh    SSL 证书申请脚本(Let's Encrypt + acme.sh),deploy.sh 初始化目录时一并上传

deploy.sh 主要能力
  目标: -t/--target all|backend|web|ssl|android|db(默认 all;--has-web=false 时默认 backend)
        支持逗号分隔多值(如 -t backend,web),按书写顺序叠加
  服务: -s/--services NAME[,NAME...] 从脚本顶部 SERVICES 表里选中本次要部署的服务(可逗号多值),
        每个服务对应 src/backend/<name>,独立服务目录/日志/supervisor 进程/数据库;
        只给 -s 不给 -t 时视为只部后端(不部 Web)。新增服务在脚本顶部四张表各追加一条
  环境: -e/--env dev|test|prod(默认 dev)
  远程: -r/--remote USER@HOST(本地 Maven 构建,rsync 上传 JAR,SSH 远程重启)
  ssl:  --target ssl --env test|prod 安装 nginx(apt)+ 主配置 + 站点配置
  db:   --target db --remote 或 --db(叠加):pg_dump 本地 dev 库 → rsync → 远程 drop+create+restore
        (破坏性,默认需输入 yes,-y 跳过);源库凭据取第一个选中服务的 src/backend/<服务>/.env
        (DB_HOST/DB_PORT/DB_USERNAME/DB_PASSWORD),同步范围 = 选中服务在 SERVICE_DBS 表里的库
  健康检查: http://127.0.0.1:<服务端口>/api/<服务名>/health,每 5s 一轮、最长等待 420s
        (SERVICE_READY_TIMEOUT 可覆盖);startsecs=10 只防立即崩溃,就绪与否由健康检查判定
  JAR 版本化: 落盘 <服务>-<版本>.jar + 稳定软链 <服务>.jar,各服务版本按自己 pom 读取,
        回滚只需把软链指回旧版本;JAR 定位兼容 <服务>/target 与多模块 <服务>/*/target
  多前端: WEB_APPS + WEB_APP_SOURCE/DEPLOY/BASE_PATH/PROJECT_ID 四张表,构建时用 NEXT_BASE_PATH
        传路由前缀(须与 nginx location 一致),并按 --env 覆盖 runtime-config.<env>.js
  supervisord 配置: 部署时 inline 生成,不依赖静态 ini 文件;文件后缀现问目标主机
        [include] files= 模式决定(.conf 或 .ini),可用 SUPERVISOR_CONF_SUFFIX 强制指定
  env 文件: 按环境选择 .env / .env.test / .env.prod(来自 src/backend/<SERVICE_NAME>/),
        部署前比对 .env 与目标环境文件的键集,缺键打警告(缺键=该环境静默缺配置)
  路径可覆盖: APP_ROOT / LOG_ROOT / SUPERVISOR_CONF / SUPERVISOR_CONF_DIR /
        SUPERVISOR_CONF_SUFFIX / NGINX_CONF_DIR / NGINX_SSL_DIR /
        WEB_DEPLOY_PATH / PUBLIC_IP(默认值见脚本顶部)
  构建日志: mvn/gradle/npm 过程日志不在终端显示,落盘 ./runtime/deploy-*-<时间戳>.log(失败时打印末尾 120 行)
  日志标签: 涉及具体服务/库/主机的日志一律点名("上传 JAR: pay → root@host:..."),多服务部署时可区分是谁
  日志格式: [YYYY-MM-DD HH:MM:SS] [deploy.sh] ... + Phase N/M 阶段编号
  状态输出: [STATUS] OK / [STATUS] ERROR 机器可读行

示例
  /new-deploy
      交互式,以当前目录名为默认服务名

  /new-deploy my-service --app-port=8080 --nginx-port=9090
      指定服务名和端口,其余交互询问

  /new-deploy my-service --app-port=8080 --nginx-port=9090 \
      --test-domain=svc.test.example.com --prod-domain=svc.example.com
      全参数命令行指定,直接生成

  /new-deploy -h
      显示本帮助

一、收集参数

1.0 检测现有脚本(Update 流程)

在执行任何参数收集之前,先检查目标工程根目录是否已存在 scripts/deploy.sh。

存在时:自动提取参数,进入 Update 流程

从现有文件中提取以下参数(精确 grep,无歧义):

参数提取方式
SERVICE_NAMEgrep '^BACKEND_DIR=' scripts/deploy.sh → 取路径最后一段
APP_PORTgrep '^APP_PORT=' scripts/deploy.sh → 取 = 右侧数值
NGINX_PORTgrep '^NGINX_PORT=' scripts/deploy.sh → 取 = 右侧数值
TEST_DOMAINgrep 'test) echo' scripts/deploy.sh → 取引号内域名
PROD_DOMAINgrep 'prod) echo' scripts/deploy.sh → 取引号内域名
HAS_WEBgrep 'DEPLOY_WEB=false' scripts/deploy.sh 出现在 parse_deploy_args 初始化处则为 false,否则为 true
HAS_ANDROID检查 usage() 中是否含 --target android 说明

提取后向用户一次性展示所有参数,格式:

检测到现有 scripts/deploy.sh,已自动提取当前参数:

  SERVICE_NAME : my-service
  APP_PORT     : 50001
  NGINX_PORT   : 50000
  TEST_DOMAIN  : svc.test.example.com
  PROD_DOMAIN  : svc.example.com
  HAS_WEB      : false
  HAS_ANDROID  : false

直接回车使用以上参数更新,或输入需修改的参数(如 HAS_ANDROID=true):
  • 用户直接回车 → 使用提取到的参数,跳过 1.2、1.3 节
  • 用户输入修改项 → 更新对应参数,其余保持提取值

然后:

  1. 用确认后的参数渲染模板,生成新版本到临时文件
  2. 展示差异(diff -u scripts/deploy.sh <新版本>,重点标出新增/删除的 target、函数)
  3. 询问:是否用新版本覆盖?(y/N)
  4. 用户确认后覆盖,并执行 chmod +x

不存在时:正常进入 1.1 → 1.2 → 1.3 收集流程


1.1 解析命令行参数

命令行写法对应参数
第一个非 --/- 开头的词SERVICE_NAME
--app-port=NAPP_PORT
--nginx-port=NNGINX_PORT
--test-domain=DOMAINTEST_DOMAIN
--prod-domain=DOMAINPROD_DOMAIN
--has-web=true|falseHAS_WEB(默认 false)
--has-android=true|falseHAS_ANDROID(默认 false)

1.2 SERVICE_NAME 确定(优先级从高到低)

  1. 命令行位置参数:直接使用,不再询问。
  2. 无位置参数:读取当前工作目录名,转为小写、空格替换为连字符,作为建议默认值,提示:

    SERVICE_NAME 未指定,建议使用当前目录名 "<目录名>" 作为服务名,直接回车确认或输入新名称:

1.3 交互询问缺失参数

SERVICE_NAME 确定后,将所有未通过命令行提供的必填参数一次性列出,统一询问:

参数说明默认值
APP_PORTSpring Boot 内部端口(只绑 127.0.0.1)无
NGINX_PORTnginx 对外监听端口无
TEST_DOMAINtest 环境域名无
PROD_DOMAINprod 环境域名无
HAS_WEB是否有前端静态资源(true/false)false
HAS_ANDROID是否有 Android 工程(true/false)false

所有参数确定后,向用户回显完整参数列表,确认无误后再生成文件。


二、生成文件清单

以下文件全部在目标工程根目录下生成:

scripts/deploy.sh
scripts/apply-ssl.sh

三、生成规则

模板来源

以下路径均相对于本 skill 目录(安装后通常为 ~/.qoder/skills/new-deploy/),模板随 skill 一起分发,不依赖任何仓库克隆或本地工程。

目标文件模板来源
scripts/deploy.shtemplates/scripts/deploy.sh
scripts/apply-ssl.shtemplates/scripts/apply-ssl.sh

占位符替换表

占位符替换为
<SERVICE_NAME>SERVICE_NAME 参数值
<APP_PORT>APP_PORT 参数值
<NGINX_PORT>NGINX_PORT 参数值
<TEST_DOMAIN>TEST_DOMAIN 参数值
<PROD_DOMAIN>PROD_DOMAIN 参数值

HAS_WEB=false 时的处理

在生成的 deploy.sh 中,将 parse_deploy_args() 里 DEPLOY_WEB 的初始值从 true 改为 false,并在 usage() 的目标说明处注明"本服务无前端,--target web 和 --target all 不适用"。

HAS_ANDROID=true 时的处理

在生成的 deploy.sh 的 usage() 中,在 android 目标说明处补充该工程的 Android 目录路径(src/android/)说明;其余逻辑无需修改(android target 默认关闭,按需通过 --target android 触发)。


四、生成后处理

chmod +x scripts/deploy.sh scripts/apply-ssl.sh

五、完成提示

生成完成后,向用户输出以下内容:

  1. 已生成文件列表(逐行列出路径)
  2. 下一步操作(用实际参数值填入,不要复制粘贴占位符):
## 下一步操作

### 首次部署(dev 环境,本机)

1. 确认 supervisord daemon 正在运行,且端口 <NGINX_PORT>/<APP_PORT> 空闲:
   supervisorctl status
   ss -tln | grep -E ':(<NGINX_PORT>|<APP_PORT>)\b'

2. 配置 dev 环境变量(deploy.sh 从 src/backend/<SERVICE_NAME>/.env 读取):
   vim src/backend/<SERVICE_NAME>/.env      # 三份 env 由 /new-java-project 生成,此处填真值
   # 只要本 skill 单独使用(不跑 /new-java-project),需自备该文件,键集与 .env.test/.env.prod 对齐

3. 执行部署:
   bash scripts/deploy.sh

### 首次部署(远程服务器)

   bash scripts/deploy.sh --remote root@<HOST>

### test / prod 环境

   # 先申请证书
   bash scripts/apply-ssl.sh test   # 或 prod
   # 部署(本机或远程)
   bash scripts/deploy.sh --env test --remote root@<HOST>
   bash scripts/deploy.sh --target ssl --env test --remote root@<HOST>

### 数据库同步(仅同步,不部署代码)

   bash scripts/deploy.sh --target db --remote root@<HOST>
   # 跳过确认(CI/自动化场景)
   bash scripts/deploy.sh --target db --remote root@<HOST> --yes

### 数据库 + 后端一起部署

   bash scripts/deploy.sh --target backend --db --env test --remote root@<HOST>

六、注意事项

  • 目标文件已存在时,走 1.0 Update 流程(自动提取参数 → 展示差异 → 确认覆盖),不要静默覆盖,也不要重新询问所有参数。
  • deploy.sh 要求在项目根目录执行(bash scripts/deploy.sh),脚本内部会校验 pwd 是否等于 $PROJECT_DIR。
  • supervisord 配置由 deploy.sh 在部署时 inline 生成到 /etc/supervisor/conf.d/<SERVICE_NAME>.<后缀>,无需在版本库中维护静态文件。后缀现问目标主机 $SUPERVISOR_CONF 的 [include] files= 模式(apt 默认 *.conf,在跑的主机常改成只 *.ini)——写错后缀的文件 supervisord 不加载也不报错,改配置会静默不生效;也可用 SUPERVISOR_CONF_SUFFIX 强制指定。
  • Spring 环境(dev/test/prod)通过 env 文件中的 SPRING_PROFILES_ACTIVE 传递,deploy.sh 不硬编码 --spring.profiles.active。
  • nginx 路径约定:/etc/nginx/conf.d/<SERVICE_NAME>.conf,SSL 证书放在 /etc/nginx/ssl/<DOMAIN>.pem。

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.