feat(install): first-party curl installer for Linux/macOS#3
feat(install): first-party curl installer for Linux/macOS#3bschellenberger2600 wants to merge 5 commits intomainfrom
Conversation
Add scripts/install.sh (parity with git-fire): resolve latest or VERSION tag, download tar.gz + checksums.txt from GitHub Releases, verify SHA256, install to INSTALL_DIR (default ~/.local/bin). Document in README and GoReleaser release footers. Windows remains WinGet or manual .zip. Made-with: Cursor
📝 WalkthroughWalkthroughAdds a curl-based installer: a new Bash installer downloads git-rain release artifacts from GitHub, verifies SHA-256 checksums, installs to a configurable directory, updates README and release footers, and adds a ShellCheck CI job for the installer. Changes
Sequence DiagramsequenceDiagram
participant User
participant Script as scripts/install.sh
participant GitHubAPI as GitHub API
participant GitHubReleases as GitHub Releases
participant FS as Local Filesystem
User->>Script: Execute curl ... | bash (with optional VERSION/INSTALL_DIR)
Script->>Script: Detect OS & architecture
Script->>GitHubAPI: Query release tag (latest or provided)
GitHubAPI-->>Script: Return tag
Script->>GitHubReleases: Download archive (.tar.gz)
GitHubReleases-->>Script: Archive bytes
Script->>GitHubReleases: Download checksums.txt
GitHubReleases-->>Script: checksums.txt
Script->>Script: Extract expected SHA-256, compute actual SHA-256
Script->>Script: Compare checksums (abort on mismatch)
Script->>Script: Extract archive, verify binary present
Script->>FS: Install binary to INSTALL_DIR (use sudo if needed)
FS-->>Script: Install success
Script-->>User: Print success / version hint
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
scripts/install.sh (1)
80-82: NormalizeVERSIONinput to accept bothv1.2.3and1.2.3.Currently the script expects a tag-like value; a bare semver leads to a 404 later. Normalizing here makes CLI behavior more forgiving.
Suggested fix
resolve_version() { if [ -n "$VERSION" ]; then - printf '%s\n' "$VERSION" + case "$VERSION" in + v*) printf '%s\n' "$VERSION" ;; + *) printf 'v%s\n' "$VERSION" ;; + esac return fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/install.sh` around lines 80 - 82, The script currently returns the raw $VERSION in the if block (if [ -n "$VERSION" ]; then printf '%s\n' "$VERSION" return) which breaks later calls when a bare semver (1.2.3) is provided; change this block to normalize $VERSION to a tag by ensuring it begins with "v" (e.g., if it does not start with "v", prepend "v") and then print the normalized value instead of the raw input so both "v1.2.3" and "1.2.3" work transparently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.goreleaser.stable.yaml:
- Around line 135-138: The stable release notes currently use the curl installer
URL referencing the main branch; update the installer command and any VERSION
placeholder so they are tag-pinned using the release tag variable: replace the
"main" path segment in the curl URL that fetches "scripts/install.sh" with the
release tag token ({{ .Tag }}) and ensure any exported/embedded VERSION value in
the snippet is set to {{ .Tag }} as well so the curl invocation and VERSION
become reproducible and tied to the release tag.
In @.goreleaser.yaml:
- Around line 99-102: Update the release footer curl command so it pins the
installer to the release tag and passes the VERSION environment to the
installer: replace the current URL that points to scripts/install.sh on main
with one using the release template variable {{ .Tag }} (e.g.,
.../raw.githubusercontent.com/.../{{ .Tag }}/scripts/install.sh) and ensure the
shell invocation passes VERSION={{ .Tag }} to bash so the installer run is
deterministic for that release.
In `@README.md`:
- Around line 95-99: The example binds VERSION and INSTALL_DIR to curl rather
than the shell that runs the installer, so the installer script (install.sh)
won't see them; fix by moving the env-var assignment to the bash invocation that
executes the downloaded script (e.g., ensure VERSION and INSTALL_DIR are
exported/prefixed on the bash side or passed via bash -s/ bash -c) so that when
curl | bash runs, the installer receives VERSION and INSTALL_DIR instead of
attaching them to curl.
In `@scripts/install.sh`:
- Around line 99-112: The install_binary function should explicitly guard
against INSTALL_DIR being a regular file: at the top of install_binary (before
writability checks) detect if the passed target_dir exists but is not a
directory (e.g., [ -e "$target_dir" ] && [ ! -d "$target_dir" ]) and fail fast
with a clear error message referencing $target_dir and $BINARY_NAME (or return
non-zero) so the subsequent mkdir/install logic doesn't produce confusing
errors; keep existing writability and mkdir code unchanged after this early
directory-type check.
---
Nitpick comments:
In `@scripts/install.sh`:
- Around line 80-82: The script currently returns the raw $VERSION in the if
block (if [ -n "$VERSION" ]; then printf '%s\n' "$VERSION" return) which breaks
later calls when a bare semver (1.2.3) is provided; change this block to
normalize $VERSION to a tag by ensuring it begins with "v" (e.g., if it does not
start with "v", prepend "v") and then print the normalized value instead of the
raw input so both "v1.2.3" and "1.2.3" work transparently.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4d07fc27-a97c-423c-bac4-9a08b1a1fe3a
📒 Files selected for processing (4)
.goreleaser.stable.yaml.goreleaser.yamlREADME.mdscripts/install.sh
…R guard
- GoReleaser footers: fetch install.sh at {{ .Tag }} and pass VERSION={{ .Tag }}
to bash for reproducible release notes.
- README: move VERSION/INSTALL_DIR to the bash side of the pipeline.
- install.sh: fail fast if INSTALL_DIR exists but is not a directory.
Addresses CodeRabbit review on PR #3.
Made-with: Cursor
|
@coderabbitai re-review |
|
✅ Actions performedReview triggered.
|
Resolve VERSION against real release tags (try v-prefix and bare), optional GITHUB_TOKEN/GH_TOKEN for the releases/latest API, defensive checksum parsing, install/tar preflight, PATH dir normalization, and README notes. Add a shellcheck job for scripts/install.sh. Made-with: Cursor
|
bugbot review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix resolved 1 of the 2 issues found in the latest run.
- ✅ Fixed: Wget path omits API version header
- Added
X-GitHub-Api-Version: 2022-11-28to the authenticated wget headers infetch_github_api.
- Added
Preview (a1e4e29df3)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,6 +10,16 @@
contents: read
jobs:
+ shellcheck:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: ShellCheck install.sh
+ run: |
+ sudo apt-get update -qq
+ sudo apt-get install -y shellcheck
+ shellcheck scripts/install.sh
+
lint:
runs-on: ubuntu-latest
steps:
@@ -44,7 +54,7 @@
uat:
runs-on: ubuntu-latest
- needs: [lint, test]
+ needs: [shellcheck, lint, test]
steps:
- uses: actions/checkout@v4
diff --git a/.goreleaser.stable.yaml b/.goreleaser.stable.yaml
--- a/.goreleaser.stable.yaml
+++ b/.goreleaser.stable.yaml
@@ -132,6 +132,11 @@
go install github.com/git-rain/git-rain@{{ .Tag }}
```
+ **curl (Linux / macOS)**
+ ```sh
+ curl -fsSL https://raw.githubusercontent.com/git-fire/git-rain/{{ .Tag }}/scripts/install.sh | VERSION={{ .Tag }} bash
+ ```
+
**Homebrew (macOS/Linuxbrew)**
```sh
brew install git-fire/tap/git-rain
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -96,6 +96,11 @@
go install github.com/git-rain/git-rain@{{ .Tag }}
```
+ **curl (Linux / macOS)**
+ ```sh
+ curl -fsSL https://raw.githubusercontent.com/git-fire/git-rain/{{ .Tag }}/scripts/install.sh | VERSION={{ .Tag }} bash
+ ```
+
**Binaries**
Download platform archives from this release's assets.
Package-manager channels are published for stable tags (`vX.Y.Z`).
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -28,6 +28,7 @@
- [Install](#install)
- [Homebrew (macOS/Linuxbrew)](#homebrew-macoslinuxbrew)
- [WinGet (Windows)](#winget-windows)
+ - [curl installer (Linux / macOS)](#curl-installer-linux--macos)
- [Linux native packages (.deb / .rpm)](#linux-native-packages-deb--rpm)
- [Go install](#go-install)
- [Binary archive (manual)](#binary-archive-manual)
@@ -65,6 +66,7 @@
|---|---|---|
| Homebrew | `brew install git-fire/tap/git-rain` | macOS, Linuxbrew |
| WinGet | `winget install git-rain.git-rain` | Windows |
+| curl script | [curl installer](#curl-installer-linux--macos) | Linux, macOS |
| Linux package | Download `.deb` or `.rpm` from [GitHub Releases](https://github.com/git-fire/git-rain/releases) | Linux |
| Go | `go install github.com/git-rain/git-rain@latest` | All (Go 1.24.2+) |
| Binary archive | [GitHub Releases](https://github.com/git-fire/git-rain/releases) | All |
@@ -82,6 +84,35 @@
winget install git-rain.git-rain+### curl installer (Linux / macOS)
+
+First-party install script (same idea as git-fire/scripts/install.sh): downloads the matching .tar.gz from Releases, verifies checksums.txt, and installs to $INSTALL_DIR (default ~/.local/bin).
+
+The main URL below always runs the installer script from the latest commit on that branch, while the binary itself comes from the latest GitHub release (or from VERSION if you set it). That is convenient for copy-paste installs, but it means the script can drift ahead of any given release. For a fully pinned install, use the release tag in the URL (as in each release’s notes) and set VERSION to the same tag.
+
+For repeated automation against the GitHub API (resolving latest), set GITHUB_TOKEN or GH_TOKEN so authenticated rate limits apply. VERSION may be a bare semver (0.9.1); the installer tries the v-prefixed release tag first, then the exact string you passed.
+
+bash +curl -fsSL https://raw.githubusercontent.com/git-fire/git-rain/main/scripts/install.sh | bash +
+
+Pin a version or install directory (environment variables must apply to bash, not curl):
+
+bash +curl -fsSL https://raw.githubusercontent.com/git-fire/git-rain/main/scripts/install.sh | VERSION=v0.9.1 INSTALL_DIR=/usr/local/bin bash +
+
+If your shell does not already include ~/.local/bin on PATH, add it (the installer prints a reminder). Example for bash (skips the line if .local/bin is already mentioned in ~/.bashrc):
+
+```bash
+if ! grep -qF '.local/bin' ~/.bashrc 2>/dev/null; then
- echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
+fi
+source ~/.bashrc
+```
+Windows is not supported by this script — use WinGet or download a .zip from Releases.
+
Linux native packages (.deb / .rpm)
Download from GitHub Releases, then:
diff --git a/scripts/install.sh b/scripts/install.sh
new file mode 100644
--- /dev/null
+++ b/scripts/install.sh
@@ -1,0 +1,287 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Install git-rain from GitHub release assets with checksum verification.
+# Usage:
+# curl -fsSL https://raw.githubusercontent.com/git-fire/git-rain/main/scripts/install.sh | bash
+# Optional env vars:
+# VERSION=v0.9.1 (must match a GitHub release tag; bare semver like 0.9.1 tries v0.9.1 first)
+# INSTALL_DIR=$HOME/.local/bin
+# REPO=git-fire/git-rain
+# GITHUB_TOKEN or GH_TOKEN (optional; increases api.github.com rate limits for "latest" resolution)
+
+REPO="${REPO:-git-fire/git-rain}"
+INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}"
+VERSION="${VERSION:-}"
+BINARY_NAME="git-rain"
+
+log() {
- printf '[git-rain install] %s\n' "$1"
+}
+fail() {
- printf '[git-rain install] ERROR: %s\n' "$1" >&2
- exit 1
+}
+need_cmd() {
- command -v "$1" >/dev/null 2>&1 || fail "required command not found: $1"
+}
+github_token() {
- printf '%s' "${GITHUB_TOKEN:-${GH_TOKEN:-}}"
+}
+download_to() {
- local src="$1"
- local dst="$2"
- if command -v curl >/dev/null 2>&1; then
- curl -fsSL "$src" -o "$dst"
- elif command -v wget >/dev/null 2>&1; then
- wget -qO "$dst" "$src"
- else
- fail "curl or wget is required"
- fi
+}
+fetch_github_api() {
- local url="$1"
- if command -v curl >/dev/null 2>&1; then
- local token
- token="$(github_token)"
- if [ -n "$token" ]; then
-
curl -fsSL \ -
-H "Authorization: Bearer ${token}" \ -
-H "Accept: application/vnd.github+json" \ -
-H "X-GitHub-Api-Version: 2022-11-28" \ -
"$url" - else
-
curl -fsSL "$url" - fi
- elif command -v wget >/dev/null 2>&1; then
- local token
- token="$(github_token)"
- if [ -n "$token" ]; then
-
wget -qO- \ -
--header="Authorization: Bearer ${token}" \ -
--header="Accept: application/vnd.github+json" \ -
--header="X-GitHub-Api-Version: 2022-11-28" \ -
"$url" - else
-
wget -qO- "$url" - fi
- else
- fail "curl or wget is required"
- fi
+}
+sha256_file() {
- local target="$1"
- if command -v sha256sum >/dev/null 2>&1; then
- sha256sum "$target" | awk '{print $1}'
- elif command -v shasum >/dev/null 2>&1; then
- shasum -a 256 "$target" | awk '{print $1}'
- else
- fail "sha256sum or shasum is required"
- fi
+}
+# First field is digest; remainder is filename (GNU text " " or binary " *").
+checksum_for_file() {
- local sums="$1"
- local want="$2"
- awk -v want="$want" '
- {
-
hash = $1 -
name = $0 -
sub(/^[^[:space:]]+[[:space:]]+/, "", name) -
sub(/^\*/, "", name) -
if (name == want) { -
print hash -
exit -
} - }' "$sums"
+}
+normalize_os() {
- local raw_os
- raw_os="$(uname -s | tr '[:upper:]' '[:lower:]')"
- case "$raw_os" in
- linux) echo "linux" ;;
- darwin) echo "darwin" ;;
- *)
-
fail "unsupported OS: $raw_os (expected linux or darwin). On Windows use WinGet or a release .zip from GitHub." -
;; - esac
+}
+normalize_arch() {
- local raw_arch
- raw_arch="$(uname -m)"
- case "$raw_arch" in
- x86_64 | amd64) echo "amd64" ;;
- aarch64 | arm64) echo "arm64" ;;
-
linux/arm is published as armv6 only; armv7l is ABI-compatible.
- armv6l | armv7l) echo "armv6" ;;
- i386 | i686) echo "386" ;;
- *)
-
fail "unsupported architecture: $raw_arch" -
;; - esac
+}
+resolve_raw_version_tag() {
- if [ -n "$VERSION" ]; then
- printf '%s\n' "$VERSION"
- return
- fi
- local api_url response tag
- api_url="https://api.github.com/repos/$REPO/releases/latest"
- response="$(fetch_github_api "$api_url")"
- tag="$(printf '%s\n' "$response" | awk -F '"' '/"tag_name"[[:space:]]*:/ {print $4; exit}')"
- [ -n "$tag" ] || fail "could not resolve latest release tag from GitHub API"
- printf '%s\n' "$tag"
+}
+release_archive_url() {
- local tag="$1"
- local archive_name="$2"
- printf 'https://github.com/%s/releases/download/%s/%s\n' "$REPO" "$tag" "$archive_name"
+}
+# Return 0 if a release asset URL responds with success (follows redirects).
+release_asset_head_ok() {
- local url="$1"
- local code
- if command -v curl >/dev/null 2>&1; then
- code="$(curl -gfsSIL -L -o /dev/null -w "%{http_code}" "$url" 2>/dev/null || printf '%s' "000")"
- [ "$code" = "200" ]
- elif command -v wget >/dev/null 2>&1; then
- wget --spider -q -L "$url"
- else
- false
- fi
+}
+# Map user input or "latest" API tag to the GitHub release tag that owns the archive.
+pick_release_tag() {
- local raw="$1"
- local -a candidates=()
- case "$raw" in
- v*)
-
candidates=("$raw" "${raw#v}") -
;; - *)
-
candidates=("v${raw}" "${raw}") -
;; - esac
- local tag archive_version archive_name url
- for tag in "${candidates[@]}"; do
- archive_version="${tag#v}"
- archive_name="${BINARY_NAME}${archive_version}${os}_${arch}.tar.gz"
- url="$(release_archive_url "$tag" "$archive_name")"
- if release_asset_head_ok "$url"; then
-
printf '%s\n' "$tag" -
return - fi
- done
- fail "no GitHub release matched VERSION=${raw} for ${os}/${arch} (check tag spelling and that this platform is published)"
+}
+normalize_path_dir() {
- local d="$1"
- while [ "${#d}" -gt 1 ] && [ "${d%/}" != "$d" ]; do
- d="${d%/}"
- done
- printf '%s\n' "$d"
+}
+install_binary() {
- local src_bin="$1"
- local target_dir="$2"
- local target_bin="$target_dir/$BINARY_NAME"
- if [ -e "$target_dir" ] && [ ! -d "$target_dir" ]; then
- fail "install path exists but is not a directory: $target_dir"
- fi
- if [ ! -d "$target_dir" ]; then
- if mkdir -p "$target_dir" 2>/dev/null; then
-
: - elif command -v sudo >/dev/null 2>&1; then
-
sudo mkdir -p "$target_dir" - else
-
fail "could not create install directory: $target_dir" - fi
- fi
- if [ -w "$target_dir" ]; then
- install -m 0755 "$src_bin" "$target_bin"
- return
- fi
- if command -v sudo >/dev/null 2>&1; then
- sudo install -m 0755 "$src_bin" "$target_bin"
- return
- fi
- fail "install directory is not writable and sudo is unavailable: $target_dir"
+}
+path_has_dir() {
- local dir
- dir="$(normalize_path_dir "$1")"
- case ":${PATH:-}:" in
- ":${dir}:") return 0 ;;
- *) return 1 ;;
- esac
+}
+# Preflight: fail fast before downloads (curl/wget checked in download_to).
+need_cmd tar
+need_cmd install
+os="$(normalize_os)"
+arch="$(normalize_arch)"
+version_tag="$(pick_release_tag "$(resolve_raw_version_tag)")"
+version="${version_tag#v}"
+
+archive_name="${BINARY_NAME}${version}${os}_${arch}.tar.gz"
+archive_url="$(release_archive_url "$version_tag" "$archive_name")"
+checksums_url="$(release_archive_url "$version_tag" "checksums.txt")"
+
+log "installing ${BINARY_NAME} ${version_tag} for ${os}/${arch}"
+
+tmp_dir="$(mktemp -d)"
+trap 'rm -rf "$tmp_dir"' EXIT
+
+archive_path="$tmp_dir/$archive_name"
+checksums_path="$tmp_dir/checksums.txt"
+
+log "downloading release archive"
+download_to "$archive_url" "$archive_path"
+
+log "downloading checksum file"
+download_to "$checksums_url" "$checksums_path"
+
+expected_sum="$(checksum_for_file "$checksums_path" "$archive_name")"
+[ -n "$expected_sum" ] || fail "could not find checksum entry for $archive_name (no asset for this OS/arch on this release?)"
+
+actual_sum="$(sha256_file "$archive_path")"
+if [ "$expected_sum" != "$actual_sum" ]; then
- fail "checksum mismatch for $archive_name"
+fi
+log "checksum verified"
+tar -xzf "$archive_path" -C "$tmp_dir"
+[ -f "$tmp_dir/$BINARY_NAME" ] || fail "archive did not contain $BINARY_NAME"
+
+install_binary "$tmp_dir/$BINARY_NAME" "$INSTALL_DIR"
+
+log "installed to $INSTALL_DIR/$BINARY_NAME"
+if ! path_has_dir "$INSTALL_DIR"; then
- log "warning: $INSTALL_DIR is not on PATH; add it to your shell profile, e.g. export PATH="$INSTALL_DIR:$PATH""
+fi
+log "verify with: $BINARY_NAME --version"
</details>
<sub>You can send follow-ups to the cloud agent <a href="https://cursor.com/agents/bc-9b515c5c-d029-48ed-bbba-f18b7df2b198">here</a>.</sub>
<!-- BUGBOT_AUTOFIX_REVIEW_FOOTNOTE_END -->
<sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7dea654c8c8e26653e2078ab27d527d03287f4b3. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
|
|
||
| **curl (Linux / macOS)** | ||
| ```sh | ||
| curl -fsSL https://raw.githubusercontent.com/git-fire/git-rain/{{ .Tag }}/scripts/install.sh | VERSION={{ .Tag }} bash |
There was a problem hiding this comment.
Prerelease footer installs wrong version silently
Medium Severity
The prerelease .goreleaser.yaml footer pipes the install script from main into bare bash without setting VERSION, while the stable .goreleaser.stable.yaml correctly uses {{ .Tag }} in both the URL and VERSION={{ .Tag }}. Without VERSION, the installer calls GitHub's /releases/latest endpoint, which only returns non-prerelease releases. Users copying the curl snippet from a prerelease's release notes would silently install the latest stable release instead of the prerelease they intended.
Reviewed by Cursor Bugbot for commit 7dea654. Configure here.
There was a problem hiding this comment.
Bugbot Autofix determined this is a false positive.
.goreleaser.yaml already uses {{ .Tag }} for the script URL and VERSION={{ .Tag }} on the curl line, matching stable behavior.
You can send follow-ups to the cloud agent here.
Match authenticated curl behavior so wget uses the same REST API version.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)
13-21: Remove redundant shellcheck installation — it's preinstalled onubuntu-latest.The
apt-get updateand install steps add ~10–20s per run unnecessarily. GitHub'subuntu-latestrunners ship withshellcheckavailable onPATH. Drop the install step or use a dedicated action likeludeeus/action-shellcheckfor PR annotations.♻️ Simplification
shellcheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: ShellCheck install.sh - run: | - sudo apt-get update -qq - sudo apt-get install -y shellcheck - shellcheck scripts/install.sh + run: shellcheck scripts/install.sh🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/ci.yml around lines 13 - 21, The workflow job "shellcheck" currently runs "apt-get update" and "apt-get install -y shellcheck" before invoking "shellcheck scripts/install.sh"; remove the redundant install steps (the "sudo apt-get update -qq" and "sudo apt-get install -y shellcheck" lines) since shellcheck is preinstalled on ubuntu-latest, or alternatively replace the install block with a dedicated action like "ludeeus/action-shellcheck" for PR annotations; keep the existing "uses: actions/checkout@v4" and the final "shellcheck scripts/install.sh" step unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 13-21: The workflow job "shellcheck" currently runs "apt-get
update" and "apt-get install -y shellcheck" before invoking "shellcheck
scripts/install.sh"; remove the redundant install steps (the "sudo apt-get
update -qq" and "sudo apt-get install -y shellcheck" lines) since shellcheck is
preinstalled on ubuntu-latest, or alternatively replace the install block with a
dedicated action like "ludeeus/action-shellcheck" for PR annotations; keep the
existing "uses: actions/checkout@v4" and the final "shellcheck
scripts/install.sh" step unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5a3d6c22-4e7d-42b2-a2e4-d05e62211b75
📒 Files selected for processing (5)
.github/workflows/ci.yml.goreleaser.stable.yaml.goreleaser.yamlREADME.mdscripts/install.sh
✅ Files skipped from review due to trivial changes (3)
- .goreleaser.stable.yaml
- .goreleaser.yaml
- README.md
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/install.sh


Summary
Adds
scripts/install.sh, matching the pattern used by git-fire:VERSIONenv, e.g.v0.9.1)git-rain_<version>_<os>_<arch>.tar.gz+checksums.txt, verifies SHA256INSTALL_DIR(default$HOME/.local/bin), usingsudoonly if the dir is not writable.zipassetsDocs
.goreleaser.yaml/.goreleaser.stable.yamlrelease footers include the one-linerSmoke test
VERSION=v0.9.1 INSTALL_DIR="$(mktemp -d)" bash scripts/install.shSummary by CodeRabbit
New Features
Documentation
Chores
Note
Medium Risk
Adds a new
curl | bashinstall path that downloads and executes remote artifacts; while checksums are verified, mistakes could break installs or create supply-chain exposure if release assets are compromised.Overview
Adds a first-party
scripts/install.shfor Linux/macOS that resolves a release tag (latest orVERSION), downloads the matching archive pluschecksums.txt, verifies SHA256, and installsgit-rainintoINSTALL_DIR(usingsudoonly when needed).Updates docs and release messaging to promote the one-line curl installer (README + GoReleaser release footers), and extends CI with a
shellcheckjob gating UAT on shell script linting.Reviewed by Cursor Bugbot for commit a1e4e29. Bugbot is set up for automated code reviews on this repo. Configure here.