Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# .github/workflows/build.yml
name: Build Binaries

on:
push:
tags:
- "v*"
workflow_dispatch: # manual trigger
inputs:
version:
description: 'Version tag'
required: true
default: 'v1.0.4'
Comment on lines +7 to +12
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 22, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

For softprops/action-gh-release@v2, what tag is used by default on workflow_dispatch events, and is tag_name required to force a specific release tag?

💡 Result:

For softprops/action-gh-release@v2, the tag_name input defaults to github.ref_name [1][2][3]. When running via a workflow_dispatch event, github.ref_name corresponds to the branch or tag from which the workflow was triggered, which may not be a valid release tag [1][2][4]. Because the action requires a valid Git tag to create a GitHub Release, it will fail if the default github.ref_name is not a valid tag [4]. Therefore, while tag_name is technically optional in the action's configuration schema, it is effectively required for workflow_dispatch events to ensure the release is associated with a specific, valid tag [4]. To force a specific release tag, you must explicitly provide the desired tag to the tag_name input [3][5][6].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".github/workflows/build.yml"
if [ ! -f "$file" ]; then
  echo "Missing $file" >&2
  exit 1
fi

echo "== Top of file =="
sed -n '1,120p' "$file" | nl -ba -w2 -s': '

echo
echo "== Release step context =="
rg -n "Create GitHub Release|action-gh-release|softprops/action-gh-release" "$file" || true

Repository: PranavU-Coder/hubfetch

Length of output: 146


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".github/workflows/build.yml"
if [ ! -f "$file" ]; then
  echo "Missing $file" >&2
  exit 1
fi

echo "== Top of file =="
sed -n '1,120p' "$file" | nl -ba -w2 -s': '

echo
echo "== Release step context =="
rg -n "Create GitHub Release|action-gh-release|softprops/action-gh-release" "$file" || true

Repository: PranavU-Coder/hubfetch

Length of output: 146


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".github/workflows/build.yml"
[ -f "$file" ] || { echo "Missing $file" >&2; exit 1; }

echo "== workflow_dispatch block (lines ~1-60) =="
awk 'NR>=1 && NR<=60 {printf "%4d: %s\n", NR, $0}' "$file" | sed -n '1,60p'

echo
echo "== Release step + surrounding lines (search) =="
awk 'NR>=1 && NR<=120 {print NR ":" $0}' "$file" | rg -n "softprops/action-gh-release|Create GitHub Release|with:|tag_name|github\.event\.inputs\.version|workflow_dispatch" -n || true

Repository: PranavU-Coder/hubfetch

Length of output: 1768


🌐 Web query:

softprops/action-gh-release v2 tag_name must exist as git tag workflow_dispatch default github.ref_name branch

💡 Result:

