Contribution Guide¶
Doc Version: 1.0.2
Last Updated: 2026-05-21
Git Commit: 61384b4a
Author: Lincoln
Welcome Contributions¶
Thank you for your interest in the JAiRouter project! We welcome all forms of contributions, including but not limited to:
- 🐛 Bug reports and fixes
- ✨ New feature development
- 📚 Documentation improvements
- 🧪 Test case additions
- 💡 Feature suggestions and discussions
Development Environment Setup¶
System Requirements¶
- Java: 17 or higher
- Maven: 3.8+ (recommended to use the built-in Maven Wrapper)
- Git: 2.20+
- IDE: IntelliJ IDEA (recommended) or Eclipse
Environment Configuration¶
Clone the Project
Verify Java Version
Build the Project
Run Tests
Start the Application
IDE Configuration¶
IntelliJ IDEA¶
- Import Project
- File → Open → Select project root directory
Choose "Import as Maven project"
Configure Code Style
- File → Settings → Editor → Code Style
Import
checkstyle.xmlconfiguration from project rootConfigure Maven
- File → Settings → Build → Build Tools → Maven
Set Maven home directory to
.mvn/wrapperwithin the projectInstall Recommended Plugins
- CheckStyle-IDEA
- SpotBugs
- SonarLint
Development Workflow¶
1. Create Branch¶
# Create feature branch from main
git checkout main
git pull origin main
git checkout -b feature/your-feature-name
# Or create fix branch
git checkout -b fix/issue-number-description
2. Development Standards¶
Code Style¶
- Follow the project's Checkstyle configuration
- Use 4 spaces for indentation, not tabs
- Line length should not exceed 120 characters
- Classes and methods require complete Javadoc comments
Naming Conventions¶
- Class names: PascalCase (e.g.,
LoadBalancerFactory) - Method names: camelCase (e.g.,
selectInstance) - Constants: UPPER_SNAKE_CASE (e.g.,
DEFAULT_TIMEOUT) - Package names: lowercase, dot-separated (e.g.,
org.unreal.modelrouter.adapter)
Comment Standards¶
/**
* Load balancer factory class
*
* <p>Responsible for creating and managing different types of load balancer instances,
* supporting dynamic switching of load balancing strategies.
*
* @author Author Name
* @since 1.0.0
*/
public class LoadBalancerFactory {
/**
* Create load balancer based on configuration
*
* @param config Load balancing configuration
* @return Load balancer instance
* @throws IllegalArgumentException when configuration is invalid
*/
public LoadBalancer createLoadBalancer(LoadBalanceConfig config) {
// Implementation logic
}
}
3. Testing Requirements¶
Unit Tests¶
- New features must include corresponding unit tests
- Test coverage should be no less than 80%
- Test class naming format:
{ClassName}Test
@ExtendWith(MockitoExtension.class)
class LoadBalancerFactoryTest {
@Mock
private LoadBalanceConfig config;
@InjectMocks
private LoadBalancerFactory factory;
@Test
@DisplayName("Should create correct load balancer based on configuration")
void shouldCreateCorrectLoadBalancer() {
// Given
when(config.getType()).thenReturn("random");
// When
LoadBalancer balancer = factory.createLoadBalancer(config);
// Then
assertThat(balancer).isInstanceOf(RandomLoadBalancer.class);
}
}
Integration Tests¶
- Key features require integration tests
- Use
@SpringBootTestfor complete application context testing
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UniversalControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void shouldHandleChatRequest() {
// Integration test logic
}
}
4. Commit Standards¶
Commit Message Format¶
Use Conventional Commits specification:
Types (type): - feat: New feature - fix: Bug fix - docs: Documentation update - style: Code formatting adjustments - refactor: Code refactoring - test: Test-related changes - chore: Build process or auxiliary tool changes
Example:
feat(loadbalancer): Add consistent hash load balancing algorithm
- Implement virtual node-based consistent hash algorithm
- Support dynamic node addition and removal
- Add corresponding unit tests
Closes #123
5. Code Review¶
Submit Pull Request¶
Push Branch
Create Pull Request
- Create PR on GitHub
- Fill in detailed PR description
Link related Issues
PR Description Template
## Change Description Briefly describe the content and purpose of this change. ## Change Type - [ ] Bug fix - [ ] New feature - [ ] Documentation update - [ ] Code refactoring - [ ] Performance optimization ## Testing - [ ] Unit tests added - [ ] Integration tests added - [ ] Manual testing passed ## Checklist - [ ] Code follows project standards - [ ] Related documentation updated - [ ] Test coverage requirements met - [ ] No Checkstyle and SpotBugs warnings ## Related Issues Closes #issue-number
Code Review Focus Points¶
Reviewer Focus Areas: - Code logic correctness - Performance impact - Security considerations - Test completeness - Documentation updates
Common Issues: - Unhandled exceptions - Resource leaks - Concurrency safety issues - Unnecessary complexity
Before You Merge: Read the CI Gates Correctly¶
Merge only when every row of gh pr checks <n> is pass or skipping — pending is not a pass.
Which rows appear depends on what you changed. Never read a missing row as green:
| Changed paths | Gates that run | Gates that do not appear |
|---|---|---|
docs/**, *.md, .cspell.json | 拼写检查, 文档质量检查, 文档代码同步检查, … | test (java-tests.yml filters on code paths) |
src/** (Java), pom.xml, resources | test, qodana, smoke, … | 拼写检查, 文档质量检查 (docs-quality.yml filters on docs paths) |
.gitignore and other unmatched paths | CodeQL / Analyze only | both of the above |
So a docs-only PR with no test row is expected, and a code-only PR with no 拼写检查 row is expected.
Trap: bot commits can hide gates. When a bot pushes to your branch (for example Auto-update sitemap.xml), the runs it triggers can stop at action_required — 0s, no jobs — and those runs do not show up in gh pr checks at all. Find them by listing runs per branch:
gh run list --branch <your-branch> --limit 10
# the same workflow appears twice, e.g.
# completed success Java 测试 38143230269 4m34s
# completed action_required Java 测试 38143237970 0s
Release each one, then re-check:
Related trap: gh pr view <n> --json mergeStateStatus may report UNSTABLE while mergeable is MERGEABLE, and the merge still succeeds — mergeable does not mean the gates ran.
Known flake. The external link check inside 文档质量检查 occasionally gets HTTP 503 for https://github.com/<owner>/<repo>/blob/master/LICENSE. Re-run that job, and say so in the PR description instead of pretending it never happened.
When CI Is Unavailable: Run the Same Gates Locally¶
GitHub Actions minutes can run out (it happened once in this repo, in Oct 2026 — see issue #334). gh pr checks then has nothing to report — but the criterion must not loosen, or an episode like #294 (merged with a red spell check) repeats. The repo ships a local replica:
# Windows (the wrapper only bypasses the execution policy that blocks unsigned .ps1 files)
scripts\test\local-gates.cmd
# docs / spelling / frontend half only (fast)
scripts\test\local-gates.cmd -SkipMaven
It reproduces the table above item by item: starts redis:7-alpine + postgres:16-alpine (same health-cmd as CI) → mvnw test → asserts the three gated tests were not skipped; then runs mkdocs build --strict, markdownlint-cli2, check-links.py --fail-on-error, check-docs-sync.py --fail-on-error, cspell and the frontend type-check.
Rules for using it (same spirit as "merge only when the gates are green"):
- SKIP is not PASS: the script lists SKIPs separately. You must state in the PR description which item did not run and why. A typical case: a
frontend/**-only PR has no changed*.md, so the spell check SKIPs — that is not a pass. - Declare the local deltas: this machine is Windows, so there is no CI Linux behavior and no cross-platform matrix; and the local
cspell@8dictionary is not identical to CI'scspell-action@v5⇒ a clean local spell check does not imply a green CI one. - Re-run after minutes are restored: once CI is back, re-run
test+文档质量检查+smokefor everything merged during the gap. - Troubleshooting and known local defects (this machine's intermittent AMSI crash, and the ignored local artifacts under
docs/that pollute the docs checks) are documented in the header ofscripts/test/local-gates.ps1. - ⚠️ Only the PowerShell version exists so far (the maintainer's machine is Windows). On Linux / macOS, follow the mapping table in that script header and run the same commands by hand — never claim in a PR that you ran something you did not.
Development Guidance¶
Adding New Adapters¶
Create Adapter Class
Register Adapter
Add Tests
Adding New Load Balancing Strategies¶
Implement Interface
Register Strategy
Adding New Rate Limiting Algorithms¶
Implement Interface
Configuration Support
Release Process¶
Version Number Standards¶
Use Semantic Versioning specification:
- MAJOR: Incompatible API changes
- MINOR: Backward-compatible feature additions
- PATCH: Backward-compatible bug fixes
Release Cadence¶
Rule: once a themed batch is merged, cut a PATCH release within 48 hours; in any case, never let more than 7 days pass.
This is not a formality — it comes from a measured lesson in this repository. In the 7 days after v3.3.0 (2026-10-07) the project accumulated 82 commits (58 substantive) with no release at all. The consequences were concrete: the behavior-changes list had to carry 9 entries at once, the release notes became hard to write, the blast radius of any unknown regression covered the whole batch, and the empty-stream regression on /v1 introduced by #305 (#356) survived an extra day.
Four supporting rules:
- Release per batch — never stockpile: once a themed batch (an EPIC or a group of related issues) is merged, ship it;
- Ship a patch within 72 hours of merging a P1 fix — do not wait for the next feature window;
- Decide the version with Semantic Versioning: a batch containing only
fix/docs/chore/test/refactor(zerofeat) is a PATCH — do not inflate it to MINOR to look important; - Release notes cover that interval only: do not repeat the previous release's behavior changes (repeating them reads as if the change happened twice); list behavior changes in the "Behavior changes to be aware of" table.
Release Checklist¶
- [ ] All tests pass:
scripts/test/local-gates.cmdis green locally (or SKIP with the reason stated in the PR / release notes), and the CItestjob passes — the three gated integration tests must not be skipped - [ ] Code quality checks pass: both Qodana and CodeQL pass
- [ ] Documentation updated: zh/en in sync, and the documentation gates that should appear for the changed paths all pass (see "Before merging: read the CI gates correctly" in this file)
- [ ] CHANGELOG updated: add the entry to
docs/{zh,en}/reference/changelog.mdand update the "current version status" inroadmap.md - [ ] Version number updated:
pom.xml, the facts block inREADME.md/README-ZH.md, and the document version block indocs/{zh,en}/reference/changelog.md— all four must agree
Community Participation¶
Reporting Issues¶
When reporting issues via GitHub Issues, please provide:
- Detailed problem description
- Reproduction steps
- Expected behavior
- Actual behavior
- Environment information (Java version, operating system, etc.)
- Related logs
Feature Suggestions¶
When submitting feature suggestions, please explain:
- Use case for the feature
- Expected implementation approach
- Impact on existing features
- Willingness to participate in development
Participating in Discussions¶
- Join project discussions
- Answer other users' questions
- Share usage experiences
- Provide improvement suggestions
Getting Help¶
If you encounter problems during development, you can get help through:
- Reviewing project documentation
- Searching existing Issues
- Creating new Issues
- Participating in community discussions
Thank you for your contributions! Every contribution makes JAiRouter better.