A synthetic mono repo demonstrating Sourcegraph batch changes capabilities.
This repository demonstrates two types of batch changes:
- Simple String Replacement - Upgrading vulnerable dependency versions
- Complex Rewrite Logic - Migrating console.* calls to structured logging
Do not deploy this code to production. This is for demonstration purposes only.
| Package | Current Version | CVEs | Patched Version |
|---|---|---|---|
| React | 19.1.0 | CVE-2025-55182, CVE-2025-55183, CVE-2025-55184, CVE-2025-67779 | 19.1.4 |
| Next.js | 15.1.0 | Affected by React Server Components vulnerabilities | 15.1.11 |
find packages -name "package.json" | xargs grep -E '"(react|next)":'Expected output (vulnerable versions):
packages/shared-ui/package.json: "react": "19.1.0"
packages/api-service/package.json: "next": "15.1.0",
packages/api-service/package.json: "react": "19.1.0",
packages/web-app/package.json: "next": "15.1.0",
packages/web-app/package.json: "react": "19.1.0",
After batch change, versions should update to react: 19.1.4 and next: 15.1.11.
This scenario demonstrates batch changes that require AST-level understanding, not just simple find/replace.
The codebase contains scattered console.log, console.error, and console.warn calls with inconsistent formatting:
// Current state (scattered throughout codebase)
console.log('Fetching episodes, id:', id);
console.error('Episode not found:', id);
console.warn('Empty search query received');
console.log('Search completed, found', results.length, 'results for query:', query);Migrate to a structured logger with metadata objects:
// Target state (using @podcast-index/shared-ui logger)
import { logger } from '@podcast-index/shared-ui';
logger.info('Fetching episodes', { id });
logger.error('Episode not found', { id });
logger.warn('Empty search query received');
logger.info('Search completed', { resultCount: results.length, query });This transformation cannot be done with simple regex because:
- Variable extraction:
console.log('msg:', var)→logger.info('msg', { var }) - Method mapping:
console.log→logger.info,console.error→logger.error - Multiple arguments: Must be restructured into message + metadata object
- String concatenation:
'msg ' + varmust become template + metadata - Import addition: Must add logger import to files that don't have it
Count console.* calls before migration:
grep -r "console\.\(log\|error\|warn\)" packages --include="*.ts" --include="*.tsx" | wc -lFiles affected:
packages/api-service/app/api/episodes/route.tspackages/api-service/app/api/search/route.tspackages/api-service/app/api/subscribe/route.tspackages/api-service/lib/podcast-data.tspackages/web-app/app/actions.ts
After batch change, all console.* calls should be replaced with logger.* calls.
Pre-built batch specifications are available in the batch-specs/ directory:
| File | Description | Transformation Type |
|---|---|---|
upgrade-react-nextjs.yaml |
Upgrade React & Next.js to patched versions | Simple string replacement |
migrate-to-structured-logger.yaml |
Convert console.* to structured logger | Complex AST rewrite (comby) |
-
Install the Sourcegraph CLI:
brew install sourcegraph/src-cli/src-cli # or curl -L https://sourcegraph.com/.api/src-cli/src_darwin_arm64 -o /usr/local/bin/src -
Authenticate with your Sourcegraph instance:
src login https://your-sourcegraph-instance.com
# Preview the dependency upgrade batch change
src batch preview -f batch-specs/upgrade-react-nextjs.yaml
# Preview the logger migration batch change
src batch preview -f batch-specs/migrate-to-structured-logger.yamlAfter reviewing the preview, click Apply in the Sourcegraph UI, or:
src batch apply -f batch-specs/upgrade-react-nextjs.yamlUses sed for simple version string replacement:
steps:
- run: sed -i 's/"react": "19.1.0"/"react": "19.1.4"/g' package.json
container: alpine:3.19Uses comby for structural code transformation:
steps:
- run: comby -in-place "console.log(':[msg]:', :[var])" "logger.info(':[msg]', { :[var] })" .ts .tsx
container: comby/combyComby understands code syntax, so :[msg] and :[var] match actual code structures, not just text patterns.
batch-changes-demo/
├── batch-specs/
│ ├── upgrade-react-nextjs.yaml # Demo 1: Version upgrades
│ └── migrate-to-structured-logger.yaml # Demo 2: Complex rewrite
├── packages/
│ ├── web-app/ # Main Next.js podcast application
│ ├── api-service/ # Backend API service
│ └── shared-ui/ # Shared React component library + logger
├── package.json # Root workspace config
└── pnpm-workspace.yaml # pnpm workspace definition
- @podcast-index/web-app: Main user-facing Next.js application with Server Components and Server Functions
- @podcast-index/api-service: Backend API providing podcast data endpoints
- @podcast-index/shared-ui: Reusable UI components (Button, Card, Input) and structured logger
- Node.js >= 18.0.0
- pnpm >= 8.0.0
pnpm installRun all services:
pnpm devOr run individual services:
# Web app (port 3000)
pnpm web-app
# API service (port 3001)
pnpm api-serviceThe API service exposes the following endpoints:
GET /api/episodes- List all podcast episodesGET /api/episodes?id=<id>- Get a specific episodeGET /api/search?q=<query>- Search episodes by title, description, or podcast namePOST /api/subscribe- Subscribe to a podcast (requirespodcastIdandemailin body)
MIT