This document describes how to write codemods (automated code modification scripts) that work with Silver-Platter.
Codemods are commands that Silver-Platter runs in version control checkouts to make automated changes. Your codemod can be written in any language and should:
- Make changes to files in the working directory
- Optionally commit those changes (or let Silver-Platter handle it)
- Exit with appropriate status codes
- Optionally write metadata about the changes
Silver-Platter runs your codemod in a clean VCS checkout. You can:
- Make and commit changes yourself - Full control over the commit process
- Just make changes - Silver-Platter will auto-commit with a reasonable message
- Make no changes - Exit successfully to indicate no changes were needed
By default, uncommitted changes are discarded (with a warning). Use --autocommit to have Silver-Platter commit them automatically.
These can be specified via command-line flags or in a recipe file:
| Option | Description | Default |
|---|---|---|
name |
Codemod identifier | Filename |
command |
Command to execute | Required |
commit-message |
Template for commit messages (Jinja2) | Auto-generated |
description |
Merge proposal description (Jinja2, markdown/plain) | Auto-generated |
resume |
Whether the command supports resuming | false |
mode |
How to publish changes: push, attempt-push, propose |
attempt-push |
propose-threshold |
Minimum change value before creating proposals | None |
autocommit |
Auto-commit uncommitted changes | true |
target-branch-url |
Override target branch URL | Base URL |
- 0: Success (changes made or no changes needed)
- 1: Failure (branch will be discarded)
- Other: Treated as failure
If your codemod supports resuming (set resume: true in config):
- Silver-Platter may provide a previous branch to continue from
- The
SVP_RESUMEenvironment variable will point to a JSON file with metadata from the last run - Your codemod should read this metadata and continue where it left off
- Carry forward any relevant context from the previous run
If resuming is not supported, previous changes are discarded and may be recreated.
| Variable | Description | Example |
|----------|-------------|---------||
| SVP_API | Silver-Platter API version | 1 |
| SVP_RESULT | Path where your codemod should write result JSON | /tmp/svp-result.json |
| Variable | Description | When Set |
|---|---|---|
COMMITTER |
Git committer identity | If configured |
SVP_RESUME |
Path to previous run's result JSON | If resuming and available |
Write a JSON file to the path specified in SVP_RESULT with these fields:
| Field | Type | Description |
|---|---|---|
code |
string | Result code (see below) |
success- Changes were successfully madenothing-to-do- No changes were needed- Other values indicate specific error types
| Field | Type | Description |
|---|---|---|
transient |
boolean | Whether the error is temporary (e.g., network issue) |
stage |
array | Stage names where the codemod failed |
description |
string | One-line description of changes or error |
value |
integer | Relative importance of changes (for prioritization) |
tags |
array | Tags to apply to the change |
context |
object | Custom data for template expansion |
target-branch-url |
string | Override target branch URL |
{
"code": "success",
"description": "Updated 5 deprecated API calls",
"value": 50,
"tags": ["api-migration", "automated"],
"context": {
"files_changed": 5,
"apis_updated": ["oldAPI", "legacyAPI"]
}
}For Debian packages, additional features are available:
Branches follow DEP-14 conventions.
| Variable | Description | Values |
|---|---|---|
DEB_SOURCE |
Source package name | e.g., nginx |
DEB_UPDATE_CHANGELOG |
Whether to update debian/changelog | update/leave |
ALLOW_REFORMATTING |
Whether reformatting is allowed | true/false |
Here's a simple codemod that updates deprecated function calls:
#!/bin/bash
# update-deprecated-api.sh
# Check if we should resume
if [ -n "$SVP_RESUME" ] && [ -f "$SVP_RESUME" ]; then
echo "Resuming from previous run..."
# Load previous state
PROCESSED_FILES=$(jq -r '.context.processed_files[]' "$SVP_RESUME" 2>/dev/null || echo "")
fi
# Make changes
CHANGED_COUNT=0
for file in $(find . -name "*.py" -type f); do
if grep -q "old_function" "$file"; then
sed -i 's/old_function/new_function/g' "$file"
((CHANGED_COUNT++))
fi
done
# Write result
if [ $CHANGED_COUNT -gt 0 ]; then
cat > "$SVP_RESULT" <<EOF
{
"code": "success",
"description": "Updated $CHANGED_COUNT files to use new API",
"value": $((CHANGED_COUNT * 10)),
"context": {
"files_changed": $CHANGED_COUNT
}
}
EOF
git add -A
git commit -m "Replace old_function with new_function
This updates deprecated API calls to use the new function name.
Affected files: $CHANGED_COUNT"
exit 0
else
cat > "$SVP_RESULT" <<EOF
{
"code": "nothing-to-do",
"description": "No deprecated API calls found"
}
EOF
exit 0
fi