Skip to content
Closed
73 changes: 24 additions & 49 deletions .github/workflows/auto-update-precommit-hooks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.11"

Expand Down Expand Up @@ -142,29 +142,6 @@ jobs:

return None

def get_latest_commit_sha(repo_url: str, branch: str = 'HEAD') -> Optional[str]:
"""Fetch latest commit SHA from a repository."""
try:
match = re.search(r'github\.com/([^/]+)/(.+?)(?:\.git)?$', repo_url)
if not match:
return None

owner, repo = match.groups()

cmd = [
'gh', 'api', '--paginate',
f'repos/{owner}/{repo}/commits',
'-q', '.[0].sha'
]

result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0 and result.stdout.strip():
return result.stdout.strip()
except Exception as e:
print(f"Warning: Error fetching latest commit for {repo_url}: {e}")

return None

def resolve_sha_to_tag(repo_url: str, sha: str) -> Optional[str]:
"""Resolve a commit SHA to its tag, if one exists."""
try:
Expand Down Expand Up @@ -236,7 +213,8 @@ jobs:

print(f"Checking updates for: {repo_url}")

# Try to get latest release first
# Only check tagged releases (Dependabot behavior)
# Skips repositories without semantic versioning
release_info = get_latest_release(repo_url)

if release_info:
Expand Down Expand Up @@ -268,19 +246,9 @@ jobs:
})
print(f" Update available: {old_version} -> {latest_tag}")
else:
# Fall back to latest commit if no releases
latest_sha = get_latest_commit_sha(repo_url)
if latest_sha and latest_sha != current_sha:
print(f" Update available (commit): {current_sha[:7]} -> {latest_sha[:7]}")
updates.append({
'repo': repo_url,
'old_sha': current_sha,
'new_sha': latest_sha,
'old_version': current_sha[:7],
'new_version': latest_sha[:7],
'semver_level': 'patch', # Default to patch for commits
'commit_range': f'{current_sha}...{latest_sha}'
})
# No tagged releases found - skip this repo (Dependabot-aligned behavior)
# This ensures we only track semantic versioned hooks
print(f" ⊘ Skipped: No tagged releases found (only tagged versions are tracked, like Dependabot)")

# Output results
if updates:
Expand Down Expand Up @@ -312,7 +280,7 @@ jobs:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.11"

Expand Down Expand Up @@ -421,7 +389,7 @@ jobs:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.11"

Expand Down Expand Up @@ -539,7 +507,7 @@ jobs:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.11"

Expand Down Expand Up @@ -588,7 +556,7 @@ jobs:
with open('configs/precommit-update-tracking.json', 'r') as f:
tracking = json.load(f)
except FileNotFoundError:
tracking = {'last_updated': datetime.utcnow().isoformat() + 'Z', 'hooks': {}}
tracking = {'last_updated': datetime.now(timezone.utc).isoformat() + 'Z', 'hooks': {}}

# Create a mapping of repo URLs to new SHAs
update_map = {update['repo']: update for update in release_info}
Expand All @@ -606,19 +574,19 @@ jobs:
'current_sha': update['new_sha'],
'current_version': update['new_version'],
'semver_levels': {
'major': datetime.utcnow().isoformat() + 'Z',
'minor': datetime.utcnow().isoformat() + 'Z',
'patch': datetime.utcnow().isoformat() + 'Z'
'major': datetime.now(timezone.utc).isoformat() + 'Z',
'minor': datetime.now(timezone.utc).isoformat() + 'Z',
'patch': datetime.now(timezone.utc).isoformat() + 'Z'
}
}
else:
semver = update['semver_level']
tracking['hooks'][repo_url]['current_sha'] = update['new_sha']
tracking['hooks'][repo_url]['current_version'] = update['new_version']
if semver != 'unknown':
tracking['hooks'][repo_url]['semver_levels'][semver] = datetime.utcnow().isoformat() + 'Z'
tracking['hooks'][repo_url]['semver_levels'][semver] = datetime.now(timezone.utc).isoformat() + 'Z'

