Skip to content

[feature/git_helper-13] Fixed Update Check and Self-update#17

Merged
justinkumpe merged 1 commit intomainfrom
dev
Dec 31, 2025
Merged

[feature/git_helper-13] Fixed Update Check and Self-update#17
justinkumpe merged 1 commit intomainfrom
dev

Conversation

@justinkumpe
Copy link
Member

@justinkumpe justinkumpe commented Dec 31, 2025

Summary by Sourcery

Improve the git-helper script’s update experience, robustness, and non-interactive behavior.

New Features:

  • Add automatic self-update capability that downloads and replaces the script from the main branch when a newer version is detected.
  • Introduce a helper to reliably resolve the script’s own on-disk path without depending on realpath.
  • Add a UI helper to display non-critical messages without exiting the helper.

Bug Fixes:

  • Fix version comparison and remote version parsing to handle whitespace and invalid formats more robustly.
  • Prevent interactive prompts when no TTY is available, avoiding hangs in non-interactive environments.
  • Ensure text-based UI fallback is always available if dialog/whiptail fail to display content.
  • Avoid running the main entrypoint when the script is sourced instead of executed.

Enhancements:

  • Route update-check informational messages through a non-exiting UI path and refine messaging around update states.

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 31, 2025

Reviewer's Guide

Refines the git-helper script’s update checking and self-update behavior, improves robustness of UI interactions (especially in non-interactive/CI contexts), and adds utilities to safely locate and replace the running script while avoiding side effects when sourced.

Sequence diagram for the updated check_updates and self-update flow

sequenceDiagram
  actor User
  participant GitHelper as GitHelperScript
  participant GitHubRaw as GitHubRawEndpoint
  participant FS as Filesystem

  User->>GitHelper: select_check_updates()
  activate GitHelper

  GitHelper->>GitHelper: cmd_check_updates()
  GitHelper->>GitHelper: fetch_latest_version()
  GitHelper->>GitHubRaw: HTTP_GET raw_git_helper.sh
  alt fetch_success
    GitHubRaw-->>GitHelper: script_contents
    GitHelper->>GitHelper: extract_and_trim_SCRIPT_VERSION()
    alt version_missing
      GitHelper->>User: ui_message_no_exit("Git Helper vSCRIPT_VERSION", "Could not retrieve version information from GitHub.")
    else version_found
      GitHelper->>GitHelper: compare_versions(SCRIPT_VERSION, latest_version)
      alt versions_equal
        GitHelper->>User: ui_message_no_exit("Git Helper vSCRIPT_VERSION", "You are running the latest version (SCRIPT_VERSION)!")
      else current_older
        GitHelper->>User: ui_message_no_exit("Git Helper vSCRIPT_VERSION", "A new version is available! ...")
        GitHelper->>User: ui_yesno("Git Helper vSCRIPT_VERSION", "Download and replace this script with the latest version now?")
        alt user_confirms_update
          GitHelper->>GitHelper: update_script_from_remote()
          GitHelper->>GitHelper: script_self_path()
          GitHelper->>GitHubRaw: wget raw_git_helper.sh
          alt download_and_sanity_ok
            GitHubRaw-->>GitHelper: new_script_file
            GitHelper->>FS: chmod +x tmp_file
            GitHelper->>FS: mv tmp_file script_self_path
            GitHelper->>User: ui_message("Git Helper vSCRIPT_VERSION", "Update complete. Please rerun the script.")
            GitHelper->>GitHelper: exit 0
          else update_failed
            GitHelper->>User: ui_message_no_exit("Git Helper vSCRIPT_VERSION", "Update failed. Please try manual update.")
          end
        else user_declines_update
          GitHelper-->>User: return_without_changes()
        end
      else current_newer
        GitHelper->>User: ui_message_no_exit("Git Helper vSCRIPT_VERSION", "You are running a development version ...")
      end
    end
  else fetch_failed
    GitHubRaw-->>GitHelper: error
    GitHelper->>User: ui_message_no_exit("Git Helper vSCRIPT_VERSION", "Failed to check for updates. Please check your internet connection.")
  end

  deactivate GitHelper
