mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-30 05:13:40 +00:00
1 line
No EOL
14 KiB
JavaScript
1 line
No EOL
14 KiB
JavaScript
"use strict";(globalThis.webpackChunkdocs_split_developer=globalThis.webpackChunkdocs_split_developer||[]).push([[1459],{2199:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>c,default:()=>h,frontMatter:()=>t,metadata:()=>i,toc:()=>o});const i=JSON.parse('{"id":"contributing","title":"Contributing Guide","description":"Welcome! This guide helps you contribute to the Tibber Prices integration.","source":"@site/docs/contributing.md","sourceDirName":".","slug":"/contributing","permalink":"/hass.tibber_prices/developer/contributing","draft":false,"unlisted":false,"editUrl":"https://github.com/jpawlowski/hass.tibber_prices/tree/main/docs/developer/docs/contributing.md","tags":[],"version":"current","lastUpdatedAt":1764985026000,"frontMatter":{},"sidebar":"tutorialSidebar","previous":{"title":"Performance Optimization","permalink":"/hass.tibber_prices/developer/performance"},"next":{"title":"Release Notes Generation","permalink":"/hass.tibber_prices/developer/release-management"}}');var r=s(4848),l=s(8453);const t={},c="Contributing Guide",d={},o=[{value:"Getting Started",id:"getting-started",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Fork and Clone",id:"fork-and-clone",level:3},{value:"Development Workflow",id:"development-workflow",level:2},{value:"1. Create a Branch",id:"1-create-a-branch",level:3},{value:"2. Make Changes",id:"2-make-changes",level:3},{value:"3. Test Locally",id:"3-test-locally",level:3},{value:"4. Write Tests",id:"4-write-tests",level:3},{value:"5. Commit Changes",id:"5-commit-changes",level:3},{value:"6. Push and Create PR",id:"6-push-and-create-pr",level:3},{value:"Pull Request Guidelines",id:"pull-request-guidelines",level:2},{value:"PR Template",id:"pr-template",level:3},{value:"PR Checklist",id:"pr-checklist",level:3},{value:"Review Process",id:"review-process",level:3},{value:"Code Review Tips",id:"code-review-tips",level:2},{value:"What Reviewers Look For",id:"what-reviewers-look-for",level:3},{value:"Responding to Feedback",id:"responding-to-feedback",level:3},{value:"Finding Issues to Work On",id:"finding-issues-to-work-on",level:2},{value:"Communication",id:"communication",level:2}];function a(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",hr:"hr",input:"input",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,l.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"contributing-guide",children:"Contributing Guide"})}),"\n",(0,r.jsx)(n.p,{children:"Welcome! This guide helps you contribute to the Tibber Prices integration."}),"\n",(0,r.jsx)(n.h2,{id:"getting-started",children:"Getting Started"}),"\n",(0,r.jsx)(n.h3,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Git"}),"\n",(0,r.jsx)(n.li,{children:"VS Code with Remote Containers extension"}),"\n",(0,r.jsx)(n.li,{children:"Docker Desktop"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"fork-and-clone",children:"Fork and Clone"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"Fork the repository on GitHub"}),"\n",(0,r.jsxs)(n.li,{children:["Clone your fork:","\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"git clone https://github.com/YOUR_USERNAME/hass.tibber_prices.git\ncd hass.tibber_prices\n"})}),"\n"]}),"\n",(0,r.jsx)(n.li,{children:"Open in VS Code"}),"\n",(0,r.jsx)(n.li,{children:'Click "Reopen in Container" when prompted'}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"The DevContainer will set up everything automatically."}),"\n",(0,r.jsx)(n.h2,{id:"development-workflow",children:"Development Workflow"}),"\n",(0,r.jsx)(n.h3,{id:"1-create-a-branch",children:"1. Create a Branch"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"git checkout -b feature/your-feature-name\n# or\ngit checkout -b fix/issue-123-description\n"})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Branch naming:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"feature/"})," - New features"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"fix/"})," - Bug fixes"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"docs/"})," - Documentation only"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"refactor/"})," - Code restructuring"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"test/"})," - Test improvements"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"2-make-changes",children:"2. Make Changes"}),"\n",(0,r.jsxs)(n.p,{children:["Edit code, following ",(0,r.jsx)(n.a,{href:"/hass.tibber_prices/developer/coding-guidelines",children:"Coding Guidelines"}),"."]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Run checks frequently:"})}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"./scripts/type-check # Pyright type checking\n./scripts/lint # Ruff linting (auto-fix)\n./scripts/test # Run tests\n"})}),"\n",(0,r.jsx)(n.h3,{id:"3-test-locally",children:"3. Test Locally"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"./scripts/develop # Start HA with integration loaded\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Access at ",(0,r.jsx)(n.a,{href:"http://localhost:8123",children:"http://localhost:8123"})]}),"\n",(0,r.jsx)(n.h3,{id:"4-write-tests",children:"4. Write Tests"}),"\n",(0,r.jsxs)(n.p,{children:["Add tests in ",(0,r.jsx)(n.code,{children:"/tests/"})," for new features:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-python",children:'@pytest.mark.unit\nasync def test_your_feature(hass, coordinator):\n """Test your new feature."""\n # Arrange\n coordinator.data = {...}\n\n # Act\n result = your_function(coordinator.data)\n\n # Assert\n assert result == expected_value\n'})}),"\n",(0,r.jsx)(n.p,{children:"Run your test:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"./scripts/test tests/test_your_feature.py -v\n"})}),"\n",(0,r.jsx)(n.h3,{id:"5-commit-changes",children:"5. Commit Changes"}),"\n",(0,r.jsxs)(n.p,{children:["Follow ",(0,r.jsx)(n.a,{href:"https://www.conventionalcommits.org/",children:"Conventional Commits"}),":"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:'git add .\ngit commit -m "feat(sensors): add volatility trend sensor\n\nAdd new sensor showing 3-hour volatility trend direction.\nIncludes attributes with historical volatility data.\n\nImpact: Users can predict when prices will stabilize or continue fluctuating."\n'})}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Commit types:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"feat:"})," - New feature"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"fix:"})," - Bug fix"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"docs:"})," - Documentation"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"refactor:"})," - Code restructuring"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"test:"})," - Test changes"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"chore:"})," - Maintenance"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:(0,r.jsx)(n.strong,{children:"Add scope when relevant:"})}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"feat(sensors):"})," - Sensor platform"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"fix(coordinator):"})," - Data coordinator"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"docs(user):"})," - User documentation"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"6-push-and-create-pr",children:"6. Push and Create PR"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-bash",children:"git push origin your-branch-name\n"})}),"\n",(0,r.jsx)(n.p,{children:"Then open Pull Request on GitHub."}),"\n",(0,r.jsx)(n.h2,{id:"pull-request-guidelines",children:"Pull Request Guidelines"}),"\n",(0,r.jsx)(n.h3,{id:"pr-template",children:"PR Template"}),"\n",(0,r.jsx)(n.p,{children:"Title: Short, descriptive (50 chars max)"}),"\n",(0,r.jsx)(n.p,{children:"Description should include:"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-markdown",children:"## What\nBrief description of changes\n\n## Why\nProblem being solved or feature rationale\n\n## How\nImplementation approach\n\n## Testing\n- [ ] Manual testing in Home Assistant\n- [ ] Unit tests added/updated\n- [ ] Type checking passes\n- [ ] Linting passes\n\n## Breaking Changes\n(If any - describe migration path)\n\n## Related Issues\nCloses #123\n"})}),"\n",(0,r.jsx)(n.h3,{id:"pr-checklist",children:"PR Checklist"}),"\n",(0,r.jsx)(n.p,{children:"Before submitting:"}),"\n",(0,r.jsxs)(n.ul,{className:"contains-task-list",children:["\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Code follows ",(0,r.jsx)(n.a,{href:"/hass.tibber_prices/developer/coding-guidelines",children:"Coding Guidelines"})]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","All tests pass (",(0,r.jsx)(n.code,{children:"./scripts/test"}),")"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Type checking passes (",(0,r.jsx)(n.code,{children:"./scripts/type-check"}),")"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Linting passes (",(0,r.jsx)(n.code,{children:"./scripts/lint-check"}),")"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Documentation updated (if needed)"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","AGENTS.md updated (if patterns changed)"]}),"\n",(0,r.jsxs)(n.li,{className:"task-list-item",children:[(0,r.jsx)(n.input,{type:"checkbox",disabled:!0})," ","Commit messages follow Conventional Commits"]}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"review-process",children:"Review Process"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Automated checks"})," run (CI/CD)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Maintainer review"})," (usually within 3 days)"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Address feedback"})," if requested"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Approval"})," \u2192 Maintainer merges"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"code-review-tips",children:"Code Review Tips"}),"\n",(0,r.jsx)(n.h3,{id:"what-reviewers-look-for",children:"What Reviewers Look For"}),"\n",(0,r.jsxs)(n.p,{children:["\u2705 ",(0,r.jsx)(n.strong,{children:"Good:"})]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Clear, self-explanatory code"}),"\n",(0,r.jsx)(n.li,{children:"Appropriate comments for complex logic"}),"\n",(0,r.jsx)(n.li,{children:"Tests covering edge cases"}),"\n",(0,r.jsx)(n.li,{children:"Type hints on all functions"}),"\n",(0,r.jsx)(n.li,{children:"Follows existing patterns"}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["\u274c ",(0,r.jsx)(n.strong,{children:"Avoid:"})]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Large PRs (>500 lines) - split into smaller ones"}),"\n",(0,r.jsx)(n.li,{children:"Mixing unrelated changes"}),"\n",(0,r.jsx)(n.li,{children:"Missing tests for new features"}),"\n",(0,r.jsx)(n.li,{children:"Breaking changes without migration path"}),"\n",(0,r.jsx)(n.li,{children:"Copy-pasted code (refactor into shared functions)"}),"\n"]}),"\n",(0,r.jsx)(n.h3,{id:"responding-to-feedback",children:"Responding to Feedback"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Don't take it personally - we're improving code together"}),"\n",(0,r.jsx)(n.li,{children:"Ask questions if feedback unclear"}),"\n",(0,r.jsx)(n.li,{children:"Push additional commits to address comments"}),"\n",(0,r.jsx)(n.li,{children:"Mark conversations as resolved when fixed"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"finding-issues-to-work-on",children:"Finding Issues to Work On"}),"\n",(0,r.jsx)(n.p,{children:"Good first issues are labeled:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"good first issue"})," - Beginner-friendly"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"help wanted"})," - Maintainers welcome contributions"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"documentation"})," - Docs improvements"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Comment on issue before starting work to avoid duplicates."}),"\n",(0,r.jsx)(n.h2,{id:"communication",children:"Communication"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"GitHub Issues"})," - Bug reports, feature requests"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Pull Requests"})," - Code discussion"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"Discussions"})," - General questions, ideas"]}),"\n"]}),"\n",(0,r.jsx)(n.p,{children:"Be respectful, constructive, and patient. We're all volunteers! \ud83d\ude4f"}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsxs)(n.p,{children:["\ud83d\udca1 ",(0,r.jsx)(n.strong,{children:"Related:"})]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"/hass.tibber_prices/developer/setup",children:"Setup Guide"})," - DevContainer setup"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"/hass.tibber_prices/developer/coding-guidelines",children:"Coding Guidelines"})," - Style guide"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"/hass.tibber_prices/developer/testing",children:"Testing"})," - Writing tests"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.a,{href:"/hass.tibber_prices/developer/release-management",children:"Release Management"})," - How releases work"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}}}]); |