Skip to content

Commit 0bae71c

Browse files
committed
fix(release): consume process streams safely and handle interrupts in ReleaseNoteGeneration
1 parent 3fd80a7 commit 0bae71c

1 file changed

Lines changed: 54 additions & 17 deletions

File tree

java-cloud-bom/release-note-generation/src/main/java/com/google/cloud/ReleaseNoteGeneration.java

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,28 @@ public static void main(String[] arguments)
119119
ReleaseNoteGeneration() {}
120120

121121
private static boolean releaseExists(String repository, String tag) {
122+
Process process = null;
122123
try {
123124
ProcessBuilder builder =
124125
new ProcessBuilder(
125126
"gh", "release", "--repo", GOOGLEAPIS_ORG + "/" + repository, "view", tag);
126-
Process process = builder.start();
127-
return process.waitFor() == 0;
128-
} catch (IOException | InterruptedException e) {
127+
builder.redirectOutput(ProcessBuilder.Redirect.DISCARD);
128+
builder.redirectError(ProcessBuilder.Redirect.DISCARD);
129+
process = builder.start();
130+
boolean finished = process.waitFor(1, TimeUnit.MINUTES);
131+
if (!finished) {
132+
return false;
133+
}
134+
return process.exitValue() == 0;
135+
} catch (IOException e) {
136+
return false;
137+
} catch (InterruptedException e) {
138+
Thread.currentThread().interrupt();
129139
return false;
140+
} finally {
141+
if (process != null && process.isAlive()) {
142+
process.destroyForcibly();
143+
}
130144
}
131145
}
132146

@@ -631,20 +645,43 @@ static String fetchReleaseNote(String owner, String repository, String tag)
631645
throws IOException, InterruptedException {
632646
// gh release --repo googleapis/java-storage view v2.16.0
633647

634-
ProcessBuilder builder =
635-
new ProcessBuilder("gh", "release", "--repo", owner + "/" + repository, "view", tag);
636-
builder.redirectErrorStream(true);
637-
Process process = builder.start();
638-
String output =
639-
new String(
640-
process.getInputStream().readAllBytes(), java.nio.charset.StandardCharsets.UTF_8);
641-
boolean finished = process.waitFor(1, TimeUnit.MINUTES);
642-
Verify.verify(finished, "The process timed out");
643-
if (process.exitValue() != 0) {
644-
System.err.println(
645-
"Warning: The command failed (release likely not found): " + output.trim());
646-
return "";
648+
File tempFile = java.nio.file.Files.createTempFile("gh-release-notes", ".txt").toFile();
649+
tempFile.deleteOnExit();
650+
651+
Process process = null;
652+
try {
653+
ProcessBuilder builder =
654+
new ProcessBuilder("gh", "release", "--repo", owner + "/" + repository, "view", tag);
655+
builder.redirectErrorStream(true);
656+
builder.redirectOutput(ProcessBuilder.Redirect.to(tempFile));
657+
658+
process = builder.start();
659+
boolean finished = process.waitFor(1, TimeUnit.MINUTES);
660+
if (!finished) {
661+
throw new IOException("The process timed out");
662+
}
663+
664+
String output =
665+
new String(
666+
java.nio.file.Files.readAllBytes(tempFile.toPath()),
667+
java.nio.charset.StandardCharsets.UTF_8);
668+
669+
if (process.exitValue() != 0) {
670+
String trimmedOutput = output.trim();
671+
String lowerOutput = trimmedOutput.toLowerCase();
672+
if (lowerOutput.contains("not found") || lowerOutput.contains("404")) {
673+
System.err.println(
674+
"Warning: The command failed (release likely not found): " + trimmedOutput);
675+
return "";
676+
}
677+
throw new IOException("The command failed: " + trimmedOutput);
678+
}
679+
return output;
680+
} finally {
681+
if (process != null && process.isAlive()) {
682+
process.destroyForcibly();
683+
}
684+
tempFile.delete();
647685
}
648-
return output;
649686
}
650687
}

0 commit comments

Comments
 (0)