@bompus/house-rules 0.0.0-stage → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +54 -0
- package/LICENSE +21 -0
- package/README.md +378 -2
- package/THIRD_PARTY_NOTICES.md +188 -0
- package/compose.mjs +125 -0
- package/composition.mjs +361 -0
- package/config-view.mjs +209 -0
- package/config.mjs +381 -0
- package/docs/assets/banner-dark.png +0 -0
- package/docs/assets/banner-light.png +0 -0
- package/docs/assets/overview.png +0 -0
- package/docs/configuration.md +269 -0
- package/docs/skill-names.md +50 -0
- package/examples/person/house-rules.json +15 -0
- package/examples/person/rules/10-tooling.md +8 -0
- package/examples/person/rules/20-reporting.md +9 -0
- package/examples/project/AGENTS.md +18 -0
- package/package.json +42 -4
- package/rule-references.mjs +91 -0
- package/rules/core.md +340 -0
- package/rules/modifiers/backlog-outline.md +25 -0
- package/rules/modifiers/backlog-visual.md +16 -0
- package/rules/modifiers/coded-offers.md +70 -0
- package/rules/modifiers/cross-session-relay.md +23 -0
- package/rules/modifiers/effort-estimates.md +41 -0
- package/rules/modifiers/land-when-done.md +12 -0
- package/rules/modifiers/low-quota-handoff.md +20 -0
- package/rules/modifiers/model-default-questions.md +33 -0
- package/rules/modifiers/multi-agent.md +38 -0
- package/rules/modifiers/no-attribution.md +16 -0
- package/rules/modifiers/periodic-updates.md +25 -0
- package/rules/modifiers/plan-files.md +82 -0
- package/rules/modifiers/question-cards.md +48 -0
- package/rules/modifiers/release-batching.md +15 -0
- package/rules/modifiers/scratch-on-disk.md +15 -0
- package/rules/modifiers/shared-host-load.md +19 -0
- package/rules/modifiers/solo-operator.md +13 -0
- package/rules/modifiers/squash-landing.md +22 -0
- package/rules/modifiers/upstream-contributions.md +45 -0
- package/rules/modifiers/web-image-formats.md +35 -0
- package/rules/references/backlog-view.md +154 -0
- package/rules/references/github-actions.md +45 -0
- package/rules/references/landing.md +39 -0
- package/rules/references/multi-agent.md +51 -0
- package/rules/references/release-batching.md +66 -0
- package/rules/references/squash-landing.md +50 -0
- package/rules/references/thread-visuals.md +45 -0
- package/setup.mjs +445 -0
- package/skills/hr-agent-guidance-audit/LICENSE +21 -0
- package/skills/hr-agent-guidance-audit/SKILL.md +91 -0
- package/skills/hr-agent-guidance-audit/agents/openai.yaml +2 -0
- package/skills/hr-agent-guidance-audit/references/prune-workflow.md +72 -0
- package/skills/hr-agent-guidance-audit/references/records-and-lessons.md +60 -0
- package/skills/hr-agent-guidance-audit/references/retirement-verdicts.md +49 -0
- package/skills/hr-agent-guidance-refresh/LICENSE +21 -0
- package/skills/hr-agent-guidance-refresh/SKILL.md +36 -0
- package/skills/hr-agent-guidance-refresh/agents/openai.yaml +2 -0
- package/skills/hr-agent-guidance-refresh/references/verification.md +47 -0
- package/skills/hr-api-exposure-check/SKILL.md +159 -0
- package/skills/hr-api-exposure-check/agents/openai.yaml +3 -0
- package/skills/hr-audit-choices/SKILL.md +67 -0
- package/skills/hr-audit-choices/agents/openai.yaml +2 -0
- package/skills/hr-benchmarking/NOTICE.md +36 -0
- package/skills/hr-benchmarking/SKILL.md +279 -0
- package/skills/hr-benchmarking/agents/openai.yaml +2 -0
- package/skills/hr-benchmarking/references/javascript.md +130 -0
- package/skills/hr-benchmarking/references/tools.md +165 -0
- package/skills/hr-benchmarking/scripts/process-attribution.ps1 +20 -0
- package/skills/hr-benchmarking/scripts/process-attribution.py +107 -0
- package/skills/hr-better-accessibility/LICENSE +22 -0
- package/skills/hr-better-accessibility/NOTICE.md +46 -0
- package/skills/hr-better-accessibility/SKILL.md +119 -0
- package/skills/hr-better-accessibility/agents/openai.yaml +3 -0
- package/skills/hr-better-accessibility/focus-and-keyboard.md +130 -0
- package/skills/hr-better-accessibility/forms.md +82 -0
- package/skills/hr-better-accessibility/hit-areas.md +98 -0
- package/skills/hr-better-accessibility/motion-and-zoom.md +81 -0
- package/skills/hr-better-accessibility/screen-readers.md +102 -0
- package/skills/hr-better-accessibility/semantics-and-aria.md +84 -0
- package/skills/hr-better-colors/LICENSE +21 -0
- package/skills/hr-better-colors/NOTICE.md +37 -0
- package/skills/hr-better-colors/SKILL.md +114 -0
- package/skills/hr-better-colors/agents/openai.yaml +3 -0
- package/skills/hr-better-colors/color-formats.md +90 -0
- package/skills/hr-better-colors/color-usage.md +140 -0
- package/skills/hr-better-colors/contrast.md +80 -0
- package/skills/hr-better-colors/palette-generation.md +104 -0
- package/skills/hr-better-colors/palette-structure.md +76 -0
- package/skills/hr-better-colors/token-naming.md +97 -0
- package/skills/hr-better-layout/LICENSE +22 -0
- package/skills/hr-better-layout/NOTICE.md +48 -0
- package/skills/hr-better-layout/SKILL.md +92 -0
- package/skills/hr-better-layout/agents/openai.yaml +3 -0
- package/skills/hr-better-layout/grouping-and-alignment.md +144 -0
- package/skills/hr-better-layout/spacing-and-adaptivity.md +215 -0
- package/skills/hr-better-typography/LICENSE +22 -0
- package/skills/hr-better-typography/NOTICE.md +46 -0
- package/skills/hr-better-typography/SKILL.md +172 -0
- package/skills/hr-better-typography/agents/openai.yaml +3 -0
- package/skills/hr-better-typography/choosing-fonts.md +69 -0
- package/skills/hr-better-typography/css-cheat-sheet.md +65 -0
- package/skills/hr-better-typography/details-and-accessibility.md +119 -0
- package/skills/hr-better-typography/spacing-and-sizing.md +131 -0
- package/skills/hr-better-typography/variable-fonts-and-opentype.md +105 -0
- package/skills/hr-better-typography/wrapping-and-punctuation.md +57 -0
- package/skills/hr-better-writing/LICENSE +22 -0
- package/skills/hr-better-writing/NOTICE.md +46 -0
- package/skills/hr-better-writing/SKILL.md +122 -0
- package/skills/hr-better-writing/agents/openai.yaml +3 -0
- package/skills/hr-code-review/LICENSE +21 -0
- package/skills/hr-code-review/NOTICE.md +26 -0
- package/skills/hr-code-review/SKILL.md +163 -0
- package/skills/hr-code-review/agents/openai.yaml +3 -0
- package/skills/hr-code-review/references/acp-client.md +43 -0
- package/skills/hr-code-review/references/evidence.md +57 -0
- package/skills/hr-code-review/references/impact.md +103 -0
- package/skills/hr-code-review/references/panel-adjudication.md +58 -0
- package/skills/hr-code-review/references/panel-plan.md +61 -0
- package/skills/hr-code-review/references/panel-recommendations.json +105 -0
- package/skills/hr-code-review/references/panel-recommendations.md +46 -0
- package/skills/hr-code-review/references/panel-setup.md +54 -0
- package/skills/hr-code-review/references/reviewer-role.md +31 -0
- package/skills/hr-code-review/scripts/acp-panel-client.mjs +299 -0
- package/skills/hr-code-review/scripts/check-receipts.mjs +263 -0
- package/skills/hr-code-review/scripts/panel-plan.mjs +69 -0
- package/skills/hr-code-review/scripts/panel-preferences.mjs +220 -0
- package/skills/hr-design-exploration/SKILL.md +105 -0
- package/skills/hr-design-exploration/agents/openai.yaml +4 -0
- package/skills/hr-diagnosing-bugs/NOTICE.md +45 -0
- package/skills/hr-diagnosing-bugs/SKILL.md +108 -0
- package/skills/hr-diagnosing-bugs/agents/openai.yaml +3 -0
- package/skills/hr-diagnosing-bugs/references/reporting.md +97 -0
- package/skills/hr-diagnosing-bugs/scripts/check-pr-offer.mjs +47 -0
- package/skills/hr-explain-code/NOTICE.md +37 -0
- package/skills/hr-explain-code/SKILL.md +110 -0
- package/skills/hr-explain-code/agents/openai.yaml +5 -0
- package/skills/hr-explain-code/references/helper-brief.md +39 -0
- package/skills/hr-extract-shared-steps/SKILL.md +134 -0
- package/skills/hr-extract-shared-steps/agents/openai.yaml +3 -0
- package/skills/hr-forgotten-work-audit/SKILL.md +130 -0
- package/skills/hr-forgotten-work-audit/references/brief-template.md +56 -0
- package/skills/hr-forgotten-work-audit/references/result-format.md +46 -0
- package/skills/hr-handoff/LICENSE +21 -0
- package/skills/hr-handoff/NOTICE.md +29 -0
- package/skills/hr-handoff/SKILL.md +114 -0
- package/skills/hr-handoff/agents/openai.yaml +5 -0
- package/skills/hr-handoff/assets/ledger.example.json +10 -0
- package/skills/hr-handoff/assets/receipt.example.json +76 -0
- package/skills/hr-handoff/assets/source.example.json +20 -0
- package/skills/hr-handoff/references/reconciliation.md +124 -0
- package/skills/hr-handoff/references/successor-thread.md +76 -0
- package/skills/hr-handoff/scripts/check-reconciliation.mjs +324 -0
- package/skills/hr-house-rules-setup/SKILL.md +114 -0
- package/skills/hr-house-rules-setup/agents/openai.yaml +5 -0
- package/skills/hr-issue-tracker-setup/SKILL.md +49 -0
- package/skills/hr-issue-tracker-setup/agents/openai.yaml +5 -0
- package/skills/hr-lean-plan/SKILL.md +146 -0
- package/skills/hr-lean-plan/agents/openai.yaml +5 -0
- package/skills/hr-maintainability-review/SKILL.md +186 -0
- package/skills/hr-maintainability-review/agents/openai.yaml +5 -0
- package/skills/hr-manual-qa/NOTICE.md +36 -0
- package/skills/hr-manual-qa/SKILL.md +37 -0
- package/skills/hr-manual-qa/agents/openai.yaml +3 -0
- package/skills/hr-navigation-retro/LICENSE +21 -0
- package/skills/hr-navigation-retro/NOTICE.md +5 -0
- package/skills/hr-navigation-retro/SKILL.md +86 -0
- package/skills/hr-navigation-retro/agents/openai.yaml +4 -0
- package/skills/hr-navigation-retro/references/inputs.md +67 -0
- package/skills/hr-navigation-retro/scripts/retro.py +552 -0
- package/skills/hr-navigation-retro/scripts/transcripts.py +205 -0
- package/skills/hr-ordering-tests/SKILL.md +51 -0
- package/skills/hr-ordering-tests/agents/openai.yaml +2 -0
- package/skills/hr-plain-prose/SKILL.md +264 -0
- package/skills/hr-plain-prose/agents/openai.yaml +3 -0
- package/skills/hr-plain-prose/scripts/check.mjs +331 -0
- package/skills/hr-pr-followup/LICENSE +21 -0
- package/skills/hr-pr-followup/NOTICE.md +9 -0
- package/skills/hr-pr-followup/SKILL.md +74 -0
- package/skills/hr-pr-followup/agents/openai.yaml +2 -0
- package/skills/hr-pr-followup/references/review-helpers.md +111 -0
- package/skills/hr-pr-followup/scripts/check-landing.py +204 -0
- package/skills/hr-pr-followup/scripts/check-pr-review.ts +510 -0
- package/skills/hr-pr-followup/scripts/merge-pr.sh +100 -0
- package/skills/hr-pr-followup/scripts/resolve-pr-thread.ts +219 -0
- package/skills/hr-pr-followup/scripts/verify-landed.sh +184 -0
- package/skills/hr-progress-report/SKILL.md +49 -0
- package/skills/hr-progress-report/agents/openai.yaml +5 -0
- package/skills/hr-read-reddit/SKILL.md +44 -0
- package/skills/hr-read-reddit/agents/openai.yaml +2 -0
- package/skills/hr-read-reddit/scripts/reddit.ts +252 -0
- package/skills/hr-read-x-links/SKILL.md +42 -0
- package/skills/hr-read-x-links/agents/openai.yaml +2 -0
- package/skills/hr-read-x-links/scripts/x-post.ts +264 -0
- package/skills/hr-research-shared-links/SKILL.md +103 -0
- package/skills/hr-split-to-prs/LICENSE +21 -0
- package/skills/hr-split-to-prs/NOTICE.md +9 -0
- package/skills/hr-split-to-prs/SKILL.md +61 -0
- package/skills/hr-split-to-prs/agents/openai.yaml +2 -0
- package/skills/hr-sqlite/SKILL.md +174 -0
- package/skills/hr-sqlite/agents/openai.yaml +2 -0
- package/skills/hr-sqlite/references/evidence.md +94 -0
- package/skills/hr-sqlite/references/tool-decisions.md +39 -0
- package/skills/hr-sqlite/scripts/inspect-sqlite.py +245 -0
- package/skills/hr-stock-ui-audit/SKILL.md +132 -0
- package/skills/hr-stock-ui-audit/agents/openai.yaml +3 -0
- package/skills/hr-stock-ui-audit/scripts/scan.mjs +619 -0
- package/skills/hr-tdd/LICENSE +21 -0
- package/skills/hr-tdd/NOTICE.md +10 -0
- package/skills/hr-tdd/SKILL.md +40 -0
- package/skills/hr-tdd/agents/openai.yaml +3 -0
- package/skills/hr-tdd/mocking.md +39 -0
- package/skills/hr-tdd/tests.md +77 -0
- package/skills/hr-test-audit/LICENSE +21 -0
- package/skills/hr-test-audit/NOTICE.md +67 -0
- package/skills/hr-test-audit/SKILL.md +146 -0
- package/skills/hr-test-audit/agents/openai.yaml +3 -0
- package/skills/hr-test-audit/scripts/floor-guard.ts +137 -0
- package/skills/hr-usage-report/SKILL.md +90 -0
- package/skills/hr-usage-report/agents/openai.yaml +2 -0
- package/skills/hr-usage-report/assets/example-report.json +125 -0
- package/skills/hr-usage-report/assets/report-template.html +377 -0
- package/skills/hr-usage-report/scripts/render-report.ts +86 -0
- package/skills/hr-usage-report/scripts/usage-by-model.ts +499 -0
- package/skills/hr-what-next/SKILL.md +151 -0
- package/skills/hr-what-next/agents/openai.yaml +4 -0
- package/skills/hr-what-next/references/reporting.md +59 -0
- package/skills/hr-what-next/scripts/check-open-work.mjs +711 -0
- package/skills/hr-writing-for-agents/NOTICE.md +46 -0
- package/skills/hr-writing-for-agents/SKILL-MECHANICS.md +83 -0
- package/skills/hr-writing-for-agents/SKILL.md +108 -0
- package/skills/hr-writing-for-agents/agents/openai.yaml +3 -0
- package/skills/hr-writing-pr/NOTICE.md +48 -0
- package/skills/hr-writing-pr/SKILL.md +119 -0
- package/skills/hr-writing-pr/agents/openai.yaml +2 -0
- package/skills/hr-writing-pr/scripts/benefit-chart.py +200 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Report whether a checkout's work has landed in the base branch.
|
|
3
|
+
|
|
4
|
+
Squash-aware: a session branch whose commits were squash-merged is never an
|
|
5
|
+
ancestor of the base, so ancestry alone would cry unlanded forever. The check
|
|
6
|
+
therefore compares content: files unique to the checkout must be identical in
|
|
7
|
+
the base. Read-only; never fetches — the caller fetches first.
|
|
8
|
+
|
|
9
|
+
It also lists live processes whose working directory is inside the checkout
|
|
10
|
+
(Linux /proc only), excluding the checker's ancestors and its pipeline. Each listed process
|
|
11
|
+
blocks worktree removal unless its PID is one you recorded when you started it. `own_session`
|
|
12
|
+
is true only for a process that descends from the nearest agent CLI above the checker (a
|
|
13
|
+
process whose comm is one of AGENT_COMMS); a process under another session of the same agent
|
|
14
|
+
host's server, or any process when the checker has no agent ancestor, is false. A process
|
|
15
|
+
reparented to init after its parent exited is false too.
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
python3 scripts/check-landing.py [--path <checkout>] [--base <ref>]
|
|
19
|
+
python3 scripts/check-landing.py --path <checkout> --fail-on-unlanded
|
|
20
|
+
|
|
21
|
+
Without --base the base is origin/HEAD (the remote's default branch, which
|
|
22
|
+
need not be main), falling back to origin/main when origin/HEAD is unset.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import argparse
|
|
26
|
+
import json
|
|
27
|
+
import os
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def git(path, *args):
|
|
33
|
+
return subprocess.run(
|
|
34
|
+
["git", *args],
|
|
35
|
+
cwd=path,
|
|
36
|
+
capture_output=True,
|
|
37
|
+
text=True,
|
|
38
|
+
timeout=60,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def default_base(path):
|
|
43
|
+
"""origin/HEAD's target (e.g. origin/fork/consolidated), else origin/main."""
|
|
44
|
+
r = git(path, "symbolic-ref", "--quiet", "--short",
|
|
45
|
+
"refs/remotes/origin/HEAD")
|
|
46
|
+
return r.stdout.strip() if r.returncode == 0 and r.stdout.strip() \
|
|
47
|
+
else "origin/main"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _ppid(pid):
|
|
51
|
+
try:
|
|
52
|
+
with open(f"/proc/{pid}/stat", encoding="utf-8", errors="replace") as f:
|
|
53
|
+
return int(f.read().rsplit(")", 1)[1].split()[1])
|
|
54
|
+
except (OSError, ValueError, IndexError):
|
|
55
|
+
return 0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# comm names of the agent CLIs. "opencode.exe" is matched without its suffix.
|
|
59
|
+
AGENT_COMMS = {"claude", "codex", "cursor-agent", "opencode", "grok", "devin", "agy"}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _comm(pid):
|
|
63
|
+
try:
|
|
64
|
+
with open(f"/proc/{pid}/comm", encoding="utf-8", errors="replace") as f:
|
|
65
|
+
return f.read().strip()
|
|
66
|
+
except OSError:
|
|
67
|
+
return ""
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _chain(pid):
|
|
71
|
+
"""pid and its parents up to, but excluding, PID 1."""
|
|
72
|
+
chain = []
|
|
73
|
+
while pid > 1 and pid not in chain:
|
|
74
|
+
chain.append(pid)
|
|
75
|
+
pid = _ppid(pid)
|
|
76
|
+
return chain
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def nearest_agent(chain, read_comm=_comm):
|
|
80
|
+
"""First PID in chain whose comm is an agent CLI, else None."""
|
|
81
|
+
for pid in chain:
|
|
82
|
+
name = read_comm(pid)
|
|
83
|
+
if name.endswith(".exe"):
|
|
84
|
+
name = name[:-4]
|
|
85
|
+
if name in AGENT_COMMS:
|
|
86
|
+
return pid
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def checkout_processes(path):
|
|
91
|
+
"""Processes whose cwd is inside path, or None without /proc."""
|
|
92
|
+
if not os.path.isdir("/proc/self"):
|
|
93
|
+
return None
|
|
94
|
+
root = os.path.realpath(path)
|
|
95
|
+
mine = _chain(os.getpid())
|
|
96
|
+
ancestors = set(mine)
|
|
97
|
+
agent = nearest_agent(mine)
|
|
98
|
+
own_group = os.getpgid(0)
|
|
99
|
+
found = []
|
|
100
|
+
for entry in os.listdir("/proc"):
|
|
101
|
+
if not entry.isdigit() or int(entry) in ancestors:
|
|
102
|
+
continue
|
|
103
|
+
try:
|
|
104
|
+
if os.getpgid(int(entry)) == own_group:
|
|
105
|
+
continue
|
|
106
|
+
cwd = os.readlink(f"/proc/{entry}/cwd")
|
|
107
|
+
with open(f"/proc/{entry}/comm", encoding="utf-8", errors="replace") as f:
|
|
108
|
+
comm = f.read().strip()
|
|
109
|
+
except (OSError, ProcessLookupError):
|
|
110
|
+
continue
|
|
111
|
+
if cwd != root and not cwd.startswith(root + os.sep):
|
|
112
|
+
continue
|
|
113
|
+
own = agent is not None and agent in _chain(int(entry))
|
|
114
|
+
found.append({"pid": int(entry), "own_session": own,
|
|
115
|
+
"comm": comm})
|
|
116
|
+
return found
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def landing_state(path, base):
|
|
120
|
+
"""Return a JSON-serializable report dict for the checkout at path."""
|
|
121
|
+
report = {"path": str(path), "base": base, "ok": False, "reason": ""}
|
|
122
|
+
r = git(path, "rev-parse", "--verify", "--quiet", base)
|
|
123
|
+
if r.returncode != 0:
|
|
124
|
+
report["reason"] = f"base ref missing: {base}"
|
|
125
|
+
return report
|
|
126
|
+
report["base_head"] = r.stdout.strip()
|
|
127
|
+
r = git(path, "rev-parse", "HEAD")
|
|
128
|
+
if r.returncode != 0:
|
|
129
|
+
report["reason"] = "not a git checkout (no HEAD)"
|
|
130
|
+
return report
|
|
131
|
+
report["head"] = r.stdout.strip()
|
|
132
|
+
r = git(path, "symbolic-ref", "--quiet", "--short", "HEAD")
|
|
133
|
+
report["branch"] = r.stdout.strip() if r.returncode == 0 else None
|
|
134
|
+
r = git(path, "status", "--porcelain")
|
|
135
|
+
if r.returncode != 0:
|
|
136
|
+
report["reason"] = "git status failed"
|
|
137
|
+
return report
|
|
138
|
+
report["clean"] = r.stdout.strip() == ""
|
|
139
|
+
report["processes"] = checkout_processes(path)
|
|
140
|
+
r = git(path, "merge-base", "--is-ancestor", "HEAD", base)
|
|
141
|
+
report["ancestor"] = r.returncode == 0
|
|
142
|
+
if report["ancestor"]:
|
|
143
|
+
report["content_landed"] = True
|
|
144
|
+
else:
|
|
145
|
+
r = git(path, "merge-base", base, "HEAD")
|
|
146
|
+
if r.returncode != 0:
|
|
147
|
+
report["reason"] = "no merge base with base ref"
|
|
148
|
+
return report
|
|
149
|
+
mb = r.stdout.strip()
|
|
150
|
+
r = git(path, "diff", "--name-only", "--no-renames", "-z", mb, "HEAD")
|
|
151
|
+
if r.returncode != 0:
|
|
152
|
+
report["reason"] = "git diff failed"
|
|
153
|
+
return report
|
|
154
|
+
files = [f for f in r.stdout.split("\0") if f]
|
|
155
|
+
report["unique_files"] = len(files)
|
|
156
|
+
if not files:
|
|
157
|
+
report["content_landed"] = True
|
|
158
|
+
else:
|
|
159
|
+
r = git(path, "diff", "--quiet", "HEAD", base, "--", *files)
|
|
160
|
+
report["content_landed"] = r.returncode == 0
|
|
161
|
+
report["indeterminate"] = False
|
|
162
|
+
if not report["content_landed"]:
|
|
163
|
+
# Base may have advanced on the same files after the merge
|
|
164
|
+
# base: then a diff is expected even for landed content.
|
|
165
|
+
r = git(path, "diff", "--name-only", "--no-renames", "-z", mb, base,
|
|
166
|
+
"--", *files)
|
|
167
|
+
if r.returncode == 0 and any(
|
|
168
|
+
f for f in r.stdout.split("\0") if f):
|
|
169
|
+
report["indeterminate"] = True
|
|
170
|
+
landed = bool(report["content_landed"])
|
|
171
|
+
if landed and report["clean"]:
|
|
172
|
+
report["ok"] = True
|
|
173
|
+
report["reason"] = "landed and clean"
|
|
174
|
+
elif landed:
|
|
175
|
+
report["reason"] = "content landed but tree is dirty"
|
|
176
|
+
elif report.get("indeterminate"):
|
|
177
|
+
report["reason"] = ("indeterminate - base advanced on touched "
|
|
178
|
+
"files, confirm PR")
|
|
179
|
+
else:
|
|
180
|
+
report["reason"] = "unlanded content vs base"
|
|
181
|
+
return report
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def main(argv=None):
|
|
185
|
+
ap = argparse.ArgumentParser(description=__doc__)
|
|
186
|
+
ap.add_argument("--path", default=".", help="checkout to inspect")
|
|
187
|
+
ap.add_argument(
|
|
188
|
+
"--base", help="base ref (default: origin/HEAD, else origin/main)"
|
|
189
|
+
)
|
|
190
|
+
ap.add_argument(
|
|
191
|
+
"--fail-on-unlanded",
|
|
192
|
+
action="store_true",
|
|
193
|
+
help="exit 1 unless the checkout is clean and landed",
|
|
194
|
+
)
|
|
195
|
+
args = ap.parse_args(argv)
|
|
196
|
+
report = landing_state(args.path, args.base or default_base(args.path))
|
|
197
|
+
print(json.dumps(report, indent=2))
|
|
198
|
+
if args.fail_on_unlanded and not report["ok"]:
|
|
199
|
+
return 1
|
|
200
|
+
return 0
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if __name__ == "__main__":
|
|
204
|
+
sys.exit(main())
|