Loading...
Loading...
Interact with Gerrit Code Review via the REST API — query changes, fetch diffs, post reviews with labels and inline comments, and manage change lifecycle.
npx skill4agent add yurnov/gerrit-in-5-min gerrit-review| Variable | Description | Example |
|---|---|---|
| Base URL of the Gerrit instance (no trailing slash) | |
| HTTP username from Gerrit → Settings → Profile | |
| HTTP credential token from Gerrit → Settings → HTTP Credentials → Generate Password | |
[!IMPORTANT] The HTTP password is NOT the user's login password. It is a separate token generated in the Gerrit web UI under Settings → HTTP Credentials → Generate Password.
curljqbase64scripts/gerrit_api.sh# Make the script executable (one-time)
chmod +x scripts/gerrit_api.sh
# Query open changes
./scripts/gerrit_api.sh query "status:open+limit:5"
# Get change details
./scripts/gerrit_api.sh get-change 12345
# List files changed in a revision
./scripts/gerrit_api.sh list-files 12345
# Get a file diff
./scripts/gerrit_api.sh get-diff 12345 "src/main/App.java"
# Get raw file content
./scripts/gerrit_api.sh get-content 12345 "src/main/App.java"
# Post a draft comment on a specific line
./scripts/gerrit_api.sh create-draft 12345 current '{"path":"src/main/App.java","line":23,"message":"Consider renaming this.","unresolved":true}'
# Post a review with a Code-Review +1 label
./scripts/gerrit_api.sh review 12345 current '{"message":"Looks good!","labels":{"Code-Review":1}}'
# Submit a change
./scripts/gerrit_api.sh submit 12345
# Abandon a change
./scripts/gerrit_api.sh abandon 12345Change-Idrefs/changes/Change-Id: I<hex>commit-msg+2refs/for/<branch>git commit --amend/a/curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
"$GERRIT_URL/a/changes/?q=status:open+limit:5")]}'curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
"$GERRIT_URL/a/changes/?q=status:open" | tail -n +2 | jq .%2FmyOrg/myProject → myOrg%2FmyProject
src/main/App.java → src%2Fmain%2FApp.javaGET /a/changes/?q=<query>&n=<limit>&o=<option>status:openstatus:mergedstatus:abandonedowner:selfreviewer:selfproject:<name>branch:<name>is:watchedis:starredafter:"2025-01-01"before:"2025-12-31"oCURRENT_REVISIONDETAILED_LABELSDETAILED_ACCOUNTSCURRENT_FILESMESSAGEScurl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
"$GERRIT_URL/a/changes/?q=status:open+owner:self&n=10&o=CURRENT_REVISION&o=DETAILED_LABELS" \
| tail -n +2 | jq .GET /a/changes/<change-id>?o=CURRENT_REVISION&o=DETAILED_LABELS<change-id>12345project~branch~Change-IdI8473b95934b5732ac55d26311a706c9c2bde9940curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
"$GERRIT_URL/a/changes/12345?o=CURRENT_REVISION&o=DETAILED_LABELS&o=DETAILED_ACCOUNTS" \
| tail -n +2 | jq .GET /a/changes/<change-id>/revisions/<revision-id>/files/current<revision-id>curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
"$GERRIT_URL/a/changes/12345/revisions/current/files/" \
| tail -n +2 | jq .FileInfo{
"/COMMIT_MSG": { "status": "A", "lines_inserted": 7, "size_delta": 551, "size": 551 },
"src/main/App.java": { "lines_inserted": 5, "lines_deleted": 3, "size_delta": 98, "size": 23348 }
}GET /a/changes/<change-id>/revisions/<revision-id>/files/<file-id>/diff<file-id>?intralineFILE_PATH="src%2Fmain%2FApp.java"
curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
"$GERRIT_URL/a/changes/12345/revisions/current/files/$FILE_PATH/diff" \
| tail -n +2 | jq .DiffInfocontentababGET /a/changes/<change-id>/revisions/<revision-id>/files/<file-id>/contentFILE_PATH="src%2Fmain%2FApp.java"
curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
"$GERRIT_URL/a/changes/12345/revisions/current/files/$FILE_PATH/content" \
| base64 -dPOST /a/changes/<change-id>/revisions/<revision-id>/review
Content-Type: application/json{
"message": "Overall review comment shown at the top",
"labels": {
"Code-Review": 1
},
"comments": {
"src/main/App.java": [
{
"line": 23,
"message": "Consider renaming this variable for clarity."
},
{
"range": {
"start_line": 50,
"start_character": 0,
"end_line": 55,
"end_character": 20
},
"message": "This block should be refactored."
}
]
}
}-2-10+1+2-10+1curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
-X POST \
-H "Content-Type: application/json" \
-d '{"message":"Looks good to me!","labels":{"Code-Review":1}}' \
"$GERRIT_URL/a/changes/12345/revisions/current/review" \
| tail -n +2 | jq .PUT /a/changes/<change-id>/revisions/<revision-id>/drafts
Content-Type: application/json{
"path": "src/main/App.java",
"line": 23,
"message": "[nit] trailing whitespace",
"unresolved": true
}curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
-X PUT \
-H "Content-Type: application/json" \
-d '{"path":"src/main/App.java","line":23,"message":"[nit] trailing whitespace","unresolved":true}' \
"$GERRIT_URL/a/changes/12345/revisions/current/drafts" \
| tail -n +2 | jq .POST /a/changes/<change-id>/submitcurl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
-X POST \
-H "Content-Type: application/json" \
-d '{}' \
"$GERRIT_URL/a/changes/12345/submit" \
| tail -n +2 | jq .POST /a/changes/<change-id>/abandon
POST /a/changes/<change-id>/restoremessage# Abandon
curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
-X POST \
-H "Content-Type: application/json" \
-d '{"message":"Superseded by change 12346"}' \
"$GERRIT_URL/a/changes/12345/abandon" \
| tail -n +2 | jq .
# Restore
curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
-X POST \
-H "Content-Type: application/json" \
-d '{"message":"Re-opening for further review"}' \
"$GERRIT_URL/a/changes/12345/restore" \
| tail -n +2 | jq .POST /a/changes/<change-id>/reviewers
Content-Type: application/json{
"reviewer": "jane.roe@example.com"
}"state": "CC"curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
-X POST \
-H "Content-Type: application/json" \
-d '{"reviewer":"jane.roe@example.com"}' \
"$GERRIT_URL/a/changes/12345/reviewers" \
| tail -n +2 | jq .PUT /a/changes/<change-id>/topic
Content-Type: application/json{
"topic": "my-feature-branch"
}curl -s --user "$GERRIT_USERNAME:$GERRIT_HTTP_PASSWORD" \
-X PUT \
-H "Content-Type: application/json" \
-d '{"topic":"my-feature-branch"}' \
"$GERRIT_URL/a/changes/12345/topic" \
| tail -n +2 | jq ../scripts/gerrit_api.sh query "status:open+reviewer:self+-owner:self"# Get change details with labels and current revision
./scripts/gerrit_api.sh get-change 12345
# List modified files
./scripts/gerrit_api.sh list-files 12345
# Read the diff for each relevant file
./scripts/gerrit_api.sh get-diff 12345 "path/to/file.java"review# Add an unresolved draft comment
./scripts/gerrit_api.sh create-draft 12345 current '{"path":"path/to/file.java","line":42,"message":"Consider using a constant here instead of a magic number.","unresolved":true}'
# Once all drafts are created, publish them and add a vote/summary message
./scripts/gerrit_api.sh review 12345 current '{
"message": "I left a few comments on the implementation. Please take a look.",
"labels": {"Code-Review": -1},
"drafts": "PUBLISH"
}'./scripts/gerrit_api.sh review 12345 current '{
"message": "Overall the approach looks solid. A few suggestions below.",
"labels": {"Code-Review": 1},
"comments": {
"path/to/file.java": [
{
"line": 42,
"message": "Consider using a constant here instead of a magic number.",
"unresolved": true
},
{
"line": 65,
"message": "Nice cleanup here.",
"unresolved": false
}
]
}
}'commentsCommentInputnotifyALLOWNERNONEOWNERnotify_detailsin_reply_tounresolvedtruefalsefix_suggestions./scripts/gerrit_api.sh submit 12345| Problem | Solution |
|---|---|
| Check |
| Verify the change number exists. Check |
| You may be trying to review a change edit, or submit a change that doesn't meet requirements. |
| JSON parse error | Make sure you strip the XSSI prefix |
| URL encoding issues | Project paths with |
GERRIT_URLGERRIT_USERNAMEGERRIT_HTTP_PASSWORDGERRIT_HTTP_PASSWORD