Путь A: Contribute в dbt-core
Если вы выбрали этот путь — поздравляем, это самый коммьюнити-visible из трёх. Цель — open и merge real Pull Request в dbt-core. Это даст вам:
- Commit с вашим именем в
dbt-core/mainbranch forever. - Mention в release notes (e.g., “Fixed by @yourusername in #12345”).
- Portfolio piece для resume.
- Networking с dbt Labs maintainers.
Реалистичная timeline: 15-30 часов, distributed over 2-6 недель (включая review iterations).
conftest.py, project layouts, pyproject.toml — discovery configuration
Step 1: Setup development environment
dbt-core uses hatch для project management. Setup:
# 1. Fork dbt-core на GitHub
# Через github.com/dbt-labs/dbt-core -> Fork button
# 2. Clone ваш fork
git clone https://github.com/YOUR_USERNAME/dbt-core.git
cd dbt-core
# 3. Add upstream remote (для syncing changes)
git remote add upstream https://github.com/dbt-labs/dbt-core.git
# 4. Install hatch
pip install hatch
# 5. Create development environment
hatch env create
# 6. Activate
hatch shell
# 7. Verify
dbt --version
# Должно показать локально установленный dbt-core (development version)
dbt-core поддерживает Python 3.10, 3.11, 3.12, 3.13 (по состоянию 2026). Используйте 3.11 или 3.12 для best compatibility:
hatch env create --python 3.11
hatch — современный Python project manager (alternative к Poetry, pipenv). dbt Labs migrated на него в 2024. Если впервые видите — это OK, основные команды стандартные: hatch shell (activate env), hatch run (execute commands), hatch test (run tests).
Verify setup
# Run some unit tests
hatch run pytest tests/unit/test_partial_parser.py -v
# Should pass all green.
# Run linting
hatch run dev:lint
# Should pass.
Если что-то fails — check requirements (Python version, dependencies). Issue trackers на GitHub имеют solutions для known setup problems.
Step 2: Найти good first issue
GitHub Issue Filtering:
URL: https://github.com/dbt-labs/dbt-core/issues
Filters:
label:good_first_issue
label:triage:accepted
is:open
Это даёт current list good first issues, которые maintainers verified.
Что искать
Process выбора
- Open 5-10 candidates.
- Read each issue carefully.
- Eliminate те, которые seem too complex.
- Pick top 2-3 candidates.
- Comment на каждом: “Hi, I’d like to work on this. Can I take it?”
- Wait for maintainer response (typically 1-3 days).
- Once approved -> start working.
Pro tip: на этом шаге легко procrastinate выбирая “perfect” issue. Don’t. Pick reasonable one, start working. Worst case — switch to another.
Step 3: Reproduce the issue
Don’t write code yet. First reproduce.
# Read the issue carefully.
# Identify reproduction steps.
# Run them locally.
# Example: issue says "dbt parse fails on YAML with X"
mkdir test_project && cd test_project
dbt init
# Create YAML with X
# Run: dbt parse
# Observe failure
If reproduction succeeds — you have failing test scenario. If fails (can’t reproduce) — either issue is stale (post comment, ask for clarification) or you’re missing something.
Common reasons fail to reproduce:
- dbt-core version mismatch (try main vs latest release).
- Environment difference (Python version, dependencies).
- Specific config not mentioned в issue.
- Issue already partially fixed.
Step 4: Write failing test
dbt-core uses pytest. Tests organized:
tests/
├── unit/ # unit tests, no DB
│ ├── parser/
│ ├── adapter/
│ └── ...
├── functional/ # integration с DBs (Postgres usually)
└── e2e/ # full CLI tests
For most good_first_issues — unit test is enough.
Example: Issue says “error message wrong on missing source”
Find related test file:
grep -r "missing source" tests/unit/
Likely finds tests/unit/parser/test_parse_sources.py. Read it:
import pytest
class TestParseMissingSources:
def test_missing_source_error_message(self):
# ... existing test scenarios ...
pass
def test_my_new_scenario(self):
"""
Test that missing source gives clear error message с file location.
"""
# arrange: project with reference to non-existent source
...
# act: run parser
with pytest.raises(MissingSourceError) as exc_info:
parse_project(project_with_missing_source)
# assert: error message contains file:line:column
error_message = str(exc_info.value)
assert "models/staging/stg_orders.sql" in error_message
assert "line 5" in error_message
assert "source('jaffle_shop', 'missing_source')" in error_message
Run the test:
hatch run pytest tests/unit/parser/test_parse_sources.py::TestParseMissingSources::test_my_new_scenario -v
Test should FAIL (red). Это ваш starting point.
Step 5: Implement the fix
Now find где fix должен быть.
# Where is MissingSourceError raised?
grep -r "MissingSourceError" core/dbt/
Read that code. Understand currently raised. Add file:line:column information.
# core/dbt/parser/sources.py (hypothetical)
class SourceParser:
def parse_source_reference(self, node, source_ref):
if source_ref.name not in self.known_sources:
raise MissingSourceError(
source_name=source_ref.name,
# BEFORE: just source name
# AFTER: include node file location
location=f"{node.original_file_path}:{node.line}:{node.column}",
)
Run test again:
hatch run pytest tests/unit/parser/test_parse_sources.py::TestParseMissingSources::test_my_new_scenario -v
Test passes? Excellent.
Make sure existing tests still pass:
hatch run pytest tests/unit/parser/
All green? Implementation done.
Step 6: Quality checks
Before opening PR:
# Linting
hatch run dev:lint
# Type checking
hatch run dev:typecheck
# All tests на your area
hatch run pytest tests/unit/parser/ -v
# (Optional) Run functional tests for affected area
hatch run pytest tests/functional/parser/ -v
Fix any failures. Lint должен быть clean.
Step 7: Write CHANGELOG entry
dbt-core uses changie для changelog management:
# Install changie если not yet
brew install miniscruff/changie/changie # macOS
# Or download from https://github.com/miniscruff/changie/releases
# Generate changelog entry
changie new
Interactive prompts:
Kind: Fix
Body: Include file location in MissingSourceError message
Custom:
Issue: 12345
PR:
This creates .changes/unreleased/Fix-...yaml. Commit it.
Step 8: Commit and push
dbt-core uses commit message conventions:
git add core/dbt/parser/sources.py tests/unit/parser/test_parse_sources.py .changes/unreleased/Fix-*.yaml
git commit -m "fix: include file location in MissingSourceError message
Issue: #12345
The error message previously showed only the source name without
indicating where in the project file the reference was made.
This change adds file:line:column to make debugging easier.
"
# Push to your fork
git push origin your-branch-name
Commit conventions (dbt-core uses these prefixes):
fix:— bug fixfeat:— new featuredocs:— documentationtest:— tests onlyrefactor:— code refactoring без behavior changechore:— maintenance, dependencies
Step 9: Open Pull Request
On GitHub:
- Navigate to your fork.
- Click “Pull Request” button.
- Base:
dbt-labs/dbt-core:main. Compare:YOUR_USERNAME/dbt-core:your-branch. - Title:
fix: include file location in MissingSourceError message - Description (use the dbt-core PR template):
## Resolves
Fixes #12345.
## Problem
The `MissingSourceError` error message previously contained only the source name. Users had difficulty locating where in the project the bad reference was made.
## Solution
Added `original_file_path:line:column` to the error message. Now users see exactly where the bad reference is.
## Checklist
- [x] I have read the [contributing guide](https://github.com/dbt-labs/dbt-core/blob/main/CONTRIBUTING.md).
- [x] I have run the test suite.
- [x] I have added new tests for my change.
- [x] I have updated documentation if needed.
- [x] I have added a CHANGELOG entry.
## Testing
```bash
hatch run pytest tests/unit/parser/test_parse_sources.py
All passing.
6. Submit.
---
## Step 10: Iterate on review
Within 1-3 days, dbt-core maintainer will review. Common feedback:
### Feedback 1: "Add more test cases"
> "Could you also test the case where source is in nested folder?"
Action: add the test case, commit, push.
### Feedback 2: "Use existing pattern"
> "dbt-core has a `format_location()` helper for this. Use that instead of manually concatenating."
Action: refactor to use the helper, commit, push.
### Feedback 3: "Update docs"
> "This changes the error format. Please update docs/migration_guide.md."
Action: update docs, commit, push.
### Feedback 4: Style nits
> "Use single quotes here. Consistent с file style."
Action: trivial change, commit, push.
### How to interact с maintainers
- **Respond promptly** (1-2 days). Maintainers have limited time.
- **Disagree politely** if you think feedback is wrong. Explain reasoning.
- **Ask if unsure** — better to clarify than guess.
- **Be patient** — review cycles can take weeks.
- **Be grateful** — maintainers volunteer their time.
---
## Step 11: Merged!
Eventually (1-4 weeks typically), maintainer says:
> "Looks great! Merging now. Thanks for the contribution!"
PR merged. Your contribution живёт в dbt-core forever.
You can:
- Add to your resume: "Contributed bug fix to dbt-core (PR #XXXXX, merged May 2026)."
- LinkedIn post: "Excited to share my first dbt-core contribution merged today!"
- Twitter/dev.to blog post.
---
## Common pitfalls
<DiagramContainer title="Чего избегать" color="red">
<Grid columns={2}>
<FlowColumn>
<DataBox variant="warning" size="sm" title="Не выбирайте сложный issue">
{'Refactoring issues, parsing engine, performance — слишком много для first PR. Pick error messages, doc improvements, edge cases. Save complex для после first merged PR.'}
</DataBox>
<DataBox variant="warning" size="sm" title="Не игнорируйте linting">
{'Failed lint в CI = "fix and re-push" cycles. Run lint locally before commit. Single most common rejected-pull-request reason.'}
</DataBox>
<DataBox variant="warning" size="sm" title="Не пропускайте tests">
{'Tests are mandatory. Maintainers require both new test (proving fix works) и existing tests pass. No tests = PR closed.'}
</DataBox>
</FlowColumn>
<FlowColumn>
<DataBox variant="warning" size="sm" title="Не быть упрямым в reviews">
{'Если maintainer says "use this pattern" — usually they right (more dbt-core context). Argue только если у вас strong technical reasoning. Otherwise — accept feedback.'}
</DataBox>
<DataBox variant="warning" size="sm" title="Не ghost после opening PR">
{'Open PR + disappear = abandoned. If you commit к contribute, follow through. Respond к reviews. Если life happens, comment "I will get back в X days" — show commitment.'}
</DataBox>
<DataBox variant="warning" size="sm" title="Не забывайте CHANGELOG entry">
{'CHANGELOG required для merge. Easy to forget. Maintainers will remind, но showing care from start makes good impression.'}
</DataBox>
</FlowColumn>
</Grid>
</DiagramContainer>
---
## Что считается "good capstone PR"
For purposes of this course:
- **Minimum**: Fix a `good_first_issue`. PR opened, ready for review.
- **Target**: Fix the issue, PR merged.
- **Stretch**: Multiple commits showing iteration на review feedback, merged. Optional second PR for related issue.
Even **opened but not yet merged** is excellent capstone — shows ability to work in real OSS.
---
## Realistic timeline expectations
```text
Day 1-2: Setup environment, fork, browse issues.
Day 3-5: Pick issue, comment, get approval.
Day 6-10: Reproduce, write test, implement fix.
Day 11-14: Quality checks, CHANGELOG, open PR.
Week 2-4: Review iterations (1-3 cycles).
Week 4-6: Merged.
Total: ~6 weeks elapsed time, 15-30 hours actual work. Distributed over time because of review delays.
Итого
- Path A capstone = opened or merged PR в dbt-core.
- Setup: fork, clone, install hatch, create env.
- Find good first issue with care:
triage:accepted, recent, scope-limited. - Reproduce the issue before writing code.
- Write failing test first (TDD approach).
- Implement fix in source code.
- Quality checks: lint, typecheck, tests pass.
- CHANGELOG entry через changie.
- Commit с conventional message format.
- PR description uses dbt-core template.
- Iterate review feedback politely и promptly.
- Timeline: ~6 weeks elapsed, 15-30 hours actual.
- Common pitfalls: complex issues, ignoring linting, no tests, stubbornness in review, ghosting.
- Even unmerged PR is excellent portfolio piece if well-crafted.
Next: урок 03 для path B (adapter), или урок 05 если path A complete и ready for portfolio packaging.