git 5.1.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -0
- data/CONTRIBUTING.md +185 -165
- data/LICENSE +1 -1
- data/README.md +151 -151
- data/git.gemspec +35 -3
- data/lib/git/command_line/base.rb +1 -2
- data/lib/git/commands/base.rb +1 -1
- data/lib/git/commands/cat_file/raw.rb +8 -7
- data/lib/git/repository/branching.rb +79 -5
- data/lib/git/version.rb +1 -1
- metadata +5 -94
- data/.claude/commands/address-copilot-reviews.md +0 -14
- data/.claude/settings.json +0 -16
- data/.claude/skills +0 -1
- data/.commitlintrc.yml +0 -38
- data/.dockerignore +0 -27
- data/.github/copilot-instructions.md +0 -30
- data/.github/hooks/bin-setup-on-worktree.json +0 -11
- data/.github/hooks/run-bin-setup-once.sh +0 -20
- data/.github/issue_template.md +0 -15
- data/.github/prompts/iteratively-address-copilot-reviews.prompt.md +0 -188
- data/.github/pull_request_template.md +0 -21
- data/.github/skills/breaking-change-analysis/SKILL.md +0 -99
- data/.github/skills/ci-cd-troubleshooting/SKILL.md +0 -264
- data/.github/skills/command-implementation/REFERENCE.md +0 -994
- data/.github/skills/command-implementation/SKILL.md +0 -230
- data/.github/skills/command-test-conventions/SKILL.md +0 -664
- data/.github/skills/command-yard-documentation/SKILL.md +0 -434
- data/.github/skills/dependency-management/SKILL.md +0 -72
- data/.github/skills/development-workflow/SKILL.md +0 -512
- data/.github/skills/facade-implementation/REFERENCE.md +0 -837
- data/.github/skills/facade-implementation/SKILL.md +0 -269
- data/.github/skills/facade-test-conventions/SKILL.md +0 -391
- data/.github/skills/facade-yard-documentation/SKILL.md +0 -435
- data/.github/skills/make-skill-template/SKILL.md +0 -226
- data/.github/skills/pr-readiness-review/SKILL.md +0 -205
- data/.github/skills/project-context/SKILL.md +0 -306
- data/.github/skills/pull-request-review/SKILL.md +0 -168
- data/.github/skills/rebase/SKILL.md +0 -148
- data/.github/skills/refactor-command-to-commandlineresult/SKILL.md +0 -131
- data/.github/skills/release-management/SKILL.md +0 -125
- data/.github/skills/resolve-feedback/SKILL.md +0 -288
- data/.github/skills/review-arguments-dsl/CHECKLIST.md +0 -788
- data/.github/skills/review-arguments-dsl/SKILL.md +0 -214
- data/.github/skills/review-cross-command-consistency/SKILL.md +0 -139
- data/.github/skills/reviewing-skills/SKILL.md +0 -214
- data/.github/skills/rspec-unit-testing-standards/SKILL.md +0 -685
- data/.github/skills/tdd-refactor-step/SKILL.md +0 -236
- data/.github/skills/test-debugging/SKILL.md +0 -161
- data/.github/skills/yard-documentation/SKILL.md +0 -981
- data/.github/skills/yard-documentation/element-rules.md +0 -162
- data/.github/skills-deprecated/README.md +0 -21
- data/.github/skills-deprecated/extract-command-from-lib/SKILL.md +0 -487
- data/.github/skills-deprecated/extract-facade-from-base-lib/KEYWORD_ARG_REMEDIATION.md +0 -22
- data/.github/skills-deprecated/extract-facade-from-base-lib/SKILL.md +0 -600
- data/.github/skills-deprecated/review-backward-compatibility/SKILL.md +0 -275
- data/.github/workflows/continuous_integration.yml +0 -358
- data/.github/workflows/enforce_conventional_commits.yml +0 -35
- data/.github/workflows/experimental_continuous_integration.yml +0 -59
- data/.github/workflows/release.yml +0 -52
- data/.github/workflows/warm_bundler_caches.yml +0 -82
- data/.gitignore +0 -30
- data/.husky/commit-msg +0 -1
- data/.husky/pre-commit +0 -13
- data/.release-please-config.json +0 -36
- data/.release-please-manifest.json +0 -3
- data/.rspec +0 -2
- data/.rubocop.yml +0 -44
- data/.rubocop_todo.yml +0 -30
- data/.yard-lint.yml +0 -75
- data/CLAUDE.md +0 -11
- data/Gemfile +0 -22
- data/Rakefile +0 -41
- data/docker/test/Dockerfile +0 -32
- data/docker/test/docker-compose.yml +0 -0
- data/package.json +0 -10
- data/redesign/1_architecture_existing.md +0 -102
- data/redesign/2_architecture_redesign.md +0 -449
- data/redesign/3_architecture_implementation.md +0 -1623
- data/redesign/Phase 4 - Step A.md +0 -366
- data/redesign/Phase 4 - Step B.md +0 -921
- data/redesign/Phase 4 - Step C.md +0 -833
- data/redesign/beta_release.md +0 -107
- data/redesign/branch_parse_refactor_plan.md +0 -163
- data/redesign/c1a-public-api-scope.tsv +0 -256
- data/redesign/c1c2_audit.md +0 -566
- data/redesign/c1c2_bucket6_lib_orphans.md +0 -626
- data/redesign/config_design.rb +0 -501
- data/redesign/index.md +0 -34
- data/redesign/info_object_migration_plan.md +0 -126
- data/redesign/integration_test_analysis.md +0 -521
- data/redesign/phase-4-step-b-test-audit.tsv +0 -485
- data/redesign/remote_refactor_plan.md +0 -164
- data/redesign/reverse_dependencies.sql +0 -44
- data/tasks/gem_tasks.rake +0 -14
- data/tasks/npm_tasks.rake +0 -7
- data/tasks/rspec.rake +0 -111
- data/tasks/rubocop.rake +0 -5
- data/tasks/test_gem.rake +0 -12
- data/tasks/yard.rake +0 -57
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: review-backward-compatibility
|
|
3
|
-
description: "Audits Git::Lib methods for backward compatibility after commands are moved to Git::Commands::* classes. Use to verify that migrated commands maintain their existing public API."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Review Backward Compatibility
|
|
7
|
-
|
|
8
|
-
Review `Git::Lib` methods for backward compatibility after commands are moved to
|
|
9
|
-
`Git::Commands::*` classes. This skill guides the process of restoring backward
|
|
10
|
-
compatibility for a specific set of git commands while maintaining the benefits of
|
|
11
|
-
the new command infrastructure.
|
|
12
|
-
|
|
13
|
-
## Contents
|
|
14
|
-
|
|
15
|
-
- [How to use this skill](#how-to-use-this-skill)
|
|
16
|
-
- [Related skills](#related-skills)
|
|
17
|
-
- [Objective](#objective)
|
|
18
|
-
- [Current Command Architecture Note](#current-command-architecture-note)
|
|
19
|
-
- [Instructions](#instructions)
|
|
20
|
-
- [Branch setup](#branch-setup)
|
|
21
|
-
- [Step 1: Identify Methods Added Since v4.3.0](#step-1-identify-methods-added-since-v430)
|
|
22
|
-
- [Step 2: Remove New Methods](#step-2-remove-new-methods)
|
|
23
|
-
- [Step 3: Restore Backward-Compatible Implementations](#step-3-restore-backward-compatible-implementations)
|
|
24
|
-
- [Step 4: Add Required Dependencies](#step-4-add-required-dependencies)
|
|
25
|
-
- [Step 5: Verify the Changes](#step-5-verify-the-changes)
|
|
26
|
-
- [Example: Stash Commands](#example-stash-commands)
|
|
27
|
-
- [Legacy Methods (v4.3.0)](#legacy-methods-v430)
|
|
28
|
-
- [New Methods (removed)](#new-methods-removed)
|
|
29
|
-
- [Implementation Pattern](#implementation-pattern)
|
|
30
|
-
- [Key Principles](#key-principles)
|
|
31
|
-
- [Validation Checklist](#validation-checklist)
|
|
32
|
-
- [Usage](#usage)
|
|
33
|
-
|
|
34
|
-
## How to use this skill
|
|
35
|
-
|
|
36
|
-
Attach this file to your Copilot Chat context, then invoke it with the git
|
|
37
|
-
command name(s) to audit. Example:
|
|
38
|
-
|
|
39
|
-
```text
|
|
40
|
-
Remove methods added to Git::Lib since v4.3.0 for the `branch` git command
|
|
41
|
-
and ensure the remaining methods are backward compatible.
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Replace `branch` with the specific git command(s) you want to audit (e.g.,
|
|
45
|
-
`worktree`, `tag`, `merge`, `reset`).
|
|
46
|
-
|
|
47
|
-
## Related skills
|
|
48
|
-
|
|
49
|
-
- [Refactor Command to CommandLineResult](../refactor-command-to-commandlineresult/SKILL.md) — migrating command classes to Base;
|
|
50
|
-
the counterpart to this skill's `Git::Lib` facade focus
|
|
51
|
-
- [Command Implementation](../command-implementation/SKILL.md) — class structure, phased rollout gates, and
|
|
52
|
-
internal compatibility contracts
|
|
53
|
-
|
|
54
|
-
## Objective
|
|
55
|
-
|
|
56
|
-
For the specified git command(s), remove methods added to `Git::Lib` since v4.3.0 and ensure that remaining methods (which existed in v4.3.0) are backward compatible.
|
|
57
|
-
|
|
58
|
-
## Current Command Architecture Note
|
|
59
|
-
|
|
60
|
-
When auditing modern implementations, assume command classes follow `Git::Commands::Base`:
|
|
61
|
-
|
|
62
|
-
- classes use `class < Git::Commands::Base` with `arguments do ... end`
|
|
63
|
-
- command entrypoint is `call(*, **)` (inherited from `Base`)
|
|
64
|
-
- exit-status behavior is centralized via `allow_exit_status` declarations on the class
|
|
65
|
-
|
|
66
|
-
Because of this, backward-compatibility adaptation should happen in `Git::Lib`
|
|
67
|
-
methods (facade/adapter layer), not by reintroducing legacy execution logic inside
|
|
68
|
-
command classes.
|
|
69
|
-
|
|
70
|
-
## Instructions
|
|
71
|
-
|
|
72
|
-
### Branch setup
|
|
73
|
-
|
|
74
|
-
All work must be done on a feature branch. **Never commit or push directly to
|
|
75
|
-
`main`.**
|
|
76
|
-
|
|
77
|
-
Before starting, create a new branch:
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
git checkout -b <feature-branch-name>
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
All commits in this workflow go on the feature branch. When work is complete,
|
|
84
|
-
open a pull request — do not merge or push directly into `main`.
|
|
85
|
-
|
|
86
|
-
### Step 1: Identify Methods Added Since v4.3.0
|
|
87
|
-
|
|
88
|
-
1. Check out the v4.3.0 tag to examine the historical state:
|
|
89
|
-
|
|
90
|
-
**Warning:** `git checkout` modifies the working tree. Stash or commit any
|
|
91
|
-
uncommitted changes first (`git stash`).
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
git checkout v4.3.0
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
2. Search `lib/git/lib.rb` for all methods related to the specified git command(s):
|
|
98
|
-
```bash
|
|
99
|
-
grep -n "def <command_name>" lib/git/lib.rb
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
3. Document each method found, including:
|
|
103
|
-
- Method name and signature
|
|
104
|
-
- Return value type (String, Array, Hash, Boolean, etc.)
|
|
105
|
-
- Exact return value format (e.g., `Array<[Integer, String]>`, `String` with specific content)
|
|
106
|
-
|
|
107
|
-
4. Return to your feature branch:
|
|
108
|
-
```bash
|
|
109
|
-
git checkout -
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
5. Search for the same command methods in the current version:
|
|
113
|
-
```bash
|
|
114
|
-
grep -n "def <command_name>" lib/git/lib.rb
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
6. Create two lists:
|
|
118
|
-
- **Legacy methods**: Methods that existed in v4.3.0 (must be preserved and made compatible)
|
|
119
|
-
- **New methods**: Methods that don't exist in v4.3.0 (should be removed)
|
|
120
|
-
|
|
121
|
-
### Step 2: Remove New Methods
|
|
122
|
-
|
|
123
|
-
1. Identify all new methods that were added after v4.3.0
|
|
124
|
-
2. Remove these methods entirely from `lib/git/lib.rb`
|
|
125
|
-
3. Remove any `require` statements that are only used by the removed methods
|
|
126
|
-
|
|
127
|
-
### Step 3: Restore Backward-Compatible Implementations
|
|
128
|
-
|
|
129
|
-
For each legacy method that needs to be preserved:
|
|
130
|
-
|
|
131
|
-
1. **Use modern command infrastructure internally:**
|
|
132
|
-
- Call the appropriate `Git::Commands::<Command>::*` class
|
|
133
|
-
- Ensure all necessary command classes are required at the top of the file
|
|
134
|
-
|
|
135
|
-
2. **Convert return values to match v4.3.0 exactly:**
|
|
136
|
-
- Compare the return type from the modern command with the v4.3.0 return type
|
|
137
|
-
- If they differ, add conversion logic to transform the result
|
|
138
|
-
- Modern commands typically return `CommandLineResult` objects with `.stdout`, `.stderr`, and `.status`
|
|
139
|
-
- Legacy methods may have returned raw strings, arrays, or other types
|
|
140
|
-
|
|
141
|
-
3. **Create helper methods if needed:**
|
|
142
|
-
- For complex conversions (e.g., parsing output into specific formats), create private helper methods
|
|
143
|
-
- Name helpers clearly (e.g., `<command>_info_to_legacy`)
|
|
144
|
-
- Place helpers near the bottom of the file in the private section
|
|
145
|
-
|
|
146
|
-
### Step 4: Add Required Dependencies
|
|
147
|
-
|
|
148
|
-
1. Ensure all necessary `require` statements are present:
|
|
149
|
-
```ruby
|
|
150
|
-
require_relative 'git/commands/<command>/<action>'
|
|
151
|
-
require_relative 'git/parsers/<command>' # if using parsers
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
2. Only keep requires for:
|
|
155
|
-
- Command classes used by the legacy methods
|
|
156
|
-
- Parsers needed for conversion
|
|
157
|
-
- Remove requires for deleted commands
|
|
158
|
-
|
|
159
|
-
### Step 5: Verify the Changes
|
|
160
|
-
|
|
161
|
-
1. Check the diff to ensure:
|
|
162
|
-
```bash
|
|
163
|
-
git diff lib/git/lib.rb
|
|
164
|
-
```
|
|
165
|
-
- All new methods are removed
|
|
166
|
-
- All legacy methods are present with correct signatures
|
|
167
|
-
- Return value conversions are in place
|
|
168
|
-
- Correct require statements are present
|
|
169
|
-
|
|
170
|
-
2. Verify that the implementation uses modern command classes:
|
|
171
|
-
```bash
|
|
172
|
-
git diff lib/git/lib.rb | grep -E "^\+.*Git::Commands::<Command>"
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
3. Check the net line change (should be negative if removing methods):
|
|
176
|
-
```bash
|
|
177
|
-
git diff --stat lib/git/lib.rb
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Example: Stash Commands
|
|
181
|
-
|
|
182
|
-
Here's how this process was applied to the `stash` commands:
|
|
183
|
-
|
|
184
|
-
### Legacy Methods (v4.3.0)
|
|
185
|
-
- `stashes_all` → returned `Array<[Integer, String]>` (index and message pairs)
|
|
186
|
-
- `stash_save(message)` → returned regex match result (truthy/falsy)
|
|
187
|
-
- `stash_apply(id)` → returned `String` (stdout)
|
|
188
|
-
- `stash_clear` → returned `String` (stdout)
|
|
189
|
-
- `stash_list` → returned `String` (stdout)
|
|
190
|
-
|
|
191
|
-
### New Methods (removed)
|
|
192
|
-
- `stash_branch`
|
|
193
|
-
- `stash_create`
|
|
194
|
-
- `stash_drop`
|
|
195
|
-
- `stash_pop`
|
|
196
|
-
- `stash_push`
|
|
197
|
-
- `stashes_list`
|
|
198
|
-
- `git_stash_show_*` methods
|
|
199
|
-
|
|
200
|
-
### Implementation Pattern
|
|
201
|
-
|
|
202
|
-
```ruby
|
|
203
|
-
# Requires at top of file
|
|
204
|
-
require_relative 'git/commands/stash/apply'
|
|
205
|
-
require_relative 'git/commands/stash/clear'
|
|
206
|
-
require_relative 'git/commands/stash/list'
|
|
207
|
-
require_relative 'git/commands/stash/push'
|
|
208
|
-
require_relative 'git/parsers/stash'
|
|
209
|
-
|
|
210
|
-
# Legacy method implementations
|
|
211
|
-
def stashes_all
|
|
212
|
-
result = Git::Commands::Stash::List.new(self).call
|
|
213
|
-
stashes = Git::Parsers::Stash.parse_list(result.stdout)
|
|
214
|
-
stashes.map { |info| stash_info_to_legacy(info) }
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def stash_save(message)
|
|
218
|
-
result = Git::Commands::Stash::Push.new(self).call(message: message)
|
|
219
|
-
result.stdout =~ /HEAD is now at/
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
def stash_apply(id = nil)
|
|
223
|
-
result = Git::Commands::Stash::Apply.new(self).call(id)
|
|
224
|
-
result.stdout
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
def stash_clear
|
|
228
|
-
result = Git::Commands::Stash::Clear.new(self).call
|
|
229
|
-
result.stdout
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def stash_list
|
|
233
|
-
result = Git::Commands::Stash::List.new(self).call
|
|
234
|
-
result.stdout
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
# Helper method (in private section)
|
|
238
|
-
private
|
|
239
|
-
|
|
240
|
-
def stash_info_to_legacy(stash_info)
|
|
241
|
-
[stash_info.index, stash_info.message]
|
|
242
|
-
end
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Key Principles
|
|
246
|
-
|
|
247
|
-
1. **Maintain exact v4.3.0 return values**: Don't change return types even slightly
|
|
248
|
-
2. **Use modern infrastructure internally**: Leverage `Git::Commands::*` classes for actual git operations
|
|
249
|
-
3. **Remove all new methods**: Don't try to make new methods backward compatible - just remove them
|
|
250
|
-
4. **Minimize changes**: Only modify what's necessary for backward compatibility
|
|
251
|
-
5. **Document conversions**: Make helper methods clear and well-named
|
|
252
|
-
6. **Apply policy at the facade**: `Git::Lib` methods pass policy options explicitly
|
|
253
|
-
(e.g. `no_edit: true`, `verbose: true`, `no_progress: true`) — command classes stay
|
|
254
|
-
neutral. See "Command-layer neutrality" in CONTRIBUTING.md.
|
|
255
|
-
|
|
256
|
-
## Validation Checklist
|
|
257
|
-
|
|
258
|
-
- [ ] Working on a feature branch (not `main`)
|
|
259
|
-
- [ ] Identified all methods for the command in v4.3.0
|
|
260
|
-
- [ ] Documented v4.3.0 return values exactly
|
|
261
|
-
- [ ] Removed all methods not present in v4.3.0
|
|
262
|
-
- [ ] Implemented legacy methods using modern command classes
|
|
263
|
-
- [ ] Added conversion logic where return types differ
|
|
264
|
-
- [ ] Created helper methods for complex conversions
|
|
265
|
-
- [ ] Updated require statements correctly
|
|
266
|
-
- [ ] Verified changes with git diff
|
|
267
|
-
- [ ] Net line count decreased (removed more than added)
|
|
268
|
-
|
|
269
|
-
## Usage
|
|
270
|
-
|
|
271
|
-
To apply this process, say:
|
|
272
|
-
|
|
273
|
-
> Remove methods added to Git::Lib since v4.3.0 for `<command_name>` git command(s) and ensure the remaining methods are backward compatible.
|
|
274
|
-
|
|
275
|
-
Replace `<command_name>` with the specific git command(s) you want to audit (e.g., `branch`, `merge`, `tag`, `reset`, etc.).
|
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: [main, 4.x]
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
# Cancel an in-progress run when the same PR (or branch) gets a new push. For
|
|
9
|
-
# pull_request events github.ref is refs/pull/<n>/merge, so runs are grouped per PR
|
|
10
|
-
# and pushing a new commit -- or force-pushing during a rebase -- no longer leaves a
|
|
11
|
-
# full matrix running to completion against a commit nobody will merge.
|
|
12
|
-
concurrency:
|
|
13
|
-
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
-
cancel-in-progress: true
|
|
15
|
-
|
|
16
|
-
jobs:
|
|
17
|
-
# RuboCop and YARD analyze source text, so their results do not depend on the
|
|
18
|
-
# runtime executing them: RuboCop's verdict is fixed by TargetRubyVersion in
|
|
19
|
-
# .rubocop.yml, not by the host Ruby. Running them once here instead of inside the
|
|
20
|
-
# matrix removes the single largest cost in the build -- RuboCop alone accounted for
|
|
21
|
-
# over half the wall time of the JRuby and TruffleRuby jobs -- while checking exactly
|
|
22
|
-
# the same things.
|
|
23
|
-
#
|
|
24
|
-
# Ruby 3.4 hosts this job rather than the newest supported Ruby because it gates
|
|
25
|
-
# merges: a lint gate should be insulated from churn in a brand-new major, and Ruby
|
|
26
|
-
# 4.0 deprecations still surface through the matrix jobs below, which do run 4.0.
|
|
27
|
-
# 3.3+ is also a hard floor here, since yard-lint is only installed on 3.3 and later
|
|
28
|
-
# (see the gemspec) and YARD itself cannot build on JRuby or TruffleRuby.
|
|
29
|
-
lint:
|
|
30
|
-
name: Lint and Docs
|
|
31
|
-
|
|
32
|
-
# Skip this job if triggered by a release PR
|
|
33
|
-
if: >-
|
|
34
|
-
github.event_name == 'workflow_dispatch' ||
|
|
35
|
-
(github.event_name == 'pull_request' && !startsWith(github.event.pull_request.head.ref, 'release-please--'))
|
|
36
|
-
|
|
37
|
-
runs-on: ubuntu-latest
|
|
38
|
-
|
|
39
|
-
steps:
|
|
40
|
-
- name: Checkout Code
|
|
41
|
-
uses: actions/checkout@v6
|
|
42
|
-
|
|
43
|
-
- name: Setup Ruby
|
|
44
|
-
uses: ruby/setup-ruby@v1
|
|
45
|
-
with:
|
|
46
|
-
ruby-version: "3.4"
|
|
47
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
48
|
-
|
|
49
|
-
- name: Run RuboCop and YARD
|
|
50
|
-
run: bundle exec rake rubocop yard
|
|
51
|
-
timeout-minutes: 15
|
|
52
|
-
|
|
53
|
-
build:
|
|
54
|
-
name: Ruby ${{ matrix.ruby }} on ${{ matrix.operating-system }}
|
|
55
|
-
|
|
56
|
-
# Skip this job if triggered by a release PR
|
|
57
|
-
if: >-
|
|
58
|
-
github.event_name == 'workflow_dispatch' ||
|
|
59
|
-
(github.event_name == 'pull_request' && !startsWith(github.event.pull_request.head.ref, 'release-please--'))
|
|
60
|
-
|
|
61
|
-
runs-on: ${{ matrix.operating-system }}
|
|
62
|
-
env: { JAVA_OPTS: -Djdk.io.File.enableADS=true }
|
|
63
|
-
|
|
64
|
-
strategy:
|
|
65
|
-
fail-fast: false
|
|
66
|
-
matrix:
|
|
67
|
-
# Only the minimum required versions of JRuby and TruffleRuby are tested.
|
|
68
|
-
#
|
|
69
|
-
ruby: ["3.2", "4.0", "truffleruby-24.2.1", "jruby-10.0.0.1"]
|
|
70
|
-
operating-system: [ubuntu-latest]
|
|
71
|
-
include:
|
|
72
|
-
- ruby: "3.2"
|
|
73
|
-
operating-system: windows-latest
|
|
74
|
-
|
|
75
|
-
steps:
|
|
76
|
-
- name: Checkout Code
|
|
77
|
-
uses: actions/checkout@v6
|
|
78
|
-
|
|
79
|
-
- name: Setup Ruby
|
|
80
|
-
uses: ruby/setup-ruby@v1
|
|
81
|
-
with:
|
|
82
|
-
ruby-version: ${{ matrix.ruby }}
|
|
83
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
84
|
-
|
|
85
|
-
# Specs only. RuboCop and YARD run once in the lint job above instead of being
|
|
86
|
-
# repeated identically on every runtime. `rake build` still runs on every
|
|
87
|
-
# platform, as a prerequisite of the Test Gem step below.
|
|
88
|
-
- name: Run Specs
|
|
89
|
-
run: bundle exec rake spec
|
|
90
|
-
timeout-minutes: 15
|
|
91
|
-
|
|
92
|
-
# The unit suite enforces 100% line and branch coverage (see the "Test coverage
|
|
93
|
-
# policy" section of CONTRIBUTING.md). The failure log names the uncovered lines
|
|
94
|
-
# and branches; this artifact adds the browsable HTML report for the same run.
|
|
95
|
-
- name: Upload Coverage Report
|
|
96
|
-
if: failure()
|
|
97
|
-
uses: actions/upload-artifact@v7
|
|
98
|
-
with:
|
|
99
|
-
name: coverage-ruby-${{ matrix.ruby }}-${{ matrix.operating-system }}
|
|
100
|
-
path: coverage/
|
|
101
|
-
if-no-files-found: ignore
|
|
102
|
-
retention-days: 7
|
|
103
|
-
|
|
104
|
-
- name: Test Gem
|
|
105
|
-
run: bundle exec rake test:gem
|
|
106
|
-
|
|
107
|
-
# The branch ruleset cannot require the matrix jobs above directly. A required status
|
|
108
|
-
# check is matched by name, and `build`'s name is a template -- GitHub only expands it
|
|
109
|
-
# into "Ruby 3.2 on ubuntu-latest" and friends when it evaluates the matrix. The
|
|
110
|
-
# job-level `if:` short-circuits before that happens, so a release PR reports one check
|
|
111
|
-
# named literally "Ruby ${{ matrix.ruby }} on ${{ matrix.operating-system }}" and the
|
|
112
|
-
# five expanded names never report at all. Required checks that never report block a PR
|
|
113
|
-
# indefinitely rather than passing, which is what stranded the v5.0.5 release PR.
|
|
114
|
-
#
|
|
115
|
-
# So the ruleset requires this job instead: one stable name, no matrix, no template to
|
|
116
|
-
# expand. It also decouples the required-check list from the matrix, so adding or
|
|
117
|
-
# dropping a Ruby version no longer needs a matching ruleset edit.
|
|
118
|
-
#
|
|
119
|
-
# This job carries the same release-PR guard as every job above, so that a release PR
|
|
120
|
-
# reports it as skipped rather than as a success for specs that never ran. Skipping is
|
|
121
|
-
# safe here and was not safe for `build`: this job's name is a literal string, so the
|
|
122
|
-
# check run exists and reports a skipped conclusion whether or not the job runs, and
|
|
123
|
-
# rulesets treat skipped as passing. A matrix job's name does not exist at all until the
|
|
124
|
-
# matrix is evaluated, which is the whole reason this job exists.
|
|
125
|
-
#
|
|
126
|
-
# `always()` is load-bearing and must stay. Without a status check function a job-level
|
|
127
|
-
# `if:` implies `success()`, so a failing matrix would skip this job -- and a skipped
|
|
128
|
-
# required check counts as passing, meaning a red build would merge. `always()` forces a
|
|
129
|
-
# real verdict on every run that is not a release PR. `!cancelled()` is not a substitute:
|
|
130
|
-
# a cancelled run would then skip the gate, and a skipped conclusion is one rulesets treat
|
|
131
|
-
# as passing -- so a build that never finished would stop blocking the merge.
|
|
132
|
-
#
|
|
133
|
-
# The case below accepts `success` only. `build` and this job now carry the same release-PR
|
|
134
|
-
# guard, so this job runs exactly when `build` ran; a `skipped` result would mean the two
|
|
135
|
-
# guards have drifted apart, and failing closed on it turns that into a loud failure rather
|
|
136
|
-
# than a silent pass.
|
|
137
|
-
build-complete:
|
|
138
|
-
name: All Specs Passed
|
|
139
|
-
|
|
140
|
-
needs: [build]
|
|
141
|
-
|
|
142
|
-
# Report a verdict on every non-release PR regardless of the matrix result, and skip
|
|
143
|
-
# on release PRs, where the matrix was never meant to run.
|
|
144
|
-
if: >-
|
|
145
|
-
always() &&
|
|
146
|
-
(github.event_name == 'workflow_dispatch' ||
|
|
147
|
-
(github.event_name == 'pull_request' && !startsWith(github.event.pull_request.head.ref, 'release-please--')))
|
|
148
|
-
|
|
149
|
-
runs-on: ubuntu-latest
|
|
150
|
-
|
|
151
|
-
steps:
|
|
152
|
-
- name: Check the result of the build job
|
|
153
|
-
run: |
|
|
154
|
-
case "${{ needs.build.result }}" in
|
|
155
|
-
success)
|
|
156
|
-
echo "build: ${{ needs.build.result }}"
|
|
157
|
-
;;
|
|
158
|
-
*)
|
|
159
|
-
echo "::error::build: ${{ needs.build.result }}"
|
|
160
|
-
exit 1
|
|
161
|
-
;;
|
|
162
|
-
esac
|
|
163
|
-
|
|
164
|
-
# Everything above runs in English, because GitHub-hosted runners generate no locale
|
|
165
|
-
# beyond C/C.UTF-8. That makes git's translated diagnostics invisible to CI even
|
|
166
|
-
# though they are the default experience for any contributor whose shell locale is not
|
|
167
|
-
# English -- so a spec that matches an English git message passes here and fails for
|
|
168
|
-
# them, on code they did not touch. This job is what stops such a spec from reaching
|
|
169
|
-
# main. See issue #1670.
|
|
170
|
-
#
|
|
171
|
-
# German because git's `de` translation is close enough to complete that a
|
|
172
|
-
# message-matching assumption cannot hide behind a string that was never translated.
|
|
173
|
-
# Most of the suite is insulated from this by the LC_ALL pin in Git::ExecutionContext;
|
|
174
|
-
# what this job really exercises is the code that bypasses that pin.
|
|
175
|
-
locale:
|
|
176
|
-
name: Non-English Locale
|
|
177
|
-
|
|
178
|
-
# Skip this job if triggered by a release PR
|
|
179
|
-
if: >-
|
|
180
|
-
github.event_name == 'workflow_dispatch' ||
|
|
181
|
-
(github.event_name == 'pull_request' && !startsWith(github.event.pull_request.head.ref, 'release-please--'))
|
|
182
|
-
|
|
183
|
-
runs-on: ubuntu-latest
|
|
184
|
-
|
|
185
|
-
# Set at job scope rather than on the spec step so that every step -- including the
|
|
186
|
-
# check below that the locale is real -- sees exactly the environment the suite runs
|
|
187
|
-
# under. Setting these before locale-gen is harmless: they are simply inert until
|
|
188
|
-
# the locale exists.
|
|
189
|
-
env:
|
|
190
|
-
LANG: de_DE.UTF-8
|
|
191
|
-
LC_ALL: de_DE.UTF-8
|
|
192
|
-
|
|
193
|
-
steps:
|
|
194
|
-
- name: Checkout Code
|
|
195
|
-
uses: actions/checkout@v6
|
|
196
|
-
|
|
197
|
-
# Two separate things are missing from a stock runner, and skipping either one
|
|
198
|
-
# leaves the env above inert -- git keeps answering in English and the job proves
|
|
199
|
-
# nothing:
|
|
200
|
-
#
|
|
201
|
-
# 1. The locale itself. Only C and C.UTF-8 are generated, so setlocale fails for
|
|
202
|
-
# anything else and every process falls back to English.
|
|
203
|
-
# 2. git's German message catalog. Unlike Debian, Ubuntu strips gettext catalogs
|
|
204
|
-
# out of packages and ships them in language packs, so the installed git has
|
|
205
|
-
# no de translation until language-pack-de provides one.
|
|
206
|
-
#
|
|
207
|
-
# `update-locale` is deliberately not run: it edits /etc/default/locale, which is
|
|
208
|
-
# only consulted for logins that do not already set LANG and LC_ALL, and this job
|
|
209
|
-
# sets both explicitly.
|
|
210
|
-
#
|
|
211
|
-
# The two apt settings below exist because this step reaches out to the Ubuntu
|
|
212
|
-
# archive, which is the only part of this job that can fail for reasons that have
|
|
213
|
-
# nothing to do with the code under test:
|
|
214
|
-
#
|
|
215
|
-
# * `Acquire::Retries` retries an individual download that fails outright,
|
|
216
|
-
# rather than failing the job on one unlucky mirror.
|
|
217
|
-
# * `timeout-minutes` bounds a mirror that accepts the connection and then
|
|
218
|
-
# stops responding, which retries cannot help with. Without it the step
|
|
219
|
-
# inherits the 6 hour job default: run 32087601711 sat here for 12 minutes
|
|
220
|
-
# before it was cancelled by hand, and would otherwise have held a runner
|
|
221
|
-
# for the rest of the day. The whole job normally finishes in 53-118
|
|
222
|
-
# seconds, so 5 minutes is generous while still failing the same morning.
|
|
223
|
-
#
|
|
224
|
-
- name: Install the German locale and message catalogs
|
|
225
|
-
timeout-minutes: 5
|
|
226
|
-
run: |
|
|
227
|
-
sudo apt-get -o Acquire::Retries=3 update -qq
|
|
228
|
-
sudo apt-get -o Acquire::Retries=3 install -y --no-install-recommends language-pack-de
|
|
229
|
-
sudo locale-gen de_DE.UTF-8
|
|
230
|
-
|
|
231
|
-
# Ruby 3.4 to share the bundler cache the lint job already warms. Nothing about
|
|
232
|
-
# this job is Ruby-version specific -- the locale is what is under test.
|
|
233
|
-
- name: Setup Ruby
|
|
234
|
-
uses: ruby/setup-ruby@v1
|
|
235
|
-
with:
|
|
236
|
-
ruby-version: "3.4"
|
|
237
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
238
|
-
|
|
239
|
-
# Guard against a vacuous pass. Diffing git's output against the same command run
|
|
240
|
-
# under LC_ALL=C proves translation is actually active, without pinning a German
|
|
241
|
-
# string that a future git release is free to reword.
|
|
242
|
-
- name: Verify the Locale Took Effect
|
|
243
|
-
run: |
|
|
244
|
-
dir="$(mktemp -d)"
|
|
245
|
-
localized="$(cd "$dir" && git status 2>&1 || true)"
|
|
246
|
-
english="$(cd "$dir" && LC_ALL=C git status 2>&1 || true)"
|
|
247
|
-
echo "LC_ALL=$LC_ALL -> $localized"
|
|
248
|
-
echo "LC_ALL=C -> $english"
|
|
249
|
-
if [ "$localized" = "$english" ]; then
|
|
250
|
-
echo "::error::git is still emitting English: de_DE.UTF-8 did not take effect, so this job would test nothing"
|
|
251
|
-
exit 1
|
|
252
|
-
fi
|
|
253
|
-
|
|
254
|
-
- name: Run Specs
|
|
255
|
-
run: bundle exec rake spec
|
|
256
|
-
timeout-minutes: 15
|
|
257
|
-
|
|
258
|
-
# On the ubuntu jobs above, `C.UTF-8` and `en_US.UTF-8` both resolve to a UTF-8 ctype
|
|
259
|
-
# (measured on the runner in issue #1669), and on windows the pinned value makes no
|
|
260
|
-
# difference under any value at all. So the non-ASCII regex coverage those jobs run
|
|
261
|
-
# passes whatever `Git::ExecutionContext` pins, and cannot tell a correct `LC_ALL`
|
|
262
|
-
# value from a wrong one. That blind spot is what let the original defect go
|
|
263
|
-
# unreported for eighteen months: the gem pinned `en_US.UTF-8`, stock Debian, Ubuntu,
|
|
264
|
-
# and RHEL images generate no such locale, git silently fell back to a C ctype, and
|
|
265
|
-
# every non-ASCII regex in `grep`, `log`, and the `config` value regexes returned a
|
|
266
|
-
# wrong answer with exit status zero -- while CI stayed green throughout.
|
|
267
|
-
#
|
|
268
|
-
# This job makes one run discriminating. `LOCPATH` overrides where glibc looks for
|
|
269
|
-
# compiled locale data, so pointing it at an empty directory takes away every locale
|
|
270
|
-
# that needs a locale archive -- `en_US.UTF-8` among them -- while leaving `C.UTF-8`
|
|
271
|
-
# working, because glibc 2.35 and later compile that one into the library itself.
|
|
272
|
-
# The suite then runs in an environment where the value shipped before #1681 fails
|
|
273
|
-
# and the value shipped now passes: no container image, no second bundle install,
|
|
274
|
-
# no cache miss. Measured on ubuntu:24.04 (glibc 2.39, the runner's base) with
|
|
275
|
-
# `en_US.UTF-8` generated first:
|
|
276
|
-
#
|
|
277
|
-
# normal en_US.UTF-8 charmap=UTF-8 C.UTF-8 charmap=UTF-8
|
|
278
|
-
# LOCPATH=empty en_US.UTF-8 charmap=ANSI_X3.4-1968 C.UTF-8 charmap=UTF-8
|
|
279
|
-
#
|
|
280
|
-
# This has to be a property of the run rather than of a spec. Never gate a spec on
|
|
281
|
-
# whether the pinned locale loads: such a spec skips itself in exactly the
|
|
282
|
-
# environments where this defect lives, which is how the defect went unreported for
|
|
283
|
-
# eighteen months.
|
|
284
|
-
#
|
|
285
|
-
# LANG is set explicitly so only `en_US.UTF-8` is taken away and the ambient
|
|
286
|
-
# environment stays UTF-8. The runner already sets this value; pinning it here keeps
|
|
287
|
-
# the job from depending on the image's default.
|
|
288
|
-
missing-locale:
|
|
289
|
-
name: Missing en_US.UTF-8 Locale
|
|
290
|
-
|
|
291
|
-
# Skip this job if triggered by a release PR
|
|
292
|
-
if: >-
|
|
293
|
-
github.event_name == 'workflow_dispatch' ||
|
|
294
|
-
(github.event_name == 'pull_request' && !startsWith(github.event.pull_request.head.ref, 'release-please--'))
|
|
295
|
-
|
|
296
|
-
runs-on: ubuntu-latest
|
|
297
|
-
|
|
298
|
-
env:
|
|
299
|
-
LANG: C.UTF-8
|
|
300
|
-
|
|
301
|
-
steps:
|
|
302
|
-
- name: Checkout Code
|
|
303
|
-
uses: actions/checkout@v6
|
|
304
|
-
|
|
305
|
-
# Exported through GITHUB_ENV rather than set at job scope because the `runner`
|
|
306
|
-
# context is not available there, and the directory has to exist before anything
|
|
307
|
-
# reads a locale -- glibc warns on every process when LOCPATH names a directory
|
|
308
|
-
# that does not exist. RUNNER_TEMP rather than the workspace so that
|
|
309
|
-
# actions/checkout cannot clean it away.
|
|
310
|
-
- name: Point LOCPATH at an Empty Directory
|
|
311
|
-
run: |
|
|
312
|
-
mkdir -p "$RUNNER_TEMP/empty-locale-dir"
|
|
313
|
-
echo "LOCPATH=$RUNNER_TEMP/empty-locale-dir" >> "$GITHUB_ENV"
|
|
314
|
-
|
|
315
|
-
# Ruby 3.4 to share the bundler cache the lint job already warms. Nothing about
|
|
316
|
-
# this job is Ruby-version specific -- the locale environment is what differs.
|
|
317
|
-
- name: Setup Ruby
|
|
318
|
-
uses: ruby/setup-ruby@v1
|
|
319
|
-
with:
|
|
320
|
-
ruby-version: "3.4"
|
|
321
|
-
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
322
|
-
|
|
323
|
-
# Guard against a vacuous pass, functionally. `locale -a` still lists en_US.utf8
|
|
324
|
-
# under LOCPATH (measured) even though setlocale then refuses it, so asking git
|
|
325
|
-
# to match is the only assertion worth making: `.` spans the two-byte U+00C4 only
|
|
326
|
-
# under a UTF-8 ctype. The metacharacter-free control has to keep matching under
|
|
327
|
-
# the removed locale as well -- it matches bytes under any ctype, so if it fails,
|
|
328
|
-
# the probe never delivered UTF-8 bytes to git and the rest proves nothing.
|
|
329
|
-
- name: Verify the Run Discriminates
|
|
330
|
-
run: |
|
|
331
|
-
dir="$(mktemp -d)"
|
|
332
|
-
cd "$dir"
|
|
333
|
-
git init -q .
|
|
334
|
-
printf '\xc3\x84PFEL sind gut\n' > w.txt
|
|
335
|
-
git add w.txt
|
|
336
|
-
|
|
337
|
-
if ! LC_ALL=C.UTF-8 git grep -q '^.PFEL' -- w.txt; then
|
|
338
|
-
echo "::error::C.UTF-8 no longer yields a UTF-8 ctype under LOCPATH, so this job would fail for the wrong reason"
|
|
339
|
-
exit 1
|
|
340
|
-
fi
|
|
341
|
-
if ! LC_ALL=en_US.UTF-8 git grep -q 'PFEL sind' -- w.txt; then
|
|
342
|
-
echo "::error::the control pattern did not match, so this probe is not delivering UTF-8 bytes to git"
|
|
343
|
-
exit 1
|
|
344
|
-
fi
|
|
345
|
-
if LC_ALL=en_US.UTF-8 git grep -q '^.PFEL' -- w.txt; then
|
|
346
|
-
echo "::error::en_US.UTF-8 still yields a UTF-8 ctype, so this job cannot detect a wrong LC_ALL pin"
|
|
347
|
-
exit 1
|
|
348
|
-
fi
|
|
349
|
-
echo "en_US.UTF-8 is unusable and C.UTF-8 works: a wrong pin fails this job"
|
|
350
|
-
|
|
351
|
-
# The whole suite rather than the non-ASCII regex spec alone: the point is that
|
|
352
|
-
# this run is indistinguishable from any other except for the missing locale, so
|
|
353
|
-
# every locale-sensitive surface added later is covered without touching this
|
|
354
|
-
# file. It also keeps the coverage gate satisfied, which a single spec file
|
|
355
|
-
# cannot do.
|
|
356
|
-
- name: Run Specs
|
|
357
|
-
run: bundle exec rake spec
|
|
358
|
-
timeout-minutes: 15
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Conventional Commits
|
|
3
|
-
|
|
4
|
-
permissions:
|
|
5
|
-
contents: read
|
|
6
|
-
|
|
7
|
-
on:
|
|
8
|
-
pull_request:
|
|
9
|
-
branches:
|
|
10
|
-
- main
|
|
11
|
-
- 4.x
|
|
12
|
-
|
|
13
|
-
# Cancel an in-progress run when the same PR gets a new push; only the commit messages
|
|
14
|
-
# as they stand after the latest push are worth linting.
|
|
15
|
-
concurrency:
|
|
16
|
-
group: ${{ github.workflow }}-${{ github.ref }}
|
|
17
|
-
cancel-in-progress: true
|
|
18
|
-
|
|
19
|
-
jobs:
|
|
20
|
-
commit-lint:
|
|
21
|
-
name: Verify Conventional Commits
|
|
22
|
-
|
|
23
|
-
# Skip this job if this is a release PR
|
|
24
|
-
if: (github.event_name == 'pull_request' && !startsWith(github.event.pull_request.head.ref, 'release-please--'))
|
|
25
|
-
|
|
26
|
-
runs-on: ubuntu-latest
|
|
27
|
-
|
|
28
|
-
steps:
|
|
29
|
-
- name: Checkout
|
|
30
|
-
uses: actions/checkout@v6
|
|
31
|
-
with: { fetch-depth: 0 }
|
|
32
|
-
|
|
33
|
-
- name: Check Commit Messages
|
|
34
|
-
uses: wagoid/commitlint-github-action@v6
|
|
35
|
-
with: { configFile: .commitlintrc.yml }
|