diff --git a/README.md b/README.md index 85d4ac3..cf194cb 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ [![Image Size](https://badges.cssnr.com/ghcr/size/smashedr/install-release)](https://github.com/smashedr/install-release/pkgs/container/install-release) [![Go Version](https://img.shields.io/github/go-mod/go-version/smashedr/install-release?logo=go&logoColor=white&label=go)](https://github.com/smashedr/install-release/blob/master/go.mod) [![Deployment Docs](https://img.shields.io/github/deployments/smashedr/install-release/docs?logo=materialformkdocs&logoColor=white&label=docs)](https://github.com/smashedr/install-release/deployments/docs) -[![Deployment Preview](https://img.shields.io/github/deployments/smashedr/install-release/preview?logo=materialformkdocs&logoColor=white&label=preview)](https://github.com/smashedr/install-release/deployments/preview) -[![Workflow Release](https://img.shields.io/github/actions/workflow/status/smashedr/install-release/release.yaml?logo=testcafe&logoColor=white&label=release)](https://github.com/smashedr/install-release/actions/workflows/release.yaml) -[![Workflow Lint](https://img.shields.io/github/actions/workflow/status/smashedr/install-release/lint.yaml?logo=testcafe&logoColor=white&label=lint)](https://github.com/smashedr/install-release/actions/workflows/lint.yaml) +[![Deployment Preview](https://img.shields.io/github/deployments/smashedr/install-release/preview?logo=labex&logoColor=white&label=preview)](https://github.com/smashedr/install-release/deployments/preview) +[![Workflow Release](https://img.shields.io/github/actions/workflow/status/smashedr/install-release/release.yaml?logo=norton&logoColor=white&label=release)](https://github.com/smashedr/install-release/actions/workflows/release.yaml) +[![Workflow Lint](https://img.shields.io/github/actions/workflow/status/smashedr/install-release/lint.yaml?logo=norton&logoColor=white&label=lint)](https://github.com/smashedr/install-release/actions/workflows/lint.yaml) [![GitHub Last Commit](https://img.shields.io/github/last-commit/smashedr/install-release?logo=listenhub&label=updated)](https://github.com/smashedr/install-release/pulse) -[![GitHub Repo Size](https://img.shields.io/github/repo-size/smashedr/install-release?logo=buffer&label=repo%20size)](https://github.com/smashedr/install-release?tab=readme-ov-file#readme) +[![GitHub Repo Size](https://img.shields.io/github/repo-size/smashedr/install-release?logo=googlecloudstorage&logoColor=white&label=repo%20size)](https://github.com/smashedr/install-release?tab=readme-ov-file#readme) [![GitHub Top Language](https://img.shields.io/github/languages/top/smashedr/install-release?logo=devbox)](https://github.com/smashedr/install-release?tab=readme-ov-file#readme) [![GitHub Contributors](https://img.shields.io/github/contributors-anon/smashedr/install-release?logo=southwestairlines)](https://github.com/smashedr/install-release/graphs/contributors) [![GitHub Issues](https://img.shields.io/github/issues/smashedr/install-release?logo=codeforces&logoColor=white)](https://github.com/smashedr/install-release/issues) @@ -31,6 +31,7 @@ Install Release - [Install](#install) +- [Features](#features) - [Usage](#usage) - [Development](#development) - [Support](#Support) @@ -38,7 +39,9 @@ CLI to Install a GitHub Release. -Easily Install GitHub Release binaries with Windows, Linux and macOS Support. +Easily Install GitHub Release binaries on Windows, Linux and macOS. + +Interactively select the release version, asset, and executable name with automatically detected presets. [![VHS Tape](https://cssnr.s3.amazonaws.com/install-release/demo.gif)](https://smashedr.github.io/install-release/) @@ -46,6 +49,17 @@ Easily Install GitHub Release binaries with Windows, Linux and macOS Support. > This project is in development. > It is functional but may have bugs. +## Features + +- Supports Windows, Linux and macOS +- Interactively Select Options +- Set Options w/ Flags or Variables +- Save or Set a Custom `bin` Path +- List and Remove Installed Apps +- Get App Information + +[![View Documentation](https://img.shields.io/badge/view_documentation-blue?style=for-the-badge&logo=quicklook)](https://smashedr.github.io/install-release/) + ## Install [![Latest Release](https://img.shields.io/github/v/release/smashedr/install-release?logo=github&label=latest%20release)](https://github.com/smashedr/install-release/releases) @@ -60,7 +74,7 @@ brew install cssnr/tap/install-release #### Bash ```shell -curl 'https://i.jpillora.com/smashedr/install-release!?as=ir' | bash +curl 'https://raw.githubusercontent.com/smashedr/install-release/refs/heads/master/scripts/install.sh' | bash ``` 💾 Alternatively, you can manually [download a release](https://github.com/smashedr/install-release/releases). @@ -87,7 +101,7 @@ docker run --rm -itv ~/bin:/out ghcr.io/smashedr/ir:latest -b /out smashedr/inst _Note: Docker requires you to mount the target bin directory._ -[![View Documentation](https://img.shields.io/badge/view_documentation-blue?style=for-the-badge&logo=googledocs&logoColor=white)](https://smashedr.github.io/install-release/) +[![View Documentation](https://img.shields.io/badge/view_documentation-blue?style=for-the-badge&logo=quicklook)](https://smashedr.github.io/install-release/) ## Usage @@ -169,7 +183,7 @@ Edit the settings. ir config ``` -[![View Documentation](https://img.shields.io/badge/view_documentation-blue?style=for-the-badge&logo=googledocs&logoColor=white)](https://smashedr.github.io/install-release/) +[![View Documentation](https://img.shields.io/badge/view_documentation-blue?style=for-the-badge&logo=quicklook)](https://smashedr.github.io/install-release/) # Development @@ -225,8 +239,8 @@ For a full list of current projects visit: [https://cssnr.github.io/](https://cs - - - Star History Chart + + + Star History Chart diff --git a/Taskfile.yml b/Taskfile.yml index 54ecb40..b606a91 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -28,6 +28,7 @@ tasks: - task: pslint pslint: + desc: Invoke-ScriptAnalyzer does NOT exit with error! platforms: [windows] cmd: powershell -Command "Invoke-ScriptAnalyzer -Path scripts -Recurse" diff --git a/assets/main.tape b/assets/main.tape index 11bc4d0..d7a500a 100644 --- a/assets/main.tape +++ b/assets/main.tape @@ -3,6 +3,19 @@ Type "ir smashedr/bup" Sleep 0.5s Enter +# select version +Wait / [0-9]\.[0-9]/ +Sleep 1.5s +Down +Sleep 0.2s +Down +Sleep 0.5s +Up +Sleep 0.2s +Up +Sleep 0.5s +Enter +# select asset Wait / bup_/ Sleep 1.5s Up @@ -14,6 +27,7 @@ Sleep 0.2s Down Sleep 0.5s Enter +# set name Wait /\> / Sleep 1s Backspace diff --git a/cmd/info.go b/cmd/info.go index 4efd042..5e5ea9c 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -31,10 +31,13 @@ var infoCmd = &cobra.Command{ } log.Info("Repository", "owner", owner, "repo", repo, "tag", tag) client := getClient() - release, err := getRelease(client, owner, repo, tag, preRelease) + release, err := getRelease(client, owner, repo, tag, preRelease, true) if err != nil { log.Fatalf("Error getting release: %v", err) } + if release == nil { + log.Fatalf("No release found") + } if verbose >= 3 { log.Debugf("%v", release) } diff --git a/cmd/install.go b/cmd/install.go index 05cbd3a..6cd48ba 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -66,10 +66,13 @@ func runInstall(cmd *cobra.Command, args []string) error { // NOSONAR client := getClient() - release, err := getRelease(client, owner, repo, tag, preRelease) + release, err := getRelease(client, owner, repo, tag, preRelease, skipPrompts) if err != nil { return fmt.Errorf("get release error: %w", err) } + if release == nil { + return fmt.Errorf("no release found") + } if verbose >= 3 { log.Debugf("release: %v", release) } @@ -392,7 +395,7 @@ func getClient() *github.Client { return github.NewClient(httpClient) } -func getRelease(client *github.Client, owner, repo, tag string, pre bool) (*github.RepositoryRelease, error) { +func getRelease(client *github.Client, owner, repo, tag string, pre, skip bool) (*github.RepositoryRelease, error) { ctx := context.Background() var release *github.RepositoryRelease var err error @@ -400,11 +403,14 @@ func getRelease(client *github.Client, owner, repo, tag string, pre bool) (*gith log.Debugf("client.Repositories.GetReleaseByTag: %v", tag) release, _, err = client.Repositories.GetReleaseByTag(ctx, owner, repo, tag) } else if pre { - log.Debugf("GetLatestRelease - Including Pre-Releases") + log.Debugf("GetLatestRelease") release, err = getLatestRelease(client, owner, repo) - } else { + } else if skip { log.Debugf("client.Repositories.GetLatestRelease") release, _, err = client.Repositories.GetLatestRelease(ctx, owner, repo) + } else { + log.Debugf("chooseRelease") + release, err = chooseRelease(client, owner, repo, 30) } if err != nil { return nil, fmt.Errorf("get release error: %w", err) @@ -413,16 +419,52 @@ func getRelease(client *github.Client, owner, repo, tag string, pre bool) (*gith } func getLatestRelease(client *github.Client, owner, repo string) (*github.RepositoryRelease, error) { + releases, err := getReleases(client, owner, repo, 1) + if err != nil { + return nil, err + } + if len(releases) == 0 { + return nil, nil + } + return releases[0], nil +} + +func getReleases(client *github.Client, owner, repo string, number int) ([]*github.RepositoryRelease, error) { ctx := context.Background() - releases, _, err := client.Repositories.ListReleases(ctx, owner, repo, &github.ListOptions{PerPage: 1}) + releases, _, err := client.Repositories.ListReleases(ctx, owner, repo, &github.ListOptions{PerPage: number}) if err != nil { return nil, err } - if len(releases) > 0 { - return releases[0], nil + return releases, nil +} + +func chooseRelease(client *github.Client, owner, repo string, number int) (*github.RepositoryRelease, error) { + releases, err := getReleases(client, owner, repo, number) + if err != nil { + return nil, fmt.Errorf("error getting releases: %w", err) + } + + log.Debugf("releases: %v", len(releases)) + var result1 int + options := make([]huh.Option[int], len(releases)) + for i, release := range releases { + options[i] = huh.NewOption(release.GetTagName(), i) } - // TODO: Consider returning an error here... - return nil, nil + form := huh.NewSelect[int](). + Title("Select a version:"). + Options(options...). + Value(&result1) + + err = form.Run() + if err != nil { + return nil, fmt.Errorf("prompt failed: %w", err) + } + log.Debugf("result1: %v", result1) + + chosen := releases[result1] + log.Debugf("release: %v", chosen) + log.Debugf("tag: %v", chosen.GetTagName()) + return chosen, nil } func ensureWinExt(destName string) string { diff --git a/docs/index.md b/docs/index.md index 55e2683..59ed116 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,11 +11,11 @@ icon: lucide/rocket [![Image Size](https://badges.cssnr.com/ghcr/size/smashedr/install-release)](https://github.com/smashedr/install-release/pkgs/container/install-release) [![Go Version](https://img.shields.io/github/go-mod/go-version/smashedr/install-release?logo=go&logoColor=white&label=go)](https://github.com/smashedr/install-release/blob/master/go.mod) [![GitHub Last Commit](https://img.shields.io/github/last-commit/smashedr/install-release?logo=listenhub&label=updated)](https://github.com/smashedr/install-release/pulse) -[![GitHub Repo Size](https://img.shields.io/github/repo-size/smashedr/install-release?logo=buffer&label=repo%20size)](https://github.com/smashedr/install-release?tab=readme-ov-file#readme) +[![GitHub Repo Size](https://img.shields.io/github/repo-size/smashedr/install-release?logo=googlecloudstorage&logoColor=white&label=repo%20size)](https://github.com/smashedr/install-release?tab=readme-ov-file#readme) [![GitHub Top Language](https://img.shields.io/github/languages/top/smashedr/install-release?logo=devbox)](https://github.com/smashedr/install-release?tab=readme-ov-file#readme) [![GitHub Contributors](https://img.shields.io/github/contributors-anon/smashedr/install-release?logo=southwestairlines)](https://github.com/smashedr/install-release/graphs/contributors) [![GitHub Issues](https://img.shields.io/github/issues/smashedr/install-release?logo=codeforces&logoColor=white)](https://github.com/smashedr/install-release/issues) -[![GitHub Discussions](https://img.shields.io/github/discussions/smashedr/install-release?logo=theconversation&logoColor=white)](https://github.com/smashedr/install-release/discussions) +[![GitHub Discussions](https://img.shields.io/github/discussions/smashedr/install-release?logo=theconversation)](https://github.com/smashedr/install-release/discussions) [![GitHub Forks](https://img.shields.io/github/forks/smashedr/install-release?style=flat&logo=forgejo&logoColor=white)](https://github.com/smashedr/install-release/forks) [![GitHub Repo Stars](https://img.shields.io/github/stars/smashedr/install-release?style=flat&logo=gleam&logoColor=white)](https://github.com/smashedr/install-release/stargazers) [![GitHub Org Stars](https://img.shields.io/github/stars/cssnr?style=flat&logo=apachespark&logoColor=white&label=org%20stars)](https://cssnr.github.io/) @@ -24,7 +24,9 @@ icon: lucide/rocket CLI to Install a GitHub Release. -Easily Install GitHub Release binaries with Windows, Linux and macOS Support. +Easily Install GitHub Release binaries on Windows, Linux and macOS. + +Interactively select the release version, asset, and executable name with automatically detected presets. --8<-- "docs/snippets/install.md" @@ -38,12 +40,12 @@ If you run into any issues or have any questions, [support](support.md) is avail ## :lucide-sparkles: Features -- Supports Windows -- Custom `bin` Path -- Automatic Release Detection -- Select Asset and Name Interactively -- Set Asset and Name Programmatically +- Supports Windows, Linux and macOS +- Interactively Select Options +- Set Options w/ Flags or Variables +- Save or Set a Custom `bin` Path - List and Remove Installed Apps +- Get App Information ## :lucide-plane-takeoff: Install diff --git a/docs/snippets/install.md b/docs/snippets/install.md index 6d4722d..70844f9 100644 --- a/docs/snippets/install.md +++ b/docs/snippets/install.md @@ -7,7 +7,7 @@ === ":lucide-terminal-square: bash" ```shell - curl 'https://i.jpillora.com/smashedr/install-release!?as=ir' | bash # (1)! + curl 'https://raw.githubusercontent.com/smashedr/install-release/refs/heads/master/scripts/install.sh' | bash # (1)! ``` 1. Alternatively, you can manually [download a release](https://github.com/smashedr/install-release/releases). diff --git a/docs/support.md b/docs/support.md index bfa7319..f823146 100644 --- a/docs/support.md +++ b/docs/support.md @@ -48,4 +48,12 @@ From here you can contact me directly, `Shane@111150265075298304`. More information available at: [https://cssnr.com/](https://cssnr.com/) -[![Image title](https://cdn.prod.website-files.com/5c14e387dab576fe667689cf/670f5a01c01ea9191809398c_support_me_on_kofi_blue.png){ width="360" }](https://ko-fi.com/cssnr) +[![Support on Ko-fi](https://cdn.prod.website-files.com/5c14e387dab576fe667689cf/670f5a01c01ea9191809398c_support_me_on_kofi_blue.png){ width="360" }](https://ko-fi.com/cssnr) + + + + + + Star History Chart + + diff --git a/scripts/install.sh b/scripts/install.sh index 750ebf4..1881245 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,72 +1,33 @@ #!/usr/bin/env bash # https://raw.githubusercontent.com/smashedr/install-release/refs/heads/master/scripts/install.sh +set -e + + OWNER="smashedr" REPO="install-release" EXE="ir" - -echo "Installing: ${OWNER}/${REPO} as ${EXE}" - TARGET_BIN="${HOME}/bin" -echo "TARGET_BIN: ${TARGET_BIN}" -set -e - -WORK_DIR=$(mktemp -d -t install-release-XXXXXXXXXX 2>&1) -echo "WORK_DIR: ${WORK_DIR}" -function _execution_trap() { - _ST="$?" - rm -rf "${WORK_DIR}" - if [[ "${_ST}" != "0" ]];then - echo "⛔ Installation Error! Exit Code: ${_ST}" - fi - exit "${_ST}" -} +echo "Installing: ${OWNER}/${REPO} as ${EXE}" -trap _execution_trap EXIT HUP INT QUIT PIPE TERM function fail() { _ST="$?" - echo "_ST: ${_ST} - Message: ${1}" 1>&2 - exit ${_ST} + echo "fail _ST: ${_ST}" + echo "⛔ ${1}" 1>&2 + if [ "$_ST" -eq 0 ]; then + exit 1 + fi + exit "${_ST}" } -# CHECKS -[ ! "$BASH_VERSION" ] && fail "Please use bash instead" -which find > /dev/null || fail "find not installed" -which xargs > /dev/null || fail "xargs not installed" -which sort > /dev/null || fail "sort not installed" -which tail > /dev/null || fail "tail not installed" -which cut > /dev/null || fail "cut not installed" -which du > /dev/null || fail "du not installed" - - -# PATH -if ! echo "${PATH}" | tr ':' '\n' | grep -qx "${TARGET_BIN}"; then - echo "⚠️ Target bin NOT in PATH: ${TARGET_BIN}" - # TODO: Add TARGET_BIN to PATH -fi - - -# GET -GET="" -if which curl > /dev/null; then - GET="curl --fail -# -L" -elif which wget > /dev/null; then - GET="wget -qO-" -else - fail "neither curl or wget are installed" -fi -if [[ -n "${GITHUB_TOKEN}" ]]; then - GET="$GET -H 'Authorization: ${GITHUB_TOKEN}'" -fi -echo "GET: ${GET}" # TODO: Exposes GITHUB_TOKEN - # OS OS=$(uname -s | tr '[:upper:]' '[:lower:]') -case "$OS" in +echo "OS: ${OS}" +case "${OS}" in darwin) OS="Darwin" FTYPE="tar.gz" @@ -75,17 +36,21 @@ linux) OS="Linux" FTYPE="tar.gz" ;; +mingw* | msys* | cygwin* | windows*) + OS="Windows" + FTYPE="zip" + ;; *) fail "unknown os: $(uname -s)" ;; esac -# TODO: Add windows support? echo "OS: ${OS}" # ARCH ARCH="$(uname -m)" -if [[ $OS = "darwin" ]] && sysctl hw.optional.arm64 2>/dev/null | grep -q ': 1'; then +echo "ARCH: ${ARCH}" +if [[ ${OS} = "Darwin" ]] && sysctl hw.optional.arm64 2>/dev/null | grep -q ': 1'; then ARCH="arm64" elif uname -m | grep -E '(aarch64|arm64)' > /dev/null; then ARCH="arm64" @@ -99,47 +64,105 @@ fi echo "ARCH: ${ARCH}" +# FTYPE +if [[ ${FTYPE} = "tar.gz" ]]; then + which tar > /dev/null || fail "tar is not installed" + which gzip > /dev/null || fail "gzip is not installed" +elif [[ ${FTYPE} = "zip" ]]; then + which unzip > /dev/null || fail "unzip is not installed" +else + fail "unknown file type: ${FTYPE}" +fi +echo "FTYPE: ${FTYPE}" + + # URL URL="https://github.com/${OWNER}/${REPO}/releases/latest/download/${EXE}_${OS}_${ARCH}.${FTYPE}" echo "URL: ${URL}" +# GET +GET="" +if which curl > /dev/null; then + GET="curl --fail -# -L" +elif which wget > /dev/null; then + GET="wget -qO-" +else + fail "neither curl or wget are installed" +fi +#if [[ -n "${GITHUB_TOKEN}" ]]; then +# GET="${GET} -H 'Authorization: ${GITHUB_TOKEN}'" +#fi +echo "GET: ${GET}" + + +# BIN +echo "Target Directory: $TARGET_BIN" +echo -n "Enter Path [press to accept]: " +read -r input +if [[ -n "${input}" ]]; then + # TODO: Sanatize TARGET_BIN + TARGET_BIN="${input}" +fi +echo "TARGET_BIN: $TARGET_BIN" + + +# PATH +if ! echo "${PATH}" | tr ':' '\n' | grep -qx "${TARGET_BIN}"; then + echo "⚠️ Target bin NOT in PATH: ${TARGET_BIN}" + # TODO: Add TARGET_BIN to PATH +fi +if [[ ! -d "${TARGET_BIN}" ]]; then + echo "⚠️ Creating bin directory: ${TARGET_BIN}" + mkdir -p "${TARGET_BIN}" || fail "mkdir failed on: ${TARGET_BIN}" +fi + + +# TEMP +TEMP_DIR=$(mktemp -d -t install-release-XXXXXXXXXX 2>&1) +echo "TEMP_DIR: ${TEMP_DIR}" + +function _execution_trap() { + _ST="$?" + rm -rf "${TEMP_DIR}" + if [[ "${_ST}" != "0" ]]; then + echo "⛔ Installation Error! Exit Code: ${_ST}" 1>&2 + fi + exit "${_ST}" +} +trap _execution_trap EXIT HUP INT QUIT PIPE TERM + + # DOWNLOAD -echo "cd ${WORK_DIR}" -cd "${WORK_DIR}" -if [[ $FTYPE = "tar.gz" ]] || [[ $FTYPE = ".tgz" ]]; then - which tar > /dev/null || fail "tar is not installed" - which gzip > /dev/null || fail "gzip is not installed" - bash -c "$GET $URL" | tar zxf - || fail "download failed" -elif [[ $FTYPE = "zip" ]]; then - which unzip > /dev/null || fail "unzip is not installed" - bash -c "$GET $URL" > tmp.zip || fail "download failed" +cd "${TEMP_DIR}" +if [[ ${FTYPE} = "tar.gz" ]]; then + bash -c "${GET} ${URL}" | tar zxf - || fail "download failed" +elif [[ ${FTYPE} = "zip" ]]; then + bash -c "${GET} ${URL}" > tmp.zip || fail "download failed" unzip -o -qq tmp.zip || fail "unzip failed" rm tmp.zip || fail "cleanup failed" -else - fail "unknown file type: $FTYPE" fi # CHMOD -TMP_BIN="${WORK_DIR}/${EXE}" -echo "TMP_BIN: ${TMP_BIN}" -chmod +x "${TMP_BIN}" || fail "chmod +x failed" +TEMP_BIN="${TEMP_DIR}/${EXE}" +echo "TEMP_BIN: ${TEMP_BIN}" +chmod +x "${TEMP_BIN}" || fail "chmod +x failed" DEST="${TARGET_BIN}/${EXE}" echo "DEST: ${DEST}" # MOVE -mv "${TMP_BIN}" "${DEST}" +mv "${TEMP_BIN}" "${DEST}" || fail "move to destination failed" -#OUT=$(mv "${TMP_BIN}" "${DEST}" 2>&1) +#OUT=$(mv "${TEMP_BIN}" "${DEST}" 2>&1) #STATUS=$? #echo "OUT: ${OUT}" #echo "STATUS: ${STATUS}" #if [[ "${STATUS}" != "0" ]]; then # if [[ $OUT =~ "Permission denied" ]]; then # echo "mv with sudo..." -# sudo mv "${TMP_BIN}" "${DEST}" || fail "sudo mv failed" +# sudo mv "${TEMP_BIN}" "${DEST}" || fail "sudo mv failed" # fi #fi