Skip to content

Resource Sync Auditor

thekingofcity edited this page Feb 25, 2026 · 1 revision

资源同步审计工具 (Resource Sync Auditor)

1. 解决的问题

railmapgen 系列仓库中,资源(Resources)的更新通常遵循 Issue 请求 -> Bot/手动创建 PR -> 合并 PR 并关闭 Issue 的流程。但在实际操作中,经常会出现以下“同步失效”的情况:

  • 孤立 Issue (Orphan Issues):用户提交了资源申请 Issue,但没有任何 PR 正在处理它(可能是漏掉了或者 Bot 还没触发)。
  • 陈旧 PR (Stale PRs):PR 依然处于 Open 状态,但它声明要修复的 Issue 已经被关闭了(可能是 Issue 被手动关闭,或者 PR 被遗忘了)。
  • 未关联 PR (Unlinked PRs):创建了 PR 但没有在描述中使用 fixes #123 等关键字显式关联 Issue,导致自动化追踪失效。

本脚本通过 GitHub GraphQL API 快速对仓库进行全量审计,一键找出这些不一致的项。

2. 环境要求

  • 已安装 GitHub CLI (gh)
  • 已登录 GitHub 账号(执行 gh auth login)。
  • 系统中安装有 jq(用于解析 JSON 数据)。

3. 使用方法

保存脚本

将脚本内容保存为 check_rmp_sync.sh 并赋予执行权限:

chmod +x check_rmp_sync.sh

执行审计

你可以指定任何 railmapgen 组织下的仓库名(默认为 railmapgen/rmp-gallery):

# 审计默认仓库
./check_rmp_sync.sh

# 审计指定的调色盘仓库
./check_rmp_sync.sh railmapgen/rmg-palette

4. 如何理解输出结果

脚本会将结果分为三个部分:

A. [ORPHAN ISSUES] - 孤立 Issue

  • 定义:标题以 Resources: 开头且处于 Open 状态,但没有任何 Open PR 引用该 Issue 编号。
  • 关注点:检查是否有带有 bug 标签的项。如果列表很长,说明有很多资源请求尚未开始处理。

B. [STALE PRS] - 陈旧 PR

  • 定义:PR 处于 Open 状态,但其关联的 Issue 已经处于 CLOSED 状态。
  • 关注点:这些通常是“僵尸 PR”。你应该检查这些 PR 是否还需要合并,或者是否应该直接关闭。

C. [UNLINKED PRS] - 未关联 PR

  • 定义:PR 标题符合规范,但描述中没有任何 fixes #issue_number 的引用。
  • 关注点:这些 PR 无法自动关闭 Issue。建议手动编辑 PR 描述添加关联,以保持项目自动化流程的完整性。

5. 脚本源代码 (check_rmp_sync.sh)

#!/bin/bash

REPO="${1:-railmapgen/rmp-gallery}"

echo "Fetching data from $REPO via GraphQL..."

# Fetch all open issues and PRs with "Resources:" prefix
DATA=$(gh api graphql -f query='
query {
  search(query: "repo:'$REPO' is:issue is:open Resources:", type: ISSUE, first: 100) {
    nodes {
      ... on Issue {
        number
        title
        labels(first: 5) { nodes { name } }
      }
    }
  }
  search_prs: search(query: "repo:'$REPO' is:pr is:open Resources:", type: ISSUE, first: 100) {
    nodes {
      ... on PullRequest {
        number
        title
        state
        closingIssuesReferences(first: 5) {
          nodes {
            number
            state
          }
        }
      }
    }
  }
}')

echo "----------------------------------------------------------------"
echo "ANALYSIS REPORT: Resources Issue/PR Sync"
echo "----------------------------------------------------------------"

# 1. Identify Orphan Issues (Open issues not referenced by any open PR)
echo "[ORPHAN ISSUES] - Open issues with no linked open PR:"
echo "$DATA" | jq -r '
  .data.search.nodes as $issues |
  .data.search_prs.nodes as $prs |
  ($prs | map(.closingIssuesReferences.nodes[].number)) as $linked_numbers |
  $issues[] | 
  select(.number as $n | $linked_numbers | any(. == $n) | not) |
  "Issue #\(.number): \(.title) [Labels: \(.labels.nodes | map(.name) | join(", "))]"
'

echo ""
# 2. Identify PRs pointing to CLOSED issues (Potential stale PRs)
echo "[STALE PRS] - Open PRs linked to closed issues:"
echo "$DATA" | jq -r '
  .data.search_prs.nodes[] | 
  select(any(.closingIssuesReferences.nodes[]?; .state == "CLOSED")) |
  "PR #\(.number): \(.title) (Links to CLOSED Issue(s): \([.closingIssuesReferences.nodes[] | select(.state == "CLOSED") | "#\(.number)"] | join(", ")))"
'

echo ""
# 3. Identify PRs with NO linked issues (Missing link or manual PR)
echo "[UNLINKED PRS] - Open PRs with no explicit issue reference:"
echo "$DATA" | jq -r '
  .data.search_prs.nodes[] | 
  select(.closingIssuesReferences.nodes | length == 0) |
  "PR #\(.number): \(.title)"
'
echo "----------------------------------------------------------------"