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.
- checksums.yaml +4 -4
- data/.github/copilot-instructions.md +67 -2705
- data/.github/pull_request_template.md +3 -1
- data/.github/skills/breaking-change-analysis/SKILL.md +102 -0
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +264 -0
- data/.github/skills/command-implementation/REFERENCE.md +993 -0
- data/.github/skills/command-implementation/SKILL.md +229 -0
- data/.github/skills/command-test-conventions/SKILL.md +660 -0
- data/.github/skills/command-yard-documentation/SKILL.md +426 -0
- data/.github/skills/dependency-management/SKILL.md +72 -0
- data/.github/skills/development-workflow/SKILL.md +506 -0
- data/.github/skills/extract-command-from-lib/SKILL.md +487 -0
- data/.github/skills/extract-facade-from-base-lib/SKILL.md +586 -0
- data/.github/skills/facade-implementation/REFERENCE.md +840 -0
- data/.github/skills/facade-implementation/SKILL.md +260 -0
- data/.github/skills/facade-test-conventions/SKILL.md +380 -0
- data/.github/skills/facade-yard-documentation/SKILL.md +429 -0
- data/.github/skills/make-skill-template/SKILL.md +176 -0
- data/.github/skills/pr-readiness-review/SKILL.md +185 -0
- data/.github/skills/project-context/SKILL.md +313 -0
- data/.github/skills/pull-request-review/SKILL.md +168 -0
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +131 -0
- data/.github/skills/release-management/SKILL.md +125 -0
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +788 -0
- data/.github/skills/review-arguments-dsl/SKILL.md +214 -0
- data/.github/skills/review-backward-compatibility/SKILL.md +275 -0
- data/.github/skills/review-cross-command-consistency/SKILL.md +139 -0
- data/.github/skills/reviewing-skills/SKILL.md +189 -0
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +639 -0
- data/.github/skills/tdd-refactor-step/SKILL.md +236 -0
- data/.github/skills/test-debugging/SKILL.md +160 -0
- data/.github/skills/yard-documentation/SKILL.md +793 -0
- data/.github/workflows/continuous_integration.yml +3 -2
- data/.github/workflows/enforce_conventional_commits.yml +1 -1
- data/.github/workflows/experimental_continuous_integration.yml +2 -2
- data/.github/workflows/release.yml +3 -4
- data/.gitignore +8 -0
- data/.husky/pre-commit +13 -0
- data/.release-please-manifest.json +1 -1
- data/.rspec +3 -0
- data/.rubocop.yml +7 -3
- data/.rubocop_todo.yml +23 -5
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -40
- data/CONTRIBUTING.md +694 -53
- data/README.md +17 -5
- data/Rakefile +61 -9
- data/commitlint.test +4 -0
- data/git.gemspec +14 -8
- data/lib/git/args_builder.rb +0 -8
- data/lib/git/base.rb +486 -410
- data/lib/git/branch.rb +380 -43
- data/lib/git/branch_delete_failure.rb +31 -0
- data/lib/git/branch_delete_result.rb +63 -0
- data/lib/git/branch_info.rb +178 -0
- data/lib/git/branches.rb +130 -24
- data/lib/git/command_line/base.rb +245 -0
- data/lib/git/command_line/capturing.rb +249 -0
- data/lib/git/command_line/result.rb +96 -0
- data/lib/git/command_line/streaming.rb +194 -0
- data/lib/git/command_line.rb +43 -322
- data/lib/git/command_line_result.rb +4 -88
- data/lib/git/commands/add.rb +131 -0
- data/lib/git/commands/am/abort.rb +43 -0
- data/lib/git/commands/am/apply.rb +252 -0
- data/lib/git/commands/am/continue.rb +43 -0
- data/lib/git/commands/am/quit.rb +43 -0
- data/lib/git/commands/am/retry.rb +47 -0
- data/lib/git/commands/am/show_current_patch.rb +64 -0
- data/lib/git/commands/am/skip.rb +42 -0
- data/lib/git/commands/am.rb +33 -0
- data/lib/git/commands/apply.rb +237 -0
- data/lib/git/commands/archive/list_formats.rb +46 -0
- data/lib/git/commands/archive.rb +140 -0
- data/lib/git/commands/arguments.rb +3510 -0
- data/lib/git/commands/base.rb +403 -0
- data/lib/git/commands/branch/copy.rb +94 -0
- data/lib/git/commands/branch/create.rb +173 -0
- data/lib/git/commands/branch/delete.rb +80 -0
- data/lib/git/commands/branch/list.rb +162 -0
- data/lib/git/commands/branch/move.rb +94 -0
- data/lib/git/commands/branch/set_upstream.rb +86 -0
- data/lib/git/commands/branch/show_current.rb +49 -0
- data/lib/git/commands/branch/unset_upstream.rb +57 -0
- data/lib/git/commands/branch.rb +34 -0
- data/lib/git/commands/cat_file/batch.rb +364 -0
- data/lib/git/commands/cat_file/filtered.rb +105 -0
- data/lib/git/commands/cat_file/raw.rb +210 -0
- data/lib/git/commands/cat_file.rb +49 -0
- data/lib/git/commands/checkout/branch.rb +151 -0
- data/lib/git/commands/checkout/files.rb +115 -0
- data/lib/git/commands/checkout.rb +38 -0
- data/lib/git/commands/checkout_index.rb +105 -0
- data/lib/git/commands/clean.rb +100 -0
- data/lib/git/commands/clone.rb +240 -0
- data/lib/git/commands/commit.rb +272 -0
- data/lib/git/commands/commit_tree.rb +100 -0
- data/lib/git/commands/config_option_syntax/add.rb +83 -0
- data/lib/git/commands/config_option_syntax/get.rb +117 -0
- data/lib/git/commands/config_option_syntax/get_all.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_color.rb +91 -0
- data/lib/git/commands/config_option_syntax/get_color_bool.rb +93 -0
- data/lib/git/commands/config_option_syntax/get_regexp.rb +115 -0
- data/lib/git/commands/config_option_syntax/get_urlmatch.rb +102 -0
- data/lib/git/commands/config_option_syntax/list.rb +107 -0
- data/lib/git/commands/config_option_syntax/remove_section.rb +74 -0
- data/lib/git/commands/config_option_syntax/rename_section.rb +78 -0
- data/lib/git/commands/config_option_syntax/replace_all.rb +104 -0
- data/lib/git/commands/config_option_syntax/set.rb +114 -0
- data/lib/git/commands/config_option_syntax/unset.rb +89 -0
- data/lib/git/commands/config_option_syntax/unset_all.rb +89 -0
- data/lib/git/commands/config_option_syntax.rb +56 -0
- data/lib/git/commands/describe.rb +155 -0
- data/lib/git/commands/diff.rb +656 -0
- data/lib/git/commands/diff_files.rb +518 -0
- data/lib/git/commands/diff_index.rb +496 -0
- data/lib/git/commands/fetch.rb +352 -0
- data/lib/git/commands/fsck.rb +136 -0
- data/lib/git/commands/gc.rb +132 -0
- data/lib/git/commands/grep.rb +338 -0
- data/lib/git/commands/init.rb +99 -0
- data/lib/git/commands/log.rb +632 -0
- data/lib/git/commands/ls_files.rb +191 -0
- data/lib/git/commands/ls_remote.rb +155 -0
- data/lib/git/commands/ls_tree.rb +131 -0
- data/lib/git/commands/maintenance/register.rb +75 -0
- data/lib/git/commands/maintenance/run.rb +104 -0
- data/lib/git/commands/maintenance/start.rb +66 -0
- data/lib/git/commands/maintenance/stop.rb +55 -0
- data/lib/git/commands/maintenance/unregister.rb +79 -0
- data/lib/git/commands/maintenance.rb +31 -0
- data/lib/git/commands/merge/abort.rb +44 -0
- data/lib/git/commands/merge/continue.rb +44 -0
- data/lib/git/commands/merge/quit.rb +46 -0
- data/lib/git/commands/merge/start.rb +245 -0
- data/lib/git/commands/merge.rb +28 -0
- data/lib/git/commands/merge_base.rb +86 -0
- data/lib/git/commands/mv.rb +77 -0
- data/lib/git/commands/name_rev.rb +114 -0
- data/lib/git/commands/pull.rb +377 -0
- data/lib/git/commands/push.rb +246 -0
- data/lib/git/commands/read_tree.rb +149 -0
- data/lib/git/commands/remote/add.rb +91 -0
- data/lib/git/commands/remote/get_url.rb +66 -0
- data/lib/git/commands/remote/list.rb +54 -0
- data/lib/git/commands/remote/prune.rb +61 -0
- data/lib/git/commands/remote/remove.rb +52 -0
- data/lib/git/commands/remote/rename.rb +69 -0
- data/lib/git/commands/remote/set_branches.rb +63 -0
- data/lib/git/commands/remote/set_head.rb +82 -0
- data/lib/git/commands/remote/set_url.rb +71 -0
- data/lib/git/commands/remote/set_url_add.rb +61 -0
- data/lib/git/commands/remote/set_url_delete.rb +64 -0
- data/lib/git/commands/remote/show.rb +71 -0
- data/lib/git/commands/remote/update.rb +72 -0
- data/lib/git/commands/remote.rb +42 -0
- data/lib/git/commands/repack.rb +277 -0
- data/lib/git/commands/reset.rb +147 -0
- data/lib/git/commands/rev_parse.rb +297 -0
- data/lib/git/commands/revert/abort.rb +45 -0
- data/lib/git/commands/revert/continue.rb +57 -0
- data/lib/git/commands/revert/quit.rb +47 -0
- data/lib/git/commands/revert/skip.rb +44 -0
- data/lib/git/commands/revert/start.rb +153 -0
- data/lib/git/commands/revert.rb +29 -0
- data/lib/git/commands/rm.rb +114 -0
- data/lib/git/commands/show.rb +632 -0
- data/lib/git/commands/show_ref/exclude_existing.rb +120 -0
- data/lib/git/commands/show_ref/exists.rb +78 -0
- data/lib/git/commands/show_ref/list.rb +145 -0
- data/lib/git/commands/show_ref/verify.rb +120 -0
- data/lib/git/commands/show_ref.rb +42 -0
- data/lib/git/commands/stash/apply.rb +75 -0
- data/lib/git/commands/stash/branch.rb +65 -0
- data/lib/git/commands/stash/clear.rb +41 -0
- data/lib/git/commands/stash/create.rb +58 -0
- data/lib/git/commands/stash/drop.rb +67 -0
- data/lib/git/commands/stash/list.rb +39 -0
- data/lib/git/commands/stash/pop.rb +78 -0
- data/lib/git/commands/stash/push.rb +103 -0
- data/lib/git/commands/stash/show.rb +149 -0
- data/lib/git/commands/stash/store.rb +63 -0
- data/lib/git/commands/stash.rb +38 -0
- data/lib/git/commands/status.rb +169 -0
- data/lib/git/commands/symbolic_ref/delete.rb +68 -0
- data/lib/git/commands/symbolic_ref/read.rb +95 -0
- data/lib/git/commands/symbolic_ref/update.rb +76 -0
- data/lib/git/commands/symbolic_ref.rb +38 -0
- data/lib/git/commands/tag/create.rb +139 -0
- data/lib/git/commands/tag/delete.rb +55 -0
- data/lib/git/commands/tag/list.rb +143 -0
- data/lib/git/commands/tag/verify.rb +71 -0
- data/lib/git/commands/tag.rb +26 -0
- data/lib/git/commands/update_ref/batch.rb +140 -0
- data/lib/git/commands/update_ref/delete.rb +92 -0
- data/lib/git/commands/update_ref/update.rb +106 -0
- data/lib/git/commands/update_ref.rb +42 -0
- data/lib/git/commands/version.rb +52 -0
- data/lib/git/commands/worktree/add.rb +140 -0
- data/lib/git/commands/worktree/list.rb +64 -0
- data/lib/git/commands/worktree/lock.rb +58 -0
- data/lib/git/commands/worktree/management_base.rb +51 -0
- data/lib/git/commands/worktree/move.rb +66 -0
- data/lib/git/commands/worktree/prune.rb +67 -0
- data/lib/git/commands/worktree/remove.rb +63 -0
- data/lib/git/commands/worktree/repair.rb +76 -0
- data/lib/git/commands/worktree/unlock.rb +47 -0
- data/lib/git/commands/worktree.rb +43 -0
- data/lib/git/commands/write_tree.rb +68 -0
- data/lib/git/commands.rb +89 -0
- data/lib/git/detached_head_info.rb +54 -0
- data/lib/git/diff.rb +297 -7
- data/lib/git/diff_file_numstat_info.rb +29 -0
- data/lib/git/diff_file_patch_info.rb +134 -0
- data/lib/git/diff_file_raw_info.rb +127 -0
- data/lib/git/diff_info.rb +169 -0
- data/lib/git/diff_path_status.rb +78 -19
- data/lib/git/diff_result.rb +32 -0
- data/lib/git/diff_stats.rb +59 -14
- data/lib/git/dirstat_info.rb +86 -0
- data/lib/git/errors.rb +65 -2
- data/lib/git/execution_context/global.rb +56 -0
- data/lib/git/execution_context/repository.rb +147 -0
- data/lib/git/execution_context.rb +482 -0
- data/lib/git/file_ref.rb +74 -0
- data/lib/git/fsck_object.rb +9 -9
- data/lib/git/fsck_result.rb +1 -1
- data/lib/git/lib.rb +1606 -1028
- data/lib/git/log.rb +15 -2
- data/lib/git/object.rb +92 -22
- data/lib/git/parsers/branch.rb +224 -0
- data/lib/git/parsers/cat_file.rb +111 -0
- data/lib/git/parsers/diff.rb +585 -0
- data/lib/git/parsers/fsck.rb +133 -0
- data/lib/git/parsers/grep.rb +42 -0
- data/lib/git/parsers/ls_tree.rb +58 -0
- data/lib/git/parsers/stash.rb +208 -0
- data/lib/git/parsers/tag.rb +257 -0
- data/lib/git/remote.rb +133 -9
- data/lib/git/repository/branching.rb +572 -0
- data/lib/git/repository/committing.rb +191 -0
- data/lib/git/repository/configuring.rb +156 -0
- data/lib/git/repository/diffing.rb +775 -0
- data/lib/git/repository/inspecting.rb +153 -0
- data/lib/git/repository/logging.rb +247 -0
- data/lib/git/repository/merging.rb +295 -0
- data/lib/git/repository/object_operations.rb +1101 -0
- data/lib/git/repository/path_resolver.rb +207 -0
- data/lib/git/repository/remote_operations.rb +753 -0
- data/lib/git/repository/shared_private.rb +51 -0
- data/lib/git/repository/staging.rb +390 -0
- data/lib/git/repository/stashing.rb +107 -0
- data/lib/git/repository/status_operations.rb +180 -0
- data/lib/git/repository/worktree_operations.rb +159 -0
- data/lib/git/repository.rb +264 -1
- data/lib/git/stash.rb +85 -4
- data/lib/git/stash_info.rb +104 -0
- data/lib/git/stashes.rb +130 -13
- data/lib/git/status.rb +224 -18
- data/lib/git/tag_delete_failure.rb +31 -0
- data/lib/git/tag_delete_result.rb +63 -0
- data/lib/git/tag_info.rb +105 -0
- data/lib/git/version.rb +109 -2
- data/lib/git/version_constraint.rb +81 -0
- data/lib/git/worktree.rb +120 -5
- data/lib/git/worktrees.rb +107 -7
- data/lib/git.rb +114 -18
- data/redesign/1_architecture_existing.md +54 -18
- data/redesign/2_architecture_redesign.md +365 -46
- data/redesign/3_architecture_implementation.md +1451 -54
- data/tasks/gem_tasks.rake +4 -0
- data/tasks/npm_tasks.rake +7 -0
- data/tasks/rspec.rake +48 -0
- data/tasks/test.rake +13 -1
- data/tasks/yard.rake +34 -7
- metadata +349 -20
- data/lib/git/index.rb +0 -6
- data/lib/git/path.rb +0 -38
- data/lib/git/working_directory.rb +0 -6
- /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.
|