Files
devops-skills/site/index.html

420 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Issue-Driven DevOps Agent | Branch-Scoped Delivery Platform</title>
<style>
:root {
--bg-0: #070b18;
--bg-1: #101936;
--bg-2: #13274f;
--line: #30406b;
--text: #ecf3ff;
--text-soft: #b9c7e6;
--brand: #36d1ff;
--brand-2: #56f6c8;
--warn: #ffd86b;
--panel: rgba(16, 25, 54, 0.76);
--panel-strong: rgba(10, 17, 38, 0.82);
--ok: #56f6c8;
--danger: #ff7f8f;
--shadow: 0 20px 60px rgba(3, 8, 26, 0.45);
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
color: var(--text);
font-family: "Space Grotesk", "PingFang SC", "Microsoft YaHei", sans-serif;
background:
radial-gradient(circle at 0% 0%, rgba(54, 209, 255, 0.22), transparent 30%),
radial-gradient(circle at 100% 10%, rgba(86, 246, 200, 0.18), transparent 28%),
linear-gradient(140deg, var(--bg-0) 0%, var(--bg-1) 42%, var(--bg-2) 100%);
line-height: 1.58;
}
.page {
max-width: 1140px;
margin: 0 auto;
padding: 24px 20px 80px;
}
.nav {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
margin-bottom: 20px;
}
.logo {
display: inline-flex;
align-items: center;
gap: 10px;
font-weight: 700;
font-size: 15px;
letter-spacing: 0.2px;
}
.logo-dot {
width: 12px;
height: 12px;
border-radius: 50%;
background: linear-gradient(120deg, var(--brand), var(--brand-2));
box-shadow: 0 0 0 5px rgba(86, 246, 200, 0.18);
}
.nav-links {
display: flex;
gap: 14px;
flex-wrap: wrap;
}
.nav a {
color: var(--text-soft);
text-decoration: none;
border: 1px solid transparent;
padding: 8px 12px;
border-radius: 999px;
}
.nav a:hover {
color: var(--text);
border-color: var(--line);
background: rgba(255, 255, 255, 0.05);
}
.hero {
border: 1px solid var(--line);
background:
linear-gradient(145deg, rgba(86, 246, 200, 0.12), transparent 35%),
linear-gradient(325deg, rgba(54, 209, 255, 0.18), transparent 40%),
var(--panel-strong);
border-radius: 24px;
padding: 34px 28px 28px;
box-shadow: var(--shadow);
position: relative;
overflow: hidden;
}
.hero::after {
content: "";
position: absolute;
right: -60px;
top: -65px;
width: 180px;
height: 180px;
background: radial-gradient(circle, rgba(86, 246, 200, 0.35), transparent 70%);
pointer-events: none;
}
.hero h1 {
margin: 0 0 10px;
font-size: clamp(30px, 4.4vw, 52px);
line-height: 1.05;
letter-spacing: -0.6px;
max-width: 880px;
}
.hero p {
margin: 0;
font-size: clamp(15px, 2.2vw, 19px);
max-width: 880px;
color: var(--text-soft);
}
.hero-cta {
margin-top: 18px;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.btn {
border: 1px solid var(--line);
border-radius: 12px;
padding: 10px 14px;
color: var(--text);
text-decoration: none;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn.primary {
border-color: transparent;
background: linear-gradient(120deg, #2db6ff, #49f2ca);
color: #06253a;
font-weight: 700;
}
.btn:hover { filter: brightness(1.06); }
.stats {
margin-top: 16px;
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 10px;
}
.stat {
border: 1px solid var(--line);
border-radius: 14px;
padding: 12px;
background: rgba(18, 30, 60, 0.58);
}
.stat .v {
font-size: 24px;
font-weight: 700;
letter-spacing: -0.3px;
}
.stat .k {
color: var(--text-soft);
font-size: 12px;
margin-top: 2px;
}
section {
margin-top: 16px;
border: 1px solid var(--line);
border-radius: 18px;
padding: 20px;
background: var(--panel);
box-shadow: var(--shadow);
}
h2 {
margin: 0 0 12px;
font-size: 26px;
line-height: 1.12;
letter-spacing: -0.25px;
}
h3 {
margin: 0 0 8px;
font-size: 18px;
line-height: 1.2;
}
p { margin: 0; color: var(--text-soft); }
.value-grid, .install-grid, .tool-grid {
display: grid;
gap: 12px;
}
.value-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.install-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.tool-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.card {
border: 1px solid #385082;
background: rgba(20, 34, 68, 0.82);
border-radius: 14px;
padding: 14px;
}
.card p { margin-top: 4px; }
.flow {
display: grid;
gap: 10px;
grid-template-columns: repeat(5, minmax(0, 1fr));
}
.step {
border: 1px dashed #4f6796;
border-radius: 12px;
padding: 10px;
background: rgba(20, 34, 68, 0.55);
}
.step strong {
display: inline-block;
margin-bottom: 6px;
color: #dff5ff;
}
.step p { font-size: 13px; }
.install-card code, pre, .tool-card code {
font-family: "Cascadia Code", Consolas, Menlo, monospace;
font-size: 12.8px;
}
pre {
margin: 8px 0 0;
border: 1px solid #415983;
border-radius: 10px;
padding: 10px;
overflow: auto;
background: #081126;
color: #dcf3ff;
white-space: pre-wrap;
word-break: break-all;
}
.copy {
margin-top: 8px;
border: 1px solid #4e6899;
background: rgba(255, 255, 255, 0.03);
color: var(--text);
border-radius: 8px;
padding: 6px 10px;
cursor: pointer;
font-size: 12px;
}
.copy.ok { border-color: #4fcd99; color: var(--ok); }
.list {
margin: 10px 0 0;
padding: 0;
list-style: none;
display: grid;
gap: 8px;
}
.list li {
border: 1px solid #3b4f78;
border-radius: 10px;
padding: 9px 10px;
color: #d2e0f9;
background: rgba(15, 25, 49, 0.7);
}
.tagline {
margin-top: 10px;
color: var(--warn);
font-weight: 600;
}
.footer {
margin-top: 16px;
border: 1px solid var(--line);
border-radius: 14px;
padding: 14px;
background: rgba(6, 11, 25, 0.66);
display: flex;
justify-content: space-between;
gap: 10px;
flex-wrap: wrap;
}
.footer a {
color: var(--brand);
text-decoration: none;
font-weight: 600;
}
.footer a:hover { text-decoration: underline; }
@media (max-width: 1040px) {
.stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.value-grid, .install-grid, .tool-grid { grid-template-columns: 1fr; }
.flow { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<main class="page">
<nav class="nav">
<div class="logo"><span class="logo-dot"></span> Issue-Driven DevOps Agent</div>
<div class="nav-links">
<a href="#install">安装</a>
<a href="#tools">工具</a>
<a href="#workflow">工作流</a>
</div>
</nav>
<header class="hero">
<h1>把 Issue 变成可追踪、可复用、可规模化的交付流水线</h1>
<p>
我们不是“会修 bug 的脚本”,而是一个面向真实研发组织的 DevOps 交付平台:
<strong>Issue → Branch → Preview Slot → 提测闭环</strong>,并且始终保留工程师对最终合并的控制权。
</p>
<div class="hero-cta">
<a class="btn primary" href="https://fun-md.com/Fun_MD/devops-skills" target="_blank" rel="noopener noreferrer">访问仓库</a>
<a class="btn" href="#install">一键安装</a>
<a class="btn" href="../skills/gitea-issue-devops-agent/SKILL.md">查看 Skill 规范</a>
</div>
<div class="stats">
<article class="stat"><div class="v">3</div><div class="k">执行模式(自动/半自动/人工)</div></article>
<article class="stat"><div class="v">5</div><div class="k">部署范围策略skip→full_stack</div></article>
<article class="stat"><div class="v">1:1</div><div class="k">Issue/Branch/Preview Slot 绑定</div></article>
<article class="stat"><div class="v">24h+</div><div class="k">可配置 TTL 自动回收</div></article>
</div>
</header>
<section id="value">
<h2>核心价值</h2>
<div class="value-grid">
<article class="card">
<h3>分支隔离,主干稳定</h3>
<p>每个 issue 分配独立分支和预览槽位,不再发生“提测相互覆盖”,主干环境用于稳定回归。</p>
</article>
<article class="card">
<h3>资源智能节流</h3>
<p>根据代码变更范围自动判定部署策略。仅前端改动时不重启服务端,直接复用共享后端。</p>
</article>
<article class="card">
<h3>证据驱动闭环</h3>
<p>自动沉淀 commit、测试结果、环境链接、验证步骤。Issue 可关闭、可回溯、可审计。</p>
</article>
</div>
<p class="tagline">这是一套用于长期演进的研发基础设施,不是临时脚本集合。</p>
</section>
<section id="workflow">
<h2>工作流拓扑</h2>
<div class="flow">
<div class="step"><strong>1. 引导连接</strong><p>输入 repo_url、api_key、mode完成连通性校验。</p></div>
<div class="step"><strong>2. 质量审计</strong><p>拉取 issue 与图片附件,做质量评分与去重分组。</p></div>
<div class="step"><strong>3. 分支执行</strong><p>严格在 issue 指定分支改动,保留变更可追踪性。</p></div>
<div class="step"><strong>4. 按范围部署</strong><p>change_scope 自动判断 skip/client/server/full_stack。</p></div>
<div class="step"><strong>5. 自动回收</strong><p>槽位 TTL + 关闭释放,减少预览环境资源占用。</p></div>
</div>
<ul class="list">
<li>工作流模板:<code>.gitea/workflows/issue-branch-preview.yml</code></li>
<li>回收模板:<code>.gitea/workflows/preview-slot-reclaim.yml</code></li>
<li>合并策略:所有模式下都要求工程师人工确认最终合并</li>
</ul>
</section>
<section id="install">
<h2>一键安装Windows / macOS / Linux</h2>
<p>以下命令会把技能安装到本机 <code>~/.codex/skills/gitea-issue-devops-agent</code></p>
<div class="install-grid">
<article class="card install-card">
<h3>Linux</h3>
<pre id="cmd-linux">curl -fsSL https://fun-md.com/Fun_MD/devops-skills/raw/branch/main/install/install.sh | bash</pre>
<button class="copy" data-target="cmd-linux">复制命令</button>
</article>
<article class="card install-card">
<h3>macOS</h3>
<pre id="cmd-macos">curl -fsSL https://fun-md.com/Fun_MD/devops-skills/raw/branch/main/install/install.sh | bash</pre>
<button class="copy" data-target="cmd-macos">复制命令</button>
</article>
<article class="card install-card">
<h3>Windows (PowerShell)</h3>
<pre id="cmd-win">powershell -NoProfile -ExecutionPolicy Bypass -Command "iwr -useb https://fun-md.com/Fun_MD/devops-skills/raw/branch/main/install/install.ps1 | iex"</pre>
<button class="copy" data-target="cmd-win">复制命令</button>
</article>
</div>
</section>
<section id="tools">
<h2>核心工具</h2>
<div class="tool-grid">
<article class="card tool-card">
<h3>issue_audit.py</h3>
<p>抓取 issue、评论和图片附件完成质量评分、去重与回归候选识别。</p>
<pre>python skills/gitea-issue-devops-agent/scripts/issue_audit.py --base-url https://fun-md.com --repo FunMD/document-collab --token &lt;TOKEN&gt; --state all --download-attachments --output-dir .tmp/issue-audit</pre>
</article>
<article class="card tool-card">
<h3>change_scope.py</h3>
<p>输出部署范围建议,决定是否需要服务端重启。</p>
<pre>python skills/gitea-issue-devops-agent/scripts/change_scope.py --repo-path . --base-ref origin/main --head-ref HEAD</pre>
</article>
<article class="card tool-card">
<h3>preview_slot_allocator.py</h3>
<p>管理 preview 槽位分配、复用、释放、TTL 回收。</p>
<pre>python skills/gitea-issue-devops-agent/scripts/preview_slot_allocator.py --state-file .tmp/preview-slots.json --slots preview-a,preview-b --repo FunMD/document-collab --issue 48 --branch dev --ttl-hours 24 --url-template https://{slot}.qa.example.com --evict-oldest</pre>
</article>
</div>
</section>
<footer class="footer">
<span>Skill Path: <code>skills/gitea-issue-devops-agent/SKILL.md</code></span>
<span><a href="https://fun-md.com/Fun_MD/devops-skills/raw/branch/main/site/index.html" target="_blank" rel="noopener noreferrer">公网页面链接</a></span>
</footer>
</main>
<script>
const copyButtons = document.querySelectorAll(".copy");
copyButtons.forEach((btn) => {
btn.addEventListener("click", async () => {
const targetId = btn.getAttribute("data-target");
const el = document.getElementById(targetId);
if (!el) return;
try {
await navigator.clipboard.writeText(el.textContent.trim());
btn.classList.add("ok");
btn.textContent = "已复制";
setTimeout(() => {
btn.classList.remove("ok");
btn.textContent = "复制命令";
}, 1400);
} catch (err) {
btn.textContent = "复制失败";
setTimeout(() => {
btn.textContent = "复制命令";
}, 1400);
}
});
});
</script>
</body>
</html>