Skip to content

Commit 719a7c9

Browse files
jurreCopilot
andcommitted
Split copilot instructions into scoped files
Split the 389-line copilot-instructions.md into a lean 81-line main file plus 4 scoped instruction files in .github/instructions/: - testing.instructions.md (applyTo: spec files) - code-quality.instructions.md (applyTo: *.rb) - class-structure.instructions.md (applyTo: core class files) - updater.instructions.md (applyTo: updater/**) Key improvements: - Add hard pre-commit checklist (rubocop/srb/rspec must pass before commit) - Document bin/test --workdir for updater testing - Document bin/test common for common/ changes - Add sub-agent validation guidance - Remove duplicated validation instructions - Only inject relevant context based on files being edited Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6bb397e commit 719a7c9

File tree

5 files changed

+333
-323
lines changed

5 files changed

+333
-323
lines changed

.github/copilot-instructions.md

Lines changed: 16 additions & 323 deletions
Original file line numberDiff line numberDiff line change
@@ -20,235 +20,15 @@ Each ecosystem implements these 7 required classes that inherit from `dependabot
2020
- `common/` - Shared base classes and utilities used by all ecosystems
2121
- `{ecosystem}/` - Each directory contains a complete gem (e.g., `go_modules/`, `bundler/`)
2222
- `omnibus/` - Meta-gem that includes all ecosystem gems
23-
- `updater/` - Service layer that orchestrates the update process
23+
- `updater/` - Service layer that orchestrates the update process (renamed to `dependabot-updater/` inside containers)
2424
- `script/` - Build and development scripts
2525

26-
**Note**: When working in containers, the `updater/` folder is renamed to `dependabot-updater/`. This affects test paths and file references inside the container.
27-
28-
## Development Workflow
29-
30-
### Local Development Setup
31-
32-
```bash
33-
# Step 1: Start the Docker development environment for a specific ecosystem
34-
bin/docker-dev-shell {ecosystem} # e.g., go_modules, bundler
35-
# This opens an interactive shell inside the container
36-
37-
# Quick command execution (non-CI):
38-
bin/test {ecosystem} [command]
39-
# e.g. bin/test uv spec/dependabot/uv/file_updater_spec.rb
40-
```
41-
42-
**Note**: The first run of `bin/docker-dev-shell` can take some minutes as it builds the Docker development image from scratch. Wait for it to complete before proceeding. Check for completion every 5 seconds. Subsequent runs will be much faster as they reuse the built image.
43-
44-
### GitHub Actions/CI Environment
45-
46-
**For GitHub Actions runners (including Copilot coding agent)**, the interactive `bin/docker-dev-shell` command will NOT work. Instead, use the non-interactive CI pattern:
47-
48-
```bash
49-
# Step 1: Build the ecosystem image
50-
script/build {ecosystem} # e.g., script/build bundler
51-
52-
# Step 2: Run commands inside the container (non-interactive)
53-
docker run --rm \
54-
--env "CI=true" \
55-
--env "DEPENDABOT_TEST_ACCESS_TOKEN=$GITHUB_TOKEN" \
56-
ghcr.io/dependabot/dependabot-updater-{ecosystem} bash -c \
57-
"cd /home/dependabot/{ecosystem} && rspec spec"
58-
59-
# Examples for specific tasks:
60-
# Run tests for bundler:
61-
docker run --rm ghcr.io/dependabot/dependabot-updater-bundler bash -c \
62-
"cd /home/dependabot/bundler && rspec spec"
63-
64-
# Run rubocop for go_modules:
65-
docker run --rm ghcr.io/dependabot/dependabot-updater-gomod bash -c \
66-
"cd /home/dependabot/go_modules && rubocop && rubocop -A"
67-
68-
# Run Sorbet type checking:
69-
docker run --rm ghcr.io/dependabot/dependabot-updater-bundler bash -c \
70-
"cd /home/dependabot && bundle exec srb tc"
71-
```
72-
73-
### Testing Changes
74-
75-
**IMPORTANT**: All testing must be done within Docker containers. The development environment, dependencies, and native helpers are containerized and will not work on the host system.
76-
77-
For quick one-off runs during local development (outside CI), prefer `bin/test {ecosystem} …` which wraps `bin/docker-dev-shell` and executes the provided command inside the correct container.
78-
79-
**Workflow**: First start the container with `bin/docker-dev-shell {ecosystem}`, then run commands within the interactive container shell:
80-
81-
```bash
82-
# Step 1: Start the container (from host)
83-
bin/docker-dev-shell bundler
84-
85-
# Step 2: Run commands inside the container shell
86-
cd {ecosystem} && rspec spec # Run ecosystem tests
87-
rubocop # Check code style
88-
rubocop -A # Auto-fix code style issues (if any found)
89-
bundle exec srb tc # Run Sorbet type checking
90-
91-
# Shortcut: run commands directly without attaching to the shell
92-
bin/test {ecosystem} spec/dependabot/{ecosystem}/file_updater_spec.rb
93-
94-
# For updater tests, note the folder name change in containers
95-
cd dependabot-updater && rspec spec # Run updater tests (not cd updater)
96-
97-
# Test changes with real repositories
98-
bin/dry-run.rb {ecosystem} {repo} --dep="specific-dependency"
99-
100-
# After making changes, run the full validation suite:
101-
bundle exec tapioca gem --verify # Verify gem type definitions
102-
bundle exec srb tc # Type check all files
103-
rubocop # Code style check
104-
rubocop -A # Auto-fix any code style issues
105-
rspec spec # Run relevant tests
106-
```
107-
108-
**Test Coverage Requirements**:
109-
110-
- All changes must be covered by tests - this is critical to prevent regressions
111-
- All existing tests must continue to pass after your changes
112-
- Add tests for new functionality before implementing the feature
113-
- When fixing bugs, add a test that reproduces the issue first
114-
- **NEVER test private methods directly** - tests should only call public interfaces
115-
- **NEVER modify production code visibility to accommodate tests** - if tests need access to private methods, the test design is wrong
116-
- **NEVER add public methods solely for testing** - this pollutes the production API and creates maintenance burden
117-
- Tests should verify behavior through public APIs, not implementation details
118-
- Tests should exercise production code paths (e.g., `fetch_files`) rather than isolated helper methods
119-
120-
### Code Style and Validation
121-
122-
After making changes, run the full validation suite:
123-
124-
```bash
125-
bundle exec tapioca gem --verify # Verify gem type definitions
126-
bundle exec srb tc # Type check all files
127-
rubocop # Code style check
128-
rubocop -A # Auto-fix any code style issues (if any found)
129-
rspec spec # Run relevant tests
130-
```
131-
132-
**Important**: Always use `rubocop -A` to automatically fix code style issues when they can be auto-corrected. This ensures consistent formatting and reduces manual work.
133-
134-
### RuboCop Best Practices
135-
136-
**Avoid adding RuboCop exceptions** unless absolutely necessary. The default approach should be to resolve offenses using proper coding practices:
137-
138-
- **Method extraction**: Break large methods into smaller, focused methods
139-
- **Class extraction**: Split large classes into smaller, single-responsibility classes
140-
- **Reduce complexity**: Simplify conditional logic and nested structures
141-
- **Improve naming**: Use clear, descriptive variable and method names
142-
- **Refactor long parameter lists**: Use parameter objects or configuration classes
143-
- **Extract constants**: Move magic numbers and strings to named constants
144-
145-
**If a RuboCop exception is truly unavoidable**, provide clear justification in a comment explaining why the rule cannot be followed and what alternative approaches were considered.
146-
147-
### Sorbet Type Checking
148-
149-
**All new files must be Sorbet strict typed at minimum**. When updating existing files with lower typing levels, increase the typing to at least `strict`:
150-
151-
```ruby
152-
# typed: strict
153-
# frozen_string_literal: true
154-
```
155-
156-
**Typing level requirements**:
157-
158-
- **New files**: Must use `# typed: strict` or higher
159-
- **Existing files**: If below `strict`, upgrade to `# typed: strict` when making changes
160-
- **Type annotations**: Add explicit type signatures for method parameters and return values
161-
- **Validation**: Always run `bundle exec srb tc` to ensure type correctness
162-
163-
**Sorbet type checking workflow**:
164-
165-
```bash
166-
# Run Sorbet type checker to identify errors
167-
bundle exec srb tc
168-
169-
# Run type checking on specific files to focus on particular issues
170-
bundle exec srb tc path/to/file.rb
171-
172-
# Use autocorrect ONLY when you have high confidence it won't cause issues
173-
bundle exec srb tc -a path/to/file.rb
174-
```
175-
176-
**Important**: Sorbet's autocorrect feature (`-a` flag) should be used cautiously as it can cause more issues than it resolves. Only use autocorrect when you have high confidence that the changes will not break code functionality.
177-
178-
Autocorrect can handle some simple cases like:
179-
- Adding missing `override.` annotations for method overrides
180-
- Adding `T.let` declarations for instance variables in strict-typed files
181-
- Adding type annotations for constants
182-
183-
However, autocorrect often creates incorrect fixes for complex type mismatches, method signature issues, and structural problems. **Always manually resolve Sorbet errors** rather than relying on autocorrect, and carefully review any autocorrected changes to ensure they maintain code correctness and intent.
184-
185-
### Code Comments and Documentation
186-
187-
**Prioritize self-documenting code over comments**. Write clear, intention-revealing code with descriptive method and variable names that eliminate the need for explanatory comments.
188-
189-
**When to use comments**:
190-
- **Business logic context**: Explain *why* something is done when the reason isn't obvious from the code
191-
- **Complex algorithms**: Document the approach or mathematical concepts
192-
- **Workarounds**: Explain why a non-obvious solution was necessary
193-
- **External constraints**: Document API limitations, system requirements, or ecosystem-specific behaviors
194-
- **TODO/FIXME**: Temporary markers for future improvements (with issue references when possible)
195-
196-
**Avoid these comment types**:
197-
- **Implementation decisions**: Don't explain what was *not* implemented or alternative approaches considered
198-
- **Obvious code explanations**: Don't restate what the code clearly does
199-
- **Apologies or justifications**: Comments defending coding choices suggest code quality issues
200-
- **Outdated information**: Remove comments that no longer apply to current implementation
201-
- **Version history**: Use git history instead of inline change logs
202-
203-
**Comment style guidelines**:
204-
```ruby
205-
# Good: Explains WHY, adds business context
206-
# Retry failed requests up to 3 times due to GitHub API rate limiting
207-
retry_count = 3
208-
209-
# Bad: Explains WHAT the code does (obvious from code)
210-
# Set retry count to 3
211-
retry_count = 3
212-
213-
# Good: Documents external constraint
214-
# GitHub API requires User-Agent header or returns 403
215-
headers['User-Agent'] = 'Dependabot/1.0'
216-
217-
# Bad: Implementation decision discussion
218-
# We decided not to cache this because it would complicate the code
219-
# and other ecosystems don't do caching here either
220-
response = fetch_data(url)
221-
```
222-
223-
**Prefer code refactoring over explanatory comments**:
224-
```ruby
225-
# Instead of commenting complex logic:
226-
# Calculate the SHA256 of downloaded file for security verification
227-
digest = Digest::SHA256.hexdigest(response.body)
228-
229-
# Extract to a well-named method:
230-
def calculate_security_checksum(content)
231-
Digest::SHA256.hexdigest(content)
232-
end
233-
```
234-
235-
### Native Helpers
236-
237-
Many ecosystems use native language helpers (Go, Node.js, Python) located in `{ecosystem}/helpers/`. These helpers run exclusively within containers and changes require rebuilding:
238-
239-
```bash
240-
# Inside dev container - native helpers only work in containerized environment
241-
{ecosystem}/helpers/build # Rebuild native helpers
242-
```
243-
244-
**Note**: Native helper changes are not automatically reflected in the container. You must rebuild them after any modifications.
245-
24626
## Key Patterns & Conventions
24727

24828
### Error Handling
24929

250-
- Use ecosystem-specific error classes that inherit from `Dependabot::DependabotError`
251-
- Native helper failures should be caught and wrapped in Ruby exceptions
30+
- Use ecosystem-specific error classes inheriting from `Dependabot::DependabotError`
31+
- Catch native helper failures and wrap them in Ruby exceptions
25232
- Network timeouts and rate limits are handled by the `common` layer
25333

25434
### File Handling
@@ -259,8 +39,8 @@ Many ecosystems use native language helpers (Go, Node.js, Python) located in `{e
25939

26040
### Version Comparison
26141

262-
- Implement ecosystem-specific `Version` classes that handle pre-releases, build metadata
263-
- Example: `Dependabot::GoModules::Version` handles Go's semantic versioning with `+incompatible` suffix
42+
- Implement ecosystem-specific `Version` classes for pre-releases, build metadata, etc.
43+
- Example: `Dependabot::GoModules::Version` handles Go semver with `+incompatible` suffix
26444

26545
### Docker Architecture
26646

@@ -270,53 +50,7 @@ dependabot-updater-{ecosystem} (contains native tools like npm, pip)
27050
├── dependabot-updater-core (Ruby runtime + common dependencies)
27151
```
27252

273-
## Testing Patterns
274-
275-
### Fixture-Based Testing
276-
277-
```ruby
278-
# Use real dependency files as fixtures
279-
let(:dependency_files) { bundler_project_dependency_files("example_project") }
280-
281-
# Helper methods in spec_helper.rb generate realistic test data
282-
```
283-
284-
### Mocking External Calls
285-
286-
- Mock HTTP requests to package registries using VCR or WebMock
287-
- Test with realistic registry responses to catch edge cases
288-
289-
## Integration Points
290-
291-
### Security Updates
292-
293-
Handle `SECURITY_ADVISORIES` environment variable for vulnerability-driven updates that target minimum safe versions rather than latest versions.
294-
295-
### Private Registries
296-
297-
Support private registry credentials through the credential proxy pattern - never store credentials in Dependabot Core directly.
298-
299-
### Cross-Platform Support
300-
301-
- **All code must run in Docker containers on Linux** - dependencies, testing, and development environments are containerized
302-
- Native helpers must support the container's architecture
303-
- Use `SharedHelpers.in_a_temporary_repo_directory` for file operations
304-
- **Never attempt to run tests or native helpers on the host system** - they will fail outside containers
305-
306-
## Common Debugging Commands
307-
308-
```bash
309-
# Debug with breakpoints
310-
DEBUG_HELPERS=true bin/dry-run.rb {ecosystem} {repo}
311-
312-
# Debug specific native helper functions
313-
DEBUG_FUNCTION=function_name bin/dry-run.rb {ecosystem} {repo}
314-
315-
# Profile performance
316-
bin/dry-run.rb {ecosystem} {repo} --profile
317-
```
318-
319-
**Note**: All debugging commands must be run within the development container after starting it with `bin/docker-dev-shell {ecosystem}`.
53+
All code runs in Docker containers on Linux. Never run tests or native helpers on the host system.
32054

32155
## File Naming Conventions
32256

@@ -325,64 +59,23 @@ bin/dry-run.rb {ecosystem} {repo} --profile
32559
- Fixtures: `{ecosystem}/spec/fixtures/`
32660
- Native helpers: `{ecosystem}/helpers/`
32761

328-
When implementing new ecosystems or modifying existing ones, always ensure the 7 core classes are implemented and follow the established inheritance patterns from `dependabot-common`.
329-
330-
## Core Class Structure Pattern
62+
When implementing or modifying ecosystems, ensure the 7 core classes are implemented and follow the inheritance patterns from `dependabot-common`.
33163

332-
**CRITICAL**: All Dependabot core classes with nested helper classes must follow the exact pattern to avoid "superclass mismatch" errors. This pattern is used consistently across all established ecosystems (bundler, npm_and_yarn, go_modules, etc.).
333-
334-
### Main Class Structure (applies to FileFetcher, FileParser, FileUpdater, UpdateChecker, etc.)
335-
```ruby
336-
# {ecosystem}/lib/dependabot/{ecosystem}/file_updater.rb (or file_fetcher.rb, file_parser.rb, etc.)
337-
require "dependabot/file_updaters"
338-
require "dependabot/file_updaters/base"
339-
340-
module Dependabot
341-
module {Ecosystem}
342-
class FileUpdater < Dependabot::FileUpdaters::Base
343-
# require_relative statements go INSIDE the class
344-
require_relative "file_updater/helper_class"
64+
## Integration Points
34565

346-
# Main logic here...
347-
end
348-
end
349-
end
66+
### Security Updates
35067

351-
Dependabot::FileUpdaters.register("{ecosystem}", Dependabot::{Ecosystem}::FileUpdater)
352-
```
68+
Handle `SECURITY_ADVISORIES` for vulnerability-driven updates that target minimum safe versions rather than latest.
35369

354-
### Helper Class Structure
355-
```ruby
356-
# {ecosystem}/lib/dependabot/{ecosystem}/file_updater/helper_class.rb
357-
require "dependabot/{ecosystem}/file_updater"
70+
### Private Registries
35871

359-
module Dependabot
360-
module {Ecosystem}
361-
class FileUpdater < Dependabot::FileUpdaters::Base
362-
class HelperClass
363-
# Helper logic nested INSIDE the main class
364-
end
365-
end
366-
end
367-
end
368-
```
72+
Support private registry credentials through the credential proxy pattern — never store credentials in Dependabot Core directly.
36973

370-
### Key Rules:
371-
1. **Main classes** inherit from appropriate base: `Dependabot::FileUpdaters::Base`, `Dependabot::FileFetchers::Base`, etc.
372-
2. **Helper classes** are nested inside the main class
373-
3. **require_relative** statements go INSIDE the main class, not at module level
374-
4. **Helper classes require the main file** first: `require "dependabot/{ecosystem}/file_updater"`
375-
5. **Never define multiple top-level classes** with same name in the same namespace
376-
6. **Backward compatibility** can use static methods that delegate to instance methods
74+
### Cross-Platform
37775

378-
### Applies To:
379-
- **FileFetcher** and its helpers (e.g., `FileFetcher::GitCommitChecker`)
380-
- **FileParser** and its helpers (e.g., `FileParser::ManifestParser`)
381-
- **FileUpdater** and its helpers (e.g., `FileUpdater::LockfileUpdater`)
382-
- **UpdateChecker** and its helpers (e.g., `UpdateChecker::VersionResolver`)
383-
- **MetadataFinder** and its helpers
384-
- **Version** and **Requirement** classes (if they have nested classes)
76+
- Use `SharedHelpers.in_a_temporary_repo_directory` for file operations
77+
- Native helpers must support the container's architecture
38578

38679
## Adding New Ecosystems
38780

388-
If you are adding a new ecosystem, follow the detailed guide in `./NEW_ECOSYSTEMS.md` which provides step-by-step instructions for implementing a new package manager ecosystem.
81+
Follow the detailed guide in `./NEW_ECOSYSTEMS.md` for step-by-step instructions on implementing a new package manager ecosystem.

0 commit comments

Comments
 (0)