git 4.3.2 → 5.0.0.beta.1

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.
Files changed (280) hide show
  1. checksums.yaml +4 -4
  2. data/.github/copilot-instructions.md +67 -2705
  3. data/.github/pull_request_template.md +3 -1
  4. data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
  5. data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
  6. data/.github/skills/command-implementation/REFERENCE.md +993 -0
  7. data/.github/skills/command-implementation/SKILL.md +229 -0
  8. data/.github/skills/command-test-conventions/SKILL.md +660 -0
  9. data/.github/skills/command-yard-documentation/SKILL.md +426 -0
  10. data/.github/skills/dependency-management/SKILL.md +72 -0
  11. data/.github/skills/development-workflow/SKILL.md +506 -0
  12. data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
  13. data/.github/skills/extract-facade-from-base-lib/SKILL.md +586 -0
  14. data/.github/skills/facade-implementation/REFERENCE.md +840 -0
  15. data/.github/skills/facade-implementation/SKILL.md +260 -0
  16. data/.github/skills/facade-test-conventions/SKILL.md +380 -0
  17. data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
  18. data/.github/skills/make-skill-template/SKILL.md +176 -0
  19. data/.github/skills/pr-readiness-review/SKILL.md +185 -0
  20. data/.github/skills/project-context/SKILL.md +313 -0
  21. data/.github/skills/pull-request-review/SKILL.md +168 -0
  22. data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
  23. data/.github/skills/release-management/SKILL.md +125 -0
  24. data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
  25. data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
  26. data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
  27. data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
  28. data/.github/skills/reviewing-skills/SKILL.md +189 -0
  29. data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
  30. data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
  31. data/.github/skills/test-debugging/SKILL.md +160 -0
  32. data/.github/skills/yard-documentation/SKILL.md +793 -0
  33. data/.github/workflows/continuous_integration.yml +3 -2
  34. data/.github/workflows/enforce_conventional_commits.yml +1 -1
  35. data/.github/workflows/experimental_continuous_integration.yml +2 -2
  36. data/.github/workflows/release.yml +3 -4
  37. data/.gitignore +8 -0
  38. data/.husky/pre-commit +13 -0
  39. data/.release-please-manifest.json +1 -1
  40. data/.rspec +3 -0
  41. data/.rubocop.yml +7 -3
  42. data/.rubocop_todo.yml +23 -5
  43. data/.yardopts +1 -0
  44. data/CHANGELOG.md +0 -40
  45. data/CONTRIBUTING.md +694 -53
  46. data/README.md +17 -5
  47. data/Rakefile +61 -9
  48. data/commitlint.test +4 -0
  49. data/git.gemspec +14 -8
  50. data/lib/git/args_builder.rb +0 -8
  51. data/lib/git/base.rb +486 -410
  52. data/lib/git/branch.rb +380 -43
  53. data/lib/git/branch_delete_failure.rb +31 -0
  54. data/lib/git/branch_delete_result.rb +63 -0
  55. data/lib/git/branch_info.rb +178 -0
  56. data/lib/git/branches.rb +130 -24
  57. data/lib/git/command_line/base.rb +245 -0
  58. data/lib/git/command_line/capturing.rb +249 -0
  59. data/lib/git/command_line/result.rb +96 -0
  60. data/lib/git/command_line/streaming.rb +194 -0
  61. data/lib/git/command_line.rb +43 -322
  62. data/lib/git/command_line_result.rb +4 -88
  63. data/lib/git/commands/add.rb +131 -0
  64. data/lib/git/commands/am/abort.rb +43 -0
  65. data/lib/git/commands/am/apply.rb +252 -0
  66. data/lib/git/commands/am/continue.rb +43 -0
  67. data/lib/git/commands/am/quit.rb +43 -0
  68. data/lib/git/commands/am/retry.rb +47 -0
  69. data/lib/git/commands/am/show_current_patch.rb +64 -0
  70. data/lib/git/commands/am/skip.rb +42 -0
  71. data/lib/git/commands/am.rb +33 -0
  72. data/lib/git/commands/apply.rb +237 -0
  73. data/lib/git/commands/archive/list_formats.rb +46 -0
  74. data/lib/git/commands/archive.rb +140 -0
  75. data/lib/git/commands/arguments.rb +3510 -0
  76. data/lib/git/commands/base.rb +403 -0
  77. data/lib/git/commands/branch/copy.rb +94 -0
  78. data/lib/git/commands/branch/create.rb +173 -0
  79. data/lib/git/commands/branch/delete.rb +80 -0
  80. data/lib/git/commands/branch/list.rb +162 -0
  81. data/lib/git/commands/branch/move.rb +94 -0
  82. data/lib/git/commands/branch/set_upstream.rb +86 -0
  83. data/lib/git/commands/branch/show_current.rb +49 -0
  84. data/lib/git/commands/branch/unset_upstream.rb +57 -0
  85. data/lib/git/commands/branch.rb +34 -0
  86. data/lib/git/commands/cat_file/batch.rb +364 -0
  87. data/lib/git/commands/cat_file/filtered.rb +105 -0
  88. data/lib/git/commands/cat_file/raw.rb +210 -0
  89. data/lib/git/commands/cat_file.rb +49 -0
  90. data/lib/git/commands/checkout/branch.rb +151 -0
  91. data/lib/git/commands/checkout/files.rb +115 -0
  92. data/lib/git/commands/checkout.rb +38 -0
  93. data/lib/git/commands/checkout_index.rb +105 -0
  94. data/lib/git/commands/clean.rb +100 -0
  95. data/lib/git/commands/clone.rb +240 -0
  96. data/lib/git/commands/commit.rb +272 -0
  97. data/lib/git/commands/commit_tree.rb +100 -0
  98. data/lib/git/commands/config_option_syntax/add.rb +83 -0
  99. data/lib/git/commands/config_option_syntax/get.rb +117 -0
  100. data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
  101. data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
  102. data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
  103. data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
  104. data/lib/git/commands/config_option_syntax/get_urlmatch.rb +102 -0
  105. data/lib/git/commands/config_option_syntax/list.rb +107 -0
  106. data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
  107. data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
  108. data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
  109. data/lib/git/commands/config_option_syntax/set.rb +114 -0
  110. data/lib/git/commands/config_option_syntax/unset.rb +89 -0
  111. data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
  112. data/lib/git/commands/config_option_syntax.rb +56 -0
  113. data/lib/git/commands/describe.rb +155 -0
  114. data/lib/git/commands/diff.rb +656 -0
  115. data/lib/git/commands/diff_files.rb +518 -0
  116. data/lib/git/commands/diff_index.rb +496 -0
  117. data/lib/git/commands/fetch.rb +352 -0
  118. data/lib/git/commands/fsck.rb +136 -0
  119. data/lib/git/commands/gc.rb +132 -0
  120. data/lib/git/commands/grep.rb +338 -0
  121. data/lib/git/commands/init.rb +99 -0
  122. data/lib/git/commands/log.rb +632 -0
  123. data/lib/git/commands/ls_files.rb +191 -0
  124. data/lib/git/commands/ls_remote.rb +155 -0
  125. data/lib/git/commands/ls_tree.rb +131 -0
  126. data/lib/git/commands/maintenance/register.rb +75 -0
  127. data/lib/git/commands/maintenance/run.rb +104 -0
  128. data/lib/git/commands/maintenance/start.rb +66 -0
  129. data/lib/git/commands/maintenance/stop.rb +55 -0
  130. data/lib/git/commands/maintenance/unregister.rb +79 -0
  131. data/lib/git/commands/maintenance.rb +31 -0
  132. data/lib/git/commands/merge/abort.rb +44 -0
  133. data/lib/git/commands/merge/continue.rb +44 -0
  134. data/lib/git/commands/merge/quit.rb +46 -0
  135. data/lib/git/commands/merge/start.rb +245 -0
  136. data/lib/git/commands/merge.rb +28 -0
  137. data/lib/git/commands/merge_base.rb +86 -0
  138. data/lib/git/commands/mv.rb +77 -0
  139. data/lib/git/commands/name_rev.rb +114 -0
  140. data/lib/git/commands/pull.rb +377 -0
  141. data/lib/git/commands/push.rb +246 -0
  142. data/lib/git/commands/read_tree.rb +149 -0
  143. data/lib/git/commands/remote/add.rb +91 -0
  144. data/lib/git/commands/remote/get_url.rb +66 -0
  145. data/lib/git/commands/remote/list.rb +54 -0
  146. data/lib/git/commands/remote/prune.rb +61 -0
  147. data/lib/git/commands/remote/remove.rb +52 -0
  148. data/lib/git/commands/remote/rename.rb +69 -0
  149. data/lib/git/commands/remote/set_branches.rb +63 -0
  150. data/lib/git/commands/remote/set_head.rb +82 -0
  151. data/lib/git/commands/remote/set_url.rb +71 -0
  152. data/lib/git/commands/remote/set_url_add.rb +61 -0
  153. data/lib/git/commands/remote/set_url_delete.rb +64 -0
  154. data/lib/git/commands/remote/show.rb +71 -0
  155. data/lib/git/commands/remote/update.rb +72 -0
  156. data/lib/git/commands/remote.rb +42 -0
  157. data/lib/git/commands/repack.rb +277 -0
  158. data/lib/git/commands/reset.rb +147 -0
  159. data/lib/git/commands/rev_parse.rb +297 -0
  160. data/lib/git/commands/revert/abort.rb +45 -0
  161. data/lib/git/commands/revert/continue.rb +57 -0
  162. data/lib/git/commands/revert/quit.rb +47 -0
  163. data/lib/git/commands/revert/skip.rb +44 -0
  164. data/lib/git/commands/revert/start.rb +153 -0
  165. data/lib/git/commands/revert.rb +29 -0
  166. data/lib/git/commands/rm.rb +114 -0
  167. data/lib/git/commands/show.rb +632 -0
  168. data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
  169. data/lib/git/commands/show_ref/exists.rb +78 -0
  170. data/lib/git/commands/show_ref/list.rb +145 -0
  171. data/lib/git/commands/show_ref/verify.rb +120 -0
  172. data/lib/git/commands/show_ref.rb +42 -0
  173. data/lib/git/commands/stash/apply.rb +75 -0
  174. data/lib/git/commands/stash/branch.rb +65 -0
  175. data/lib/git/commands/stash/clear.rb +41 -0
  176. data/lib/git/commands/stash/create.rb +58 -0
  177. data/lib/git/commands/stash/drop.rb +67 -0
  178. data/lib/git/commands/stash/list.rb +39 -0
  179. data/lib/git/commands/stash/pop.rb +78 -0
  180. data/lib/git/commands/stash/push.rb +103 -0
  181. data/lib/git/commands/stash/show.rb +149 -0
  182. data/lib/git/commands/stash/store.rb +63 -0
  183. data/lib/git/commands/stash.rb +38 -0
  184. data/lib/git/commands/status.rb +169 -0
  185. data/lib/git/commands/symbolic_ref/delete.rb +68 -0
  186. data/lib/git/commands/symbolic_ref/read.rb +95 -0
  187. data/lib/git/commands/symbolic_ref/update.rb +76 -0
  188. data/lib/git/commands/symbolic_ref.rb +38 -0
  189. data/lib/git/commands/tag/create.rb +139 -0
  190. data/lib/git/commands/tag/delete.rb +55 -0
  191. data/lib/git/commands/tag/list.rb +143 -0
  192. data/lib/git/commands/tag/verify.rb +71 -0
  193. data/lib/git/commands/tag.rb +26 -0
  194. data/lib/git/commands/update_ref/batch.rb +140 -0
  195. data/lib/git/commands/update_ref/delete.rb +92 -0
  196. data/lib/git/commands/update_ref/update.rb +106 -0
  197. data/lib/git/commands/update_ref.rb +42 -0
  198. data/lib/git/commands/version.rb +52 -0
  199. data/lib/git/commands/worktree/add.rb +140 -0
  200. data/lib/git/commands/worktree/list.rb +64 -0
  201. data/lib/git/commands/worktree/lock.rb +58 -0
  202. data/lib/git/commands/worktree/management_base.rb +51 -0
  203. data/lib/git/commands/worktree/move.rb +66 -0
  204. data/lib/git/commands/worktree/prune.rb +67 -0
  205. data/lib/git/commands/worktree/remove.rb +63 -0
  206. data/lib/git/commands/worktree/repair.rb +76 -0
  207. data/lib/git/commands/worktree/unlock.rb +47 -0
  208. data/lib/git/commands/worktree.rb +43 -0
  209. data/lib/git/commands/write_tree.rb +68 -0
  210. data/lib/git/commands.rb +89 -0
  211. data/lib/git/detached_head_info.rb +54 -0
  212. data/lib/git/diff.rb +297 -7
  213. data/lib/git/diff_file_numstat_info.rb +29 -0
  214. data/lib/git/diff_file_patch_info.rb +134 -0
  215. data/lib/git/diff_file_raw_info.rb +127 -0
  216. data/lib/git/diff_info.rb +169 -0
  217. data/lib/git/diff_path_status.rb +78 -19
  218. data/lib/git/diff_result.rb +32 -0
  219. data/lib/git/diff_stats.rb +59 -14
  220. data/lib/git/dirstat_info.rb +86 -0
  221. data/lib/git/errors.rb +65 -2
  222. data/lib/git/execution_context/global.rb +56 -0
  223. data/lib/git/execution_context/repository.rb +147 -0
  224. data/lib/git/execution_context.rb +482 -0
  225. data/lib/git/file_ref.rb +74 -0
  226. data/lib/git/fsck_object.rb +9 -9
  227. data/lib/git/fsck_result.rb +1 -1
  228. data/lib/git/lib.rb +1606 -1028
  229. data/lib/git/log.rb +15 -2
  230. data/lib/git/object.rb +92 -22
  231. data/lib/git/parsers/branch.rb +224 -0
  232. data/lib/git/parsers/cat_file.rb +111 -0
  233. data/lib/git/parsers/diff.rb +585 -0
  234. data/lib/git/parsers/fsck.rb +133 -0
  235. data/lib/git/parsers/grep.rb +42 -0
  236. data/lib/git/parsers/ls_tree.rb +58 -0
  237. data/lib/git/parsers/stash.rb +208 -0
  238. data/lib/git/parsers/tag.rb +257 -0
  239. data/lib/git/remote.rb +133 -9
  240. data/lib/git/repository/branching.rb +572 -0
  241. data/lib/git/repository/committing.rb +191 -0
  242. data/lib/git/repository/configuring.rb +156 -0
  243. data/lib/git/repository/diffing.rb +775 -0
  244. data/lib/git/repository/inspecting.rb +153 -0
  245. data/lib/git/repository/logging.rb +247 -0
  246. data/lib/git/repository/merging.rb +295 -0
  247. data/lib/git/repository/object_operations.rb +1101 -0
  248. data/lib/git/repository/path_resolver.rb +207 -0
  249. data/lib/git/repository/remote_operations.rb +753 -0
  250. data/lib/git/repository/shared_private.rb +51 -0
  251. data/lib/git/repository/staging.rb +390 -0
  252. data/lib/git/repository/stashing.rb +107 -0
  253. data/lib/git/repository/status_operations.rb +180 -0
  254. data/lib/git/repository/worktree_operations.rb +159 -0
  255. data/lib/git/repository.rb +264 -1
  256. data/lib/git/stash.rb +85 -4
  257. data/lib/git/stash_info.rb +104 -0
  258. data/lib/git/stashes.rb +130 -13
  259. data/lib/git/status.rb +224 -18
  260. data/lib/git/tag_delete_failure.rb +31 -0
  261. data/lib/git/tag_delete_result.rb +63 -0
  262. data/lib/git/tag_info.rb +105 -0
  263. data/lib/git/version.rb +109 -2
  264. data/lib/git/version_constraint.rb +81 -0
  265. data/lib/git/worktree.rb +120 -5
  266. data/lib/git/worktrees.rb +107 -7
  267. data/lib/git.rb +114 -18
  268. data/redesign/1_architecture_existing.md +54 -18
  269. data/redesign/2_architecture_redesign.md +365 -46
  270. data/redesign/3_architecture_implementation.md +1451 -54
  271. data/tasks/gem_tasks.rake +4 -0
  272. data/tasks/npm_tasks.rake +7 -0
  273. data/tasks/rspec.rake +48 -0
  274. data/tasks/test.rake +13 -1
  275. data/tasks/yard.rake +34 -7
  276. metadata +349 -20
  277. data/lib/git/index.rb +0 -6
  278. data/lib/git/path.rb +0 -38
  279. data/lib/git/working_directory.rb +0 -6
  280. /data/{release-please-config.json → .release-please-config.json} +0 -0
