Name production & external services 神州 (not 线上). Full IA: flywheel vs code vs shenzhou, tab boundaries, data model, phased rollout, read-only iron rules. Cross-link from forgejo observe doc.
102 lines
4.4 KiB
Markdown
102 lines
4.4 KiB
Markdown
# joy web · 代码态势(三平面)
|
||
|
||
> Phase 3 · **态势而非仓库浏览器** · 2026-07-10
|
||
|
||
## 产品定义
|
||
|
||
| 是 | 否 |
|
||
|----|-----|
|
||
| CI 节点健康(runner / zombie TASK) | 自动清容器 / 重启 runner |
|
||
| 本地 Git dirty / ahead / behind | 在 joy 里 commit / push |
|
||
| 待处理 PR、CI 红、未读通知 | 迷你 GitHub 仓列表 |
|
||
| 镜像滞后/过期(供应链) | 1200 仓目录浏览 |
|
||
| 深链回 feicode.com | 替代 devops `fei` CLI |
|
||
|
||
**分工**:feicode/Forgejo = 远程真源 · **本地 Git** = Mac 工作区 · **CI 节点** = devops + feicode-prod runner · **`fei`** = 代码操作 · **joy web 代码 tab** = 工程态势。
|
||
|
||
**与「神州」的边界**:公网站 SLA、生产主机磁盘/nginx、SSL → 见 [`joy-shenzhou.md`](./joy-shenzhou.md)(导航名 **神州**,不是「线上」)。同一台 `feicode-prod` 可两面切开——**runner/zombie 归代码**,站点与主机指标归神州。
|
||
|
||
## 三平面(一屏)
|
||
|
||
| # | 平面 | 数据源 | 看什么 |
|
||
|---|------|--------|--------|
|
||
| ① | CI/CD 节点 | SSH `devops` / `feicode-prod` | system unit / act_runner、zombie 归组(workflow/image)、recent task 镜像负载 |
|
||
| ② | 本地 Git | Mac `~/Projects/linuxjoy` + `joy-cli` | ahead/behind、dirty、linked worktrees |
|
||
| ③ | feicode API | `https://feicode.com/api/v1` | PR 人/机拆分、CI 红 streak/慢性、通知、镜像、自有热更新 |
|
||
|
||
### 深挖结论(2026-07-10)
|
||
|
||
| 信号 | 事实 | 处置边界 |
|
||
|------|------|----------|
|
||
| zombie ×7 | 全是 `Mautic-tests-and-validations` 留下的 mysql/mariadb service 容器,Up 3 weeks | **只观察**;清理由 devops/change |
|
||
| runner 忙 | devops/feicode 日志大量 `mautic/*` `wp-cli/*`(**镜像仓** `has_actions` 仍触发) | 策略:禁镜像 Actions 或限流(需 devops) |
|
||
| open PR | listed 几乎全是 Renovate Configure;`open_prs_human=0` 常见 | UI 人/机拆分,bot 降权 |
|
||
| CI 红 | `feibisi/linuxjoy` `syntax` **连续失败 ≥5(慢性)** | 修 workflow / shellcheck,非 runner 挂 |
|
||
| 本地 | main ahead 未推 + dirty;linuxjoy 多 worktree | 观察;不在 joy 里 push |
|
||
|
||
## 数据字段 `dashboard.forgejo`
|
||
|
||
```text
|
||
view: situation
|
||
planes: [feicode, ci_nodes, local_git]
|
||
ci_nodes: {
|
||
nodes[{ zombie_groups, recent_load{top,mirror_heavy}, ... }],
|
||
zombie_groups[], summary{runners_*, zombie_total, mirror_heavy_nodes}
|
||
}
|
||
local_git: { repos[{ worktrees{linked,paths} }], summary{dirty,ahead,linked_worktrees,...} }
|
||
attention: {
|
||
open_prs[], open_prs_human[], open_prs_bot[],
|
||
ci_red[{ streak, chronic, head_branch, age_hours }],
|
||
notifications[]
|
||
}
|
||
summary: {
|
||
open_prs_human, open_prs_bot, ci_red, ci_chronic,
|
||
ci_runners_*, ci_zombie, ci_mirror_heavy,
|
||
local_*, local_worktrees, attention_score
|
||
}
|
||
```
|
||
|
||
## 配置
|
||
|
||
- Token:`~/.config/forgejo/token` 或 `JOY_FORGEJO_TOKEN`
|
||
- 白名单:`~/.config/joy/forgejo.yml`(见 `configs/forgejo.example.yml`)
|
||
- `first_party_orgs` / `pinned_repos`
|
||
- `local_repos`:本地仓列表(默认 linuxjoy + joy-cli)
|
||
- HTTP **强制不走系统代理**(Mac 代理会导致 feicode 超时)
|
||
- CI 节点依赖 SSH 别名:`devops`、`feicode-prod`(ProxyJump 见 linuxjoy SSH config)
|
||
|
||
## 实测基线(2026-07-10)
|
||
|
||
| 节点 | 状态 |
|
||
|------|------|
|
||
| devops `forgejo-runner` system unit | active(user unit 可能 inactive,以 system 为准) |
|
||
| feicode-prod `forgejo-runner-01` | Up(act_runner daemon) |
|
||
| feicode-prod zombie TASK | 常见:Mautic 相关 `GITEA-ACTIONS-TASK-*` 长期 Up |
|
||
|
||
zombie **只观察不清理**;清理属 change/control,走 devops。
|
||
|
||
## 与 fei CLI
|
||
|
||
devops `~/bin/fei`:clone / pr / issue / release / notify / admin / push…
|
||
Agent 写代码走 **fei**;人在飞轮里看 **joy 代码 tab**。
|
||
|
||
## 验收
|
||
|
||
```bash
|
||
PYTHONPATH=~/Projects/joy-cli/src python3 -c "
|
||
from joy.dashboard.forgejo import collect_forgejo
|
||
import json
|
||
d=collect_forgejo()
|
||
print('ok', d.get('ok'), 'planes', d.get('planes'))
|
||
print('summary', json.dumps(d.get('summary'), ensure_ascii=False)[:400])
|
||
ci=d.get('ci_nodes') or {}
|
||
print('ci', (ci.get('summary') or {}))
|
||
for n in (ci.get('nodes') or []):
|
||
print(' ', n.get('id'), n.get('status'), 'zombie', n.get('zombie_count'))
|
||
lg=d.get('local_git') or {}
|
||
print('git', (lg.get('summary') or {}))
|
||
for r in (lg.get('repos') or []):
|
||
print(' ', r.get('id'), r.get('status'), 'ahead', r.get('ahead'), 'dirty', r.get('dirty'))
|
||
"
|
||
# 浏览器 → 代码 → 态势:应见 ① CI 节点 ② 本地 Git ③ PR/镜像
|
||
```
|