diff --git a/java-cloud-bom/release-note-generation/src/main/java/com/google/cloud/ReleaseNoteGeneration.java b/java-cloud-bom/release-note-generation/src/main/java/com/google/cloud/ReleaseNoteGeneration.java index 483df61ba1ed..4420e6dc33b4 100644 --- a/java-cloud-bom/release-note-generation/src/main/java/com/google/cloud/ReleaseNoteGeneration.java +++ b/java-cloud-bom/release-note-generation/src/main/java/com/google/cloud/ReleaseNoteGeneration.java @@ -34,9 +34,11 @@ import com.google.common.collect.Sets; import com.google.common.collect.Sets.SetView; import com.google.common.collect.Streams; -import com.google.common.io.Files; import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -46,7 +48,6 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.codec.Charsets; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; @@ -108,21 +109,49 @@ public static void main(String[] arguments) ReleaseNoteGeneration generation = new ReleaseNoteGeneration(); String report = generation.generateReport(bom, googleCloudJavaVersion); - Files.asCharSink(new File(RELEASE_NOTE_FILE_NAME), Charsets.UTF_8).write(report); + Files.writeString(Path.of(RELEASE_NOTE_FILE_NAME), report); System.out.println("Wrote " + RELEASE_NOTE_FILE_NAME); } @VisibleForTesting final StringBuilder report = new StringBuilder(); + private boolean monorepoReleaseExists = true; @VisibleForTesting ReleaseNoteGeneration() {} + private static boolean releaseExists(String repository, String tag) { + Process process = null; + try { + ProcessBuilder builder = + new ProcessBuilder( + "gh", "release", "--repo", GOOGLEAPIS_ORG + "/" + repository, "view", tag); + builder.redirectOutput(ProcessBuilder.Redirect.DISCARD); + builder.redirectError(ProcessBuilder.Redirect.DISCARD); + process = builder.start(); + boolean finished = process.waitFor(1, TimeUnit.MINUTES); + if (!finished) { + return false; + } + return process.exitValue() == 0; + } catch (IOException e) { + return false; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } finally { + if (process != null && process.isAlive()) { + process.destroyForcibly(); + } + } + } + @VisibleForTesting String generateReport(Bom bom, String googleCloudJavaVersion) throws MavenRepositoryException, ArtifactDescriptorException, IOException, InterruptedException { + monorepoReleaseExists = releaseExists("google-cloud-java", "v" + googleCloudJavaVersion); Bom previousBom = previousBom(bom); DefaultArtifact bomArtifact = new DefaultArtifact(bom.getCoordinates()); @@ -422,10 +451,15 @@ private static String releaseUrlForSplitRepo(String libraryName, String version) "https://github.com/googleapis/java-%s/releases/tag/v%s", libraryName, version); } - private static String releaseUrlForMonorepo(String libraryName, String version) { - // libraryName is unused for the monorepo release note as of Dec 2022 - return String.format( - "https://github.com/googleapis/google-cloud-java/releases/tag/v%s", version); + private String releaseUrlForMonorepo(String libraryName, String version) { + if (monorepoReleaseExists) { + return String.format( + "https://github.com/googleapis/google-cloud-java/releases/tag/v%s", version); + } else { + return String.format( + "https://github.com/googleapis/google-cloud-java/releases/tag/v%s-%s", + version, libraryName); + } } /** @@ -612,16 +646,40 @@ static String fetchReleaseNote(String owner, String repository, String tag) throws IOException, InterruptedException { // gh release --repo googleapis/java-storage view v2.16.0 - ProcessBuilder builder = - new ProcessBuilder("gh", "release", "--repo", owner + "/" + repository, "view", tag); - builder.redirectErrorStream(true); - Process process = builder.start(); - String output = - new String( - process.getInputStream().readAllBytes(), java.nio.charset.StandardCharsets.UTF_8); - boolean finished = process.waitFor(1, TimeUnit.MINUTES); - Verify.verify(finished, "The process timed out"); - Verify.verify(0 == process.exitValue(), "The command failed: %s", output); - return output; + File tempFile = Files.createTempFile("gh-release-notes", ".txt").toFile(); + tempFile.deleteOnExit(); + + Process process = null; + try { + ProcessBuilder builder = + new ProcessBuilder("gh", "release", "--repo", owner + "/" + repository, "view", tag); + builder.redirectErrorStream(true); + builder.redirectOutput(ProcessBuilder.Redirect.to(tempFile)); + + process = builder.start(); + boolean finished = process.waitFor(1, TimeUnit.MINUTES); + if (!finished) { + throw new IOException("The process timed out"); + } + + String output = new String(Files.readAllBytes(tempFile.toPath()), StandardCharsets.UTF_8); + + if (process.exitValue() != 0) { + String trimmedOutput = output.trim(); + String lowerOutput = trimmedOutput.toLowerCase(); + if (lowerOutput.contains("not found") || lowerOutput.contains("404")) { + System.err.println( + "Warning: The command failed (release likely not found): " + trimmedOutput); + return ""; + } + throw new IOException("The command failed: " + trimmedOutput); + } + return output; + } finally { + if (process != null && process.isAlive()) { + process.destroyForcibly(); + } + tempFile.delete(); + } } }