Skip to content

Replace API

The Replace API enables bulk search and replace operations across multiple repositories with automatic merge request creation.

The replace API uses a two-phase approach for safety and efficiency:

  1. Preview: Search for matches and return what will be changed
  2. Execute: Use matches from preview to perform replacements and create MRs

This design ensures:

  • Users always see exactly what will change before committing
  • Execute phase is fast (no re-searching needed)
  • Exact consistency between preview and execution
  • All changes go through merge request review
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ POST /preview │────▶│ Review matches │────▶│ POST /execute │
│ │ │ (with repo IDs) │ │ (creates MR) │
└─────────────────┘ └─────────────────┘ └─────────────────┘

Search for matches without making any changes.

POST /api/v1/replace/preview
{
"search_pattern": "oldFunction",
"replace_with": "newFunction",
"is_regex": false,
"case_sensitive": true,
"file_patterns": ["*.go", "*.ts"],
"repos": ["myorg/api"]
}
FieldTypeRequiredDescription
search_patternstringYesText or regex pattern to search for
replace_withstringYesReplacement text
is_regexbooleanNoTreat search_pattern as regex (default: false)
case_sensitivebooleanNoCase-sensitive matching (default: false)
file_patternsstring[]NoFilter files by glob patterns
reposstring[]NoFilter to specific repositories
{
"results": [
{
"repository_id": 1,
"repo": "myorg/api",
"file": "internal/service.go",
"line": 42,
"content": "func oldFunction() {"
},
{
"repository_id": 1,
"repo": "myorg/api",
"file": "internal/handler.go",
"line": 15,
"content": "result := oldFunction()"
},
{
"repository_id": 2,
"repo": "myorg/web",
"file": "src/api.ts",
"line": 8,
"content": "const data = oldFunction();"
}
],
"total": 3,
"repos_count": 2,
"files_count": 3
}

Execute replacements using matches from preview. This creates a background job that will make the changes and create a merge request.

POST /api/v1/replace/execute
{
"search_pattern": "oldFunction",
"replace_with": "newFunction",
"is_regex": false,
"case_sensitive": true,
"file_patterns": ["*.go", "*.ts"],
"matches": [
{
"repository_id": 1,
"repository_name": "myorg/api",
"file_path": "internal/service.go"
},
{
"repository_id": 1,
"repository_name": "myorg/api",
"file_path": "internal/handler.go"
},
{
"repository_id": 2,
"repository_name": "myorg/web",
"file_path": "src/api.ts"
}
],
"branch_name": "refactor/rename-function",
"mr_title": "Rename oldFunction to newFunction",
"mr_description": "Automated refactoring via code-search"
}
FieldTypeRequiredDescription
search_patternstringYesSame pattern used in preview
replace_withstringYesReplacement text
is_regexbooleanNoTreat search_pattern as regex
case_sensitivebooleanNoCase-sensitive matching
file_patternsstring[]NoFile patterns (from preview)
matchesobject[]YesMatches from preview (see below)
branch_namestringNoBranch name for changes (auto-generated if not specified)
mr_titlestringNoMR/PR title (auto-generated if not specified)
mr_descriptionstringNoMR/PR description (auto-generated if not specified)
user_tokenstringNoPersonal access token (required in read-only mode)
FieldTypeRequiredDescription
repository_idnumberYesRepository ID from preview
repository_namestringYesRepository name from preview
file_pathstringYesFile path from preview
{
"job_id": "job_abc123",
"status": "pending",
"message": "Replace job queued"
}

Get all replace jobs.

GET /api/v1/replace/jobs
[
{
"id": "job_abc123",
"type": "replace",
"status": "running",
"payload": {
"search_pattern": "oldFunction",
"replace_with": "newFunction"
},
"progress": {
"current": 2,
"total": 3,
"message": "Processing repository 2/3: myorg/web"
},
"created_at": "2024-01-15T10:30:00Z"
}
]

Get a specific replace job.

GET /api/v1/replace/jobs/{id}
{
"id": "job_abc123",
"type": "replace",
"status": "completed",
"payload": {
"search_pattern": "oldFunction",
"replace_with": "newFunction",
"matches": [
{"repository_id": 1, "repository_name": "myorg/api", "file_path": "internal/service.go"}
]
},
"result": {
"repositories_processed": 2,
"files_modified": 3,
"merge_requests_created": 2
},
"created_at": "2024-01-15T10:30:00Z",
"completed_at": "2024-01-15T10:32:00Z"
}
Terminal window
# Step 1: Preview changes
curl -X POST "http://localhost:8080/api/v1/replace/preview" \
-H "Content-Type: application/json" \
-d '{
"search_pattern": "oldFunction",
"replace_with": "newFunction",
"file_patterns": ["*.go"]
}'
# Step 2: Execute with matches from preview
curl -X POST "http://localhost:8080/api/v1/replace/execute" \
-H "Content-Type: application/json" \
-d '{
"search_pattern": "oldFunction",
"replace_with": "newFunction",
"file_patterns": ["*.go"],
"matches": [
{"repository_id": 1, "repository_name": "myorg/api", "file_path": "internal/service.go"},
{"repository_id": 1, "repository_name": "myorg/api", "file_path": "internal/handler.go"}
],
"create_mr": true,
"mr_title": "Rename oldFunction to newFunction"
}'
# Check job status
curl "http://localhost:8080/api/v1/replace/jobs/job_abc123"
Terminal window
# Preview
curl -X POST "http://localhost:8080/api/v1/replace/preview" \
-H "Content-Type: application/json" \
-d '{
"search_pattern": "v([0-9]+)\\.([0-9]+)\\.([0-9]+)",
"replace_with": "v$1.$2.999",
"is_regex": true,
"file_patterns": ["*.go", "version.txt"]
}'
Terminal window
# Preview
curl -X POST "http://localhost:8080/api/v1/replace/preview" \
-H "Content-Type: application/json" \
-d '{
"search_pattern": "get([A-Z]\\w+)ById",
"replace_with": "find$1ById",
"is_regex": true
}'
StatusDescription
400Invalid request (missing required fields)
400matches is required for execute
500Internal server error
{
"error": "'matches' is required - call preview endpoint first to get matches"
}