Skip to content
Merged
140 changes: 140 additions & 0 deletions .github/scripts/issue_reminder_no_pr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#!/usr/bin/env bash
set -euo pipefail

# Env:
# GH_TOKEN - provided by GitHub Actions
# REPO - owner/repo (fallback to GITHUB_REPOSITORY)
# DAYS - reminder threshold in days (default 7)

REPO="${REPO:-${GITHUB_REPOSITORY:-}}"
DAYS="${DAYS:-7}"

if [ -z "$REPO" ]; then
echo "ERROR: REPO environment variable not set."
exit 1
fi

echo "------------------------------------------------------------"
echo " Issue Reminder Bot (No PR)"
echo " Repo: $REPO"
echo " Threshold: $DAYS days"
echo "------------------------------------------------------------"
echo

NOW_TS=$(date +%s)

# Cross-platform timestamp parsing (Linux + macOS/BSD)
parse_ts() {
local ts="$1"
if date --version >/dev/null 2>&1; then
date -d "$ts" +%s # GNU date (Linux)
else
date -j -f "%Y-%m-%dT%H:%M:%SZ" "$ts" +"%s" # macOS/BSD
fi
}

# Fetch open ISSUES (not PRs) that have assignees
ISSUES=$(gh api "repos/$REPO/issues" \
--paginate \
--jq '.[] | select(.state=="open" and (.assignees | length > 0) and (.pull_request | not)) | .number')

if [ -z "$ISSUES" ]; then
echo "No open issues with assignees found."
exit 0
fi

for ISSUE in $ISSUES; do
echo "============================================================"
echo " ISSUE #$ISSUE"
echo "============================================================"

ISSUE_JSON=$(gh api "repos/$REPO/issues/$ISSUE")
ASSIGNEES=$(echo "$ISSUE_JSON" | jq -r '.assignees[].login')

if [ -z "$ASSIGNEES" ]; then
echo "[INFO] No assignees? Skipping."
echo
continue
fi

echo "[INFO] Assignees: $ASSIGNEES"
echo

# Check if this issue already has a reminder comment from ReminderBot
EXISTING_COMMENT=$(gh api "repos/$REPO/issues/$ISSUE/comments" \
--jq ".[] | select(.user.login == \"github-actions[bot]\") | select(.body | contains(\"ReminderBot\")) | .id" \
| head -n1)

if [ -n "$EXISTING_COMMENT" ]; then
echo "[INFO] Reminder comment already posted on this issue."
echo
continue
fi

# Get assignment time (use the last assigned event or issue creation time)
ASSIGN_TS=$(gh api "repos/$REPO/issues/$ISSUE/events" \
--jq ".[] | select(.event==\"assigned\") | .created_at" \
| tail -n1)

if [ -z "$ASSIGN_TS" ]; then
echo "[WARN] No assignment event found, falling back to issue creation."
ASSIGN_TS=$(echo "$ISSUE_JSON" | jq -r '.created_at')
fi

ASSIGN_TS_SEC=$(parse_ts "$ASSIGN_TS")
DIFF_DAYS=$(( (NOW_TS - ASSIGN_TS_SEC) / 86400 ))

echo "[INFO] Assigned/Created at: $ASSIGN_TS"
echo "[INFO] Days since assignment: $DIFF_DAYS"

