Auto-update workflow for pre-commit hooks - #48
Conversation
- Introduced `configs/precommit-update-tracking.json` to track hook updates and semver levels. - Added `configs/precommit-updates-config.json` for workflow configuration, including cooldown periods and hooks to skip. - Created documentation on how to use the auto-update workflow, detailing manual and scheduled triggers, cooldown periods, and PR structure. - Developed a comprehensive reference for the auto-update workflow, outlining inputs, job outputs, and error handling.
… pre-commit hooks
| cooldown_major_days: | ||
| description: "Cooldown period for major version updates (days)" | ||
| required: false | ||
| default: "28" | ||
| type: string | ||
| cooldown_minor_days: | ||
| description: "Cooldown period for minor version updates (days)" | ||
| required: false | ||
| default: "14" | ||
| type: string | ||
| cooldown_patch_days: | ||
| description: "Cooldown period for patch version updates (days)" | ||
| required: false | ||
| default: "7" | ||
| type: string | ||
| skip_hooks: | ||
| description: "Comma-separated list of hook repo URLs to skip (e.g., https://github.com/owner/repo)" | ||
| required: false | ||
| default: "" | ||
| type: string | ||
| force_update: | ||
| description: "Bypass cooldown periods and update all eligible hooks" | ||
| required: false | ||
| default: false | ||
| type: boolean | ||
| schedule: | ||
| # Run weekly on Tuesday at 03:00 UTC |
There was a problem hiding this comment.
🟡 Changes recommended
Multiple runtime failures and release-validation flaws currently prevent safe, reliable operation.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds scheduled and manual automation for updating pre-commit hooks with cooldown tracking and generated pull requests.
Changes:
- Adds the auto-update workflow and configuration.
- Tracks hook versions and cooldown timestamps.
- Documents workflow operation and configuration.
File summaries
| File | Description |
|---|---|
.github/workflows/auto-update-precommit-hooks.yml |
Detects, filters, and proposes hook updates. |
configs/precommit-updates-config.json |
Defines update defaults and exclusions. |
configs/precommit-update-tracking.json |
Initializes hook update history. |
docs/how-to/use-auto-update-precommit-hooks-workflow.md |
Provides usage instructions. |
docs/reference/auto-update-precommit-hooks.md |
Documents the workflow contract. |
Review details
Suppressed comments (1)
.github/workflows/auto-update-precommit-hooks.yml:116
--paginateemits one selected SHA per API page, so repositories with more than one page of commits produce a newline-separated string rather than one SHA. That value is then written intorev. Fetch the requested branch/HEAD commit resource directly and return its single.sha.
# Try to get the latest release
cmd = [
'gh', 'api', '--paginate',
- Files reviewed: 5/5 changed files
- Comments generated: 17
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| @@ -0,0 +1,698 @@ | |||
| name: Auto-Update Pre-Commit Hooks | |||
…racking for pre-commit hooks
…re-commit updates
…just datetime handling to use timezone-aware objects
…r improved reliability
…mplify remote URL handling
…es and skip repos without tagged releases
…comment preservation
There was a problem hiding this comment.
🟡 Changes recommended
The workflow has security-significant cooldown flaws and several defects that prevent reliable triggering, release detection, and repeat execution.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (4)
.github/workflows/auto-update-precommit-hooks.yml:327
- This measures time since the repository's previous update, not the age of the candidate upstream release. Once the previous-update timer expires, a release published minutes ago is accepted immediately, so the advertised supply-chain cooldown provides no observation period for that release. Carry the release publication timestamp from detection and compare the configured cooldown against it.
hook_info = tracking.get('hooks', {}).get(repo, {})
last_updated = hook_info.get('semver_levels', {}).get(semver_level)
if last_updated:
last_updated_dt = datetime.fromisoformat(last_updated.replace('Z', '+00:00'))
.github/workflows/auto-update-precommit-hooks.yml:432
- This function ignores
old_shaandnew_shaand fetches the repository's newest commits instead, so the generated PR can list unrelated commits. Truncating here also makescommit_countat most 10, rendering the “and N more” path unreachable. Use the compare endpoint and let PR rendering perform the display truncation.
# Note: This is a simplified approach; ideally we'd use the commit comparison API
# For MVP, we'll just fetch recent commits
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
commits = result.stdout.strip().split('\n')
return commits[:10] # Return first 10 commits
docs/how-to/use-auto-update-precommit-hooks-workflow.md:228
- This relative link resolves to
docs/how-to/.pre-commit-config.yaml, which does not exist. Traverse back to the repository root as the reference page does.
- [.pre-commit-config.yaml](.pre-commit-config.yaml) — your repository's pre-commit hooks
.github/workflows/auto-update-precommit-hooks.yml:580
- The workflow never refreshes the top-level
last_updatedvalue before writing this file, so it remains at its initial timestamp after every generated update PR and no longer represents the documented “last workflow update.” Set it alongside the per-hook timestamps before serialization.
with open('configs/precommit-update-tracking.json', 'w') as f:
json.dump(tracking, f, indent=2)
- Files reviewed: 5/5 changed files
- Comments generated: 12
- Review effort level: Balanced
| name: Auto-Update Pre-Commit Hooks | ||
|
|
||
| on: | ||
| workflow_call: |
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| pip install ruamel.yaml |
| 'semver_levels': { | ||
| 'major': datetime.now(timezone.utc).isoformat() + 'Z', | ||
| 'minor': datetime.now(timezone.utc).isoformat() + 'Z', | ||
| 'patch': datetime.now(timezone.utc).isoformat() + 'Z' | ||
| } |
| if semver != 'unknown': | ||
| tracking['hooks'][repo_url]['semver_levels'][semver] = datetime.now(timezone.utc).isoformat() + 'Z' | ||
|
|
||
| tracking['hooks'][repo_url]['last_updated'] = datetime.now(timezone.utc).isoformat() + 'Z' |
| cmd = [ | ||
| 'gh', 'api', '--paginate', | ||
| f'repos/{owner}/{repo}/releases', | ||
| '-q', '.[0].tag_name' | ||
| ] |
| else: | ||
| # 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)") |
| pr_body = generate_pr_body(release_info, skipped, cooldown_config, force_update) | ||
|
|
||
| # Create branch and commit | ||
| branch_name = f"chore/precommit-updates-{datetime.now(timezone.utc).strftime('%Y%m%d')}" |
| "cooldown_days": { | ||
| "major": 28, | ||
| "minor": 14, | ||
| "patch": 7 | ||
| }, | ||
| "hooks_to_skip": [], |
| "patch": 7 | ||
| }, | ||
| "hooks_to_skip": [], | ||
| "enable_auto_updates": true |
| repo_url = repo_entry.get('repo') | ||
| if repo_url in update_map: | ||
| update = update_map[repo_url] | ||
| repo_entry['rev'] = update['new_sha'] |
Pull Request
Overview
The introduction of an auto-update workflow for pre-commit hooks streamlines the process of keeping hooks up-to-date, reducing manual intervention and ensuring timely updates based on semver levels.
What Changed
Validation
The workflow was tested by manually triggering updates and verifying that pull requests were created with the correct structure and information. All configurations were reviewed for accuracy.
Reviewer Notes
Consider potential risks associated with bypassing cooldown periods, which may increase exposure to supply chain attacks. Review the documentation for clarity and completeness. Follow-up work may include refining the workflow based on user feedback.