Last active
August 31, 2023 15:26
-
-
Save sunix/8d1d598463a4b79c99b109136aae9f67 to your computer and use it in GitHub Desktop.
release script for jkube
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///usr/bin/env jbang "$0" "$@" ; exit $? | |
// //DEPS <dependency1> <dependency2> | |
//DEPS org.jline:jline:3.16.0 | |
//DEPS de.codeshelf.consoleui:consoleui:0.0.13 | |
//DEPS org.fusesource.jansi:jansi:2.3.4 | |
//DEPS info.picocli:picocli:4.6.1 | |
//DEPS org.apache.maven:maven-model:3.8.1 | |
//DEPS org.apache.commons:commons-exec:1.3 | |
//DEPS org.yaml:snakeyaml:1.29 | |
import static java.lang.System.*; | |
import java.io.FileReader; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.lang.ProcessBuilder.Redirect; | |
import java.text.SimpleDateFormat; | |
import java.time.LocalDate; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.stream.Stream; | |
import org.apache.maven.model.Model; | |
import org.apache.maven.model.io.xpp3.MavenXpp3Reader; | |
import org.codehaus.plexus.util.xml.pull.XmlPullParserException; | |
import org.yaml.snakeyaml.DumperOptions; | |
import org.yaml.snakeyaml.Yaml; | |
import de.codeshelf.consoleui.prompt.ConsolePrompt; | |
import de.codeshelf.consoleui.prompt.InputResult; | |
import de.codeshelf.consoleui.prompt.ListResult; | |
import de.codeshelf.consoleui.prompt.PromtResultItemIF; | |
import de.codeshelf.consoleui.prompt.builder.ListPromptBuilder; | |
import de.codeshelf.consoleui.prompt.builder.PromptBuilder; | |
import jline.TerminalFactory; | |
import picocli.CommandLine; | |
public class jrelease { | |
public static void main(String... args) throws InterruptedException, IOException, XmlPullParserException { | |
print("Welcome to @|green JKube release|@ script"); | |
String currentVersion = retrieveCurrentVersionFromPomFile(); | |
print("Current version is @|bold,green " + currentVersion + "|@\n"); | |
// guess the next maven release version from the current version | |
String nextReleaseVersion = guessNextReleaseVersion(currentVersion); | |
// prompt the user for the release version | |
nextReleaseVersion = promptWithSuggestion("Enter the release version to use", nextReleaseVersion); | |
print("Chosen release version is @|bold,green " + nextReleaseVersion + "|@"); | |
// guess the next X.Y-SNAPSHOT version from the next release version by | |
// incrementing the minor version | |
String nextSnapshotVersion = guessNextSnapshotVersion(nextReleaseVersion); | |
// prompt the user for the next snapshot version | |
nextSnapshotVersion = promptWithSuggestion("Enter the next snapshot version to use", nextSnapshotVersion); | |
print("Chosen next snapshot version is @|bold,green " + nextSnapshotVersion + "|@"); | |
// display the git remotes | |
print("Git remotes are:"); | |
executeInteractiveCommand("bash", "-c", "git remote -v"); | |
// choose the git remote to use as a main repository | |
String gitUpstreamRemote = promptWithSuggestion("Enter the git remote to use as the upstream", "origin"); | |
// choose the git remote to use as a fork repository | |
String gitForkRemote = promptWithSuggestion("Enter the git remote to use as a fork", "fork"); | |
// choose the branch name to use for the release | |
String releaseBranchName = promptWithSuggestion("Enter the branch name to use for the release", "release-" | |
+ nextReleaseVersion.replace(".", "-")); | |
// 1. Make sure the branch to release is up to date on your fork (master by | |
// default) | |
printStep(1, "Make sure the branch to release is up to date on your fork (master by default)"); | |
executeStep("git fetch --all && git checkout master && git reset --hard " + gitUpstreamRemote + "/master"); | |
executeStep("git checkout -b " + releaseBranchName); | |
print("Check that the branch is up to date with the remote"); | |
executeStep("git --no-pager log -n 5 --pretty=oneline --abbrev-commit --graph --decorate"); | |
// 2. Set release version | |
// ./scripts/release.sh setReleaseVersion 1.13.1 | |
// Make sure project.build.outputTimestamp property gets updated | |
printStep(2, "Set release version"); | |
executeStep("./scripts/release.sh setReleaseVersion " + nextReleaseVersion); | |
// 3. mvn clean install -DskipTests | |
printStep(3, "mvn clean install -DskipTests"); | |
print("Skipping this step for now"); | |
//executeStep("mvn clean install -DskipTests"); | |
// 4. Update Quickstarts version | |
// ./scripts/quickstarts.sh version | |
printStep(4, "Update Quickstarts version"); | |
executeStep("./scripts/quickstarts.sh version"); | |
// 5. Replace ### 1.13-SNAPSHOT with ### 1.13.0 (2023-06-14) in CHANGELOG.md | |
// get the current snapshot version | |
printStep(5, "Replace ### x.x-SNAPSHOT with ### x.y.z (202x-xx-xx) in CHANGELOG.md"); | |
String changelogNewReleaseHeader = "### " + nextReleaseVersion + " (" | |
+ new SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date()) + ")"; | |
executeStep("sed -i 's/### " + currentVersion + "/" + changelogNewReleaseHeader + "/g' CHANGELOG.md"); | |
// 6. Update bug templates to add versions: | |
// .github/ISSUE_TEMPLATE/bug_report.yml | |
printStep(6, "Update bug templates .github/ISSUE_TEMPLATE/bug_report.yml to add versions"); | |
executeStep("sed -E '/(- )\"SNAPSHOT\".*/{p;s//\\1\"" | |
+ nextReleaseVersion | |
+ "\"/}' -i .github/ISSUE_TEMPLATE/bug_report.yml"); | |
// 7. Send a message to Gitter channel `Starting release process for v1.13.1` | |
printStep(7, "Send a message to Gitter channel `Starting release process for v" + nextReleaseVersion + "`"); | |
print("Press enter to continue"); | |
// wait for the user to press enter | |
System.in.read(); | |
// 8. Git add and Commit ‘[RELEASE] Updated project version to 1.13.1’ | |
printStep(8, "Git add and Commit ‘[RELEASE] Updated project version to " + nextReleaseVersion + "’"); | |
executeStep("git add . && git commit -m \"[RELEASE] Updated project version to " + nextReleaseVersion + "\""); | |
// 9. Set snapshot version | |
// ./scripts/release.sh setReleaseVersion 1.14-SNAPSHOT | |
printStep(9, "Set snapshot version"); | |
executeStep("./scripts/release.sh setReleaseVersion " + nextSnapshotVersion); | |
// 10. Add ### 1.14-SNAPSHOT line to CHANGELOG.md | |
printStep(10, "Add ### " + nextSnapshotVersion + " line to CHANGELOG.md"); | |
executeStep("sed -E '/" + escape(changelogNewReleaseHeader) + "/{s//### " + nextSnapshotVersion | |
+ "\\n\\n\\0/}' -i CHANGELOG.md"); | |
// 11. Git add and commit ‘[RELEASE] Prepare for next development iteration’ | |
printStep(11, "Git add and commit ‘[RELEASE] Prepare for next development iteration’"); | |
executeStep("git add . && git commit -m \"[RELEASE] Prepare for next development iteration\""); | |
// 12. Create Pull Request | |
printStep(12, "Create Pull Request"); | |
executeStep("git push " + gitForkRemote + " " + releaseBranchName); | |
print("Create the PR in github using the branch " + releaseBranchName + " in the " + gitForkRemote | |
+ " repository"); | |
print("Press enter to continue"); | |
System.in.read(); | |
// 13. After rebase and merge create tag for release in first commit | |
printStep(13, "After rebase and merge create tag for release in first commit"); | |
executeStep("git fetch --all && git checkout master && git reset --hard " + gitUpstreamRemote + "/master && git --no-pager log -n 5 --pretty=oneline --abbrev-commit --graph --decorate"); | |
String gitRevToTag = promptWithSuggestion("Enter the git rev of the commit [RELEASE] Updated project version to "+ nextReleaseVersion, "xxxxxxx"); | |
executeStep("git tag -a v" + nextReleaseVersion + " " + gitRevToTag + " -m \"" + nextReleaseVersion + " ("+ new SimpleDateFormat("yyyy-MM-dd").format(new java.util.Date()) + ")\""); | |
executeStep("git push " + gitUpstreamRemote + " v" + nextReleaseVersion); | |
// 14. https://ci.eclipse.org/jkube | |
printStep(14, "https://ci.eclipse.org/jkube"); | |
// - Run build simplified-maven-central-release with tag as RELEASE_TAG build parameter | |
print("- Run build https://ci.eclipse.org/jkube/job/ReleasePipelines/job/simplified-maven-central-release/ with tag v"+ nextReleaseVersion+" as RELEASE_TAG build parameter"); | |
print("Press enter to continue"); | |
System.in.read(); | |
// - Run simplified-downloads-eclipse-release with tag as RELEASE_TAG build parameter -> check https://download.eclipse.org/jkube/ https://ci.eclipse.org/jkube/job/simplified-maven-central-release/ | |
print("- Run https://ci.eclipse.org/jkube/job/ReleasePipelines/job/simplified-downloads-eclipse-release/ with tag v"+ nextReleaseVersion+" as RELEASE_TAG build parameter"); | |
print("Press enter to continue"); | |
System.in.read(); | |
// 15. Wait for maven central (check https://repo1.maven.org/maven2/org/eclipse/jkube/kubernetes-maven-plugin-doc/ ) | |
printStep(15, "Wait for maven central, check"); | |
print("- Check https://download.eclipse.org/jkube/"); | |
print("- Check https://repo1.maven.org/maven2/org/eclipse/jkube/kubernetes-maven-plugin-doc/"); | |
print("Press enter to continue"); | |
System.in.read(); | |
// 16. Create GitHub release from previously pushed tag to upstream, enable `discussions` | |
// Add changelog | |
// ./scripts/changelog.sh extract 1.13.1 | |
printStep(16, "Create GitHub release from previously pushed tag to upstream, enable `discussions`"); | |
print("Add changelog this to the release description:"); | |
executeInteractiveCommand("bash", "-c", "./scripts/changelog.sh extract " + nextReleaseVersion); | |
// 17. Tag new release in https://github.com/jkubeio/jkube-website (keep empty title/description) | |
printStep(17, "Tag new release in https://github.com/jkubeio/jkube-website (keep empty title/description)"); | |
print("Press enter to continue"); | |
System.in.read(); | |
// 18. Publish tweet in jkubeio profile | |
printStep(18, "Publish tweet in jkubeio profile"); | |
// print the message to tweet: | |
// 🔥 @ECDTools #JKube new release 🚀 | |
// 📦 v1.14.0 | |
// ✨ Helidon support | |
// ✨ several improvements for helm | |
// ✨ CustomResource fragment improvements | |
// 🐞 Many bug fixes & improvements | |
// | |
//📢 Please help us spread the word & share your experience @jkubeio | |
// | |
// https://github.com/eclipse/jkube/releases/tag/v1.14.0 | |
print("🔥 @ECDTools #JKube new release 🚀"); | |
print("📦 v" + nextReleaseVersion); | |
print("✨ new feat"); | |
print("✨ another great feature"); | |
print("✨ some other improvements"); | |
print("🐞 Many bug fixes & improvements"); | |
print(""); | |
print("📢 Please help us spread the word & share your experience @jkubeio"); | |
print(""); | |
print("https://github.com/eclipse/jkube/releases/tag/v" + nextReleaseVersion); | |
print(""); | |
print("Press enter to continue"); | |
System.in.read(); | |
// 19. Announce the release in Gitter | |
printStep(19, "Announce the release in Gitter"); | |
print("🔥 Eclipse JKube new release 🚀"); | |
print("📦 v" + nextReleaseVersion); | |
print("✨ new feat"); | |
print("✨ another great feature"); | |
print("✨ some other improvements"); | |
print("🐞 Many bug fixes & improvements"); | |
print(""); | |
print("📢 Please help us spread the word & share your experience https://twitter.com/jkubeio"); | |
print(""); | |
print("https://github.com/eclipse/jkube/releases/tag/v" + nextReleaseVersion); | |
print(""); | |
print("Press enter to continue"); | |
System.in.read(); | |
// 20. Publish release in https://projects.eclipse.org/projects/ecd.jkube | |
printStep(20, "Publish release in https://projects.eclipse.org/projects/ecd.jkube"); | |
print("Press enter to continue"); | |
System.in.read(); | |
// 21. Run the Gradle verification test: | |
// https://github.com/jkubeio/jkube-integration-tests/actions/workflows/smoke-tests.yml | |
printStep(21, "Run the Gradle verification test: https://github.com/jkubeio/jkube-integration-tests/actions/workflows/smoke-tests.yml"); | |
print("Press enter to continue"); | |
System.in.read(); | |
} | |
private static String escape(String changelogNewReleaseHeader) { | |
return changelogNewReleaseHeader.replace("(", "\\(").replace(")", "\\)"); | |
} | |
private static String retrieveCurrentVersionFromPomFile() { | |
String currentVersion = "1.14-SNAPSHOT"; | |
try { | |
MavenXpp3Reader reader = new MavenXpp3Reader(); | |
Model model = reader.read(new FileReader("pom.xml")); | |
currentVersion = model.getVersion(); | |
} catch (Exception e) { | |
// just use the default version | |
} | |
return currentVersion; | |
} | |
private static void print(String cmd) { | |
out.println(text(cmd)); | |
} | |
public static String text(String txt) { | |
return CommandLine.Help.Ansi.AUTO.text(txt).toString(); | |
} | |
private static String guessNextSnapshotVersion(String nextReleaseVersion) { | |
String nextSnapshotVersion = ""; | |
String[] nextReleaseVersionParts = nextReleaseVersion.split("\\."); | |
if (nextReleaseVersionParts.length == 3) { | |
int minorVersion = Integer.parseInt(nextReleaseVersionParts[1]); | |
nextSnapshotVersion = nextReleaseVersionParts[0] + "." + (minorVersion + 1) + "-SNAPSHOT"; | |
} else { | |
String[] minorVersionParts = nextReleaseVersionParts[1].split("-"); | |
int minorVersion = Integer.parseInt(minorVersionParts[0]); | |
nextSnapshotVersion = nextReleaseVersionParts[0] + "." + (minorVersion + 1) + "-SNAPSHOT"; | |
} | |
return nextSnapshotVersion; | |
} | |
private static String promptWithSuggestion(String message, String defaultValue) throws IOException { | |
try { | |
ConsolePrompt prompt = new ConsolePrompt(); | |
PromptBuilder promptBuilder = prompt.getPromptBuilder(); | |
promptBuilder.createInputPrompt().name("name").message(text(message)).defaultValue(defaultValue) | |
.addPrompt(); | |
// create a PromptBuilder with editable suggestion | |
HashMap<String, ? extends PromtResultItemIF> result = prompt.prompt(promptBuilder.build()); | |
return ((InputResult) result.get("name")).getInput(); | |
} finally { | |
try { | |
TerminalFactory.get().restore(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
private static String guessNextReleaseVersion(String currentVersion) { | |
String nextReleaseVersion = ""; | |
String[] currentVersionParts = currentVersion.split("\\."); | |
if (currentVersionParts.length == 3) { | |
String[] patchVersionParts = currentVersionParts[2].split("-"); | |
int patchVersion = Integer.parseInt(patchVersionParts[0]); | |
nextReleaseVersion = currentVersionParts[0] + "." + currentVersionParts[1] + "." + (patchVersion + 1); | |
} else { | |
String[] minorVersionParts = currentVersionParts[1].split("-"); | |
int minorVersion = Integer.parseInt(minorVersionParts[0]); | |
nextReleaseVersion = currentVersionParts[0] + "." + minorVersion + ".0"; | |
} | |
return nextReleaseVersion; | |
} | |
private static void printStep(int step, String desc) { | |
out.println(text( | |
"\n🔵 @|bold,green Step " + step + ". |@ " + desc)); | |
} | |
private static void executeInteractiveCommand(String... command) throws IOException, InterruptedException { | |
// convert the unix command to an array taking into account the quotes | |
ProcessBuilder p = new ProcessBuilder(command); | |
p.redirectInput(Redirect.INHERIT); | |
p.redirectOutput(Redirect.INHERIT); | |
p.redirectError(Redirect.INHERIT); | |
Process process = p.start(); | |
process.waitFor(); | |
} | |
private static void executeStep(String cmd) | |
throws IOException, InterruptedException { | |
String selectedId = ""; | |
try { | |
ConsolePrompt prompt = new ConsolePrompt(); | |
PromptBuilder promptBuilder = prompt.getPromptBuilder(); | |
ListPromptBuilder chooserBuilder = promptBuilder.createListPrompt() | |
.name("idList") | |
.message(text("Choose an action")); | |
chooserBuilder | |
.newItem().name("1").text("Execute command: " + cmd).add(); | |
chooserBuilder | |
.newItem().name("2").text("Start interactive shell").add(); | |
chooserBuilder | |
.newItem().name("3").text("Skip").add(); | |
chooserBuilder.addPrompt(); | |
HashMap<String, ? extends PromtResultItemIF> result = prompt.prompt(promptBuilder.build()); | |
selectedId = ((ListResult) result.get("idList")).getSelectedId(); | |
} finally { | |
try { | |
TerminalFactory.get().restore(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
switch (selectedId) { | |
case "1": | |
executeInteractiveCommand("bash", "-c", "set -x; " + cmd); | |
break; | |
case "2": | |
print("Default command is: \n" + cmd); | |
print("Type `exit` to continue"); | |
executeInteractiveCommand("bash", "--norc"); | |
break; | |
case "3": | |
print("Skipping"); | |
break; | |
default: | |
print("None of the options was selected, skipping"); | |
break; | |
} | |
} | |
private static String promptList(String message, Stream<String> optionList) throws IOException { | |
try { | |
ConsolePrompt prompt = new ConsolePrompt(); | |
PromptBuilder promptBuilder = prompt.getPromptBuilder(); | |
ListPromptBuilder chooserBuilder = promptBuilder.createListPrompt() | |
.name("idList") | |
.message(text(message)); | |
optionList.forEach( | |
(s) -> chooserBuilder.newItem().text(s).add()); | |
chooserBuilder.addPrompt(); | |
HashMap<String, ? extends PromtResultItemIF> result = prompt.prompt(promptBuilder.build()); | |
return ((ListResult) result.get("idList")).getSelectedId(); | |
} finally { | |
try { | |
TerminalFactory.get().restore(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
public static void step6AddVersionToBugReportYml(String versioString) throws IOException { | |
out.println(text( | |
"\n🔵 @|bold,green Step 6. |@ Update bug templates .github/ISSUE_TEMPLATE/bug_report.yml to add versions")); | |
DumperOptions dumperOptions = new DumperOptions(); | |
dumperOptions.setIndent(2); | |
dumperOptions.setPrettyFlow(true); | |
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); | |
Yaml yaml = new Yaml(dumperOptions); | |
Map<String, Object> bugReport = yaml | |
.load(new FileReader(".github/ISSUE_TEMPLATE/bug_report.yml")); | |
ArrayList<Map<String, Object>> body = (ArrayList) bugReport.get("body"); | |
// get the item where id is equal to version | |
Map<String, Object> versionItem = body.stream().filter( | |
item -> "version".equals(item.get("id"))).findFirst() | |
.orElse(null); | |
if (versionItem != null) { | |
// get the options | |
Map<String, Object> attributes = (Map<String, Object>) versionItem.get("attributes"); | |
ArrayList<String> options = (ArrayList) attributes.get("options"); | |
// add the new version | |
options.add(versioString); | |
// save the file | |
yaml.dump(bugReport, | |
new FileWriter(".github/ISSUE_TEMPLATE/bug_report.yml")); | |
} | |
} | |
private static String executeCommandAndReturnOutput(String command) throws IOException { | |
ProcessBuilder p = new ProcessBuilder("bash", "-c", command); | |
// start the process and return the output | |
p.redirectInput(Redirect.INHERIT); | |
p.redirectOutput(Redirect.PIPE); | |
p.redirectError(Redirect.INHERIT); | |
Process process = p.start(); | |
try { | |
process.waitFor(); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
return process.getOutputStream().toString(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment