Lab 2.2: Prepare a Patch Using Apache Practices

Background

The word "patch" in Apache lore conjures a .patch file emailed to a mailing list or attached to JIRA. That is not how Apache Tez works today. Read .asf.yaml and the Jenkinsfile in the checkout (you did, in Lab 2.1) and the current reality is unambiguous: Tez is a GitHub pull-request project whose issue tracker is Apache JIRA. Your "patch" is a PR; its identity is the JIRA key TEZ-XXXX carried in the branch name, the commit subject, and the PR title.

This lab walks the complete modern flow on a real but trivial change — a Javadoc improvement in tez-api. Trivial is intentional: the goal is to burn the workflow into muscle memory — fork, branch, format, gate, commit, push, PR, respond to Yetus — not to write impressive code.

Why This Lab Matters for Contributors

  • The mechanics are where first-time contributors lose the most time and credibility: a wrong commit subject, a missing local gate, a formatting-churn diff. Get them automatic and reviewers can focus on your logic.
  • Every check that fails in CI has a local command that would have caught it. Learning that mapping is the difference between a green first push and a three-day red-CI slog.
  • The TEZ-XXXX: convention is not cosmetic — it is what links your PR to JIRA (via .asf.yaml's jira_options: link) and what a committer's squash-merge preserves.

Prerequisites

  • Lab 2.1 complete — you can navigate the modules.
  • A GitHub account and an Apache JIRA account (issues.apache.org — self-service signup).
  • git, a JDK 21+, and Maven 3.9.14+ (java -version, mvn -version — see the repo README.md "Requirements").
  • git config user.name and user.email set to your real identity.

Step-by-Step Tasks

Step 1: Fork, Clone, and Set Remotes

You cannot push to apache/tez — .asf.yaml protects master. Work from a fork.

# Fork apache/tez in the GitHub UI, then:
git clone git@github.com:<your-user>/tez.git
cd tez

# Add the canonical repo as 'upstream' so you can stay current
git remote add upstream https://github.com/apache/tez.git
git remote -v
# origin    <your fork>   (push)
# upstream  apache/tez    (fetch)

Note: gh repo fork apache/tez --clone does all of this in one command if you have the GitHub CLI, including setting the upstream remote.

Step 2: Find or File the JIRA Issue

Every change needs a TEZ-XXXX. For this lab, either find a real Minor/Trivial Javadoc issue or file one:

# Browse open, unassigned, low-priority issues:
#   https://issues.apache.org/jira/issues/?jql=project=TEZ AND resolution=Unresolved
#     AND priority in (Minor, Trivial) AND assignee is EMPTY ORDER BY updated DESC

Before you touch code, comment on the issue ("I'm looking into this") so you do not duplicate another contributor's in-flight work. If you are filing a fresh one, keep the summary specific: "Improve Javadoc for Vertex.addDataSink()," not "docs." Filing conventions and how committers read JIRA are in jira-review.

Step 3: Branch from an Up-to-Date master

git fetch upstream
git checkout -b TEZ-XXXX upstream/master

The branch name is conventionally just the JIRA key. Confirm you started from current master:

git log -1 --oneline upstream/master   # your branch tip should match this

Step 4: Make the Change

Open a public method in tez-api that is missing Javadoc. Vertex.addDataSink(...) is a good candidate:

grep -n "public Vertex addDataSink" \
  tez-api/src/main/java/org/apache/tez/dag/api/Vertex.java

Add or complete the Javadoc. Follow the house style you will see across tez-api:

/**
 * Adds a {@link DataSinkDescriptor} to this vertex. The sink receives the
 * output produced by this vertex's tasks.
 *
 * @param outputName the name identifying this sink; must be unique within the vertex
 * @param dataSink   the descriptor defining the sink's output and its committer
 * @return this {@link Vertex}, to allow method chaining
 */
public Vertex addDataSink(String outputName, DataSinkDescriptor dataSink) {

Rules that keep checkstyle happy (JavadocStyle, JavadocMethod in the checkstyle config):

  • First sentence is imperative and ends with a period ("Adds a…", not "This method adds a…").
  • Every parameter has a @param; a non-void method has a @return.
  • Use {@link ClassName} for type references and {@code x} for literals.

Step 5: Format with Spotless — Before Anything Else

Spotless runs in the Maven validate phase, so if your formatting is off, the build fails before tests even compile. Run its auto-fixer first — it corrects import order (java, javax, org.apache, com, net, io), trailing whitespace, the final newline, and the license header for you:

mvn spotless:apply -pl tez-api
mvn spotless:check -pl tez-api    # must pass now

Step 6: Run the Local Gates

Reproduce, locally, what precommit will run remotely. These are the exact checks dev-support/tez-personality.sh fires for a changed .java file:

# Compile (with the strict lint profile precommit uses)
mvn compile -pl tez-api -Ptest-patch -q

# Checkstyle — fails the build on any violation
mvn checkstyle:check -pl tez-api

# License header audit
mvn apache-rat:check -pl tez-api

# SpotBugs static analysis
mvn compile spotbugs:spotbugs -Pspotbugs -pl tez-api

# The module's tests (a Javadoc change still runs them; validate-phase gates fire)
mvn test -pl tez-api -q

Every one must be BUILD SUCCESS. If checkstyle reports a violation even on a line you did not write but that is inside your diff's hunk, you own it — fix it.

Step 7: Commit with the Enforced Subject Format

Verify the format against real history before you commit:

git log --oneline -8

You will see subjects like TEZ-4683: Fix tez framework mode config name (#455) (Raghav Aggarwal reviewed by Laszlo Bodor). The (#455) and (… reviewed by …) are appended by the committer at squash-merge — you do not write them. Your job is the subject prefix:

git add tez-api/src/main/java/org/apache/tez/dag/api/Vertex.java
git commit -m "TEZ-XXXX: Improve Javadoc for Vertex.addDataSink()"

Warning: The old TEZ-1234. Description (period) form appears in ancient history. Modern Tez uses a colon: TEZ-XXXX: Description. Match what the recent git log shows, not what a decade of stale tutorials claim. A malformed subject breaks the JIRA↔PR linkage.

Step 8: Push and Open the PR

git push -u origin TEZ-XXXX

Open the PR against apache/tez master. There is no PR template (confirm: ls .github shows only workflows/), so write the body yourself. A good body:

### What
Adds complete Javadoc (`@param`/`@return`) to `Vertex.addDataSink()`.

### Why
The method had no parameter documentation; new users had to read the
implementation to understand `outputName` vs `dataSink`.

### Testing
- `mvn spotless:check -pl tez-api`      : pass
- `mvn checkstyle:check -pl tez-api`    : pass
- `mvn apache-rat:check -pl tez-api`    : pass
- `mvn test -pl tez-api`                : pass

JIRA: https://issues.apache.org/jira/browse/TEZ-XXXX

Title the PR exactly TEZ-XXXX: Improve Javadoc for Vertex.addDataSink(). Because .asf.yaml sets jira_options: link, the PR is auto-linked back to the JIRA issue.

Step 9: Read and Respond to Precommit

Two systems report:

  • GitHub Actions (build.yml) shows a compile matrix result inline on the PR — green checkmarks per Java/OS combination.
  • Jenkins/Yetus posts a comment with a per-check table and emoji votes (+1/-1) for compile, unit, checkstyle, spotbugs, javadoc, and — since you touched no shell or docs — nothing for shellcheck/codespell.

When a check is -1:

Yetus check -1What it meansLocal reproduction
checkstyleStyle violation in your diffmvn checkstyle:check -pl <module>; open target/checkstyle-result.xml
unitA test failedmvn test -pl <module> -am -Dtest=<Class>
spotbugsNew static-analysis bugmvn compile spotbugs:spotbugs -Pspotbugs -pl <module>; open the spotbugsXml.xml report
javacCompile/lint failuremvn compile -pl <module> -Ptest-patch
javadocJavadoc won't buildmvn javadoc:javadoc -pl <module>
asflicenseMissing ASF headermvn apache-rat:check; add the header from dev-support/spotless/license.java

Fix locally, git commit a new commit (do not force-push away the review history — the committer squashes at merge), and git push. Yetus re-runs on the new head.

Step 10: Review Your Own PR as a Committer Would

Before you ask for review, self-check:

  1. Does git diff upstream/master contain only the intended change — no formatting churn, no generated files?
  2. Do all local gates pass (spotless:check, checkstyle:check, apache-rat:check, scoped tests)?
  3. Is the commit subject and PR title exactly TEZ-XXXX: Description?
  4. Does the PR body explain what, why, and how tested, with the JIRA link?
  5. If this were a behavioral change, is there a test that fails before and passes after? (For pure Javadoc, none — and you say so.)

Any "no" is a fix-before-you-ask item.


Deliverables

  • A fork of apache/tez with upstream configured and a TEZ-XXXX branch off current master.
  • A JIRA issue you commented on (or filed) for the change.
  • A clean mvn spotless:check, mvn checkstyle:check, and mvn apache-rat:check on tez-api.
  • A commit whose subject is TEZ-XXXX: Description (verified with git log -1 --pretty=%s).
  • An opened PR against master with a self-written body (what/why/testing/JIRA link).
  • A written mapping of each Yetus -1 check to the local command that reproduces it.

Troubleshooting

SymptomHow to detectFix
Diff shows hundreds of unintended linesgit diff upstream/master --statYou reformatted the file; run git checkout -- <file>, redo the edit, spotless:apply only.
Spotless fails in validate before testsBuild stops at spotless-checkmvn spotless:apply then re-run.
Generated protobuf files in the diff.java under target/generated-sources stagedNever stage target/; revert them.
git diff upstream/master is emptyBuild ran but branch is behindRebase: git fetch upstream && git rebase upstream/master.
Checkstyle fails on a line you didn't writeViolation inside your hunkYou own lines in your diff; fix it.
PR not linked to JIRATitle lacks a valid TEZ-XXXX:Rename the PR title to the exact form.
Yetus never commentsWrong base branch, or PR is a draftTarget master; mark the PR ready.

Stretch Goals

  1. Do it for real. Find an actual open Minor/Trivial Javadoc or typo issue, and take it all the way to an opened PR (do not merge — that is a committer's action).
  2. Read three merged PRs' review threads. On GitHub, filter is:pr is:merged on apache/tez, open three small ones, and count how many review rounds each took and what the reviewer asked for. This calibrates what "done" looks like.
  3. Trigger every Yetus check once. In a scratch branch, make a one-line change to a .sh file and confirm shellcheck fires; a one-line change to a .md and confirm codespell fires — matching personality_file_filter in dev-support/tez-personality.sh.
  4. Reproduce the whole precommit locally. Read the Jenkinsfile: it diffs origin/master...HEAD and runs test-patch.sh. You can approximate the same by running the Step 6 gates over exactly the modules your diff touches.

Validation / Self-check

You are done when you can answer these without notes:

  1. Where does Tez code get submitted today, and where do bugs get filed — and which repo file proves it?
  2. What is the exact commit-subject format, and which parts does the committer add at merge rather than you?
  3. Which command auto-fixes formatting, and why must it run before you commit?
  4. Name four local commands that reproduce four different Yetus precommit checks.
  5. Why do you add new commits (not force-push) while a PR is under review?
  6. There is no PR template — so what must a good PR body contain, and why does the title matter for JIRA?

Next: Lab 2.3 — Fix It: NPE-class bug in TezTaskAttemptID.fromString.