tracking['hooks'][repo_url]['last_updated'] = datetime.utcnow().isoformat() + 'Z'
tracking['hooks'][repo_url]['last_updated'] = datetime.now(timezone.utc).isoformat() + 'Z'

# Write updated files
with open('.pre-commit-config.yaml', 'w') as f:
Expand Down Expand Up @@ -743,7 +711,7 @@ jobs:
pr_body = generate_pr_body(release_info, skipped, cooldown_config)

# Create branch and commit
branch_name = f"chore/precommit-updates-{datetime.utcnow().strftime('%Y%m%d')}"
branch_name = f"chore/precommit-updates-{datetime.now(timezone.utc).strftime('%Y%m%d')}"

subprocess.run(['git', 'config', 'user.name', 'github-actions[bot]'], check=True)
subprocess.run(['git', 'config', 'user.email', '41898282+github-actions[bot]@users.noreply.github.com'], check=True)
Expand All @@ -753,8 +721,15 @@ jobs:
commit_msg = f"chore(pre-commit): auto-update hooks\n\nUpdated {len(release_info)} pre-commit hook(s)"
subprocess.run(['git', 'commit', '-m', commit_msg], check=True)

# Use GitHub CLI to authenticate git for pushing
# gh auth setup-git configures git to use gh's stored credentials
subprocess.run(['gh', 'auth', 'setup-git'], check=True)

# Push branch
subprocess.run(['git', 'push', '-u', 'origin', branch_name], check=True, env={**os.environ, 'GIT_TRACE': '1'})
subprocess.run(
['git', 'push', '--force-with-lease', '-u', 'origin', branch_name],
check=True
)

# Create PR using GitHub CLI
pr_result = subprocess.run(
Expand Down
23 changes: 13 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
repos:
- repo: https://github.com/zizmorcore/zizmor-pre-commit
rev: 451b56af716f9f0d0c2b816503a3fd0cf8b036fa # frozen: v1.29.0
hooks:
- id: zizmor
args: [--fix, --persona=pedantic]
- repo: https://github.com/compilerla/conventional-pre-commit
rev: 3db014c16a9d31997ab8c07a4d61fcce936c8f0d # frozen: v4.4.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]
- repo: https://github.com/zizmorcore/zizmor-pre-commit
rev: fa412071e4f5d44d44f9e365f4676f9df92456a2
hooks:
- id: zizmor
args:
- --fix
- --persona=pedantic
- repo: https://github.com/compilerla/conventional-pre-commit
rev: 91ab4bf57e58b32adf1a122681f6ebe164d081c8
hooks:
- id: conventional-pre-commit
stages:
- commit-msg
16 changes: 8 additions & 8 deletions configs/precommit-update-tracking.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,24 @@
"last_updated": "2026-09-10T00:00:00Z",
"hooks": {
"https://github.com/zizmorcore/zizmor-pre-commit": {
"last_updated": "2026-09-10T00:00:00Z",
"current_sha": "451b56af716f9f0d0c2b816503a3fd0cf8b036fa",
"current_version": "v1.29.0",
"last_updated": "2026-09-10T11:02:34.747610+00:00Z",
"current_sha": "fa412071e4f5d44d44f9e365f4676f9df92456a2",
"current_version": "v1.30.1",
"semver_levels": {
"major": "2026-09-10T00:00:00Z",
"minor": "2026-09-10T00:00:00Z",
"minor": "2026-09-10T11:02:34.747601+00:00Z",
"patch": "2026-09-10T00:00:00Z"
}
},
"https://github.com/compilerla/conventional-pre-commit": {
"last_updated": "2026-09-10T00:00:00Z",
"current_sha": "3db014c16a9d31997ab8c07a4d61fcce936c8f0d",
"last_updated": "2026-09-10T11:02:34.747616+00:00Z",
"current_sha": "91ab4bf57e58b32adf1a122681f6ebe164d081c8",
"current_version": "v4.4.0",
"semver_levels": {
"major": "2026-09-10T00:00:00Z",
"minor": "2026-09-10T00:00:00Z",
"patch": "2026-09-10T00:00:00Z"
"patch": "2026-09-10T11:02:34.747614+00:00Z"
}
}
}
}
}