Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Provides reusable helpers sourced by scripts:
| `configure_gh_auth [scope_hint]` | Bridge GITHUB_TOKEN→GH_TOKEN or verify gh auth session |
| `validate_github_token [bearer]` | Verify GITHUB_TOKEN via /user endpoint |
| `validate_slug <value> <label>` | Reject values with non-alphanumeric/hyphen/underscore chars |
| `is_bsd_date` | Returns 0 if `date` is BSD-style (macOS), 1 for GNU (Linux); branch between `date -v` and `date -d` syntax |
| `gh_api <path> [--api-version V] [curl args...]` | Bearer-auth REST helper with 5-retry rate-limit handling; optional `--api-version` overrides the default `2022-11-28` header; returns literal `__404__` or `__422__` for those HTTP statuses — callers must check for these sentinels |
| `gh_api_paginate <path> [filter] [version]` | Paginated REST helper, follows Link headers, streams items; returns silently with empty output on 404/422 |
| `get_enterprise_orgs` | Three-tier enterprise org resolver (REST → GraphQL → /user/orgs) |
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ bats tests/test_common.bats

| File | What it covers |
|------|----------------|
| `tests/test_common.bats` | `lib/github-common.sh` — pure-logic functions (`validate_slug`, `require_env_var`, `require_command`, `err`, `configure_gh_auth`, `validate_token`, `get_repo_page_count`) and API helpers (`gh_api` sentinels, `gh_api_paginate`) |
| `tests/test_common.bats` | `lib/github-common.sh` — pure-logic functions (`validate_slug`, `require_env_var`, `require_command`, `err`, `configure_gh_auth`, `validate_token`, `get_repo_page_count`, `is_bsd_date`) and API helpers (`gh_api` sentinels, `gh_api_paginate`) |
| `tests/test_script_validation.bats` | Every script — missing required env vars exit 1, invalid CLI args exit 1, `--help` exits 0, script-specific enum/allowlist validation |
| `tests/mock_curl.sh` | Universal drop-in curl mock (used by both test files); response data via env vars `MOCK_CURL_CODE`, `MOCK_CURL_BODY`, `MOCK_CURL_LINK` |

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,7 @@ All scripts can leverage a shared utility library for common operations like val
- `validate_token <VAR_NAME> [bearer]` — Validate GitHub token by calling `/user` endpoint
- `validate_github_token [bearer]` — Convenience wrapper for `GITHUB_TOKEN` validation
- `validate_slug <value> <label>` — Exit if value contains characters other than alphanumeric, hyphen, or underscore
- `is_bsd_date` — Return 0 if the system `date` is BSD-style (macOS), 1 for GNU (Linux); use to branch between `date -v` and `date -d` syntax

**Auth helpers:**
- `configure_gh_auth [scope_hint]` — Bridge `GITHUB_TOKEN→GH_TOKEN` for scripts that use the `gh` CLI, or verify an active `gh` auth session if no token is set
Expand Down
10 changes: 10 additions & 0 deletions lib/github-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# validate_github_token [bearer] — verify GITHUB_TOKEN via /user endpoint
# validate_token <VAR_NAME> — verify a secondary token variable
# validate_slug <value> [label] — exit if value contains unsafe chars
# is_bsd_date — 0 if `date` is BSD-style (macOS), 1 for GNU (Linux)
# gh_api <path|url> [--api-version V] [curl args…] — Bearer-auth REST helper with retry;
# returns "__404__"/"__422__" (exit 0) for those codes
# gh_api_paginate <path> [filter] [version] — paginated REST, follows Link headers;
Expand Down Expand Up @@ -153,6 +154,15 @@ get_repo_page_count() {
echo "${pages:-1}"
}

###
## is_bsd_date
## Returns 0 if the system `date` is BSD-style (macOS), 1 for GNU (Linux).
## Use to branch between `date -v` and `date -d` syntax.
###
is_bsd_date() {
date -v-1d > /dev/null 2>&1
}

###
## validate_slug <value> <label>
## Exits with status 1 if the value contains characters other than
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ trap cleanup EXIT
###
calculate_cutoff_date() {
# Using 'date' compatible with both GNU (Linux) and BSD (macOS)
if date -v-1d > /dev/null 2>&1; then
if is_bsd_date; then
# BSD date (macOS)
CUTOFF_DATE=$(date -u -v-${YEARS_THRESHOLD}y +"%Y-%m-%dT%H:%M:%SZ")
else
Expand Down Expand Up @@ -98,7 +98,7 @@ fetch_old_repos() {

if [[ "$REPO_UPDATEDAT" < "$cutoff_date" ]]; then
local UPDATED_EPOCH CURRENT_EPOCH DAYS_SINCE
if date -v-1d > /dev/null 2>&1; then
if is_bsd_date; then
UPDATED_EPOCH=$(date -jf "%Y-%m-%dT%H:%M:%SZ" "$REPO_UPDATEDAT" +%s 2>/dev/null || echo "0")
else
UPDATED_EPOCH=$(date -d "$REPO_UPDATEDAT" +%s 2>/dev/null || echo "0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ _CURR_YEAR=$(date +%Y)
_CURR_MONTH=$(( 10#$(date +%m) )) # strip leading zero for arithmetic
_CURR_DAY=$(( 10#$(date +%d) ))

if date -v-1m +%Y >/dev/null 2>&1; then
if is_bsd_date; then
# BSD date (macOS)
_PREV_YEAR=$(date -v-1m +%Y)
_PREV_MONTH=$(( 10#$(date -v-1m +%m) ))
Expand Down
11 changes: 11 additions & 0 deletions tests/test_common.bats
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ _mock_curl() {
[ "$status" -eq 1 ]
}

# ─── is_bsd_date ──────────────────────────────────────────────────────────────

@test "is_bsd_date: matches whether 'date -v' is supported on this system" {
run bash -c "GITHUB_TOKEN=x source '${LIB_PATH}' 2>/dev/null; is_bsd_date"
if date -v-1d > /dev/null 2>&1; then
[ "$status" -eq 0 ]
else
[ "$status" -eq 1 ]
fi
}

# ─── require_env_var ──────────────────────────────────────────────────────────

@test "require_env_var: exits 1 when variable is unset" {
Expand Down