Loading

File-Level Changes

Change Details Files
Add robust self-path resolution and automatic self-update mechanism using wget, with sanity checks and permission handling.
  • Introduce script_self_path helper that uses realpath when available and falls back to manual path resolution
  • Add update_script_from_remote function to download latest script from GitHub to a temp file, sanity-check it, preserve execute bit, and atomically replace the current script file
  • Wire self-update into the update check flow to optionally download and replace the script when a newer version is found
git_helpers/git-helper.sh
Harden UI behavior and non-interactive usage, preventing hanging prompts and ensuring fallback text output.
  • Update detect_ui to skip installation prompts when stdin is not a TTY
  • Add ui_message_no_exit for non-critical messages that don’t trigger exit prompts
  • Extend ui_show_text_file with a fallback_to_text helper and use it for all UI_TOOL modes, only prompting for Enter when a TTY is present
  • Guard prompt_exit_after_display to only prompt when a TTY is available
git_helpers/git-helper.sh
Make version comparison and remote version fetching more robust.
  • Trim whitespace around version strings in compare_versions and validate they match a numeric dotted format before comparing
  • Enhance fetch_latest_version to handle missing SCRIPT_VERSION lines and trim whitespace from the extracted version value
  • Adjust cmd_check_updates to use ui_message_no_exit for non-fatal messages and to handle compare_versions return code safely by temporarily disabling set -e
git_helpers/git-helper.sh
Adjust update messaging and main entrypoint semantics to better support sourcing and dev versions.
  • Change messaging for up-to-date, outdated, and development-version cases to use the new non-exiting UI helper and to encourage in-script self-update instead of manual git pull instructions
  • Ensure cmd_check_updates returns 0 on completion and exits immediately after a successful self-update
  • Wrap main invocation so it only runs when the script is executed directly, not when sourced
  • Update SCRIPT_VERSION constant to 0.0.1
git_helpers/git-helper.sh

Possibly linked issues

  • #feature/git_helper: PR refines version comparison, error handling, UX, and adds automated self-update, directly fulfilling the version/update issue.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@justinkumpe justinkumpe merged commit 2725ebb into main Dec 31, 2025
2 of 3 checks passed
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In cmd_check_updates, toggling set +e/set -e around compare_versions can unexpectedly change the shell’s errexit behavior for callers; consider capturing the exit code via if ! compare_versions ...; then or using a subshell to avoid mutating global shell options.
  • The update_script_from_remote function requires wget while fetch_latest_version uses curl; to avoid surprising runtime failures on systems with only one tool installed, consider using a single HTTP client (or a shared helper that tries both) for both version check and self-update.
  • The SCRIPT_VERSION constant was changed from 1.0.0 to 0.0.1, which will cause the update logic to treat this build as older than any existing 1.x release; double-check that this version downgrade is intentional and aligns with how remote versions are tagged.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `cmd_check_updates`, toggling `set +e`/`set -e` around `compare_versions` can unexpectedly change the shell’s errexit behavior for callers; consider capturing the exit code via `if ! compare_versions ...; then` or using a subshell to avoid mutating global shell options.
- The `update_script_from_remote` function requires `wget` while `fetch_latest_version` uses `curl`; to avoid surprising runtime failures on systems with only one tool installed, consider using a single HTTP client (or a shared helper that tries both) for both version check and self-update.
- The `SCRIPT_VERSION` constant was changed from `1.0.0` to `0.0.1`, which will cause the update logic to treat this build as older than any existing `1.x` release; double-check that this version downgrade is intentional and aligns with how remote versions are tagged.

## Individual Comments

### Comment 1
<location> `git_helpers/git-helper.sh:441-443` </location>
<code_context>
     return 0
   fi
