Skip to content

Commit a5d6ec8

Browse files
authored
Allow automatic checksums.json and version update for Dotnet and python. (#45)
* Allow automatic checksums.json and version update for Dotnet and python. * address comment
1 parent e35b7a0 commit a5d6ec8

5 files changed

Lines changed: 95 additions & 75 deletions

File tree

scripts/update-sdk-checksums/main.go

Lines changed: 88 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -27,45 +27,48 @@ import (
2727
"strings"
2828
)
2929

30+
// --- General Project Configuration ---
3031
const (
3132
githubOwner = "google"
3233
githubRepo = "test-server"
3334
projectName = "test-server"
34-
35-
sdkDir = "sdks/typescript"
36-
postinstallJSFile = "postinstall.js"
37-
checksumsJSONFile = "checksums.json"
38-
testServerVersionVar = "TEST_SERVER_VERSION"
39-
)
40-
41-
var (
42-
sdkPostinstallPath string
43-
sdkChecksumsJSONPath string
4435
)
4536

46-
func initPaths() error {
47-
// Determine the project root. This assumes the script might be run
48-
// from the project root or from within its own directory 'scripts/update-sdk-checksums'.
49-
wd, err := os.Getwd()
50-
if err != nil {
51-
return fmt.Errorf("failed to get current working directory: %w", err)
52-
}
53-
54-
// If current working directory is 'scripts/update-sdk-checksums', go up two levels.
55-
// Otherwise, assume we are already at the project root.
56-
if filepath.Base(wd) == "update-sdk-checksums" && filepath.Base(filepath.Dir(wd)) == "scripts" {
57-
wd = filepath.Dir(filepath.Dir(wd))
58-
}
37+
// --- SDK Specific Configurations ---
5938

60-
sdkPostinstallPath = filepath.Join(wd, sdkDir, postinstallJSFile)
61-
sdkChecksumsJSONPath = filepath.Join(wd, sdkDir, checksumsJSONFile)
39+
// SDKConfig holds the unique properties for each SDK that needs updating.
40+
type SDKConfig struct {
41+
Name string // e.g., "TypeScript", "Python"
42+
SDKDir string // Relative path to the SDK's directory
43+
InstallScriptFile []string // A list of files to update with the new version
44+
ChecksumsJSONFile string // e.g., "checksums.json"
45+
VersionVarName string // The name of the version constant/variable in the install script
46+
}
6247

63-
// Verify postinstall.js path exists to give early feedback
64-
if _, err := os.Stat(sdkPostinstallPath); os.IsNotExist(err) {
65-
return fmt.Errorf("postinstall.js not found at %s. Ensure you are running the script from the project root, or the script needs path adjustment", sdkPostinstallPath)
66-
}
67-
// checksums.json might not exist initially, which is fine for updateChecksumsJSON.
68-
return nil
48+
// sdksToUpdate is the list of all SDKs this script should manage.
49+
// Add a new entry here to support another SDK.
50+
var sdksToUpdate = []SDKConfig{
51+
{
52+
Name: "TypeScript",
53+
SDKDir: "sdks/typescript",
54+
InstallScriptFile: []string{"postinstall.js"},
55+
ChecksumsJSONFile: "checksums.json",
56+
VersionVarName: "TEST_SERVER_VERSION",
57+
},
58+
{
59+
Name: "Python",
60+
SDKDir: "sdks/python/src/test_server_sdk",
61+
InstallScriptFile: []string{"install.py"},
62+
ChecksumsJSONFile: "checksums.json",
63+
VersionVarName: "TEST_SERVER_VERSION",
64+
},
65+
{
66+
Name: "Dotnet",
67+
SDKDir: "sdks/dotnet",
68+
InstallScriptFile: []string{"BinaryInstaller.cs", "TestServerSdk.cs", "tools/installer/Program.cs"},
69+
ChecksumsJSONFile: "checksums.json",
70+
VersionVarName: "TEST_SERVER_VERSION",
71+
},
6972
}
7073

7174
func fetchChecksumsTxt(version string) (string, error) {
@@ -119,72 +122,67 @@ func parseChecksumsTxt(checksumsText string) (map[string]string, error) {
119122
return checksums, nil
120123
}
121124

122-
func updateChecksumsJSON(newVersion string, newChecksumsMap map[string]string) error {
123-
allChecksums := make(map[string]map[string]string)
125+
func updateChecksumsJSON(checksumsJSONPath, newVersion string, newChecksumsMap map[string]string) error {
126+
allChecksums := make(map[string]map[string]string) // Reset if unmarshal fails
124127

125-
if _, err := os.Stat(sdkChecksumsJSONPath); err == nil { // Check if file exists
126-
existingJSON, errFileRead := os.ReadFile(sdkChecksumsJSONPath)
128+
if _, err := os.Stat(checksumsJSONPath); err == nil {
129+
existingJSON, errFileRead := os.ReadFile(checksumsJSONPath)
127130
if errFileRead != nil {
128-
return fmt.Errorf("failed to read existing %s: %w", sdkChecksumsJSONPath, errFileRead)
131+
return fmt.Errorf("failed to read existing %s: %w", checksumsJSONPath, errFileRead)
129132
}
130-
if len(existingJSON) > 0 { // Only unmarshal if not empty
133+
if len(existingJSON) > 0 {
131134
if errUnmarshal := json.Unmarshal(existingJSON, &allChecksums); errUnmarshal != nil {
132-
fmt.Printf("Warning: Could not parse existing %s, will overwrite. Error: %v\n", sdkChecksumsJSONPath, errUnmarshal)
133-
allChecksums = make(map[string]map[string]string) // Reset if unmarshal fails
135+
fmt.Printf("Warning: Could not parse existing %s, will overwrite. Error: %v\n", checksumsJSONPath, errUnmarshal)
136+
allChecksums = make(map[string]map[string]string)
134137
}
135138
}
136139
} else if !os.IsNotExist(err) { // If error is not "file does not exist", then it's a problem
137-
return fmt.Errorf("failed to stat %s: %w", sdkChecksumsJSONPath, err)
140+
return fmt.Errorf("failed to stat %s: %w", checksumsJSONPath, err)
138141
}
139-
// If file does not exist, allChecksums remains an empty map, which is fine.
140142

141143
allChecksums[newVersion] = newChecksumsMap
142144
updatedJSON, err := json.MarshalIndent(allChecksums, "", " ")
143145
if err != nil {
144146
return fmt.Errorf("failed to marshal updated checksums JSON: %w", err)
145147
}
146148

147-
// Append a newline character to match the Node script's output and common file ending.
148149
updatedJSON = append(updatedJSON, '\n')
149150

150-
err = os.WriteFile(sdkChecksumsJSONPath, updatedJSON, 0644)
151+
err = os.WriteFile(checksumsJSONPath, updatedJSON, 0644)
151152
if err != nil {
152-
return fmt.Errorf("failed to write updated %s: %w", sdkChecksumsJSONPath, err)
153+
return fmt.Errorf("failed to write updated %s: %w", checksumsJSONPath, err)
153154
}
154-
fmt.Printf("Updated %s with checksums for version %s.\n", sdkChecksumsJSONPath, newVersion)
155+
fmt.Printf("Updated %s with checksums for version %s.\n", checksumsJSONPath, newVersion)
155156
return nil
156157
}
157158

158-
func updatePostinstallVersion(newVersion string) error {
159-
content, err := os.ReadFile(sdkPostinstallPath)
159+
func updateVersionInFile(filePath, newVersion, varName string) error {
160+
content, err := os.ReadFile(filePath)
160161
if err != nil {
161-
return fmt.Errorf("failed to read %s: %w", sdkPostinstallPath, err)
162+
return fmt.Errorf("failed to read %s: %w", filePath, err)
162163
}
163164

164-
re := regexp.MustCompile(`(?m)^\s*const TEST_SERVER_VERSION = .*$`)
165+
re := regexp.MustCompile(fmt.Sprintf(`(?m)(^\s*.*\b%s\b\s*=\s*['"]).*?(['"].*$)`, varName))
165166

166167
if !re.Match(content) {
167-
return fmt.Errorf("could not find '%s' constant in %s. Pattern not matched: %s", testServerVersionVar, sdkPostinstallPath, re.String())
168+
// If the variable isn't in the file, it's not an error. Just skip it.
169+
fmt.Printf("Note: Did not find '%s' in %s, skipping update for this file.\n", varName, filePath)
170+
return nil
168171
}
169172

170-
replacement := fmt.Sprintf("const TEST_SERVER_VERSION = '%s';", newVersion)
173+
replacement := []byte(fmt.Sprintf(`${1}%s${2}`, newVersion))
171174

172-
updatedContent := re.ReplaceAllString(string(content), replacement)
175+
updatedContent := re.ReplaceAll(content, replacement)
173176

174-
err = os.WriteFile(sdkPostinstallPath, []byte(updatedContent), 0644)
177+
err = os.WriteFile(filePath, updatedContent, 0644)
175178
if err != nil {
176-
return fmt.Errorf("failed to write updated %s: %w", sdkPostinstallPath, err)
179+
return fmt.Errorf("failed to write updated %s: %w", filePath, err)
177180
}
178-
fmt.Printf("Updated %s in %s to %s.\n", testServerVersionVar, sdkPostinstallPath, newVersion)
181+
fmt.Printf("Updated %s in %s to %s.\n", varName, filePath, newVersion)
179182
return nil
180183
}
181184

182185
func main() {
183-
if err := initPaths(); err != nil {
184-
fmt.Fprintf(os.Stderr, "Error initializing paths: %v\n", err)
185-
os.Exit(1)
186-
}
187-
188186
if len(os.Args) < 2 {
189187
fmt.Fprintln(os.Stderr, "Usage: go run scripts/update-sdk-checksums/main.go <version_tag>")
190188
fmt.Fprintln(os.Stderr, "Example: go run scripts/update-sdk-checksums/main.go v0.1.0")
@@ -196,8 +194,7 @@ func main() {
196194
os.Exit(1)
197195
}
198196

199-
fmt.Printf("Updating TypeScript SDK to use test-server version: %s\n", newVersion)
200-
197+
fmt.Printf("Fetching checksums for test-server version: %s\n", newVersion)
201198
checksumsText, err := fetchChecksumsTxt(newVersion)
202199
if err != nil {
203200
fmt.Fprintf(os.Stderr, "\nError fetching checksums.txt: %v\n", err)
@@ -210,19 +207,39 @@ func main() {
210207
os.Exit(1)
211208
}
212209

213-
if err := updateChecksumsJSON(newVersion, newChecksumsMap); err != nil {
214-
fmt.Fprintf(os.Stderr, "\nError updating %s: %v\n", sdkChecksumsJSONPath, err)
215-
os.Exit(1)
210+
var failedSDKs []string
211+
212+
for _, sdk := range sdksToUpdate {
213+
fmt.Printf("\n--- Updating %s SDK ---\n", sdk.Name)
214+
215+
sdkChecksumsJSONPath := filepath.Join(sdk.SDKDir, sdk.ChecksumsJSONFile)
216+
if err := updateChecksumsJSON(sdkChecksumsJSONPath, newVersion, newChecksumsMap); err != nil {
217+
fmt.Fprintf(os.Stderr, "Error updating %s: %v\n", sdkChecksumsJSONPath, err)
218+
failedSDKs = append(failedSDKs, sdk.Name)
219+
continue
220+
}
221+
222+
var sdkScriptUpdateFailed bool
223+
for _, scriptFile := range sdk.InstallScriptFile {
224+
sdkInstallScriptPath := filepath.Join(sdk.SDKDir, scriptFile)
225+
if err := updateVersionInFile(sdkInstallScriptPath, newVersion, sdk.VersionVarName); err != nil {
226+
fmt.Fprintf(os.Stderr, "Error updating %s: %v\n", sdkInstallScriptPath, err)
227+
sdkScriptUpdateFailed = true
228+
break
229+
}
230+
}
231+
232+
if sdkScriptUpdateFailed {
233+
failedSDKs = append(failedSDKs, sdk.Name)
234+
continue // Move to the next SDK
235+
}
216236
}
217237

218-
if err := updatePostinstallVersion(newVersion); err != nil {
219-
fmt.Fprintf(os.Stderr, "\nError updating %s: %v\n", sdkPostinstallPath, err)
238+
if len(failedSDKs) > 0 {
239+
fmt.Fprintf(os.Stderr, "\nUpdate failed for the following SDKs: %v\n", failedSDKs)
220240
os.Exit(1)
221241
}
222242

223-
fmt.Println("\nSuccessfully updated SDK checksums and version.")
224-
fmt.Println("Please review the changes in:")
225-
fmt.Printf(" - %s\n", sdkChecksumsJSONPath)
226-
fmt.Printf(" - %s\n", sdkPostinstallPath)
243+
fmt.Println("\nSuccessfully updated all SDK checksums and versions.")
227244
fmt.Println("Then commit them to your repository.")
228245
}

sdks/dotnet/BinaryInstaller.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ public static class BinaryInstaller
3333
private const string GithubOwner = "google";
3434
private const string GithubRepo = "test-server";
3535
private const string ProjectName = "test-server";
36+
public const string TEST_SERVER_VERSION = "v0.2.7";
3637

3738
/// <summary>
3839
/// Ensures the test-server binary for the given version is present in the specified output directory.
3940
/// It will download the release asset from GitHub, verify its SHA256 checksum, extract it, and set executable permissions.
4041
/// The checksums are read from a 'checksums.json' file expected to be embeded into the TestServerSdk.dll.
4142
/// </summary>
42-
public static async Task EnsureBinaryAsync(string outDir, string version = "v0.2.7")
43+
public static async Task EnsureBinaryAsync(string outDir, string version = TEST_SERVER_VERSION)
4344
{
4445
var assembly = Assembly.GetExecutingAssembly();
4546
var resourceName = "TestServerSdk.checksums.json";

sdks/dotnet/TestServerSdk.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class TestServerProcess
4545
private Process? _process;
4646
private readonly TestServerOptions _options;
4747
private readonly string _binaryPath;
48+
public const string TEST_SERVER_VERSION = "v0.2.7";
4849

4950
public TestServerProcess(TestServerOptions options)
5051
{
@@ -64,7 +65,7 @@ private string GetBinaryPath()
6465
{
6566
var targetDir = Path.GetDirectoryName(p) ?? Path.GetFullPath(Directory.GetCurrentDirectory());
6667
Console.WriteLine($"[TestServerSdk] test-server not found at {p}. Installing into {targetDir}...");
67-
BinaryInstaller.EnsureBinaryAsync(targetDir, "v0.2.7").GetAwaiter().GetResult();
68+
BinaryInstaller.EnsureBinaryAsync(targetDir, TEST_SERVER_VERSION).GetAwaiter().GetResult();
6869
if (File.Exists(p)) return p;
6970
throw new FileNotFoundException($"[TestServerSdk] After installation, test-server binary still not found at: {p}");
7071
}

sdks/dotnet/tools/installer/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using System;
1818
using System.Threading.Tasks;
1919
using TestServerSdk;
20+
public const string TEST_SERVER_VERSION = "v0.2.7";
2021

2122
// This program is just a thin wrapper around the installer logic in the SDK.
2223
if (args.Length == 0)
@@ -26,7 +27,7 @@
2627
}
2728

2829
string outDir = args[0];
29-
string version = args.Length > 1 ? args[1] : "v0.2.7";
30+
string version = args.Length > 1 ? args[1] : TEST_SERVER_VERSION;
3031

3132
await BinaryInstaller.EnsureBinaryAsync(outDir, version);
3233
return 0;

sdks/python/src/test_server_sdk/checksums.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
"test-server_Windows_i386.zip": "6980c83e2118ed739dad53af29dc302b78ec89804f7ff7d7b5e39dcadbab3e83",
8080
"test-server_Windows_x86_64.zip": "8a4e36c8fa2d17a256a31956a3cb2851d27a30f423449911caf0b3ec76b9a602"
8181
},
82-
"v0.2.7": {
82+
"v0.2.7": {
8383
"test-server_Darwin_arm64.tar.gz": "0fd90238ccf90d74daef781b972c8b864063a40563259f689444d4f0ed41fb14",
8484
"test-server_Darwin_x86_64.tar.gz": "8b7853069a9c98585a8075a90db94e73f1a769494fa5ac097c00f5e0c0630f06",
8585
"test-server_Linux_arm64.tar.gz": "5dd5ae382db835427a62f4e65d73952b6f6452b5690d6623414f343f04a0b5de",

0 commit comments

Comments
 (0)