From f61702c00623daf52a9a7a6cc592c748845cab10 Mon Sep 17 00:00:00 2001 From: Oliver Weiler Date: Mon, 7 Mar 2022 23:29:39 +0100 Subject: [PATCH] Add Homebrew support (#1042) * Add Homebrew formula template * Add brew packager * Remove selfupdate functionality when installed via Homebrew * Configure JRELEASER_HOMEBREW_GITHUB_TOKEN * Order configuration alphabetically --- .github/workflows/release.yml | 1 + gradle/release.gradle | 5 +- .../sdkman-cli/brew/README.md.tpl | 29 ++++++ .../sdkman-cli/brew/formula.rb.tpl | 35 +++++++ src/main/bash/sdkman-help.sh | 6 +- src/main/bash/sdkman-main.sh | 10 +- .../sdkman/env/SdkmanBashEnvBuilder.groovy | 3 +- .../groovy/sdkman/specs/SelfupdateSpec.groovy | 91 +++++++++++++++++++ 8 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 src/jreleaser/distributions/sdkman-cli/brew/README.md.tpl create mode 100644 src/jreleaser/distributions/sdkman-cli/brew/formula.rb.tpl create mode 100644 src/test/groovy/sdkman/specs/SelfupdateSpec.groovy diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 285c92244..d10656121 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,6 +17,7 @@ jobs: JRELEASER_TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_API_SECRET }} JRELEASER_TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }} JRELEASER_TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} + JRELEASER_HOMEBREW_GITHUB_TOKEN: ${{ secrets.HOMEBREW_GITHUB_TOKEN }} services: mongodb: image: mongo:3.2 diff --git a/gradle/release.gradle b/gradle/release.gradle index 7d20c6a3d..641870020 100644 --- a/gradle/release.gradle +++ b/gradle/release.gradle @@ -35,9 +35,12 @@ jreleaser { artifact { path = "build/distributions/{{distributionName}}-${sdkmanVersion}.zip" } + brew { + active = 'ALWAYS' + } } } - + announce { twitter { active = 'RELEASE' diff --git a/src/jreleaser/distributions/sdkman-cli/brew/README.md.tpl b/src/jreleaser/distributions/sdkman-cli/brew/README.md.tpl new file mode 100644 index 000000000..8c000a8b9 --- /dev/null +++ b/src/jreleaser/distributions/sdkman-cli/brew/README.md.tpl @@ -0,0 +1,29 @@ +# SDKMAN! Homebrew Tap + +A Homebrew tap containing the Formula for the SDKMAN! CLI. + +## Installation + +```sh +$ brew tap sdkman/tap +$ brew install sdkman +``` + +After successful installation add the following lines to the end of your `.bash_profile` + +```sh +export SDKMAN_DIR=$(brew --prefix sdkman)/libexec +[[ -s "${SDKMAN_DIR}/bin/sdkman-init.sh" ]] && source "${SDKMAN_DIR}/bin/sdkman-init.sh" +``` + +Open a new terminal and type + +```sh +sdk version +``` + +The output should look similar to this + +```sh +SDKMAN {{version}} +``` \ No newline at end of file diff --git a/src/jreleaser/distributions/sdkman-cli/brew/formula.rb.tpl b/src/jreleaser/distributions/sdkman-cli/brew/formula.rb.tpl new file mode 100644 index 000000000..d42d839e0 --- /dev/null +++ b/src/jreleaser/distributions/sdkman-cli/brew/formula.rb.tpl @@ -0,0 +1,35 @@ +class {{brewFormulaName}} < Formula + desc "{{projectDescription}}" + homepage "{{projectWebsite}}" + url "{{distributionUrl}}" + version "{{projectVersion}}" + sha256 "{{distributionChecksumSha256}}" + license "{{projectLicense}}" + + def install + libexec.install Dir["*"] + + %w[tmp ext etc var archives candidates].each { |dir| mkdir libexec/dir } + + system "curl", "-s", "https://api.sdkman.io/2/candidates/all", "-o", libexec/"var/candidates" + + (libexec/"etc/config").write <<~EOS + sdkman_auto_answer=false + sdkman_auto_complete=true + sdkman_auto_env=false + sdkman_auto_update=false + sdkman_beta_channel=false + sdkman_colour_enable=true + sdkman_curl_connect_timeout=7 + sdkman_curl_max_time=10 + sdkman_debug_mode=false + sdkman_insecure_ssl=false + sdkman_rosetta2_compatible=false + sdkman_selfupdate_feature=false + EOS + end + + test do + assert_match {{projectVersion}}, shell_output("export SDKMAN_DIR=#{libexec} && source #{libexec}/bin/sdkman-init.sh && sdk version") + end +end diff --git a/src/main/bash/sdkman-help.sh b/src/main/bash/sdkman-help.sh index 88eebfc6e..6fe593bac 100644 --- a/src/main/bash/sdkman-help.sh +++ b/src/main/bash/sdkman-help.sh @@ -36,7 +36,11 @@ function __sdk_help() { __sdkman_echo_no_colour " broadcast or b" __sdkman_echo_no_colour " help" __sdkman_echo_no_colour " offline [enable|disable]" - __sdkman_echo_no_colour " selfupdate [force]" + + if [[ "$sdkman_selfupdate_feature" == "true" ]]; then + __sdkman_echo_no_colour " selfupdate [force]" + fi + __sdkman_echo_no_colour " update" __sdkman_echo_no_colour " flush [archives|tmp|broadcast|metadata|version]" __sdkman_echo_no_colour "" diff --git a/src/main/bash/sdkman-main.sh b/src/main/bash/sdkman-main.sh index d134231e2..ee51b0d87 100644 --- a/src/main/bash/sdkman-main.sh +++ b/src/main/bash/sdkman-main.sh @@ -103,9 +103,11 @@ function sdk() { # Check if it is a valid command CMD_FOUND="" - CMD_TARGET="${SDKMAN_DIR}/src/sdkman-${COMMAND}.sh" - if [[ -f "$CMD_TARGET" ]]; then - CMD_FOUND="$CMD_TARGET" + if [[ "$COMMAND" != "selfupdate" || "$sdkman_selfupdate_feature" == "true" ]]; then + CMD_TARGET="${SDKMAN_DIR}/src/sdkman-${COMMAND}.sh" + if [[ -f "$CMD_TARGET" ]]; then + CMD_FOUND="$CMD_TARGET" + fi fi # Check if it is a sourced function @@ -165,7 +167,7 @@ function sdk() { fi # Attempt upgrade after all is done - if [[ "$COMMAND" != "selfupdate" && "$sdkman_selfupdate_enable" == true ]]; then + if [[ "$COMMAND" != "selfupdate" && "$sdkman_selfupdate_feature" == "true" && "$sdkman_auto_update" == "true" ]]; then __sdkman_auto_update "$SDKMAN_REMOTE_VERSION" "$SDKMAN_VERSION" fi return $final_rc diff --git a/src/test/groovy/sdkman/env/SdkmanBashEnvBuilder.groovy b/src/test/groovy/sdkman/env/SdkmanBashEnvBuilder.groovy index e24b22be2..ee6d0e6ed 100644 --- a/src/test/groovy/sdkman/env/SdkmanBashEnvBuilder.groovy +++ b/src/test/groovy/sdkman/env/SdkmanBashEnvBuilder.groovy @@ -30,7 +30,8 @@ class SdkmanBashEnvBuilder { Map config = [ sdkman_auto_answer : 'false', - sdkman_beta_channel: 'false' + sdkman_beta_channel: 'false', + sdkman_selfupdate_feature: 'true' ] File sdkmanDir, sdkmanBinDir, sdkmanVarDir, sdkmanSrcDir, sdkmanEtcDir, sdkmanExtDir, sdkmanArchivesDir, diff --git a/src/test/groovy/sdkman/specs/SelfupdateSpec.groovy b/src/test/groovy/sdkman/specs/SelfupdateSpec.groovy new file mode 100644 index 000000000..2ac64e547 --- /dev/null +++ b/src/test/groovy/sdkman/specs/SelfupdateSpec.groovy @@ -0,0 +1,91 @@ +package sdkman.specs + +import sdkman.support.SdkmanEnvSpecification + +import java.time.Instant + +import static java.time.temporal.ChronoUnit.DAYS + +class SelfupdateSpec extends SdkmanEnvSpecification { + static final String CANDIDATES_API = "http://localhost:8080/2" + static final String BROADCAST_API_LATEST_ID_ENDPOINT = "$CANDIDATES_API/broadcast/latest/id" + static final String VERSION_ENDPOINT = "$CANDIDATES_API/broker/download/sdkman/version/stable" + + def setup() { + curlStub.primeWith(BROADCAST_API_LATEST_ID_ENDPOINT, "echo dbfb025be9f97fda2052b5febcca0155") + curlStub.primeWith(VERSION_ENDPOINT, "echo 5.0.0") + } + + def "should list selfupdate as a valid command when the selfupdate feature is toggled on"() { + given: + bash = sdkmanBashEnvBuilder + .withConfiguration("sdkman_selfupdate_feature", selfUpdateFeature) + .build() + + bash.start() + bash.execute("source $bootstrapScript") + + when: + bash.execute("sdk help") + + then: + verifyOutput(bash.output) + + where: + selfUpdateFeature | verifyOutput + "false" | { !it.contains("selfupdate") } + "true" | { it.contains("selfupdate") } + } + + def "should source sdkman-selfupdate.sh when the selfupdate feature is toggled on"() { + given: + bash = sdkmanBashEnvBuilder + .withConfiguration("sdkman_selfupdate_feature", selfupdateFeature) + .build() + + bash.start() + bash.execute("source $bootstrapScript") + + when: + bash.execute("sdk selfupdate") + + then: + verifyOutput(bash.output) + + where: + selfupdateFeature | verifyOutput + "false" | { it.contains("Invalid command: selfupdate") } + "true" | { it.contains("No update available at this time.") } + } + + def "should perform an autoupdate when the selfupdate feature is toggled on and autoupdate is enabled"() { + given: + new File("$sdkmanDotDirectory/var/delay_upgrade").with { + parentFile.mkdirs() + createNewFile() + lastModified = Instant.now().minus(2, DAYS).toEpochMilli() + } + + bash = sdkmanBashEnvBuilder + .withSdkmanVersion("4.0.0") + .withConfiguration("sdkman_selfupdate_feature", selfupdateFeature) + .withConfiguration("sdkman_auto_update", autoUpdateEnabled) + .withConfiguration("sdkman_auto_answer", "true") + .build() + + bash.start() + bash.execute("source $bootstrapScript") + + when: + bash.execute("sdk version") + + then: + verifyOutput(bash.output) + + where: + selfupdateFeature | autoUpdateEnabled | verifyOutput + "true" | "true" | { it.contains("ATTENTION: A new version of SDKMAN is available...") } + "true" | "false" | { !it.contains("ATTENTION: A new version of SDKMAN is available...") } + "false" | "true" | { !it.contains("ATTENTION: A new version of SDKMAN is available...") } + } +}