# Check if any open PRs are linked to this issue
PR_NUMBERS=$(gh api \
-H "Accept: application/vnd.github.mockingbird-preview+json" \
"repos/$REPO/issues/$ISSUE/timeline" \
--jq ".[]
| select(.event == \"cross-referenced\")
| select(.source.issue.pull_request != null)
| .source.issue.number" 2>/dev/null || true)

OPEN_PR_FOUND=""
if [ -n "$PR_NUMBERS" ]; then
for PR_NUM in $PR_NUMBERS; do
PR_STATE=$(gh pr view "$PR_NUM" --repo "$REPO" --json state --jq '.state' 2>/dev/null || true)
if [ "$PR_STATE" = "OPEN" ]; then
OPEN_PR_FOUND="$PR_NUM"
break
fi
done
fi

if [ -n "$OPEN_PR_FOUND" ]; then
echo "[KEEP] An OPEN PR #$OPEN_PR_FOUND is linked to this issue → skip reminder."
echo
continue
fi

echo "[RESULT] No OPEN PRs linked to this issue."

# Check if threshold has been reached
if [ "$DIFF_DAYS" -lt "$DAYS" ]; then
echo "[WAIT] Only $DIFF_DAYS days (< $DAYS) → not yet time for reminder."
echo
continue
fi

echo "[REMIND] Issue #$ISSUE assigned for $DIFF_DAYS days, posting reminder."

# Post reminder comment
MESSAGE="Hi, this is ReminderBot. This issue has been assigned but has had no pull request created. Are you still planning on working on the issue?

From the Python SDK Team"

gh issue comment "$ISSUE" --repo "$REPO" --body "$MESSAGE"

echo "[DONE] Posted reminder comment on issue #$ISSUE."
echo
done

echo "------------------------------------------------------------"
echo " Issue Reminder Bot (No PR) complete."
echo "------------------------------------------------------------"
31 changes: 31 additions & 0 deletions .github/workflows/bot-issue-reminder-no-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: bot-issue-reminder-no-pr

on:
schedule:
- cron: "0 10 * * *"
workflow_dispatch:

permissions:
contents: read
issues: write
pull-requests: read

jobs:
reminder:
runs-on: ubuntu-latest

steps:
- name: Harden the runner
uses: step-security/harden-runner@df199fb7be9f65074067a9eb93f12bb4c5547cf2
with:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@11bd71901afe3a2e8f79ce2a49e69702a58361bd

- name: Post reminder on assigned issues with no PRs
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
DAYS: 7
run: bash .github/scripts/issue_reminder_no_pr.sh
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
## [Unreleased]

### Added

- Modularized `transfer_transaction_fungible` example by introducing `account_balance_query()` & `transfer_transaction()`.Renamed `transfer_tokens()` → `main()`
- Phase 2 of the inactivity-unassign bot:Automatically detects stale open pull requests (no commit activity for 21+ days), comments with a helpful InactivityBot message, closes the stale PR, and unassigns the contributor from the linked issue.
- Added **str**() to CustomFixedFee and updated examples and tests accordingly.
Expand All @@ -19,11 +20,12 @@ This changelog is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.
- Made custom fraction fee end to end
- feat: AccountCreateTransaction now supports both PrivateKey and PublicKey [#939](https://github.com/hiero-ledger/hiero-sdk-python/issues/939)
- Added Acceptance Criteria section to Good First Issue template for better contributor guidance (#997)
- Added __str__() to CustomRoyaltyFee and updated examples and tests accordingly (#986)
- Added **str**() to CustomRoyaltyFee and updated examples and tests accordingly (#986)
- Restore bug and feature request issue templates (#996)(https://github.com/hiero-ledger/hiero-sdk-python/issues/996)
- Support selecting specific node account ID(s) for queries and transactions and added `Network._get_node()` with updated execution flow (#362)
- Add TLS support with two-stage control (`set_transport_security()` and `set_verify_certificates()`) for encrypted connections to Hedera networks. TLS is enabled by default for hosted networks (mainnet, testnet, previewnet) and disabled for local networks (solo, localhost) (#855)
- Add PR inactivity reminder bot for stale pull requests `.github/workflows/pr-inactivity-reminder-bot.yml`
- Added Issue Reminder (no-PR) bot, `.github/scripts/issue_reminder_no_pr.sh` and `.github/workflows/bot-issue-reminder-no-pr.yml` to automatically detect assigned issues with no linked pull requests for 7+ days and post a gentle ReminderBot comment.(#951)

### Changed

Expand Down