+  
+  # Validate versions are in correct format
+  if ! [[ "$v1" =~ ^[0-9]+(\.[0-9]+)*$ ]] || ! [[ "$v2" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
+    return 1
+  fi
+  
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Returning `1` on invalid version format conflates "older" with "invalid"

The regex check now makes invalid version strings (e.g. `v1.2.3` or empty) return `1`, which the contract uses for `version1 < version2`. In `cmd_check_updates` this will look like "current version is older" and may spuriously prompt updates when the remote version is malformed. Please return a distinct status for invalid input and handle it explicitly at the call site, or reject malformed versions earlier in `fetch_latest_version`.

Suggested implementation:

```
  v1="${v1#"${v1%%[![:space:]]*}"}"
  v1="${v1%"${v1##*[![:space:]]}"}"
  v2="${v2#"${v2%%[![:space:]]*}"}"
  v2="${v2%"${v2##*[![:space:]]}"}"

  # Validate versions are in correct format; return distinct status for invalid input
  if ! [[ "$v1" =~ ^[0-9]+(\.[0-9]+)*$ ]] || ! [[ "$v2" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
    return 2
  fi

  if [[ "$v1" == "$v2" ]]; then
    return 0
  fi


```

To fully implement the change in behavior, the call sites of this version comparison function need to be updated:

1. In `cmd_check_updates` (or whichever function calls the version comparison), handle the new `2` status code explicitly as "invalid / malformed version" and **do not** treat it as "current version is older". For example:
   - On status `0`: versions equal → "up to date".
   - On status `1`: current version older → offer update.
   - On status `2`: log a warning about malformed local/remote version and skip update suggestion (or surface an error).
2. If there is a `fetch_latest_version` function that may return malformed versions, optionally add validation there too and fail early (e.g., return an empty string or an error) so that the compare function is not called with obviously bad input.
3. Update any tests or scripts that depend on the previous contract (`1` meaning only "older") to account for the new distinct error status.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +441 to +443
# Validate versions are in correct format
if ! [[ "$v1" =~ ^[0-9]+(\.[0-9]+)*$ ]] || ! [[ "$v2" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
return 1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Returning 1 on invalid version format conflates "older" with "invalid"

The regex check now makes invalid version strings (e.g. v1.2.3 or empty) return 1, which the contract uses for version1 < version2. In cmd_check_updates this will look like "current version is older" and may spuriously prompt updates when the remote version is malformed. Please return a distinct status for invalid input and handle it explicitly at the call site, or reject malformed versions earlier in fetch_latest_version.

Suggested implementation:

  v1="${v1#"${v1%%[![:space:]]*}"}"
  v1="${v1%"${v1##*[![:space:]]}"}"
  v2="${v2#"${v2%%[![:space:]]*}"}"
  v2="${v2%"${v2##*[![:space:]]}"}"

  # Validate versions are in correct format; return distinct status for invalid input
  if ! [[ "$v1" =~ ^[0-9]+(\.[0-9]+)*$ ]] || ! [[ "$v2" =~ ^[0-9]+(\.[0-9]+)*$ ]]; then
    return 2
  fi

  if [[ "$v1" == "$v2" ]]; then
    return 0
  fi


To fully implement the change in behavior, the call sites of this version comparison function need to be updated:

  1. In cmd_check_updates (or whichever function calls the version comparison), handle the new 2 status code explicitly as "invalid / malformed version" and do not treat it as "current version is older". For example:
    • On status 0: versions equal → "up to date".
    • On status 1: current version older → offer update.
    • On status 2: log a warning about malformed local/remote version and skip update suggestion (or surface an error).
  2. If there is a fetch_latest_version function that may return malformed versions, optionally add validation there too and fail early (e.g., return an empty string or an error) so that the compare function is not called with obviously bad input.
  3. Update any tests or scripts that depend on the previous contract (1 meaning only "older") to account for the new distinct error status.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant