269 lines
59 KiB
JavaScript
269 lines
59 KiB
JavaScript
import{_ as i,o as a,c as n,a2 as p}from"./chunks/framework.BbmSSMjL.js";const g=JSON.parse('{"title":"11.11 CI/CD 流水线","description":"","frontmatter":{},"headers":[],"relativePath":"zh/deploy/ci-cd.md","filePath":"zh/deploy/ci-cd.md"}'),l={name:"zh/deploy/ci-cd.md"};function h(k,s,t,e,r,d){return a(),n("div",null,[...s[0]||(s[0]=[p(`<h1 id="_11-11-CI-CD-流水线" tabindex="-1">11.11 CI/CD 流水线 <a class="header-anchor" href="#_11-11-CI-CD-流水线" aria-label="Permalink to "11.11 CI/CD 流水线""></a></h1><div class="tip custom-block"><p class="custom-block-title">概述</p><p>本节介绍项目的持续集成/持续部署(CI/CD)方案,包括 GitHub Actions 和 GitLab CI 的配置示例,以及自动化测试、构建和部署流程。</p></div><div class="info custom-block"><p class="custom-block-title">模板说明</p><p>本项目仓库当前未内置 <code>.github/workflows</code> 或 <code>.gitee/workflows</code>,以下配置为<strong>通用模板</strong>:按实际代码托管平台(GitHub / Gitee / GitLab)调整后放入对应目录即可使用。</p></div><h2 id="流水线架构" tabindex="-1">流水线架构 <a class="header-anchor" href="#流水线架构" aria-label="Permalink to "流水线架构""></a></h2><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>代码提交 → 代码检查 → 单元测试 → 构建打包 → 部署上线</span></span>
|
||
<span class="line"><span> │ │ │ │ │</span></span>
|
||
<span class="line"><span> ▼ ▼ ▼ ▼ ▼</span></span>
|
||
<span class="line"><span> Git Push Pint PHPUnit Docker 生产环境</span></span>
|
||
<span class="line"><span> ESLint (sqlite) Image</span></span></code></pre></div><h2 id="GitHub-Actions" tabindex="-1">GitHub Actions <a class="header-anchor" href="#GitHub-Actions" aria-label="Permalink to "GitHub Actions""></a></h2><h3 id="后端-CI-配置" tabindex="-1">后端 CI 配置 <a class="header-anchor" href="#后端-CI-配置" aria-label="Permalink to "后端 CI 配置""></a></h3><div class="language-yaml vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">yaml</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># .github/workflows/backend-ci.yml — 后端持续集成</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 触发条件:push 到 main/develop 分支,或向 main 发起 PR</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 执行环境:Ubuntu 最新版</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 流程:代码风格检查 → 单元测试 → 覆盖率上传</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 说明:phpunit.xml 已配置 sqlite :memory: 测试库,无需外部数据库服务</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Backend CI</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;">on</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> push</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> branches</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">main</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> develop</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # push 到这些分支时触发</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> pull_request</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> branches</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">main</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 向 main 发起 PR 时触发</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">jobs</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> test</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> runs-on</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ubuntu-latest</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 使用 GitHub 托管的最新 Ubuntu 运行器</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> steps</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 拉取代码(checkout@v4 是 GitHub 官方 Action)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> uses</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> actions/checkout@v4</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装 PHP 8.3 及所需扩展</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Setup PHP</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> uses</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> shivammathur/setup-php@v2</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 第三方 Action,自动安装 PHP</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> with</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> php-version</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">8.3</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # PHP 版本(Laravel 13 要求)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> extensions</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pdo_mysql, mbstring, gd, bcmath, zip, redis</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> coverage</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> xdebug</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 代码覆盖率工具</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装 Composer 依赖(--no-progress 隐藏进度条,--prefer-dist 下载压缩包更快)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Install Dependencies</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> composer install --no-progress --prefer-dist</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 准备运行环境</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Prepare Environment</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> |</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> cp .env.example .env # 复制环境配置模板</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> php artisan key:generate # 生成应用密钥</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 代码风格检查(Laravel Pint,PSR-12 + Laravel 风格)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Code Style Check</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> vendor/bin/pint --test</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 运行单元测试(composer test = config:clear + artisan test,</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # phpunit.xml 使用 sqlite :memory:,不依赖 MySQL)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Run Tests</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> composer test -- --coverage-text</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 上传覆盖率报告到 Codecov(免费的覆盖率追踪平台)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Upload Coverage</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> uses</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> codecov/codecov-action@v3</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> with</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> file</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ./coverage.xml</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 覆盖率报告文件</span></span></code></pre></div><div class="tip custom-block"><p class="custom-block-title">无外部依赖的测试</p><p><code>phpunit.xml</code> 将 <code>DB_CONNECTION</code> 设为 <code>sqlite</code>、<code>DB_DATABASE</code> 设为 <code>:memory:</code>,单元测试在内存库中运行,CI 无需启动 MySQL 容器。如需对真实 MySQL 做集成测试,再参考下文 GitLab CI 的 services 配置。</p></div><h3 id="前端-CI-配置" tabindex="-1">前端 CI 配置 <a class="header-anchor" href="#前端-CI-配置" aria-label="Permalink to "前端 CI 配置""></a></h3><div class="language-yaml vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">yaml</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># .github/workflows/frontend-ci.yml — 前端持续集成</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 触发条件:仅当 ui/ 目录下的文件变更时触发(避免后端改动触发前端 CI)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 流程:Lint → 类型检查 → 构建</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Frontend CI</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;">on</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> push</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> branches</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">main</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">,</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> develop</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> paths</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ui/**</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 仅 ui/ 目录变更时触发</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> pull_request</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> branches</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">main</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> paths</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">ui/**</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">jobs</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> test</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> runs-on</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ubuntu-latest</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> steps</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> uses</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> actions/checkout@v4</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装 Node.js 22 并配置 pnpm 缓存</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Setup Node.js</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> uses</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> actions/setup-node@v4</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> with</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> node-version</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">22</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # Node.js 版本(22 LTS;根目录 Vite 7 要求 20.19+/22.12+)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> cache</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">pnpm</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 启用 pnpm 缓存(加速依赖安装)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> cache-dependency-path</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ui/pnpm-lock.yaml</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 缓存依赖的 lockfile 路径</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 全局安装 pnpm 包管理器</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Install pnpm</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> npm install -g pnpm</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装前端依赖(--frozen-lockfile 确保版本与 lockfile 一致)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Install Dependencies</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> working-directory</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ui</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 在 ui/ 目录下执行</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pnpm install --frozen-lockfile</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # ESLint 代码风格检查(脚本自带 --fix,会自动修复可修复问题)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Lint</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> working-directory</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ui</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pnpm lint:eslint</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # TypeScript 类型检查(发现类型错误)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Type Check</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> working-directory</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ui</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pnpm type:check</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 生产环境构建(验证构建是否成功)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Build</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> working-directory</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ui</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pnpm build</span></span></code></pre></div><div class="info custom-block"><p class="custom-block-title">前端暂无单元测试脚本</p><p><code>ui/package.json</code> 未提供 <code>test</code> 脚本(如后续引入 Vitest,再补 <code>pnpm test</code> 步骤)。</p></div><h3 id="自动部署配置" tabindex="-1">自动部署配置 <a class="header-anchor" href="#自动部署配置" aria-label="Permalink to "自动部署配置""></a></h3><div class="language-yaml vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">yaml</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># .github/workflows/deploy.yml — 自动部署</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 触发条件:push 到 main 分支,或打 v* 标签</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 流程:构建 Docker 镜像 → 推送到镜像仓库 → SSH 部署到服务器</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Deploy</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#1E754F;">on</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> push</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> branches</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">main</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> tags</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;"> '</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">v*</span><span style="--shiki-dark:#DEE492;--shiki-light:#B5695977;">'</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 匹配 v1.0.0、v2.1.3 等标签</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">jobs</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> deploy</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> runs-on</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ubuntu-latest</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> needs</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;"> [</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;">test</span><span style="--shiki-dark:#F6F6F4;--shiki-light:#999999;">]</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 依赖 test job 通过后才执行</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> if</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> github.ref == 'refs/heads/main'</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 仅 main 分支触发部署</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> steps</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> uses</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> actions/checkout@v4</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 构建 Docker 镜像(用 git commit SHA 作为版本标签)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 项目自带 Dockerfile 与 docker-compose.yml(含 docker/.env.docker)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Build Docker Image</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> |</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker build -t myapp:\${{ github.sha }} . # 用 commit SHA 标记</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker tag myapp:\${{ github.sha }} myapp:latest # 同时打 latest 标签</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 推送镜像到 Docker Hub(secrets 在 GitHub 仓库设置中配置)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Push to Registry</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> |</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> echo \${{ secrets.DOCKER_PASSWORD }} | docker login -u \${{ secrets.DOCKER_USERNAME }} --password-stdin</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker push myapp:\${{ github.sha }} # 推送版本标签</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker push myapp:latest # 推送 latest 标签</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 通过 SSH 连接服务器执行部署命令</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Deploy to Server</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> uses</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> appleboy/ssh-action@v1</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 第三方 SSH Action</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> with</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> host</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> \${{ secrets.SERVER_HOST }}</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 服务器地址</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> username</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> \${{ secrets.SERVER_USER }}</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # SSH 用户名</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> key</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> \${{ secrets.SSH_KEY }}</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # SSH 私钥</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> script</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> |</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> cd /opt/myapp # 进入项目目录</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker compose --env-file docker/.env.docker pull # 拉取最新镜像</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker compose --env-file docker/.env.docker up -d --build</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> # 数据库结构变更:手动执行 document/mysql 下的 SQL 脚本(本项目无 migration)</span></span></code></pre></div><h2 id="GitLab-CI" tabindex="-1">GitLab CI <a class="header-anchor" href="#GitLab-CI" aria-label="Permalink to "GitLab CI""></a></h2><div class="language-yaml vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">yaml</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># .gitlab-ci.yml — GitLab CI/CD 配置</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 阶段:test → build → deploy</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 缓存:vendor/ 和 node_modules/ 按分支缓存,加速后续构建</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># =============================================================================</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">stages</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> test</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 测试阶段</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> build</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 构建阶段</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> deploy</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 部署阶段</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 全局变量(所有 job 共享)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">variables</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> MYSQL_ROOT_PASSWORD</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> root</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 测试数据库密码(集成测试用)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> MYSQL_DATABASE</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> test_db</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 测试数据库名</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 后端测试</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">backend:test</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> stage</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> test</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> image</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> php:8.3-cli</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # PHP 8.3 CLI 镜像</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> services</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> mysql:8.0</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # MySQL 服务容器(集成测试用;单元测试走 sqlite 内存库)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> script</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装系统依赖(PHP 扩展编译需要)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> apt-get update && apt-get install -y libpq-dev libzip-dev</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装 PHP 扩展</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker-php-ext-install pdo_mysql zip</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pecl install redis && docker-php-ext-enable redis</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装 Composer 依赖</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> composer install --no-progress</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 准备环境并执行测试</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> cp .env.example .env</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> php artisan key:generate</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> vendor/bin/pint --test</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 代码风格检查</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> composer test</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 运行测试(phpunit.xml 用 sqlite :memory:)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> cache</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> key</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> \${CI_COMMIT_REF_SLUG}</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 按分支名缓存</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> paths</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> vendor/</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 缓存 Composer 依赖</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 前端测试</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">frontend:test</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> stage</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> test</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> image</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> node:22</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # Node.js 22 镜像</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> script</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> cd ui</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> npm install -g pnpm</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 全局安装 pnpm</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pnpm install --frozen-lockfile</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 安装依赖</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pnpm lint:eslint</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 代码风格检查</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pnpm type:check</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # TypeScript 类型检查</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> pnpm build</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 生产构建</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> cache</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> key</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> \${CI_COMMIT_REF_SLUG}</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> paths</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ui/node_modules/</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 缓存前端依赖</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># 生产部署(仅 main 分支)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># -----------------------------------------------------------------------------</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;">deploy:production</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> stage</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> deploy</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> only</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> main</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 仅 main 分支触发</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> script</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker build -t myapp:$CI_COMMIT_SHA .</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 构建镜像</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> docker push myapp:$CI_COMMIT_SHA</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 推送到仓库</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # SSH 到服务器执行部署</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;"> -</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> ssh $SERVER_USER@$SERVER_HOST "cd /opt/myapp && docker compose --env-file docker/.env.docker up -d --build"</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> environment</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> production</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> url</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> https://api.example.com</span></span></code></pre></div><h2 id="部署策略" tabindex="-1">部署策略 <a class="header-anchor" href="#部署策略" aria-label="Permalink to "部署策略""></a></h2><h3 id="蓝绿部署" tabindex="-1">蓝绿部署 <a class="header-anchor" href="#蓝绿部署" aria-label="Permalink to "蓝绿部署""></a></h3><div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span>当前版本(蓝) → 新版本(绿)</span></span>
|
||
<span class="line"><span> │ │</span></span>
|
||
<span class="line"><span> ▼ ▼</span></span>
|
||
<span class="line"><span> Nginx 切换流量 ← 验证通过</span></span></code></pre></div><h3 id="滚动更新" tabindex="-1">滚动更新 <a class="header-anchor" href="#滚动更新" aria-label="Permalink to "滚动更新""></a></h3><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># Docker Swarm 滚动更新</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># --update-parallelism 1 → 每次只更新 1 个容器实例</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># --update-delay 30s → 每批更新间隔 30 秒(观察健康状态)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># --image myapp:v2.0 → 新版本镜像</span></span>
|
||
<span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># myapp_web → 服务名称</span></span>
|
||
<span class="line"><span style="--shiki-dark:#62E884;--shiki-light:#59873A;">docker</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> service</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> update</span><span style="--shiki-dark:#F286C4;--shiki-light:#A65E2B;"> \\</span></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> --update-parallelism</span><span style="--shiki-dark:#BF9EEE;--shiki-light:#2F798A;"> 1</span><span style="--shiki-dark:#F286C4;--shiki-light:#A65E2B;"> \\</span></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> --update-delay</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> 30s</span><span style="--shiki-dark:#F286C4;--shiki-light:#A65E2B;"> \\</span></span>
|
||
<span class="line"><span style="--shiki-dark:#BF9EEE;--shiki-light:#A65E2B;"> --image</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> myapp:v2.0</span><span style="--shiki-dark:#F286C4;--shiki-light:#A65E2B;"> \\</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> myapp_web</span></span></code></pre></div><h2 id="通知集成" tabindex="-1">通知集成 <a class="header-anchor" href="#通知集成" aria-label="Permalink to "通知集成""></a></h2><h3 id="部署通知-钉钉-飞书-" tabindex="-1">部署通知(钉钉/飞书) <a class="header-anchor" href="#部署通知-钉钉-飞书-" aria-label="Permalink to "部署通知(钉钉/飞书)""></a></h3><div class="language-yaml vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">yaml</span><pre class="shiki shiki-themes dracula-soft vitesse-light vp-code" tabindex="0"><code><span class="line"><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"># GitHub Actions 部署成功通知(发送到钉钉机器人)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">-</span><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> name</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> Notify on Success</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> if</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> success()</span><span style="--shiki-dark:#7B7F8B;--shiki-light:#A0ADA0;"> # 仅在部署成功时执行</span></span>
|
||
<span class="line"><span style="--shiki-dark:#97E1F1;--shiki-light:#998418;"> run</span><span style="--shiki-dark:#F286C4;--shiki-light:#999999;">:</span><span style="--shiki-dark:#F286C4;--shiki-light:#1E754F;"> |</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> # curl 发送 POST 请求到钉钉 Webhook</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> # -H → 设置请求头为 JSON 格式</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> # -d → 发送 JSON 消息体(Markdown 格式)</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> curl -X POST "\${{ secrets.DINGTALK_WEBHOOK }}" \\</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> -H 'Content-Type: application/json' \\</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> -d '{</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> "msgtype": "markdown",</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> "markdown": {</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> "title": "部署成功",</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> "text": "## ✅ 部署成功\\n- **项目**: myapp\\n- **分支**: \${{ github.ref_name }}\\n- **提交**: \${{ github.sha }}\\n- **时间**: $(date)"</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> }</span></span>
|
||
<span class="line"><span style="--shiki-dark:#E7EE98;--shiki-light:#B56959;"> }'</span></span></code></pre></div><h2 id="相关文档" tabindex="-1">相关文档 <a class="header-anchor" href="#相关文档" aria-label="Permalink to "相关文档""></a></h2><ul><li><a href="/zh/deploy/docker.html">Docker 生产部署</a></li><li><a href="/zh/deploy/backend.html">后端部署</a></li><li><a href="/zh/deploy/frontend.html">前端部署</a></li></ul>`,26)])])}const c=i(l,[["render",h]]);export{g as __pageData,c as default};
|