@@ -0,0 +1,260 @@
1
+ ---
2
+ name: facade-implementation
3
+ description: "Scaffolds new and reviews existing Git::Repository facade methods (organized into Git::Repository::* topic modules) with unit tests, integration tests, and YARD docs. Use when adding a new facade method to Git::Repository, updating an existing facade method, choosing or creating a topic module under lib/git/repository/, or reviewing a facade method for correctness."
4
+ ---
5
+
6
+ # Facade Implementation
7
+
8
+ Scaffold new and review existing facade methods on `Git::Repository`. Facade methods
9
+ live in topic modules under `lib/git/repository/<topic>.rb` (e.g.
10
+ {Git::Repository::Staging}) and are included into the `Git::Repository` class.
11
+
12
+ A facade method is the public-API entry point that orchestrates one or more
13
+ `Git::Commands::*` calls, optional argument pre-processing, and optional output
14
+ parsing into rich Ruby return values. See
15
+ [redesign/2_architecture_redesign.md §2.1](../../../redesign/2_architecture_redesign.md)
16
+ for the five facade responsibilities this layer is designed around.
17
+
18
+ ## Contents
19
+
20
+ - [Related skills](#related-skills)
21
+ - [Input](#input)
22
+ - [Existing facade source](#existing-facade-source)
23
+ - [Existing facade tests](#existing-facade-tests)
24
+ - [Underlying command class(es)](#underlying-command-classes)
25
+ - [Underlying parsers (if any)](#underlying-parsers-if-any)
26
+ - [Reference](#reference)
27
+ - [Workflow](#workflow)
28
+ - [Output](#output)
29
+
30
+ ## Related skills
31
+
32
+ - [Facade Test Conventions](../facade-test-conventions/SKILL.md) — unit and
33
+ integration test conventions for facade methods (load when scaffolding or
34
+ reviewing tests)
35
+ - [Facade YARD Documentation](../facade-yard-documentation/SKILL.md) — facade-specific
36
+ YARD rules for module-level and method-level docs
37
+ - [Extract Facade from Base/Lib](../extract-facade-from-base-lib/SKILL.md) — when a
38
+ new facade method is migrated from `Git::Base` or `Git::Lib`, the extraction
39
+ workflow drives this skill in scaffold/update mode
40
+ - [Command Implementation](../command-implementation/SKILL.md) — the underlying
41
+ `Git::Commands::*` classes a facade method calls. Scaffold any missing command
42
+ class first.
43
+ - [YARD Documentation](../yard-documentation/SKILL.md) — baseline YARD formatting
44
+ rules
45
+ - [RSpec Unit Testing Standards](../rspec-unit-testing-standards/SKILL.md) — baseline
46
+ RSpec rules
47
+ - [Project Context](../project-context/SKILL.md) — three-layer architecture overview
48
+
49
+ ## Input
50
+
51
+ The user provides:
52
+
53
+ 1. **Method name** — the public Ruby method name (e.g. `add`, `branches_all`,
54
+ `commit`).
55
+ 2. **Git operation(s)** — which `Git::Commands::*` class(es) the method orchestrates.
56
+ If the relevant command class does not exist yet, scaffold it first via
57
+ [Command Implementation](../command-implementation/SKILL.md).
58
+ 3. **Optional context** — the source `Git::Lib` / `Git::Base` method when migrating
59
+ (handled by [Extract Facade from Base/Lib](../extract-facade-from-base-lib/SKILL.md)).
60
+
61
+ > **Note:** `Git::Repository` is intentionally empty during early phases of the
62
+ > redesign. Its `initialize(execution_context:)` constructor is introduced
63
+ > alongside the first facade method extraction; subsequent extractions only
64
+ > add new topic modules and `include` lines.
65
+
66
+ The agent then gathers:
67
+
68
+ ### Existing facade source
69
+
70
+ Read `lib/git/repository.rb` to see the `include Git::Repository::<Topic>` lines and
71
+ which topic modules exist. List `lib/git/repository/` to see all current topic
72
+ modules and the facade methods they already define.
73
+
74
+ Skip when scaffolding into a brand-new topic module.
75
+
76
+ ### Existing facade tests
77
+
78
+ Read `spec/unit/git/repository/<topic>_spec.rb` and
79
+ `spec/integration/git/repository/<topic>_spec.rb` (if present). Use as supplemental
80
+ evidence of the existing test style before extending or reviewing.
81
+
82
+ ### Underlying command class(es)
83
+
84
+ Read `lib/git/commands/<command>.rb` for each command the facade method calls.
85
+ The command's `arguments do` block defines the option keys the facade may forward,
86
+ and the YARD `@!method call` block documents what each option does. The facade must
87
+ not pass option keys the command does not declare.
88
+
89
+ ### Underlying parsers (if any)
90
+
91
+ Read `lib/git/parsers/<parser>.rb` for any parser the facade uses to transform
92
+ command stdout into structured data.
93
+
94
+ ## Reference
95
+
96
+ See [REFERENCE.md](REFERENCE.md) for the full reference covering:
97
+
98
+ - Files to generate
99
+ - Topic module selection (existing modules + decision rules for creating a new module)
100
+ - Designing a facade method (return type, signature, body shape)
101
+ - Topic module skeleton (file layout)
102
+ - The five facade responsibilities as a checklist
103
+ - Argument pre-processing patterns (path normalization, option whitelisting via
104
+ `SharedPrivate.assert_valid_opts!` + `private_constant`,
105
+ deprecation handling, defaults)
106
+ - Internal helpers and encapsulation (sibling `module_function` modules under
107
+ `lib/git/repository/` instead of private methods on `Git::Repository`;
108
+ bare-noun naming; growth path from `SharedPrivate` to responsibility-named
109
+ modules)
110
+ - When to call multiple commands (orchestration sequences)
111
+ - When to use a parser vs. raw stdout
112
+ - When to use a result-class factory method
113
+ - Common failures (one-line delegation when orchestration is needed; leaking
114
+ command-class types into the public API; bypassing the execution context;
115
+ hardcoding policy options the caller cannot override)
116
+
117
+ Subagents load REFERENCE.md directly during the workflow steps that need it.
118
+
119
+ ## Workflow
120
+
121
+ This skill supports three modes. Determine which mode applies before starting:
122
+
123
+ - **Scaffold** — adding a new facade method (and possibly a new topic module).
124
+ Follow all steps.
125
+ - **Update** — modifying an existing facade method (e.g. adding a new option to
126
+ forward). Skip step 2 (module selection); steps 3a–3c are extending existing files
127
+ rather than creating them.
128
+ - **Review** — auditing an existing facade method (no changes). Follow all steps but
129
+ produce findings instead of code.
130
+
131
+ 1. **Gather input** — collect the method name, target git operation(s), and any
132
+ migration source per [Input](#input). Read the underlying command class(es) and
133
+ parser(s) the method will call.
134
+
135
+ 2. **Choose the topic module** — load
136
+ [REFERENCE.md](REFERENCE.md) and apply [Topic module
137
+ selection](REFERENCE.md#topic-module-selection):
138
+
139
+ - Prefer extending an existing module under `lib/git/repository/`.
140
+ - Create a new module only when the topic is recognizable — preferably
141
+ matching a git-scm category (<https://git-scm.com/docs>) — and the methods
142
+ would be awkward to place in any existing module. The deciding factor is
143
+ topic fit, not method count; a single method that is genuinely distinct
144
+ can start its own module.
145
+ - New module names follow the two-tier convention: gerund (`Staging`, `Logging`,
146
+ `Diffing`) for single-action modules; `Noun + Operations` (`RemoteOperations`,
147
+ `ObjectOperations`) for mixed-bag modules. See
148
+ [REFERENCE.md §Naming a new topic module](REFERENCE.md#naming-a-new-topic-module).
149
+
150
+ 3. **For the facade method**, repeat steps 3a–3e:
151
+
152
+ a. **Scaffold the facade method (subagent)** *(scaffold/update modes only)* —
153
+ delegate to a subagent: load [REFERENCE.md](REFERENCE.md) and the
154
+ [Facade YARD Documentation](../facade-yard-documentation/SKILL.md) skill,
155
+ then create or extend `lib/git/repository/<topic>.rb` using the [Designing
156
+ a facade method](REFERENCE.md#designing-a-facade-method) section and
157
+ [Topic module skeleton](REFERENCE.md#topic-module-skeleton). For new topic
158
+ modules, also add the `require` and `include` lines to
159
+ `lib/git/repository.rb`.
160
+
161
+ Steps 3b and 3c may run **in parallel** (they produce independent files).
162
+
163
+ b. **Scaffold unit tests (subagent)** *(scaffold/update modes only)* — delegate
164
+ to a subagent: load **[Facade Test
165
+ Conventions](../facade-test-conventions/SKILL.md)** (which loads [RSpec Unit
166
+ Testing Standards](../rspec-unit-testing-standards/SKILL.md)), then create or
167
+ extend `spec/unit/git/repository/<topic>_spec.rb` following the unit
168
+ conventions (stub `Git::Commands::*` and `Git::Parsers::*` via
169
+ `instance_double`; assert delegation contracts; cover each pre-processing
170
+ branch).
171
+
172
+ c. **Scaffold integration tests (subagent)** *(scaffold/update modes only)* —
173
+ delegate to a subagent: load **[Facade Test
174
+ Conventions](../facade-test-conventions/SKILL.md)**, then create or extend
175
+ `spec/integration/git/repository/<topic>_spec.rb` following the integration
176
+ conventions (real git in a temp repository; assert end-to-end Ruby return
177
+ value, not intermediate command results). Skip integration tests for true
178
+ one-line delegators that add no orchestration on top of the underlying
179
+ command — the command's own integration tests already cover that path.
180
+
181
+ Steps 3d and 3e may run **in parallel** (they review independent file sets).
182
+
183
+ d. **Review Facade Tests (subagent)** — delegate to a subagent: load and apply
184
+ **[Facade Test Conventions](../facade-test-conventions/SKILL.md)** against the
185
+ unit and integration spec files. In *scaffold/update* modes, fix all findings
186
+ and repeat until clean. In *review* mode, record findings only.
187
+
188
+ e. **Review YARD Documentation (subagent)** — delegate to a subagent: load and
189
+ apply **[Facade YARD Documentation](../facade-yard-documentation/SKILL.md)**
190
+ against the topic module file. In *scaffold/update* modes, fix all findings
191
+ and repeat until clean. In *review* mode, record findings only.
192
+
193
+ 4. **Review facade shape and orchestration** — load
194
+ [REFERENCE.md](REFERENCE.md) and verify against the [Five facade
195
+ responsibilities checklist](REFERENCE.md#the-five-facade-responsibilities-checklist),
196
+ the [Designing a facade method](REFERENCE.md#designing-a-facade-method) section, and
197
+ [Common failures](REFERENCE.md#common-failures). Confirm the method:
198
+
199
+ - delegates to a `Git::Commands::*` class via `@execution_context` (never
200
+ constructs commands with `self` or builds CLI argv directly)
201
+ - does not return a `Git::CommandLineResult` from the public contract unless
202
+ that is the documented return type for the entire topic module
203
+ - whitelists forwarded options when the caller's hash is opaque
204
+ (per-method `<METHOD>_ALLOWED_OPTS` constant +
205
+ `SharedPrivate.assert_valid_opts!(allowed, **)` — do **not**
206
+ also `slice`; see [Option
207
+ whitelisting](REFERENCE.md#option-whitelisting-preventing-api-expansion))
208
+ - places each `<METHOD>_ALLOWED_OPTS` constant **immediately before** the
209
+ method that uses it (not grouped at the top of the module)
210
+ - handles defaults and deprecations explicitly, not by relying on command
211
+ internals
212
+ - is explicitly classified as `legacy-contract` (legacy predecessor exists)
213
+ or `5.x-native` (new facade API), and signature shape matches that
214
+ classification
215
+ - has tests that verify call-shape compatibility when classification is
216
+ `legacy-contract` (positional hash and/or keyword-arg / `**opts` forms where required)
217
+
218
+ 5. **Run quality gates** — discover the prerequisite tasks for `default:parallel`
219
+ and run them sequentially, fixing failures before advancing:
220
+
221
+ ```bash
222
+ bundle exec ruby -e "require 'rake'; load 'Rakefile'; puts Rake::Task['default:parallel'].prerequisites"
223
+ ```
224
+
225
+ Run each listed task **individually** in order via `bundle exec rake <task>`
226
+ (one task per invocation). On failure, fix the issue and re-run that same task.
227
+ Continue until every task passes on its first attempt with no fixes needed.
228
+
229
+ ## Output
230
+
231
+ For **scaffold** and **update** modes, produce:
232
+
233
+ 1. **Topic module** — `lib/git/repository/<topic>.rb` (created or extended)
234
+ 2. **Facade wiring** — `lib/git/repository.rb` updated with `require` and `include`
235
+ when a new topic module was created
236
+ 3. **Unit tests** — `spec/unit/git/repository/<topic>_spec.rb`
237
+ 4. **Integration tests** — `spec/integration/git/repository/<topic>_spec.rb`
238
+ (omit only for true one-line delegators)
239
+ 5. **All quality gates pass** — rspec, minitest, rubocop, and yard all green
240
+
241
+ For **review** mode, produce:
242
+
243
+ | Check | Status | Issue |
244
+ | --- | --- | --- |
245
+ | Topic module placement | Pass/Fail | ... |
246
+ | Orchestration via `@execution_context` | Pass/Fail | ... |
247
+ | Argument pre-processing complete | Pass/Fail | ... |
248
+ | Option whitelisting (where required) | Pass/Fail | ... |
249
+ | `*_ALLOWED_OPTS` placed immediately before its method | Pass/Fail | ... |
250
+ | Signature classification documented | Pass/Fail | ... |
251
+ | Signature shape matches classification | Pass/Fail | ... |
252
+ | Return value matches documented contract | Pass/Fail | ... |
253
+ | Parser/result-class wiring correct | Pass/Fail | ... |
254
+ | YARD docs complete | Pass/Fail | ... |
255
+ | Unit + integration coverage | Pass/Fail | ... |
256
+
257
+ Then list required fixes.
258
+ > **Branch workflow:** Implement scaffolding or updates on a feature branch.
259
+ > Never commit or push directly to `main` — open a pull request when changes
260
+ > are ready to merge.
@@ -0,0 +1,380 @@
1
+ ---
2
+ name: facade-test-conventions
3
+ description: "Conventions for writing and reviewing unit and integration tests for Git::Repository facade methods (modules under lib/git/repository/). Use when scaffolding new facade tests or auditing existing ones in spec/unit/git/repository/ and spec/integration/git/repository/."
4
+ ---
5
+
6
+ # Facade Test Conventions
7
+
8
+ Conventions for writing and reviewing unit and integration tests for facade
9
+ methods on `Git::Repository::*` modules.
10
+
11
+ ## Contents
12
+
13
+ - [Related skills](#related-skills)
14
+ - [Input](#input)
15
+ - [Reference](#reference)
16
+ - [Unit tests](#unit-tests)
17
+ - [Setup pattern](#setup-pattern)
18
+ - [Cover these cases](#cover-these-cases)
19
+ - [Expectations for command invocation](#expectations-for-command-invocation)
20
+ - [What not to test](#what-not-to-test)
21
+ - [Unit test grouping](#unit-test-grouping)
22
+ - [Integration tests](#integration-tests)
23
+ - [When to write integration tests](#when-to-write-integration-tests)
24
+ - [When to skip integration tests](#when-to-skip-integration-tests)
25
+ - [Integration test grouping](#integration-test-grouping)
26
+ - [What integration tests assert](#what-integration-tests-assert)
27
+ - [What integration tests do not assert](#what-integration-tests-do-not-assert)
28
+ - [Workflow](#workflow)
29
+ - [Output](#output)
30
+ - [When writing new facade tests](#when-writing-new-facade-tests)
31
+ - [When reviewing existing facade tests](#when-reviewing-existing-facade-tests)
32
+
33
+ ## Related skills
34
+
35
+ - [RSpec Unit Testing Standards](../rspec-unit-testing-standards/SKILL.md) — baseline
36
+ RSpec rules that govern all unit test structure, naming, setup, stubbing, and
37
+ coverage; this skill adds facade-specific conventions on top
38
+ - [Facade Implementation](../facade-implementation/SKILL.md) — facade module
39
+ structure and orchestration patterns
40
+ - [Facade YARD Documentation](../facade-yard-documentation/SKILL.md) — YARD docs
41
+ for facade modules and methods
42
+ - [Command Test Conventions](../command-test-conventions/SKILL.md) — sibling skill
43
+ that tests the underlying `Git::Commands::*` classes the facade calls
44
+
45
+ ## Input
46
+
47
+ The invocation needs the unit and/or integration spec file(s) to review. Including
48
+ the corresponding facade module file (`lib/git/repository/<topic>.rb`) provides
49
+ useful context for verifying delegation contracts and option forwarding.
50
+
51
+ **Prerequisite:** Read the **entire** [RSpec Unit Testing
52
+ Standards](../rspec-unit-testing-standards/SKILL.md) skill (line 1 through EOF)
53
+ before beginning. It defines the baseline Rules 1–28 that this skill extends.
54
+
55
+ ## Reference
56
+
57
+ ### Unit tests
58
+
59
+ Facade unit tests verify the **orchestration contract** between the facade method
60
+ and the components it calls (`Git::Commands::*`, `Git::Parsers::*`,
61
+ `Git::ExecutionContext::Repository`). They do not run real git.
62
+
63
+ The collaborators (commands, parsers) are stubbed via `instance_double`. The unit
64
+ test asserts:
65
+
66
+ 1. The facade constructs each command class with the injected
67
+ `@execution_context`.
68
+ 2. Each command's `#call` is invoked with the expected positional and keyword
69
+ arguments (verifying argument pre-processing).
70
+ 3. For multi-command sequences, the calls happen in the documented order.
71
+ 4. The parser/result-class is invoked with the command's stdout (when applicable).
72
+ 5. The facade returns the value its public contract documents.
73
+
74
+ #### Setup pattern
75
+
76
+ ```ruby
77
+ RSpec.describe Git::Repository::Staging do
78
+ let(:execution_context) { instance_double(Git::ExecutionContext::Repository) }
79
+ let(:described_instance) { Git::Repository.new(execution_context: execution_context) }
80
+ let(:command_result) { instance_double(Git::CommandLineResult, stdout: '') }
81
+ let(:add_command) { instance_double(Git::Commands::Add) }
82
+ let(:add_result) { command_result }
83
+
84
+ before do
85
+ allow(Git::Commands::Add).to receive(:new).with(execution_context).and_return(add_command)
86
+ end
87
+
88
+ describe '#add' do
89
+ # ...
90
+ end
91
+ end
92
+ ```
93
+
94
+ The shared `command_result` `let` provides a default empty-stdout result; each
95
+ per-command alias (`add_result`, `branch_list_result`, ...) lets individual
96
+ tests override stdout in isolation — e.g.
97
+ `let(:add_result) { instance_double(Git::CommandLineResult, stdout: 'fixture output') }`
98
+ in a nested `context` — without affecting other tests in the file.
99
+
100
+ Setup invariants:
101
+
102
+ - The subject is an instance of `Git::Repository`, **not** the module itself.
103
+ Modules are mixed into the class; tests must exercise the class to reflect
104
+ real call sites.
105
+ - `execution_context` is an `instance_double(Git::ExecutionContext::Repository)`
106
+ — never a `double('ExecutionContext')` and never a real context.
107
+ - Each command class is stubbed with `allow(Klass).to receive(:new).with(execution_context).and_return(...)`
108
+ so the facade's command construction (with the right execution context) is
109
+ verified by the stub.
110
+
111
+ #### Cover these cases
112
+
113
+ - **Default invocation** — facade called with no arguments (or only required
114
+ positional args) delegates with the documented defaults. Assert the return
115
+ value once per facade method to verify pass-through.
116
+ - **Each positional argument variation** — single value, array, nil where
117
+ applicable.
118
+ - **Each option the facade exposes** — including aliases, deprecated keys, and
119
+ policy defaults the facade applies (`no_edit: true`, etc.).
120
+ - **Multi-command sequences** — when the facade calls more than one command,
121
+ use `expect ... receive(:call).with(...).ordered` to assert ordering and
122
+ intermediate-result wiring.
123
+ - **Parser invocation** — when the facade uses a `Git::Parsers::*` class,
124
+ stub the parser and assert it is called with the command's stdout. Assert the
125
+ facade returns what the parser returned.
126
+ - **Raw `CommandLineResult` return** — when the facade's contract is to
127
+ return the command's `Git::CommandLineResult` directly (not `.stdout` and
128
+ not a parser output), assert `eq(<command>_result)` to verify pass-through.
129
+ - **Option whitelisting** — when the facade defines a `<METHOD>_ALLOWED_OPTS`
130
+ constant and calls `Git::Repository::Internal.assert_valid_opts!`, test that
131
+ an unknown key raises `ArgumentError` and a known key is forwarded.
132
+ - **Deprecation handling** — when the facade rewrites or warns on deprecated
133
+ keys, test that the deprecation warning is emitted and the new key is
134
+ forwarded.
135
+ - **Signature compatibility call shapes** — when a facade method preserves a
136
+ legacy public contract, include tests for each call shape the 4.x public API
137
+ used (positional hash and/or keyword-arg / `**opts` where applicable).
138
+
139
+ #### Expectations for command invocation
140
+
141
+ Use the standard rspec-mocks form (no command-specific helper exists for the
142
+ facade layer):
143
+
144
+ ```ruby
145
+ it 'delegates to Git::Commands::Add#call with the given path' do
146
+ expect(add_command).to receive(:call).with('path/to/file.rb').and_return(add_result)
147
+ described_instance.add('path/to/file.rb')
148
+ end
149
+ ```
150
+
151
+ For command + parser orchestration (single command whose stdout is fed to a
152
+ parser), use `.ordered` to assert the call sequence:
153
+
154
+ ```ruby
155
+ it 'lists branches then parses the output' do
156
+ expect(branch_list_command).to(
157
+ receive(:call)
158
+ .with(all: true, format: Git::Parsers::Branch::FORMAT_STRING)
159
+ .and_return(branch_list_result)
160
+ .ordered
161
+ )
162
+
163
+ expect(Git::Parsers::Branch).to(
164
+ receive(:parse_list)
165
+ .with(branch_list_result.stdout)
166
+ .and_return(parsed_branches)
167
+ .ordered
168
+ )
169
+
170
+ expect(described_instance.branches_all).to eq(parsed_branches)
171
+ end
172
+ ```
173
+
174
+ For genuinely multi-command orchestration (the facade calls more than one
175
+ command), chain `.ordered` across each command's `#call`, wiring intermediate
176
+ results through as needed:
177
+
178
+ ```ruby
179
+ it 'saves the stash then lists stashes' do
180
+ expect(stash_save_command).to(
181
+ receive(:call).with(message: 'wip').and_return(stash_save_result).ordered
182
+ )
183
+
184
+ expect(stash_list_command).to(
185
+ receive(:call).and_return(stash_list_result).ordered
186
+ )
187
+
188
+ expect(described_instance.stash_save_and_list(message: 'wip')).to eq(parsed_stashes)
189
+ end
190
+ ```
191
+
192
+ #### What not to test
193
+
194
+ - **Command argv building.** That is the command class's contract and is covered
195
+ by `spec/unit/git/commands/<command>_spec.rb`. The facade unit test should
196
+ stub `#call` and assert the keyword arguments the facade passes — not assert
197
+ on the CLI tokens that reach git.
198
+ - **Parser internals.** Stub the parser class method and assert the facade calls
199
+ it with the right input. Parser parsing is covered by `spec/unit/git/parsers/`.
200
+ - **Real command execution.** Facade unit tests must not exercise
201
+ `Git::ExecutionContext::Repository` for real. Use `instance_double`.
202
+ - **Multiple input strings exercising the same code path** — one test per
203
+ argument type is sufficient (string vs. array vs. nil), not one per value.
204
+ - **`#initialize` of the facade module.** The module is mixed into
205
+ `Git::Repository`; constructor coverage belongs to `repository_spec.rb`.
206
+
207
+ #### Unit test grouping
208
+
209
+ One `describe '#<method_name>'` block per facade method. Inside, use flat
210
+ `context` blocks per argument variation. Optional sections at the end (in order)
211
+ when present:
212
+
213
+ - `context 'option whitelisting'` —
214
+ `Git::Repository::Internal.assert_valid_opts!` raises on unknown keys and
215
+ forwards known keys unchanged (no `slice` — the assertion is the only
216
+ enforcement mechanism)
217
+ - `context 'deprecation handling'` — `Git::Deprecation.warn` assertions and
218
+ key-rewrite tests
219
+ - `context 'input validation'` — `ArgumentError` raised by the facade itself
220
+ (not by the command)
221
+ - `context 'signature compatibility'` — for legacy-contract methods, exercises
222
+ required call shapes (legacy positional hash and/or keyword-arg / `**opts` forms)
223
+
224
+ The exit code section that command specs use does **not** apply to facade specs
225
+ — exit-status handling is the command's concern; the facade's tests assume the
226
+ command either returns a result or raises.
227
+
228
+ ### Integration tests
229
+
230
+ Facade integration tests run real git in a temp repository and verify the
231
+ **end-to-end Ruby return value** of the facade method.
232
+
233
+ Each integration spec file tests **one facade module** (one
234
+ `spec/integration/git/repository/<topic>_spec.rb`). Inside, group by facade
235
+ method.
236
+
237
+ #### When to write integration tests
238
+
239
+ Facade integration tests are the **exception, not the default**. Most facade
240
+ behavior is already covered end-to-end by the underlying command's own
241
+ integration tests; re-running real git through the facade re-exercises the
242
+ same code path without adding signal.
243
+
244
+ Write a facade integration test only when the facade adds behavior that is
245
+ **not** exercised by any single command's integration tests:
246
+
247
+ - **Multi-command orchestration** — the facade calls more than one command
248
+ and the integration test confirms the documented end-to-end value emerges
249
+ from the sequence against real git.
250
+ - **Facade-owned post-processing of real git output** — the facade itself
251
+ (not the command) parses, aggregates, or transforms raw command output
252
+ before returning. A real git invocation proves the post-processing handles
253
+ actual output rather than a mocked string.
254
+
255
+ #### When to skip integration tests
256
+
257
+ Skip for everything else, including:
258
+
259
+ - **One-line delegators** that pass arguments through to a single command
260
+ with no pre/post-processing (e.g. `Git::Repository::Staging#add`,
261
+ `#reset`).
262
+ - **Single-command facade methods that delegate parsing to a parser or
263
+ result-class factory** — the command's own integration test already
264
+ exercises that command + parser against real git.
265
+ - **Argument pre-processing** (path normalization, deprecation key rewrites,
266
+ option whitelisting) — these are pure-Ruby transforms with no git
267
+ involvement; unit tests prove them and real git adds no signal.
268
+ - **Error-path assertions** (`raise_error(Git::FailedError)`) — these test
269
+ the command's error wrapping, not the facade.
270
+
271
+ When skipping, document why with a code comment in the spec file or a `#`
272
+ header in `spec/integration/git/repository/<topic>_spec.rb` explaining which
273
+ methods are covered exclusively by command integration tests.
274
+
275
+ #### Integration test grouping
276
+
277
+ Mirror the [Command Test Conventions](../command-test-conventions/SKILL.md)
278
+ integration grouping. Use a multi-command or post-processing facade method —
279
+ single-command delegators do not warrant integration tests (see [When to skip
280
+ integration tests](#when-to-skip-integration-tests)):
281
+
282
+ The shared context (e.g. `'in an empty repository'`) provides `repo` and
283
+ `repo_dir` helpers. Facade integration specs must override `execution_context`
284
+ to a `Git::ExecutionContext::Repository` (the shared context's default is
285
+ `repo.lib`, a `Git::Lib`). Stage any required repository state in a `before`
286
+ block inside the spec itself.
287
+
288
+ ```ruby
289
+ RSpec.describe Git::Repository::Stashing, :integration do
290
+ include_context 'in an empty repository' # provides repo and repo_dir helpers
291
+
292
+ let(:execution_context) { Git::ExecutionContext::Repository.from_base(repo) }
293
+ let(:described_instance) { Git::Repository.new(execution_context: execution_context) }
294
+
295
+ before do
296
+ write_file('README.md', 'initial')
297
+ repo.add('README.md')
298
+ repo.commit('Initial commit')
299
+ write_file('README.md', 'work in progress')
300
+ repo.add('README.md')
301
+ end
302
+
303
+ describe '#stash_save_and_list' do
304
+ it 'returns the new stash entry after saving' do
305
+ result = described_instance.stash_save_and_list(message: 'wip')
306
+ expect(result).to all(be_a(Git::Stash))
307
+ expect(result.first.message).to include('wip')
308
+ end
309
+ end
310
+ end
311
+ ```
312
+
313
+ One `context 'when the command succeeds'` block (or just `it` blocks directly
314
+ under `describe`) per facade method, with one or more variations that exercise
315
+ the orchestration sequence or post-processing. Do **not** add a `context 'when
316
+ the command fails'` block — error wrapping is the command's concern and is
317
+ covered by command integration tests.
318
+
319
+ #### What integration tests assert
320
+
321
+ - The Ruby return value's **structure and key fields** (e.g., classes,
322
+ required attributes, presence of expected entries).
323
+ - Multi-command orchestration produces the documented end-to-end value, not
324
+ intermediate command results.
325
+ - For signature-compatibility behavior that is user-visible at runtime,
326
+ integration coverage may assert that legacy call shapes are accepted.
327
+
328
+ #### Review checks for signature policy
329
+
330
+ When reviewing existing facade tests, add these checks:
331
+
332
+ 1. If the method is `legacy-contract`, unit tests cover required call shapes.
333
+ 2. Test expectations validate public contract behavior, not only command
334
+ delegation internals.
335
+
336
+ #### What integration tests do not assert
337
+
338
+ - Specific CLI tokens reaching git (covered by command unit tests).
339
+ - Specific git output formatting (testing git, not the facade).
340
+ - Edge cases that vary between git versions in immaterial ways. Anchor
341
+ assertions on stable inputs (paths, ref names) the test controls — not on git
342
+ message phrasing.
343
+
344
+ ## Workflow
345
+
346
+ 1. Load the [RSpec Unit Testing
347
+ Standards](../rspec-unit-testing-standards/SKILL.md) skill (line 1 through
348
+ EOF).
349
+ 2. Read the spec file(s) under review and the corresponding facade module
350
+ (`lib/git/repository/<topic>.rb`) plus the underlying `Git::Commands::*` and
351
+ `Git::Parsers::*` files the facade calls.
352
+ 3. Audit each spec against the rules in [Reference](#reference), checking unit
353
+ and integration tests separately.
354
+ 4. Produce the [Output](#output).
355
+
356
+ ## Output
357
+
358
+ ### When writing new facade tests
359
+
360
+ Produce the unit and (when applicable) integration spec files following the
361
+ patterns above. Then self-verify by running every checklist item in the
362
+ [Reference](#reference) section against your output.
363
+
364
+ ### When reviewing existing facade tests
365
+
366
+ Provide:
367
+
368
+ 1. issue table
369
+
370
+ | Check | Status | Issue |
371
+ | --- | --- | --- |
372
+
373
+ 2. corrected snippets for failing checks
374
+
375
+ 3. **Self-verify before concluding** — re-run the reference against your proposed
376
+ snippets until all checks pass.
377
+
378
+ > **Branch workflow:** Implement any new or updated tests on a feature branch.
379
+ > Never commit or push directly to `main` — open a pull request when changes are
380
+ > ready to merge.