11import { execSync } from "node:child_process" ;
22import * as fs from "node:fs" ;
3+ import fg from "fast-glob" ;
34
45// This script is used by the `release.yml` workflow to update the version of the packages being released.
56// The standard step is only to run `changeset version` but this does not update the package-lock.json file.
@@ -13,41 +14,108 @@ execSync("npm install", {
1314 stdio : "inherit" ,
1415} ) ;
1516
16- // Update Dockerfile and README version references after changeset updates package.json
17+ // Update all version references across the codebase after changeset updates package.json
1718try {
1819 const packageJson = JSON . parse ( fs . readFileSync ( "./packages/sandbox/package.json" , "utf-8" ) ) ;
1920 const newVersion = packageJson . version ;
2021
21- const dockerfilePath = "./examples/basic/Dockerfile" ;
22- let dockerfileContent = fs . readFileSync ( dockerfilePath , "utf-8" ) ;
22+ console . log ( `\n🔍 Searching for version references to update to ${ newVersion } ...\n` ) ;
2323
24- // Update the production image version in the comment
25- dockerfileContent = dockerfileContent . replace (
26- / # F R O M d o c k e r \. i o \/ c l o u d f l a r e \/ s a n d b o x : [ \d . ] + / ,
27- `# FROM docker.io/cloudflare/sandbox:${ newVersion } `
28- ) ;
24+ // Patterns to match version references in different contexts
25+ const versionPatterns = [
26+ // Docker image versions (production and test)
27+ {
28+ pattern : / F R O M d o c k e r \. i o \/ c l o u d f l a r e \/ s a n d b o x : [ \d . ] + / g,
29+ replacement : `FROM docker.io/cloudflare/sandbox:${ newVersion } ` ,
30+ description : "Production Docker image" ,
31+ } ,
32+ {
33+ pattern : / # F R O M d o c k e r \. i o \/ c l o u d f l a r e \/ s a n d b o x : [ \d . ] + / g,
34+ replacement : `# FROM docker.io/cloudflare/sandbox:${ newVersion } ` ,
35+ description : "Commented production Docker image" ,
36+ } ,
37+ {
38+ pattern : / F R O M c l o u d f l a r e \/ s a n d b o x - t e s t : [ \d . ] + / g,
39+ replacement : `FROM cloudflare/sandbox-test:${ newVersion } ` ,
40+ description : "Test Docker image" ,
41+ } ,
42+ {
43+ pattern : / d o c k e r \. i o \/ c l o u d f l a r e \/ s a n d b o x - t e s t : [ \d . ] + / g,
44+ replacement : `docker.io/cloudflare/sandbox-test:${ newVersion } ` ,
45+ description : "Test Docker image (docker.io)" ,
46+ } ,
47+ // Image tags in docker commands
48+ {
49+ pattern : / c l o u d f l a r e \/ s a n d b o x : [ \d . ] + / g,
50+ replacement : `cloudflare/sandbox:${ newVersion } ` ,
51+ description : "Docker image reference" ,
52+ } ,
53+ {
54+ pattern : / c l o u d f l a r e \/ s a n d b o x - t e s t : [ \d . ] + / g,
55+ replacement : `cloudflare/sandbox-test:${ newVersion } ` ,
56+ description : "Test Docker image reference" ,
57+ } ,
58+ ] ;
2959
30- // Update the test image version
31- dockerfileContent = dockerfileContent . replace (
32- / F R O M c l o u d f l a r e \/ s a n d b o x - t e s t : [ \d . ] + / ,
33- `FROM cloudflare/sandbox-test:${ newVersion } `
34- ) ;
60+ // Files to search and update
61+ const filePatterns = [
62+ "**/*.md" , // All markdown files
63+ "**/Dockerfile" , // All Dockerfiles
64+ "**/Dockerfile.*" , // Dockerfile variants
65+ "**/*.ts" , // TypeScript files (for documentation comments)
66+ "**/*.js" , // JavaScript files
67+ "**/*.json" , // JSON configs (but not package.json/package-lock.json)
68+ "**/*.yaml" , // YAML configs
69+ "**/*.yml" , // YML configs
70+ ] ;
3571
36- fs . writeFileSync ( dockerfilePath , dockerfileContent ) ;
37- console . log ( `✅ Updated Dockerfile versions to ${ newVersion } ` ) ;
72+ // Ignore patterns
73+ const ignorePatterns = [
74+ "**/node_modules/**" ,
75+ "**/dist/**" ,
76+ "**/build/**" ,
77+ "**/.git/**" ,
78+ "**/package.json" , // Don't modify package.json (changeset does this)
79+ "**/package-lock.json" , // Don't modify package-lock.json (npm install does this)
80+ "**/.github/changeset-version.ts" , // Don't modify this script itself
81+ ] ;
3882
39- // Update README.md
40- const readmePath = "./README.md" ;
41- let readmeContent = fs . readFileSync ( readmePath , "utf-8" ) ;
83+ // Find all matching files
84+ const files = await fg ( filePatterns , {
85+ ignore : ignorePatterns ,
86+ onlyFiles : true ,
87+ } ) ;
4288
43- // Update the Docker image version in README
44- readmeContent = readmeContent . replace (
45- / F R O M d o c k e r \. i o \/ c l o u d f l a r e \/ s a n d b o x : [ \d . ] + / ,
46- `FROM docker.io/cloudflare/sandbox:${ newVersion } `
47- ) ;
89+ console . log ( `📁 Found ${ files . length } files to check\n` ) ;
4890
49- fs . writeFileSync ( readmePath , readmeContent ) ;
50- console . log ( `✅ Updated README.md version to ${ newVersion } ` ) ;
91+ let updatedFilesCount = 0 ;
92+ let totalReplacementsCount = 0 ;
93+
94+ for ( const file of files ) {
95+ let content = fs . readFileSync ( file , "utf-8" ) ;
96+ let fileModified = false ;
97+ let fileReplacementsCount = 0 ;
98+
99+ // Try all patterns on this file
100+ for ( const { pattern, replacement, description } of versionPatterns ) {
101+ const matches = content . match ( pattern ) ;
102+ if ( matches ) {
103+ content = content . replace ( pattern , replacement ) ;
104+ fileModified = true ;
105+ fileReplacementsCount += matches . length ;
106+ }
107+ }
108+
109+ if ( fileModified ) {
110+ fs . writeFileSync ( file , content ) ;
111+ updatedFilesCount ++ ;
112+ totalReplacementsCount += fileReplacementsCount ;
113+ console . log ( ` ✅ ${ file } (${ fileReplacementsCount } replacement${ fileReplacementsCount > 1 ? 's' : '' } )` ) ;
114+ }
115+ }
116+
117+ console . log ( `\n✨ Updated ${ totalReplacementsCount } version reference${ totalReplacementsCount !== 1 ? 's' : '' } across ${ updatedFilesCount } file${ updatedFilesCount !== 1 ? 's' : '' } ` ) ;
118+ console . log ( ` New version: ${ newVersion } \n` ) ;
51119
52120} catch ( error ) {
53121 console . error ( "❌ Failed to update file versions:" , error ) ;
0 commit comments