Gitlab CI
What is Gitlab CI?
Key features of what can be done with an AI agent in Gitlab CI:
1. Create your gitlab-ci.yml in your project:
gitlab-ci.yml in your project:stages:
- review
claude-code-review:
variables:
REVIEW_MARKER: "<!-- claude-code-review -->"
GIT_DEPTH: 0 # Needed for long history
tags:
- claude-review
stage: review
image: node:20-alpine
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" # Makes the job only run in merge requests
before_script:
- apk add --no-cache curl jq git # Install used tools
- mkdir -p /root/.claude/projects # Needed just to not see claude code error in pipeline
- adduser -D claude && chown -R claude:claude $CI_PROJECT_DIR
script:
# Setup
- npm install -g @anthropic-ai/claude-code @musistudio/claude-code-router
- mkdir -p ~/.claude-code-router
# Same config from Claude Code setup guide
- |
cat > ~/.claude-code-router/config.json << EOF
{
"HOST": "127.0.0.1",
"PORT": 3456,
"API_TIMEOUT_MS": "600000",
"Providers": [
{
"name": "nexosai",
"api_base_url": "https://api.nexos.ai/v1/chat/completions",
"api_key": "${LLM_API_KEY}",
"models": [
"claude-opus-4-1-20250805",
"claude-haiku-4-5-20251001"
],
"transformer": {
"use": [
"OpenAI"
]
}
}
],
"Router": {
"default": "nexosai,claude-haiku-4-5-20251001",
"background": "nexosai,claude-haiku-4-5-20251001",
"webSearch": "nexosai,claude-haiku-4-5-20251001",
"think": "nexosai,claude-opus-4-1-20250805",
"longContext": "nexosai,claude-haiku-4-5-20251001",
"longContextThreshold": 60000
}
}
EOF
# Starting router and providing a delay
- npx @musistudio/claude-code-router start &
- sleep 3
# Adding a hidden review marker into the review file which will allow later to edit same note instead of creating multiple
- echo "$REVIEW_MARKER" > /tmp/review.md
# Fetching branch and retrieving changed files
- su claude -c "git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
- CHANGED_FILES=$(su claude -c "git diff --name-only origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME...HEAD -- '*.go'")
# Actually calling Claude Code
- |
echo "You are a code reviewer. Review the following changed Go files:
$CHANGED_FILES
Use View to examine each file.
Output ONLY raw GitLab-compatible markdown with your findings.
No preamble, no explanation, no summary - just the markdown review content itself." | \
su claude -c '
ANTHROPIC_BASE_URL=http://127.0.0.1:3456 \
ANTHROPIC_API_KEY=placeholder \
claude --print --dangerously-skip-permissions \
--allowedTools "View,GlobTool,GrepTool"
' >> /tmp/review.md
# Posting the note
- |
# find existing note ID
NOTE_ID=$(curl -s --header "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \
"$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes" \
| jq -r --arg marker "$REVIEW_MARKER" '.[] | select(.body | contains($marker)) | .id' | head -1)
if [ -n "$NOTE_ID" ]; then
# Update existing note
curl --fail --request PUT \
--header "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \
--header "Content-Type: application/json" \
--data "$(jq -Rs '{body: .}' /tmp/review.md)" \
"$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes/$NOTE_ID"
else
# Create new note
curl --fail --request POST \
--header "PRIVATE-TOKEN: ${GITLAB_API_TOKEN}" \
--header "Content-Type: application/json" \
--data "$(jq -Rs '{body: .}' /tmp/review.md)" \
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes"
fi2. Create your access keys and pipeline variables in Gitlab:
Tip:
Last updated

