Level 2: OpenSearch Contributor Onboarding
Level 1 gave you a working OpenSearch you can build, test, and run. This
level turns that capability into merged pull requests. You will learn how OpenSearch is actually
contributed to: the GitHub-based model (issues and PRs, no JIRA), the DCO sign-off that
replaces a CLA, the mandatory CHANGELOG.md entry, the precommit/CI gate, the review loop, and the
backport mechanism. By the end you will have walked a trivial change, a realistic good-first-issue
fix, and a code review from the maintainer's side of the table.
This is deliberately a workflow level. The contributions are surgical — a doc fix, a validation message, a missing test. Nothing here will surprise a reviewer. That is the point: you drill the mechanics now so that Levels 3–9 can be about the engine.
Learning Objectives
By the end of Level 2 you must be able to:
- Describe the OpenSearch contribution model end-to-end: issue → fork → branch → signed commit → PR → CI → review → merge → backport.
- Find and qualify a
good first issuewithout stepping on another contributor. - Make a clean, signed (
git commit -s) commit that passes the DCO check. - Add a correct
CHANGELOG.mdentry under## [Unreleased]. - Run
./gradlew spotlessApplyand./gradlew precommitlocally so CI passes on the first push. - Open a PR that satisfies the PR template, understand each CI check, and respond to review without thrashing.
- Explain what the
backport 2.xlabel does and when to apply it.
The OpenSearch Contribution Model
OpenSearch development happens entirely on GitHub at
github.com/opensearch-project/OpenSearch. There is no Apache JIRA, no patch files, and
no CLA. If you have contributed to an Apache project (like the Tez curriculum's JIRA + .patch
flow), unlearn that here — OpenSearch is a fork-and-pull-request project.
The pieces you must internalize:
| Artifact | What it is | Where |
|---|---|---|
| Issue | A bug, enhancement, or task. The unit of "what should change." | GitHub Issues, labeled (good first issue, bug, flaky-test, …). |
| Pull Request (PR) | Your proposed change, against main. | GitHub PRs, from your fork's branch. |
| DCO | Developer Certificate of Origin. Replaces a CLA. Asserted by a Signed-off-by line. | Every commit: git commit -s. Enforced by the DCO check. |
CHANGELOG.md | A human-readable log; every user-facing PR adds one line. | Under ## [Unreleased], in an Added/Changed/Fixed/… section. |
MAINTAINERS.md | Who can approve/merge, and who owns which areas. | Repo root. |
| PR template | .github/pull_request_template.md — the checklist your PR must satisfy. | Auto-filled into the PR body. |
| SPDX header | The Apache-2.0 license header every source file carries. | Top of every .java file (precommit enforces it). |
The governance context — TSC, the OpenSearch Software Foundation under the Linux Foundation, the forum and Slack — is covered in release-governance and community interaction. For contribution mechanics, GitHub + DCO + CHANGELOG is all you need.
DCO, not CLA
The DCO is a lightweight assertion — by signing off, you certify you wrote the change or have the right to submit it under the project's license. You assert it per-commit:
git commit -s -m "Your message"
-s appends a trailer:
Signed-off-by: Your Name <your.email@example.com>
The name and email must match your git config user.name / user.email. A bot enforces this on
every PR; a commit without a valid Signed-off-by blocks the merge. There is no separate agreement
to sign — this line is the agreement. You will do this for real in
Lab 2.2.
The CHANGELOG entry
OpenSearch keeps a CHANGELOG.md (Keep-a-Changelog style). Almost every PR must add one line
under the ## [Unreleased] heading, in the right subsection, with a link to the PR:
## [Unreleased 3.x]
### Added
- Add `foo` parameter to the `_bar` API ([#12345](https://github.com/opensearch-project/OpenSearch/pull/12345))
### Fixed
- Fix misleading validation message in `RestSomethingAction` ([#12346](https://github.com/opensearch-project/OpenSearch/pull/12346))
A missing CHANGELOG entry is the single most common reason a first PR gets a "please add a changelog entry" comment and an extra review round. (Purely internal changes — e.g. a test-only refactor — can sometimes use the "skip changelog" label, but default to adding one.)
Finding a Good First Issue
Restrict yourself, at this level, to issues labeled good first issue. They are curated to be
scoped, self-contained, and low-risk.
# Browser:
# https://github.com/opensearch-project/OpenSearch/issues?q=is:open+label:%22good+first+issue%22
# gh CLI — list and inspect:
gh issue list --repo opensearch-project/OpenSearch \
--label "good first issue" --state open --limit 30
gh issue view 12345 --repo opensearch-project/OpenSearch --comments
Qualify before you claim. A good Level 2 issue:
- has the
good first issuelabel and is not assigned to anyone; - has no open linked PR (
gh issue viewshows linked PRs); - has a clear, bounded description — you can state the fix in one sentence;
- has no unresolved design debate in the comments.
When you find one, leave a short comment ("I'd like to work on this") before you start, so you do not duplicate someone's in-flight work. Etiquette is detailed in Community Interaction.
Warning: Do not open a PR and then find out two other people already did. Read the full comment thread and the linked-PR list first. This is the same discipline as the Tez "read all comments before claiming" rule — the platform changed, the etiquette did not.
The PR Lifecycle
flowchart TD
A["Find/claim a good first issue"] --> B["Fork opensearch-project/OpenSearch"]
B --> C["git clone your fork; add upstream remote"]
C --> D["git checkout -b fix/issue-12345"]
D --> E["Make the surgical change"]
E --> F["Add a CHANGELOG.md entry under [Unreleased]"]
F --> G["./gradlew spotlessApply"]
G --> H["./gradlew precommit + scoped tests"]
H --> I["git commit -s (DCO sign-off)"]
I --> J["git push origin fix/issue-12345"]
J --> K["Open PR against main; fill the template"]
K --> L["CI runs: gradle-check, assemble, precommit, DCO, CHANGELOG"]
L -->|red| H
L -->|green| M["Maintainer review"]
M -->|changes requested| E
M -->|approved| N["Maintainer merges (squash) to main"]
N --> O["Add 'backport 2.x' label -> bot opens backport PR"]
The full state machine in words:
- Fork the repo to your account; clone your fork; add the canonical repo as the
upstreamremote so you can keepmaincurrent. - Branch from an up-to-date
main(fix/...orfeature/...). - Change exactly what the issue asks — nothing more (scope creep kills first PRs).
- CHANGELOG: add one line under
## [Unreleased]. - Format and gate locally:
spotlessApply, thenprecommit, then the scoped tests for what you touched. (From Lab 1.2.) - Commit with
-sso the DCO check passes. - Push and open a PR against
main; complete the PR template. - CI runs the checks (below). Green is required.
- Review: a maintainer (from
MAINTAINERS.md) reviews. Respond to every comment; push more signed commits (do not force-push away the review history unless asked). - Merge: a maintainer squash-merges. If the fix belongs on the maintenance line, they (or you,
if you have rights) add the
backport 2.xlabel and a bot opens the backport PR.
The CI checks you will see
| Check | What it verifies | Local equivalent |
|---|---|---|
| DCO | Every commit has a valid Signed-off-by. | git commit -s |
| Changelog | A CHANGELOG.md entry was added (or the skip label applied). | edit CHANGELOG.md |
| gradle-check | The big one: builds + runs the relevant tests + precommit across affected projects. | ./gradlew :server:check (subset) |
| assemble | The distribution still builds. | ./gradlew assemble |
| precommit | Static analysis: checkstyle, forbidden APIs, SPDX headers, etc. | ./gradlew precommit |
Running spotlessApply + precommit + the scoped tests locally before you push is the single
biggest lever on review speed. Detail on quality expectations is in
PR Quality and Preparation.
Deliverables
Demonstrate all of the following before advancing to Level 3:
-
A fork of
opensearch-project/OpenSearchwithupstreamconfigured, and a topic branch off an up-to-datemain(Lab 2.1, Lab 2.2). -
A signed commit whose
Signed-off-bymatches your git identity (a passing local DCO check). -
A correct
CHANGELOG.mdentry under## [Unreleased]. -
A clean local
./gradlew spotlessApply+./gradlew precommit. -
A walked good-first-issue fix with a unit test using
assertThrows/assertEquals(Lab 2.3). - A completed review of the flawed example PR — you found every issue a maintainer would flag (Lab 2.4).
-
A written explanation of what
backport 2.xdoes and when to apply it.
Common Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
Forgetting -s on the commit | DCO check fails; PR blocked | git commit -s; fix history with git commit --amend -s or git rebase --signoff. |
Signed-off-by email ≠ git email | DCO check fails | Set git config user.email to match; re-sign. |
No CHANGELOG.md entry | Changelog check fails; extra review round | Add one line under ## [Unreleased] linking your PR. |
Skipping spotlessApply | precommit/CI fails on formatting | Run ./gradlew spotlessApply before committing. |
| Scope creep ("while I'm here…") | Reviewer asks for a split; PR stalls for weeks | One logical change per PR. File a follow-up issue for the rest. |
| Force-pushing over review history | Reviewers lose the thread of what changed | Add new signed commits during review; squash happens at merge. |
| Opening a PR for a claimed issue | Duplicate work, community friction | Check assignee and linked PRs; comment before starting. |
| Treating the PR template as boilerplate | Missing checkboxes; reviewer asks you to redo it | Fill it honestly — tests, CHANGELOG, related issues, DCO. |
PR Profile: Level 2 Graduate
A Level 2 graduate can credibly open these PRs end-to-end, with passing CI on the first or second push:
| PR type | Example | Test requirement |
|---|---|---|
| Doc/example fix | Correct an outdated curl or a wrong Javadoc @param | None — docs only; still needs DCO + (often) CHANGELOG |
| Validation-message fix | Clarify a confusing error from a *Request.validate() or a REST parser | A unit test asserting the new message (Lab 2.3) |
| Missing-assertion / test clarity | Add an assertEquals with a message to an under-checked test | Re-run the test class |
| Misleading log line | Convert a string-concat LOG.info to placeholders; add context | Usually none; manual run noted in the PR |
You are not yet ready to submit: changes to coordination, allocation, the engine, the search path, or anything touching the wire protocol / BWC. Those are Levels 3–9. What you are ready for is the thing most contributors get wrong: a clean, focused, well-tested, properly-signed PR with a CHANGELOG entry that a maintainer can merge without a five-round back-and-forth.
Next: Lab 2.1 — Navigate the OpenSearch Repository Structure.