The softprops/action-gh-release action (including v2) does not strictly require the tag_name to exist as a pre-existing Git tag in your repository before the action runs [1][2]. If you do not explicitly provide a tag_name, the action defaults to using github.ref_name [1][2]. When triggered by a workflow_dispatch or other events, github.ref_name will reflect the branch or tag name that triggered the workflow [1][2]. If you want to use this action to create a release based on a specific commit or branch, you can explicitly set the tag_name input [1][2]. Key considerations: 1. Tag Creation: If the tag_name provided does not exist as a Git reference, the action can still create a GitHub Release associated with the provided target_commitish (which defaults to the repository's default branch) [1][2]. 2. Workflow Triggers: When using workflow_dispatch, github.ref_name will typically be the branch from which the workflow was manually triggered. If you manually trigger the workflow on a branch, the action will use that branch name as the release tag_name unless you override it [1][2]. 3. Permissions: Ensure your job has the appropriate permissions (contents: write) to create releases, otherwise you may encounter a 403 error [3]. In summary, while the action is commonly used with Git tags (e.g., via on: push: tags:), it is flexible enough to create releases for arbitrary commit SHAs or branch names by explicitly defining the tag_name input [1][2].

Citations:


Use the workflow_dispatch version input for the release tag (tag_name)

.github/workflows/build.yml defines workflow_dispatch.inputs.version, but the “Create GitHub Release” step (softprops/action-gh-release@v2) never uses it; without tag_name, the action uses github.ref_name (typically the branch name for manual dispatch), so the created release tag won’t match the operator’s chosen version.

Proposed fix
       - name: Create GitHub Release
         uses: softprops/action-gh-release@v2
         with:
+          tag_name: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }}
           files: artifacts/*
           generate_release_notes: true
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 7 - 12, The workflow defines
workflow_dispatch.inputs.version but the release step
(softprops/action-gh-release@v2) doesn't use it, so the action falls back to
github.ref_name; update the release step to pass the user-provided input as the
tag by setting the action input tag_name to the dispatch input (use
github.event.inputs.version), e.g. add tag_name: ${{ github.event.inputs.version
}} (and optionally use the same input for name/release_name) so the created
release uses the chosen version.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@PranavU-Coder, glad you agree! When you're ready, you can apply the proposed fix to ensure the workflow_dispatch-triggered release uses the operator-supplied version instead of falling back to github.ref_name (the branch name):

       - name: Create GitHub Release
         uses: softprops/action-gh-release@v2
         with:
+          tag_name: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }}
           files: artifacts/*
           generate_release_notes: true

This way, both push-tag and manual dispatch workflows will correctly target the intended release tag.


jobs:
build:
Expand Down
6 changes: 3 additions & 3 deletions contrib/aur/PKGBUILD
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Mirror only. Canonical source: ssh://aur@aur.archlinux.org/hubfetch.git
# Maintainer: Pranav <your@email.com>
# Maintainer: Pranav pranavu8406@gmail.com
pkgname=hubfetch
pkgver=1.0.3
pkgver=1.0.4
pkgrel=1
pkgdesc="A CLI ricing tool designed to fetch GitHub user stats"
arch=('any')
Expand All @@ -10,7 +10,7 @@ license=('MIT')
depends=('python' 'python-click' 'python-requests' 'python-rich')
makedepends=('python-build' 'python-installer' 'python-wheel' 'python-hatchling')
source=("https://files.pythonhosted.org/packages/source/h/hubfetch/hubfetch-$pkgver.tar.gz")
sha256sums=('b9f7faece2cbc7d855bc4ef2d673a9b8e3abeb728d752c075069c5f01f322f72')
sha256sums=('fc737855e34d5c2d70290f261460cf41d6228d1d0c3fd374679517836ec8022e')

build() {
cd "hubfetch-$pkgver"
Expand Down
33 changes: 16 additions & 17 deletions contrib/homebrew/homebrew.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
# Mirror only. Canonical source: https://github.com/PranavU-Coder/homebrew-tap
class Hubfetch < Formula
include Language::Python::Virtualenv

desc "Python CLI tool to check GitHub stats via terminal"
homepage "https://github.com/PranavU-Coder/hubfetch"
url "https://files.pythonhosted.org/packages/b6/0e/64e95a784f2b90715a4242dd9d90cbcdabc2e74c528bb9c86baaae86c10a/hubfetch-1.0.3.tar.gz"
sha256 "b9f7faece2cbc7d855bc4ef2d673a9b8e3abeb728d752c075069c5f01f322f72"
url "https://files.pythonhosted.org/packages/df/7a/15d0b9767c9f36e15e20547c932ed8117b6bc7b17f176ee19e023ad02f2d/hubfetch-1.0.4.tar.gz"
sha256 "fc737855e34d5c2d70290f261460cf41d6228d1d0c3fd374679517836ec8022e"
license "MIT"

depends_on "python@3.14"

resource "certifi" do
url "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz"
sha256 "e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"
url "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz"
sha256 "69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d"
end

resource "charset-normalizer" do
Expand All @@ -21,18 +20,18 @@ class Hubfetch < Formula
end

resource "click" do
url "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz"
sha256 "12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a"
url "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz"
sha256 "918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96"
end

resource "idna" do
url "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz"
sha256 "795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"
url "https://files.pythonhosted.org/packages/1a/88/bcf9709822fe69d02c2a6a77956c98ce6ea8ca8767a9aadcedc7eb6a2390/idna-3.16.tar.gz"
sha256 "d7a6da03db833450fca25d2358ac9ff06cd624577a4aea3a596d5c0f77b8e03d"
end

resource "markdown-it-py" do
url "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz"
sha256 "cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"
url "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz"
sha256 "04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49"
end

resource "mdurl" do
Expand All @@ -46,18 +45,18 @@ class Hubfetch < Formula
end

resource "requests" do
url "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz"
sha256 "18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517"
url "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz"
sha256 "f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed"
end

resource "rich" do
url "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz"
sha256 "b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b"
url "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz"
sha256 "edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36"
end

resource "urllib3" do
url "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz"
sha256 "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"
url "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz"
sha256 "231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"
end

def install
Expand Down
6 changes: 3 additions & 3 deletions contrib/scoop/hubfetch.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"version": "1.0.3",
"version": "1.0.4",
"description": "CLI tool to fetch and visualize your GitHub stats in the terminal.",
"homepage": "https://github.com/PranavU-Coder/hubfetch",
"license": "MIT",
"notes": "Run 'hubfetch auth' to set up your GitHub Personal Access Token before first use.",
"url": "https://github.com/PranavU-Coder/hubfetch/releases/download/v1.0.3/hubfetch.exe",
"hash": "d06c4d19189ecd361151559901e75ba464c1fa5a973f56a18f282b71e6216f0e",
"url": "https://github.com/PranavU-Coder/hubfetch/releases/download/v1.0.4/hubfetch.exe",
"hash": "",
Comment thread
PranavU-Coder marked this conversation as resolved.
"bin": "hubfetch.exe",
"checkver": "github",
"autoupdate": {
Expand Down
9 changes: 2 additions & 7 deletions hubfetch/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,19 @@ def ensure_avatar(username: str, current_avatar_url: str) -> Path | None:
dest = avatar_path(username)
meta = _load_json(META_FILE)
now = datetime.now(timezone.utc).isoformat()
cached_url = meta.get("avatar_url")
last_checked_raw = meta.get("avatar_last_checked")

# first run
if not dest.exists() or not last_checked_raw:
if _download_avatar(current_avatar_url, dest):
meta.update({"avatar_url": current_avatar_url, "avatar_last_checked": now})
_save_json(META_FILE, meta)
return dest
return None

# within 6 hours, serve from disk
if not _is_stale(last_checked_raw, AVATAR_REFRESH):
return dest

# past 6 hours, re-download only if URL changed
if current_avatar_url != cached_url:
_download_avatar(current_avatar_url, dest)
# turns out GitHub avatar urls don't change so fuck this shit honestly
_download_avatar(current_avatar_url, dest)

meta.update({"avatar_url": current_avatar_url, "avatar_last_checked": now})
_save_json(META_FILE, meta)
Comment on lines +67 to 70
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 22, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle avatar download failure before advancing cache metadata.

If _download_avatar fails on Line 67, Lines 69-70 still mark the avatar as freshly checked. That suppresses retries for 6 hours and can leave stale/broken cache state.

Proposed fix
-    _download_avatar(current_avatar_url, dest)
-
-    meta.update({"avatar_url": current_avatar_url, "avatar_last_checked": now})
-    _save_json(META_FILE, meta)
+    if _download_avatar(current_avatar_url, dest):
+        meta.update({"avatar_url": current_avatar_url, "avatar_last_checked": now})
+        _save_json(META_FILE, meta)
+    else:
+        # Keep prior last_checked so next call retries sooner.
+        if not dest.exists():
+            return None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@hubfetch/cache.py` around lines 67 - 70, The code updates cache metadata
(meta.update and _save_json with META_FILE) immediately after calling
_download_avatar(current_avatar_url, dest), which means a failed download still
marks avatar_last_checked and suppresses retries; change this so the metadata is
only updated when _download_avatar succeeds: wrap the download call to detect
success (either by its return value or by catching exceptions from
_download_avatar), log or handle the failure without touching meta, and only
perform meta.update({"avatar_url": current_avatar_url, "avatar_last_checked":
now}) and _save_json(META_FILE, meta) when the download completed successfully
(referencing _download_avatar, meta.update, _save_json, META_FILE,
avatar_last_checked, current_avatar_url).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

will look into it

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@PranavU-Coder, sounds good! When you do, the proposed fix in the comment above should be a straightforward change — just gate the meta.update and _save_json calls on the return value of _download_avatar. Feel free to ping me if you have any questions. 🐇

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "hubfetch"
version = "1.0.3"
version = "1.0.4"
description = "A CLI ricing tool designed to fetch GitHub user stats"
readme = "README.md"
requires-python = ">=3.14"
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading